From 9b4abd2858ebfd1b663dcbdf525687f75967a4a8 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 7 Jan 2026 07:00:33 -0500 Subject: [PATCH 001/138] wip --- .changeset/empty-knives-walk.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/empty-knives-walk.md diff --git a/.changeset/empty-knives-walk.md b/.changeset/empty-knives-walk.md new file mode 100644 index 000000000..dbfa077b1 --- /dev/null +++ b/.changeset/empty-knives-walk.md @@ -0,0 +1,5 @@ +--- +'@fuzdev/fuz_css': minor +--- + +implement CSS literal classes From 73b6f72439f0a1ddb033527c242b02ef41acc9a0 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 7 Jan 2026 08:59:19 -0500 Subject: [PATCH 002/138] wip --- src/routes/docs/classes/+page.svelte | 667 +++++++++++++++------- src/routes/docs/introduction/+page.svelte | 13 +- src/routes/fuz.css | 3 - 3 files changed, 457 insertions(+), 226 deletions(-) diff --git a/src/routes/docs/classes/+page.svelte b/src/routes/docs/classes/+page.svelte index 58ea9bf97..91e3cf90e 100644 --- a/src/routes/docs/classes/+page.svelte +++ b/src/routes/docs/classes/+page.svelte @@ -6,237 +6,453 @@ import TomeSection from '@fuzdev/fuz_ui/TomeSection.svelte'; import TomeLink from '@fuzdev/fuz_ui/TomeLink.svelte'; - import UnfinishedImplementationWarning from '$routes/docs/UnfinishedImplementationWarning.svelte'; import ModuleLink from '$routes/ModuleLink.svelte'; const LIBRARY_ITEM_NAME = 'classes'; - const GLYPH_IDEA = '⌆'; // TODO from fuz_util, upstreamed from Zzz? + const GLYPH_IDEA = '⌆'; const tome = get_tome_by_name(LIBRARY_ITEM_NAME); - - // TODO show these with `Details` hiding their expanded set of values or something better (interpolated using this shorthand as the source of truth? isn't that complex) - - // TODO generate these from `$lib/css_classes.ts` - const style_utility_groups: Array<{group: string; items: Array}> = [ - { - group: 'Position and display', - items: [ - `position_static|relative|absolute|fixed|sticky|$globals`, - // TODO think about making `display_` bold, and making this more systematic in general - `display_none|contents|block|flow_root|inline|inline_block|run_in|list_item|inline_list_item|flex|inline_flex|grid|inline_grid|ruby|block_ruby|table|inline_table|$globals`, - `visibility_visible|hidden|collapse|$globals`, - `float_left|right|none|inline_start|inline_end|$globals`, - 'opacity_0-100', - 'overflow_auto|hidden|scroll|clip|visible', - 'overflow_x|y_auto|hidden|scroll|clip|visible', - `overflow_wrap_normal|anywhere|break_word|$globals`, - `scrollbar_width_auto|thin|none|$globals`, - `scrollbar_gutter_auto|stable|stable_both_edges|$globals`, - ], - }, - { - group: 'Flexbox and grid', - items: [ - 'flex_1', - 'flex_wrap_wrap|wrap_reverse|nowrap|$globals', - 'flex_direction_row|column|row_reverse|column_reverse|$globals', - 'flex_grow|shrink_1|0', - 'align_items_center|start|end|baseline|stretch', - 'align_content_center|start|end|baseline|space_between|space_around|space_evenly|stretch', - 'align_self_center|start|end|baseline|stretch', - 'justify_content_center|start|end|left|right|space_between|space_around|space_evenly|stretch', - 'justify_items_center|start|end|left|right|baseline|stretch', - 'justify_self_center|start|end|left|right|baseline|stretch', - ], - }, - { - group: 'Sizing and spacing', - items: [ - 'width|height_0|100|1px-3px|auto|max_content|min_content|fit_content|stretch', - 'width|height_xs5-xl15', - 'top|bottom|left|right_0|100|1px-3px|auto', - 'top|bottom|left|right_xs5-xl15', - 'inset_0|1px-3px|xs5-xl15', - 'p|pt|pr|pb|pl|px|py_xs5-xl15', - 'p|pt|pr|pb|pl|px|py_0|1px-3px', - 'pt|pr|pb|pl_100', - 'm|mt|mr|mb|ml|mx|my_xs5-xl15', - 'm|mt|mr|mb|ml|mx|my_0|1px-3px|auto', - 'mt|mr|mb|ml_100', - 'gap_xs5-xl15', - 'column|row_gap_xs5-xl15', - 'width_upto_xs-xl', // TODO rename? min/max? minned/maxxed? atmost/atleast? - 'width_atleast_xs-xl', - 'height_upto_xs-xl', - 'height_atleast_xs-xl', - ], - }, - { - group: 'Typography', - items: [ - 'font_family_sans|serif|mono', - 'line_height_xs-xl|0|1', - 'font_size_xs-xl9', - 'icon_size_xs-xl3', - 'text_align_start|end|left|right|center|justify|justify_all|match_parent', - 'vertical_align_baseline|sub|super|text_top|text_bottom|middle|top|bottom', - `word_break_normal|break_all|keep_all|$globals`, - 'white_space_normal|nowrap|pre|pre_wrap|pre_line|break_spaces', - `white_space_collapse_collapse|preserve|preserve_breaks|preserve_spaces|break_spaces|$globals`, - 'text_wrap_wrap|nowrap|balance|pretty|stable', - `user_select_none|auto|text|all|$globals`, - 'font_weight_100-900', - 'ellipsis', - ], - }, - { - group: 'Colors', - items: [ - 'text_color_0-10', - 'darken|lighten_1-9', - 'bg|fg', - 'bg|fg_1-9', - 'color_darken|lighten_1-9', - 'color_bg|fg', - 'color_bg|fg_1-9', - 'hue_a-j', - 'color_a-j_1-9', - 'bg_a-j_1-9', - ], - }, - { - group: 'Borders and outlines', - items: [ - 'border_color_1-5', // TODO change this - 'border_color_a-j', - 'border_color_transparent', - 'border_width_0-9', - 'outline_width_0|focused|active', - `border_style_none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset|$globals`, - 'border_radius_xs3-xl', - 'border_radius_0-100', - 'border_top|bottom_left|right_radius_xs3-xl', - 'border_top|bottom_left|right_radius_0-100', - ], - }, - { - group: 'Shadows', - items: [ - 'shadow_xs-xl', - 'shadow_top|bottom_xs-xl', - 'shadow_inset_xs-xl', - 'shadow_inset_top|bottom_xs-xl', - 'shadow_color_highlight|glow|shroud', - 'shadow_color_a-j', - 'shadow_alpha_1-5', - 'shadow_inherit|none', - ], - }, - { - group: 'Transforms and visual effects', - items: ['flip_x|y|xy', 'pixelated'], - }, - { - group: 'Composite classes', - items: [ - 'box', - 'column', - 'row', - 'formatted', - 'selected', - 'selectable', - 'clickable', - 'pane', - 'panel', - 'icon_button', - 'plain', - 'menu_item', - 'chevron', - 'chip', - ], - }, - ]; - - // TODO extract a `GithubLink` like `MdnLink` - - Both the docs and implementation of these need a lot more work. - - -

Fuz CSS has three CSS files, two of which are required:

- -${'<' as string}script> - import '@fuzdev/fuz_css/style.css'; // required - import '@fuzdev/fuz_css/theme.css'; // required, can bring your own - import '$routes/fuz.css'; // optional, generated by \`gen_fuz_css\` - // ... -`} - /> + +

Fuz CSS provides three types of classes:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
TypeExamplePurpose
token classes.p_md, .color_a_5, .gap_lgmap to style variables (CSS custom properties)
composite classes.box, .row, .ellipsismulti-property shortcuts
literal classes.display:flex, .hover:opacity:80%arbitrary CSS property:value pairs

- The fuz.css file is created on demand with the utility classes that your code - uses, if any. For now it requires Gro to - generate it, but it isn't hard to make your own integration using the helpers - gen_fuz_css.ts. I can add a Vite plugin if - there's demand. + Token classes are the primary choice for spacing, colors, and sizes - they + ensure consistency with the design system. Composite classes provide + shortcuts for repeated patterns. Literal classes are an escape hatch for arbitrary + CSS, especially useful for cross-component styling and responsive/state modifiers.

+ + + +

+ Token classes map to style variables. They use + underscore syntax because they're shorthand for design tokens, so they have consistent + casing in both JS and CSS: +

+ +

Spacing

+
    +
  • .p|pt|pr|pb|pl|px|py_xs5-xl15
  • +
  • .m|mt|mr|mb|ml|mx|my_xs5-xl15
  • +
  • .gap|column_gap|row_gap_xs5-xl15
  • +
  • .top|bottom|left|right_xs5-xl15
  • +
  • .inset_xs5-xl15
  • +
+

Sizing

+
    +
  • .width|height_xs5-xl15
  • +
  • .width_upto|atleast_xs-xl
  • +
  • .height_upto|atleast_xs-xl
  • +
+

Colors

+
    +
  • .color_a-j_1-9
  • +
  • .bg|fg_1-9
  • +
  • .bg_a-j_1-9
  • +
  • .text_color_0-10
  • +
  • .darken|lighten_1-9
  • +
  • .hue_a-j
  • +
+

Typography

+
    +
  • .font_family_sans|serif|mono
  • +
  • .font_size_xs-xl9
  • +
  • .line_height_xs-xl
  • +
  • .icon_size_xs-xl3
  • +
+

Borders

+
    +
  • .border_color_1-5
  • +
  • .border_color_a-j
  • +
  • .border_width_0-9
  • +
  • .border_radius_xs3-xl
  • +
  • .outline_width_0|focused|active
  • +
+

Shadows

+
    +
  • .shadow_xs-xl
  • +
  • .shadow_inset_xs-xl
  • +
  • .shadow_color_a-j
  • +
  • .shadow_alpha_1-5
  • +
+
+ + + +

Multi-property shortcuts for repeated patterns. Define your own in a composites file:

+ +

Built-in composites:

+
    +
  • .box - centered flex container
  • +
  • .row - horizontal flex row
  • +
  • .column - vertical flex column
  • +
  • .formatted - formatted text block
  • +
  • .ellipsis - text overflow ellipsis
  • +
  • .selected - selected state styling
  • +
  • .selectable - selectable element styling
  • +
  • .clickable - clickable element styling
  • +
  • .pane - pane container
  • +
  • .panel - panel container
  • +
  • .icon_button - icon button styling
  • +
  • .plain - plain/reset styling
  • +
  • .menu_item - menu item styling
  • +
  • .chevron - chevron indicator
  • +
  • .chip - chip/tag styling
  • +
+
+ + + +

+ Fuz supports CSS-literal syntax: property:value. +

+
    +
  • + similar to Tailwind but more verbose, nudging you toward Svelte's <style> tags +
  • +
  • enables composition across component boundaries
  • +
  • + more power than inline style attributes (modifiers for hover, responsive, dark + mode) +
  • +
+ +
+ + +
+ + +
+ + +
`} + /> +

+ The ~ character represents a space in class names (since CSS classes can't + contain spaces). Use it for multi-value properties like margin:0~auto. +

+ + +

Common patterns

+

Layout and display:

+
    +
  • .display:none|block|flex|grid|inline|inline-block|contents
  • +
  • .position:static|relative|absolute|fixed|sticky
  • +
  • .visibility:visible|hidden|collapse
  • +
  • .overflow:auto|hidden|scroll|clip|visible
  • +
+

Flexbox and grid:

+
    +
  • .flex-direction:row|column|row-reverse|column-reverse
  • +
  • .flex-wrap:wrap|nowrap|wrap-reverse
  • +
  • .align-items:center|start|end|baseline|stretch
  • +
  • + .justify-content:center|start|end|space-between|space-around|space-evenly +
  • +
  • .flex:1, .flex-grow:1|0, .flex-shrink:1|0
  • +
+

Typography:

+
    +
  • .text-align:left|center|right|justify
  • +
  • .white-space:normal|nowrap|pre|pre-wrap|pre-line
  • +
  • .word-break:normal|break-all|keep-all
  • +
  • .text-wrap:wrap|nowrap|balance|pretty
  • +
  • .user-select:none|auto|text|all
  • +
+

Borders and effects:

+
    +
  • .border-style:none|solid|dashed|dotted
  • +
  • .float:left|right|none
  • +
  • .cursor:pointer|default|grab|text|not-allowed
  • +
  • .pointer-events:none|auto
  • +
+ + - + +

+ Modifiers wrap CSS in conditions. This is what makes utility classes more powerful than inline + styles - you can apply styles based on viewport, state, or color scheme. +

+ +

Responsive modifiers

+

Mobile-first breakpoints:

+ + + + + + + + + + + + + + + +
PrefixWidthCSS
sm:40rem (640px)@media (width >= 40rem)
md:48rem (768px)@media (width >= 48rem)
lg:64rem (1024px)@media (width >= 64rem)
xl:80rem (1280px)@media (width >= 80rem)
2xl:96rem (1536px)@media (width >= 96rem)
+ +
+ + +
...`} /> - +

@@ -148,12 +148,12 @@

-
diff --git a/src/routes/docs/colors/+page.svelte b/src/routes/docs/colors/+page.svelte index da09f0b2c..09113739b 100644 --- a/src/routes/docs/colors/+page.svelte +++ b/src/routes/docs/colors/+page.svelte @@ -136,7 +136,7 @@ {/each} -
+
diff --git a/src/routes/docs/elements/+page.svelte b/src/routes/docs/elements/+page.svelte index 24b98c4a3..7fe395d47 100644 --- a/src/routes/docs/elements/+page.svelte +++ b/src/routes/docs/elements/+page.svelte @@ -244,8 +244,8 @@ tdtdtd - \n\t...\n`} /> - + \n\t...\n
`} /> + diff --git a/src/routes/docs/forms/+page.svelte b/src/routes/docs/forms/+page.svelte index b8773de9a..217c98dc5 100644 --- a/src/routes/docs/forms/+page.svelte +++ b/src/routes/docs/forms/+page.svelte @@ -109,7 +109,7 @@ out:fly={{y: 100, duration: ANIMATION_DURATION_FAST}} > cannot create account because the docs are fake - diff --git a/src/routes/docs/shading/+page.svelte b/src/routes/docs/shading/+page.svelte index 69a4c2281..476e8d6fd 100644 --- a/src/routes/docs/shading/+page.svelte +++ b/src/routes/docs/shading/+page.svelte @@ -193,7 +193,7 @@
{#each opacity_classes as opacity_class (opacity_class)}
-
+
.{opacity_class}
{/each} diff --git a/src/routes/fuz.css b/src/routes/fuz.css index 877d13c73..eb37229a7 100644 --- a/src/routes/fuz.css +++ b/src/routes/fuz.css @@ -436,21 +436,6 @@ a.chip { .shadow_alpha_5 { --shadow_alpha: var(--shadow_alpha_5); } -.width_100 { - width: 100%; -} -.height_100 { - height: 100%; -} -.top_0 { - top: 0; -} -.right_0 { - right: 0; -} -.inset_0 { - inset: 0; -} .p_sm { padding: var(--space_sm); } @@ -650,6 +635,9 @@ a.chip { .font-weight\:950 { font-weight: 950; } +.inset\:0 { + inset: 0; +} .opacity\:0 { opacity: 0; } @@ -683,5 +671,8 @@ a.chip { .white-space\:nowrap { white-space: nowrap; } +.width\:100\% { + width: 100%; +} /* generated by src/routes/fuz.gen.css.ts */ diff --git a/src/routes/library.json b/src/routes/library.json index 338b5aa6f..5b5fea5dd 100644 --- a/src/routes/library.json +++ b/src/routes/library.json @@ -288,7 +288,7 @@ "kind": "variable", "doc_comment": "All built-in CSS class definitions (token classes + composites).", "see_also": ["`generate_classes_css`"], - "source_line": 44, + "source_line": 43, "type_signature": "Record" } ], @@ -2256,7 +2256,7 @@ { "name": "ModifierType", "kind": "type", - "doc_comment": "Type of modifier determining its position in the class name and CSS output.\n\nOrder in class names: `[media]:[ancestor]:[state...]:[pseudo-element]:property:value`", + "doc_comment": "Type of modifier determining its position in the class name and CSS output.\n\nOrder in class names: `[media:][ancestor:][state...:][pseudo-element:]property:value`", "source_line": 19, "type_signature": "ModifierType" }, diff --git a/src/test/fixtures/css_classes_fixture.json b/src/test/fixtures/css_classes_fixture.json index 018cddd52..f39a3aaae 100644 --- a/src/test/fixtures/css_classes_fixture.json +++ b/src/test/fixtures/css_classes_fixture.json @@ -75,8 +75,6 @@ "font_family_sans": {"declaration": "font-family: var(--font_family_sans);"}, "font_family_serif": {"declaration": "font-family: var(--font_family_serif);"}, "font_family_mono": {"declaration": "font-family: var(--font_family_mono);"}, - "line_height_0": {"declaration": "line-height: 0;"}, - "line_height_1": {"declaration": "line-height: 1;"}, "line_height_xs": {"declaration": "line-height: var(--line_height_xs);"}, "line_height_sm": {"declaration": "line-height: var(--line_height_sm);"}, "line_height_md": {"declaration": "line-height: var(--line_height_md);"}, @@ -449,7 +447,6 @@ "outline_color_h": {"declaration": "outline-color: var(--border_color_h);"}, "outline_color_i": {"declaration": "outline-color: var(--border_color_i);"}, "outline_color_j": {"declaration": "outline-color: var(--border_color_j);"}, - "border_width_0": {"declaration": "border-width: 0;"}, "border_width_1": {"declaration": "border-width: var(--border_width_1);"}, "border_width_2": {"declaration": "border-width: var(--border_width_2);"}, "border_width_3": {"declaration": "border-width: var(--border_width_3);"}, @@ -459,7 +456,6 @@ "border_width_7": {"declaration": "border-width: var(--border_width_7);"}, "border_width_8": {"declaration": "border-width: var(--border_width_8);"}, "border_width_9": {"declaration": "border-width: var(--border_width_9);"}, - "outline_width_0": {"declaration": "outline-width: 0;"}, "outline_width_1": {"declaration": "outline-width: var(--border_width_1);"}, "outline_width_2": {"declaration": "outline-width: var(--border_width_2);"}, "outline_width_3": {"declaration": "outline-width: var(--border_width_3);"}, @@ -660,16 +656,6 @@ "shadow_alpha_3": {"declaration": "--shadow_alpha: var(--shadow_alpha_3);"}, "shadow_alpha_4": {"declaration": "--shadow_alpha: var(--shadow_alpha_4);"}, "shadow_alpha_5": {"declaration": "--shadow_alpha: var(--shadow_alpha_5);"}, - "width_0": {"declaration": "width: 0;"}, - "width_100": {"declaration": "width: 100%;"}, - "width_1px": {"declaration": "width: 1px;"}, - "width_2px": {"declaration": "width: 2px;"}, - "width_3px": {"declaration": "width: 3px;"}, - "width_auto": {"declaration": "width: auto;"}, - "width_max_content": {"declaration": "width: max-content;"}, - "width_min_content": {"declaration": "width: min-content;"}, - "width_fit_content": {"declaration": "width: fit-content;"}, - "width_stretch": {"declaration": "width: stretch;"}, "width_xs5": {"declaration": "width: var(--space_xs5);"}, "width_xs4": {"declaration": "width: var(--space_xs4);"}, "width_xs3": {"declaration": "width: var(--space_xs3);"}, @@ -693,16 +679,6 @@ "width_xl13": {"declaration": "width: var(--space_xl13);"}, "width_xl14": {"declaration": "width: var(--space_xl14);"}, "width_xl15": {"declaration": "width: var(--space_xl15);"}, - "height_0": {"declaration": "height: 0;"}, - "height_100": {"declaration": "height: 100%;"}, - "height_1px": {"declaration": "height: 1px;"}, - "height_2px": {"declaration": "height: 2px;"}, - "height_3px": {"declaration": "height: 3px;"}, - "height_auto": {"declaration": "height: auto;"}, - "height_max_content": {"declaration": "height: max-content;"}, - "height_min_content": {"declaration": "height: min-content;"}, - "height_fit_content": {"declaration": "height: fit-content;"}, - "height_stretch": {"declaration": "height: stretch;"}, "height_xs5": {"declaration": "height: var(--space_xs5);"}, "height_xs4": {"declaration": "height: var(--space_xs4);"}, "height_xs3": {"declaration": "height: var(--space_xs3);"}, @@ -726,12 +702,6 @@ "height_xl13": {"declaration": "height: var(--space_xl13);"}, "height_xl14": {"declaration": "height: var(--space_xl14);"}, "height_xl15": {"declaration": "height: var(--space_xl15);"}, - "top_0": {"declaration": "top: 0;"}, - "top_100": {"declaration": "top: 100%;"}, - "top_1px": {"declaration": "top: 1px;"}, - "top_2px": {"declaration": "top: 2px;"}, - "top_3px": {"declaration": "top: 3px;"}, - "top_auto": {"declaration": "top: auto;"}, "top_xs5": {"declaration": "top: var(--space_xs5);"}, "top_xs4": {"declaration": "top: var(--space_xs4);"}, "top_xs3": {"declaration": "top: var(--space_xs3);"}, @@ -755,12 +725,6 @@ "top_xl13": {"declaration": "top: var(--space_xl13);"}, "top_xl14": {"declaration": "top: var(--space_xl14);"}, "top_xl15": {"declaration": "top: var(--space_xl15);"}, - "right_0": {"declaration": "right: 0;"}, - "right_100": {"declaration": "right: 100%;"}, - "right_1px": {"declaration": "right: 1px;"}, - "right_2px": {"declaration": "right: 2px;"}, - "right_3px": {"declaration": "right: 3px;"}, - "right_auto": {"declaration": "right: auto;"}, "right_xs5": {"declaration": "right: var(--space_xs5);"}, "right_xs4": {"declaration": "right: var(--space_xs4);"}, "right_xs3": {"declaration": "right: var(--space_xs3);"}, @@ -784,12 +748,6 @@ "right_xl13": {"declaration": "right: var(--space_xl13);"}, "right_xl14": {"declaration": "right: var(--space_xl14);"}, "right_xl15": {"declaration": "right: var(--space_xl15);"}, - "bottom_0": {"declaration": "bottom: 0;"}, - "bottom_100": {"declaration": "bottom: 100%;"}, - "bottom_1px": {"declaration": "bottom: 1px;"}, - "bottom_2px": {"declaration": "bottom: 2px;"}, - "bottom_3px": {"declaration": "bottom: 3px;"}, - "bottom_auto": {"declaration": "bottom: auto;"}, "bottom_xs5": {"declaration": "bottom: var(--space_xs5);"}, "bottom_xs4": {"declaration": "bottom: var(--space_xs4);"}, "bottom_xs3": {"declaration": "bottom: var(--space_xs3);"}, @@ -813,12 +771,6 @@ "bottom_xl13": {"declaration": "bottom: var(--space_xl13);"}, "bottom_xl14": {"declaration": "bottom: var(--space_xl14);"}, "bottom_xl15": {"declaration": "bottom: var(--space_xl15);"}, - "left_0": {"declaration": "left: 0;"}, - "left_100": {"declaration": "left: 100%;"}, - "left_1px": {"declaration": "left: 1px;"}, - "left_2px": {"declaration": "left: 2px;"}, - "left_3px": {"declaration": "left: 3px;"}, - "left_auto": {"declaration": "left: auto;"}, "left_xs5": {"declaration": "left: var(--space_xs5);"}, "left_xs4": {"declaration": "left: var(--space_xs4);"}, "left_xs3": {"declaration": "left: var(--space_xs3);"}, @@ -842,12 +794,6 @@ "left_xl13": {"declaration": "left: var(--space_xl13);"}, "left_xl14": {"declaration": "left: var(--space_xl14);"}, "left_xl15": {"declaration": "left: var(--space_xl15);"}, - "inset_0": {"declaration": "inset: 0;"}, - "inset_100": {"declaration": "inset: 100%;"}, - "inset_1px": {"declaration": "inset: 1px;"}, - "inset_2px": {"declaration": "inset: 2px;"}, - "inset_3px": {"declaration": "inset: 3px;"}, - "inset_auto": {"declaration": "inset: auto;"}, "inset_xs5": {"declaration": "inset: var(--space_xs5);"}, "inset_xs4": {"declaration": "inset: var(--space_xs4);"}, "inset_xs3": {"declaration": "inset: var(--space_xs3);"}, @@ -872,10 +818,6 @@ "inset_xl14": {"declaration": "inset: var(--space_xl14);"}, "inset_xl15": {"declaration": "inset: var(--space_xl15);"}, "p_0": {"declaration": "padding: 0;"}, - "p_100": {"declaration": "padding: 100%;"}, - "p_1px": {"declaration": "padding: 1px;"}, - "p_2px": {"declaration": "padding: 2px;"}, - "p_3px": {"declaration": "padding: 3px;"}, "p_xs5": {"declaration": "padding: var(--space_xs5);"}, "p_xs4": {"declaration": "padding: var(--space_xs4);"}, "p_xs3": {"declaration": "padding: var(--space_xs3);"}, @@ -900,10 +842,6 @@ "p_xl14": {"declaration": "padding: var(--space_xl14);"}, "p_xl15": {"declaration": "padding: var(--space_xl15);"}, "pt_0": {"declaration": "padding-top: 0;"}, - "pt_100": {"declaration": "padding-top: 100%;"}, - "pt_1px": {"declaration": "padding-top: 1px;"}, - "pt_2px": {"declaration": "padding-top: 2px;"}, - "pt_3px": {"declaration": "padding-top: 3px;"}, "pt_xs5": {"declaration": "padding-top: var(--space_xs5);"}, "pt_xs4": {"declaration": "padding-top: var(--space_xs4);"}, "pt_xs3": {"declaration": "padding-top: var(--space_xs3);"}, @@ -928,10 +866,6 @@ "pt_xl14": {"declaration": "padding-top: var(--space_xl14);"}, "pt_xl15": {"declaration": "padding-top: var(--space_xl15);"}, "pr_0": {"declaration": "padding-right: 0;"}, - "pr_100": {"declaration": "padding-right: 100%;"}, - "pr_1px": {"declaration": "padding-right: 1px;"}, - "pr_2px": {"declaration": "padding-right: 2px;"}, - "pr_3px": {"declaration": "padding-right: 3px;"}, "pr_xs5": {"declaration": "padding-right: var(--space_xs5);"}, "pr_xs4": {"declaration": "padding-right: var(--space_xs4);"}, "pr_xs3": {"declaration": "padding-right: var(--space_xs3);"}, @@ -956,10 +890,6 @@ "pr_xl14": {"declaration": "padding-right: var(--space_xl14);"}, "pr_xl15": {"declaration": "padding-right: var(--space_xl15);"}, "pb_0": {"declaration": "padding-bottom: 0;"}, - "pb_100": {"declaration": "padding-bottom: 100%;"}, - "pb_1px": {"declaration": "padding-bottom: 1px;"}, - "pb_2px": {"declaration": "padding-bottom: 2px;"}, - "pb_3px": {"declaration": "padding-bottom: 3px;"}, "pb_xs5": {"declaration": "padding-bottom: var(--space_xs5);"}, "pb_xs4": {"declaration": "padding-bottom: var(--space_xs4);"}, "pb_xs3": {"declaration": "padding-bottom: var(--space_xs3);"}, @@ -984,10 +914,6 @@ "pb_xl14": {"declaration": "padding-bottom: var(--space_xl14);"}, "pb_xl15": {"declaration": "padding-bottom: var(--space_xl15);"}, "pl_0": {"declaration": "padding-left: 0;"}, - "pl_100": {"declaration": "padding-left: 100%;"}, - "pl_1px": {"declaration": "padding-left: 1px;"}, - "pl_2px": {"declaration": "padding-left: 2px;"}, - "pl_3px": {"declaration": "padding-left: 3px;"}, "pl_xs5": {"declaration": "padding-left: var(--space_xs5);"}, "pl_xs4": {"declaration": "padding-left: var(--space_xs4);"}, "pl_xs3": {"declaration": "padding-left: var(--space_xs3);"}, @@ -1012,10 +938,6 @@ "pl_xl14": {"declaration": "padding-left: var(--space_xl14);"}, "pl_xl15": {"declaration": "padding-left: var(--space_xl15);"}, "px_0": {"declaration": "padding-left: 0;\tpadding-right: 0;"}, - "px_100": {"declaration": "padding-left: 100%;\tpadding-right: 100%;"}, - "px_1px": {"declaration": "padding-left: 1px;\tpadding-right: 1px;"}, - "px_2px": {"declaration": "padding-left: 2px;\tpadding-right: 2px;"}, - "px_3px": {"declaration": "padding-left: 3px;\tpadding-right: 3px;"}, "px_xs5": {"declaration": "padding-left: var(--space_xs5);\tpadding-right: var(--space_xs5);"}, "px_xs4": {"declaration": "padding-left: var(--space_xs4);\tpadding-right: var(--space_xs4);"}, "px_xs3": {"declaration": "padding-left: var(--space_xs3);\tpadding-right: var(--space_xs3);"}, @@ -1040,10 +962,6 @@ "px_xl14": {"declaration": "padding-left: var(--space_xl14);\tpadding-right: var(--space_xl14);"}, "px_xl15": {"declaration": "padding-left: var(--space_xl15);\tpadding-right: var(--space_xl15);"}, "py_0": {"declaration": "padding-top: 0;\tpadding-bottom: 0;"}, - "py_100": {"declaration": "padding-top: 100%;\tpadding-bottom: 100%;"}, - "py_1px": {"declaration": "padding-top: 1px;\tpadding-bottom: 1px;"}, - "py_2px": {"declaration": "padding-top: 2px;\tpadding-bottom: 2px;"}, - "py_3px": {"declaration": "padding-top: 3px;\tpadding-bottom: 3px;"}, "py_xs5": {"declaration": "padding-top: var(--space_xs5);\tpadding-bottom: var(--space_xs5);"}, "py_xs4": {"declaration": "padding-top: var(--space_xs4);\tpadding-bottom: var(--space_xs4);"}, "py_xs3": {"declaration": "padding-top: var(--space_xs3);\tpadding-bottom: var(--space_xs3);"}, @@ -1068,10 +986,6 @@ "py_xl14": {"declaration": "padding-top: var(--space_xl14);\tpadding-bottom: var(--space_xl14);"}, "py_xl15": {"declaration": "padding-top: var(--space_xl15);\tpadding-bottom: var(--space_xl15);"}, "m_0": {"declaration": "margin: 0;"}, - "m_100": {"declaration": "margin: 100%;"}, - "m_1px": {"declaration": "margin: 1px;"}, - "m_2px": {"declaration": "margin: 2px;"}, - "m_3px": {"declaration": "margin: 3px;"}, "m_auto": {"declaration": "margin: auto;"}, "m_xs5": {"declaration": "margin: var(--space_xs5);"}, "m_xs4": {"declaration": "margin: var(--space_xs4);"}, @@ -1097,10 +1011,6 @@ "m_xl14": {"declaration": "margin: var(--space_xl14);"}, "m_xl15": {"declaration": "margin: var(--space_xl15);"}, "mt_0": {"declaration": "margin-top: 0;"}, - "mt_100": {"declaration": "margin-top: 100%;"}, - "mt_1px": {"declaration": "margin-top: 1px;"}, - "mt_2px": {"declaration": "margin-top: 2px;"}, - "mt_3px": {"declaration": "margin-top: 3px;"}, "mt_auto": {"declaration": "margin-top: auto;"}, "mt_xs5": {"declaration": "margin-top: var(--space_xs5);"}, "mt_xs4": {"declaration": "margin-top: var(--space_xs4);"}, @@ -1126,10 +1036,6 @@ "mt_xl14": {"declaration": "margin-top: var(--space_xl14);"}, "mt_xl15": {"declaration": "margin-top: var(--space_xl15);"}, "mr_0": {"declaration": "margin-right: 0;"}, - "mr_100": {"declaration": "margin-right: 100%;"}, - "mr_1px": {"declaration": "margin-right: 1px;"}, - "mr_2px": {"declaration": "margin-right: 2px;"}, - "mr_3px": {"declaration": "margin-right: 3px;"}, "mr_auto": {"declaration": "margin-right: auto;"}, "mr_xs5": {"declaration": "margin-right: var(--space_xs5);"}, "mr_xs4": {"declaration": "margin-right: var(--space_xs4);"}, @@ -1155,10 +1061,6 @@ "mr_xl14": {"declaration": "margin-right: var(--space_xl14);"}, "mr_xl15": {"declaration": "margin-right: var(--space_xl15);"}, "mb_0": {"declaration": "margin-bottom: 0;"}, - "mb_100": {"declaration": "margin-bottom: 100%;"}, - "mb_1px": {"declaration": "margin-bottom: 1px;"}, - "mb_2px": {"declaration": "margin-bottom: 2px;"}, - "mb_3px": {"declaration": "margin-bottom: 3px;"}, "mb_auto": {"declaration": "margin-bottom: auto;"}, "mb_xs5": {"declaration": "margin-bottom: var(--space_xs5);"}, "mb_xs4": {"declaration": "margin-bottom: var(--space_xs4);"}, @@ -1184,10 +1086,6 @@ "mb_xl14": {"declaration": "margin-bottom: var(--space_xl14);"}, "mb_xl15": {"declaration": "margin-bottom: var(--space_xl15);"}, "ml_0": {"declaration": "margin-left: 0;"}, - "ml_100": {"declaration": "margin-left: 100%;"}, - "ml_1px": {"declaration": "margin-left: 1px;"}, - "ml_2px": {"declaration": "margin-left: 2px;"}, - "ml_3px": {"declaration": "margin-left: 3px;"}, "ml_auto": {"declaration": "margin-left: auto;"}, "ml_xs5": {"declaration": "margin-left: var(--space_xs5);"}, "ml_xs4": {"declaration": "margin-left: var(--space_xs4);"}, @@ -1213,10 +1111,6 @@ "ml_xl14": {"declaration": "margin-left: var(--space_xl14);"}, "ml_xl15": {"declaration": "margin-left: var(--space_xl15);"}, "mx_0": {"declaration": "margin-left: 0;\tmargin-right: 0;"}, - "mx_100": {"declaration": "margin-left: 100%;\tmargin-right: 100%;"}, - "mx_1px": {"declaration": "margin-left: 1px;\tmargin-right: 1px;"}, - "mx_2px": {"declaration": "margin-left: 2px;\tmargin-right: 2px;"}, - "mx_3px": {"declaration": "margin-left: 3px;\tmargin-right: 3px;"}, "mx_auto": {"declaration": "margin-left: auto;\tmargin-right: auto;"}, "mx_xs5": {"declaration": "margin-left: var(--space_xs5);\tmargin-right: var(--space_xs5);"}, "mx_xs4": {"declaration": "margin-left: var(--space_xs4);\tmargin-right: var(--space_xs4);"}, @@ -1242,10 +1136,6 @@ "mx_xl14": {"declaration": "margin-left: var(--space_xl14);\tmargin-right: var(--space_xl14);"}, "mx_xl15": {"declaration": "margin-left: var(--space_xl15);\tmargin-right: var(--space_xl15);"}, "my_0": {"declaration": "margin-top: 0;\tmargin-bottom: 0;"}, - "my_100": {"declaration": "margin-top: 100%;\tmargin-bottom: 100%;"}, - "my_1px": {"declaration": "margin-top: 1px;\tmargin-bottom: 1px;"}, - "my_2px": {"declaration": "margin-top: 2px;\tmargin-bottom: 2px;"}, - "my_3px": {"declaration": "margin-top: 3px;\tmargin-bottom: 3px;"}, "my_auto": {"declaration": "margin-top: auto;\tmargin-bottom: auto;"}, "my_xs5": {"declaration": "margin-top: var(--space_xs5);\tmargin-bottom: var(--space_xs5);"}, "my_xs4": {"declaration": "margin-top: var(--space_xs4);\tmargin-bottom: var(--space_xs4);"}, From d9b0882192114fc412f2268ae59846c8579b8cfa Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 14 Jan 2026 07:40:08 -0500 Subject: [PATCH 072/138] wip --- CLAUDE.md | 78 +- TODO_VITE_PLUGIN.md | 308 +++ eslint.config.js | 3 +- examples/vite-preact/index.html | 12 + examples/vite-preact/package-lock.json | 2158 +++++++++++++++++++++ examples/vite-preact/package.json | 20 + examples/vite-preact/src/App.tsx | 159 ++ examples/vite-preact/src/main.tsx | 8 + examples/vite-preact/src/vite-env.d.ts | 6 + examples/vite-preact/tsconfig.json | 21 + examples/vite-preact/vite.config.ts | 17 + examples/vite-react/index.html | 12 + examples/vite-react/package-lock.json | 1909 ++++++++++++++++++ examples/vite-react/package.json | 23 + examples/vite-react/src/App.tsx | 159 ++ examples/vite-react/src/main.tsx | 8 + examples/vite-react/src/vite-env.d.ts | 6 + examples/vite-react/tsconfig.json | 20 + examples/vite-react/vite.config.ts | 17 + examples/vite-solid/index.html | 12 + examples/vite-solid/package-lock.json | 2007 +++++++++++++++++++ examples/vite-solid/package.json | 20 + examples/vite-solid/src/App.tsx | 158 ++ examples/vite-solid/src/main.tsx | 8 + examples/vite-solid/src/vite-env.d.ts | 6 + examples/vite-solid/tsconfig.json | 21 + examples/vite-solid/vite.config.ts | 17 + examples/vite-svelte/index.html | 12 + examples/vite-svelte/package-lock.json | 1464 ++++++++++++++ examples/vite-svelte/package.json | 19 + examples/vite-svelte/src/App.svelte | 152 ++ examples/vite-svelte/src/main.ts | 8 + examples/vite-svelte/src/vite-env.d.ts | 6 + examples/vite-svelte/tsconfig.json | 19 + examples/vite-svelte/vite.config.ts | 15 + src/lib/example_class_utilities.ts | 111 ++ src/lib/file_filter.ts | 35 + src/lib/gen_fuz_css.ts | 22 +- src/lib/vite_plugin_fuz_css.ts | 500 +++++ src/routes/ThemeForm.svelte | 3 +- src/routes/docs/classes/+page.svelte | 115 +- src/routes/docs/examples/+page.svelte | 29 + src/routes/docs/introduction/+page.svelte | 4 +- src/routes/docs/tomes.ts | 9 + src/routes/docs/typography/+page.svelte | 2 +- src/routes/fuz.css | 23 + src/routes/library.json | 264 ++- src/test/vite_plugin_examples.test.ts | 212 ++ 48 files changed, 10157 insertions(+), 60 deletions(-) create mode 100644 TODO_VITE_PLUGIN.md create mode 100644 examples/vite-preact/index.html create mode 100644 examples/vite-preact/package-lock.json create mode 100644 examples/vite-preact/package.json create mode 100644 examples/vite-preact/src/App.tsx create mode 100644 examples/vite-preact/src/main.tsx create mode 100644 examples/vite-preact/src/vite-env.d.ts create mode 100644 examples/vite-preact/tsconfig.json create mode 100644 examples/vite-preact/vite.config.ts create mode 100644 examples/vite-react/index.html create mode 100644 examples/vite-react/package-lock.json create mode 100644 examples/vite-react/package.json create mode 100644 examples/vite-react/src/App.tsx create mode 100644 examples/vite-react/src/main.tsx create mode 100644 examples/vite-react/src/vite-env.d.ts create mode 100644 examples/vite-react/tsconfig.json create mode 100644 examples/vite-react/vite.config.ts create mode 100644 examples/vite-solid/index.html create mode 100644 examples/vite-solid/package-lock.json create mode 100644 examples/vite-solid/package.json create mode 100644 examples/vite-solid/src/App.tsx create mode 100644 examples/vite-solid/src/main.tsx create mode 100644 examples/vite-solid/src/vite-env.d.ts create mode 100644 examples/vite-solid/tsconfig.json create mode 100644 examples/vite-solid/vite.config.ts create mode 100644 examples/vite-svelte/index.html create mode 100644 examples/vite-svelte/package-lock.json create mode 100644 examples/vite-svelte/package.json create mode 100644 examples/vite-svelte/src/App.svelte create mode 100644 examples/vite-svelte/src/main.ts create mode 100644 examples/vite-svelte/src/vite-env.d.ts create mode 100644 examples/vite-svelte/tsconfig.json create mode 100644 examples/vite-svelte/vite.config.ts create mode 100644 src/lib/example_class_utilities.ts create mode 100644 src/lib/file_filter.ts create mode 100644 src/lib/vite_plugin_fuz_css.ts create mode 100644 src/routes/docs/examples/+page.svelte create mode 100644 src/test/vite_plugin_examples.test.ts diff --git a/CLAUDE.md b/CLAUDE.md index c876d36e9..3442d2507 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,7 +9,7 @@ For code style, see the `fuz-stack` skill. For UI components (themes, color sche ```bash gro check # typecheck, test, lint, format check (run before committing) gro typecheck # typecheck only (faster iteration) -gro test # run tests with vitest +gro test # run tests (SKIP_EXAMPLE_TESTS=1 to skip slow integration tests) gro gen # regenerate theme.css and other .gen files gro build # build the package for production ``` @@ -36,7 +36,12 @@ gro build # build the package for production ### Smart utility class generation -[gen_fuz_css.ts](src/lib/gen_fuz_css.ts) scans source files with AST-based extraction ([css_class_extractor.ts](src/lib/css_class_extractor.ts)), collects class names, and outputs only CSS for classes actually used. Supports Svelte 5.16+ class syntax (`class={[...]}`, `class={{...}}`), clsx/cn calls, and `// @fuz-classes` comment hints. +Two generators available: + +1. **Gro generator** - [gen_fuz_css.ts](src/lib/gen_fuz_css.ts) for SvelteKit projects using Gro +2. **Vite plugin** - [vite_plugin_fuz_css.ts](src/lib/vite_plugin_fuz_css.ts) for Svelte/React/Preact/Solid via `virtual:fuz.css` + +Both use AST-based extraction ([css_class_extractor.ts](src/lib/css_class_extractor.ts)) and output only CSS for classes actually used. Supports Svelte 5.16+ class syntax, JSX `className`, clsx/cn calls, and `// @fuz-classes` comment hints. ### Three class types @@ -72,7 +77,26 @@ See [variables.ts](src/lib/variables.ts) for definitions, [variable_data.ts](src ## Usage -Import [style.css](src/lib/style.css) + [theme.css](src/lib/theme.css) for base styles. Optionally generate project-specific `fuz.css` using [gen_fuz_css()](src/lib/gen_fuz_css.ts) in a Gro generator. +Import [style.css](src/lib/style.css) + [theme.css](src/lib/theme.css) for base styles. Generate utility classes via: + +**SvelteKit (Gro):** Use [gen_fuz_css()](src/lib/gen_fuz_css.ts) in a `.gen.css.ts` file. + +**Vite (Svelte/React/Preact/Solid):** + +```ts +// vite.config.ts +import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; +import jsx from 'acorn-jsx'; // only needed for JSX frameworks + +export default defineConfig({ + plugins: [vite_plugin_fuz_css({acorn_plugins: [jsx()]})] +}); + +// main.ts +import '@fuzdev/fuz_css/style.css'; +import '@fuzdev/fuz_css/theme.css'; +import 'virtual:fuz.css'; +``` ## Docs @@ -92,22 +116,29 @@ Import [style.css](src/lib/style.css) + [theme.css](src/lib/theme.css) for base **CSS extraction:** -- [css_class_extractor.ts](src/lib/css_class_extractor.ts) - AST-based class extraction from Svelte/TS files, `SourceLocation`, `ExtractionResult` +- [css_class_extractor.ts](src/lib/css_class_extractor.ts) - AST-based class extraction from Svelte/TS/JSX files +- [file_filter.ts](src/lib/file_filter.ts) - `FileFilter` type and `filter_file_default` for filtering extractable files +- [diagnostics.ts](src/lib/diagnostics.ts) - `SourceLocation`, `ExtractionDiagnostic`, `GenerationDiagnostic` types **CSS generation:** -- [gen_fuz_css.ts](src/lib/gen_fuz_css.ts) - Main generator API for Gro, includes per-file caching with content hash validation -- [css_cache.ts](src/lib/css_cache.ts) - Cache infrastructure for incremental extraction (`.fuz/cache/css/`) -- [css_classes.ts](src/lib/css_classes.ts) - `CssClasses` collection class for tracking extracted classes per-file -- [css_class_generation.ts](src/lib/css_class_generation.ts) - Type definitions (`CssClassDefinition`, `CssClassInterpreterContext`), `generate_classes_css()`, CSS escaping -- [css_class_definitions.ts](src/lib/css_class_definitions.ts) - Combined token + composite class definitions, the main class registry -- [css_class_generators.ts](src/lib/css_class_generators.ts) - Class template generation functions for token classes +- [gen_fuz_css.ts](src/lib/gen_fuz_css.ts) - Gro generator API with per-file caching +- [vite_plugin_fuz_css.ts](src/lib/vite_plugin_fuz_css.ts) - Vite plugin for Svelte/React/Preact/Solid, `virtual:fuz.css` virtual module with HMR +- [css_cache.ts](src/lib/css_cache.ts) - Cache infrastructure (`.fuz/cache/css/`) +- [css_classes.ts](src/lib/css_classes.ts) - `CssClasses` collection for tracking classes per-file +- [css_class_generation.ts](src/lib/css_class_generation.ts) - `CssClassDefinition` types, `generate_classes_css()` +- [css_class_definitions.ts](src/lib/css_class_definitions.ts) - Combined token + composite class registry +- [css_class_generators.ts](src/lib/css_class_generators.ts) - Token class template generators - [css_class_composites.ts](src/lib/css_class_composites.ts) - Composite classes (`.box`, `.row`, `.column`, `.ellipsis`, `.pane`, `.panel`) -- [css_class_resolution.ts](src/lib/css_class_resolution.ts) - `resolve_classes()` helper for composing class definitions via `classes` property -- [css_class_interpreters.ts](src/lib/css_class_interpreters.ts) - Two interpreters: `modified_class_interpreter` (handles `hover:box`, `md:p_lg`) and `css_literal_interpreter` (handles `display:flex`) -- [css_literal.ts](src/lib/css_literal.ts) - CSS-literal parser, validator, `extract_and_validate_modifiers()` -- [css_ruleset_parser.ts](src/lib/css_ruleset_parser.ts) - CSS ruleset parsing via Svelte's parser, selector modification for modifiers -- [modifiers.ts](src/lib/modifiers.ts) - Declarative modifier definitions (breakpoints, states, pseudo-elements) +- [css_class_resolution.ts](src/lib/css_class_resolution.ts) - `resolve_classes()` for composing definitions +- [css_class_interpreters.ts](src/lib/css_class_interpreters.ts) - `modified_class_interpreter` and `css_literal_interpreter` +- [css_literal.ts](src/lib/css_literal.ts) - CSS-literal parser and validator +- [css_ruleset_parser.ts](src/lib/css_ruleset_parser.ts) - CSS ruleset parsing, selector modification +- [modifiers.ts](src/lib/modifiers.ts) - Modifier definitions (breakpoints, states, pseudo-elements) + +**Example utilities:** + +- [example_class_utilities.ts](src/lib/example_class_utilities.ts) - Demo exports for testing node_modules extraction **Stylesheets:** @@ -121,12 +152,25 @@ Import [style.css](src/lib/style.css) + [theme.css](src/lib/theme.css) for base - [fuz.css](src/routes/fuz.css) - Generated optimized utility classes for this site - [fuz.gen.css.ts](src/routes/fuz.gen.css.ts) - Generator using `gen_fuz_css()` +### Examples - [examples/](examples/) + +Vite plugin examples: + +- [vite-svelte/](examples/vite-svelte/) - Svelte 5 example +- [vite-react/](examples/vite-react/) - React 19 example +- [vite-preact/](examples/vite-preact/) - Preact example +- [vite-solid/](examples/vite-solid/) - Solid example + +Each demonstrates token, composite, and literal classes with responsive/hover/dark modifiers. Uses classes from [example_class_utilities.ts](src/lib/example_class_utilities.ts) to verify node_modules extraction. + ### Tests - [src/test/](src/test/) - [variables.test.ts](src/test/variables.test.ts) - Variable consistency (no duplicates, valid names) - [css_cache.test.ts](src/test/css_cache.test.ts) - Cache save/load, version invalidation, atomic writes -- [css_class_generation.test.ts](src/test/css_class_generation.test.ts) - CSS escaping, generation, interpreters, CssClasses -- [css_class_resolution.test.ts](src/test/css_class_resolution.test.ts) - Class resolution, cycle detection, error handling +- [css_class_generation.test.ts](src/test/css_class_generation.test.ts) - CSS escaping, generation, interpreters +- [css_class_resolution.test.ts](src/test/css_class_resolution.test.ts) - Class resolution, cycle detection - [css_class_extractor.test.ts](src/test/css_class_extractor.test.ts) - AST extraction, location tracking +- [css_class_extractor.jsx.test.ts](src/test/css_class_extractor.jsx.test.ts) - JSX-specific extraction - [css_literal.test.ts](src/test/css_literal.test.ts) - CSS-literal parsing, validation, modifiers - [css_ruleset_parser.test.ts](src/test/css_ruleset_parser.test.ts) - Ruleset parsing, selector modification +- [vite_plugin_examples.test.ts](src/test/vite_plugin_examples.test.ts) - Integration tests building examples (skip with `SKIP_EXAMPLE_TESTS=1`) diff --git a/TODO_VITE_PLUGIN.md b/TODO_VITE_PLUGIN.md new file mode 100644 index 000000000..b1a347610 --- /dev/null +++ b/TODO_VITE_PLUGIN.md @@ -0,0 +1,308 @@ +# Vite Plugin for fuz_css + +Alternative to the Gro generator for projects using Vite directly. + +## Architecture + +### Transform-based extraction (like UnoCSS) + +Instead of filesystem scanning, use Vite's `transform()` hook to extract classes from every file Vite processes. This automatically includes node_modules dependencies as they're imported. + +``` +File imported → transform() extracts classes → registry updated + ↓ + virtual:fuz.css ← generates CSS from registry +``` + +### Lazy generation with incremental HMR + +1. First request for `virtual:fuz.css` generates CSS from current registry +2. Subsequent transforms may discover new classes +3. New classes trigger HMR update of virtual module +4. Dev mode may see multiple CSS updates during initial load (acceptable) +5. Production builds process all files before bundling (CSS complete) + +## Implementation + +### Plugin file + +`src/lib/vite_plugin_fuz_css.ts` exports single identifier `vite_plugin_fuz_css`. + +```ts +import type {Plugin} from 'vite'; + +export interface VitePluginFuzCssOptions { + // Same options as GenFuzCssOptions where applicable + filter_file?: (path: string) => boolean; + class_definitions?: Record; + class_interpreters?: Array; + include_classes?: Iterable; + exclude_classes?: Iterable; + acorn_plugins?: Array; + on_error?: 'log' | 'throw'; +} + +export const vite_plugin_fuz_css = (options?: VitePluginFuzCssOptions): Plugin => { + // ... +}; +``` + +### Plugin hooks + +| Hook | Purpose | +|------|---------| +| `configResolved` | Get project root for cache paths | +| `configureServer` | Set up file watcher for deletion handling | +| `buildStart` | Load CSS properties for validation | +| `resolveId` | Resolve `virtual:fuz.css` to internal ID | +| `load` | Generate CSS from current class registry | +| `transform` | Extract classes from each file, update registry, trigger HMR | + +Note: `handleHotUpdate` is not needed - the `transform` hook handles file changes (it runs on every file edit), and `configureServer` sets up `watcher.on('unlink')` for file deletion. + +### Class registry + +Global mutable state within plugin instance: + +```ts +interface ClassRegistry { + // file path → extracted classes with locations + files: Map>>; + // file path → content hash (for caching) + hashes: Map; + // aggregated classes (recomputed on change) + all_classes: Set | null; // null = dirty, needs recompute +} +``` + +### Transform hook + +```ts +transform(code, id) { + // Early filter - skip test files, .gen files, non-extractable extensions + if (!filter_file(id)) return null; + + // Compute content hash + const hash = compute_hash(code); + if (registry.hashes.get(id) === hash) return null; // unchanged + + // Extract classes + const result = extract_css_classes_with_locations(code, { + filename: id, + acorn_plugins, + }); + + // Update registry + registry.files.set(id, result.classes); + registry.hashes.set(id, hash); + registry.all_classes = null; // mark dirty + + // If virtual module already loaded, trigger HMR + if (virtual_module_loaded) { + invalidate_virtual_module(); + } + + return null; // don't transform the code itself +} +``` + +### Virtual module + +```ts +const VIRTUAL_ID = 'virtual:fuz.css'; +const RESOLVED_ID = '\0virtual:fuz.css'; // \0 prefix = Vite convention + +resolveId(id) { + if (id === VIRTUAL_ID) return RESOLVED_ID; +} + +load(id) { + if (id === RESOLVED_ID) { + virtual_module_loaded = true; + return generate_css_from_registry(); + } +} +``` + +### HMR + +HMR is triggered from within the `transform` hook when classes change: + +```ts +// Called from transform() after registry update +const invalidate_virtual_module = () => { + if (!server) return; + + // Debounce: wait 10ms for more changes before triggering HMR + if (hmr_timeout) clearTimeout(hmr_timeout); + hmr_timeout = setTimeout(() => { + const mod = server.moduleGraph.getModuleById(RESOLVED_ID); + if (mod) { + server.moduleGraph.invalidateModule(mod); + server.ws.send({ + type: 'update', + updates: [{ + type: 'css-update', + path: VIRTUAL_ID, + acceptedPath: VIRTUAL_ID, + timestamp: Date.now(), + }], + }); + } + }, 10); +}; +``` + +File deletion is handled via `configureServer`: + +```ts +configureServer(dev_server) { + server = dev_server; + dev_server.watcher.on('unlink', (file) => { + if (registry.files.has(file)) { + registry.files.delete(file); + registry.hashes.delete(file); + registry.all_classes = null; + // Also delete cache file + delete_cached_extraction(get_file_cache_path(file)); + invalidate_virtual_module(); + } + }); +} +``` + +## Caching + +Reuse per-file content hash caching from current system: + +- Cache location: `.fuz/cache/css/` (same as Gro) +- On transform: check cache before extracting +- On file change: invalidate cache entry +- Refactor `css_cache.ts` if needed for shared API + +## Examples + +Directory structure: + +``` +examples/ +├── vite-react/ +│ ├── package.json +│ ├── vite.config.ts +│ ├── index.html +│ └── src/ +│ ├── main.tsx +│ └── App.tsx +├── vite-preact/ +│ ├── package.json +│ ├── vite.config.ts +│ ├── index.html +│ └── src/ +│ ├── main.tsx +│ └── App.tsx +└── vite-solid/ + ├── package.json + ├── vite.config.ts + ├── index.html + └── src/ + ├── main.tsx + └── App.tsx +``` + +### Example UI scope + +Minimal but demonstrates multiple patterns: + +- Responsive layout (column on mobile, row on desktop) +- Token classes (spacing, colors, typography) +- Literal classes (display, flex properties) +- State modifiers (hover effects) +- Dark mode modifier +- Composite classes (box, row) + +Self-explanatory UI - users understand what they're seeing at a glance. + +### Example vite.config.ts + +```ts +import {defineConfig} from 'vite'; +import react from '@vitejs/plugin-react'; +import jsx from 'acorn-jsx'; +import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; + +export default defineConfig({ + plugins: [ + react(), + vite_plugin_fuz_css({ + acorn_plugins: [jsx()], + }), + ], +}); +``` + +### Example usage + +```tsx +// src/main.tsx +import '@fuzdev/fuz_css/style.css'; +import '@fuzdev/fuz_css/theme.css'; +import 'virtual:fuz.css'; + +import {createRoot} from 'react-dom/client'; +import App from './App'; + +createRoot(document.getElementById('root')!).render(); +``` + +### Package.json dependencies + +```json +{ + "devDependencies": { + "@fuzdev/fuz_css": "file:../..", + "vite": "^6", + "acorn-jsx": "^5" + } +} +``` + +## Tasks + +### Phase 1: Core plugin + +1. Create `src/lib/vite_plugin_fuz_css.ts` with basic structure +2. Implement `resolveId` and `load` for virtual module +3. Implement `transform` hook with class extraction +4. Implement class registry and CSS generation +5. Add HMR support via `handleHotUpdate` +6. Integrate per-file caching + +### Phase 2: Examples + +1. Create `examples/vite-react/` with minimal setup +2. Create `examples/vite-preact/` +3. Create `examples/vite-solid/` +4. Verify all examples work with `npm install && npm run dev` + +### Phase 3: Polish + +1. Add TypeScript types for virtual module (`virtual:fuz.css`) +2. Error handling and diagnostics +3. Test with real-world usage patterns +4. Documentation updates + +## Future work + +- **Auto-detect framework**: Infer acorn-jsx need from package.json dependencies +- **Vue SFC support**: Parse `:class` bindings (needs vue-template-compiler) +- **Physical file output**: Option to write fuz.css for debugging/CI +- **Configurable virtual module name**: `virtual:fuz.css` vs custom +- **Build-time optimization**: Pre-extract during `buildStart` for faster cold starts +- **Shared cache with Gro**: Ensure cache format compatibility + +## Unknowns + +- **Transform order**: Does Vite guarantee transform completes before load of dependent modules? Need to verify CSS is ready when components render. +- **Pre-bundled dependencies**: Vite pre-bundles node_modules. Does transform hook see original source or bundled output? May affect extraction accuracy. +- **SSR considerations**: How does virtual module work in SSR builds? +- **Large codebases**: Performance of extracting on every transform vs batching. diff --git a/eslint.config.js b/eslint.config.js index 75527ca8a..c59655eb8 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -2,4 +2,5 @@ import {configs, ts_config} from '@ryanatkn/eslint-config'; ts_config.rules['no-console'] = 1; -export default configs; +// Ignore examples directory - each example has its own tsconfig +export default [{ignores: ['examples/**']}, ...configs]; diff --git a/examples/vite-preact/index.html b/examples/vite-preact/index.html new file mode 100644 index 000000000..75bf0acd5 --- /dev/null +++ b/examples/vite-preact/index.html @@ -0,0 +1,12 @@ + + + + + + fuz_css + Preact + + +
+ + + diff --git a/examples/vite-preact/package-lock.json b/examples/vite-preact/package-lock.json new file mode 100644 index 000000000..50ca6c6b5 --- /dev/null +++ b/examples/vite-preact/package-lock.json @@ -0,0 +1,2158 @@ +{ + "name": "vite-preact-fuz-css-example", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vite-preact-fuz-css-example", + "dependencies": { + "preact": "^10" + }, + "devDependencies": { + "@fuzdev/fuz_css": "file:../..", + "@preact/preset-vite": "^2", + "acorn-jsx": "^5", + "typescript": "^5", + "vite": "^6" + } + }, + "../..": { + "name": "@fuzdev/fuz_css", + "version": "0.43.0", + "dev": true, + "license": "MIT", + "devDependencies": { + "@changesets/changelog-git": "^0.2.1", + "@fuzdev/fuz_code": "^0.39.0", + "@fuzdev/fuz_ui": "^0.177.0", + "@fuzdev/fuz_util": "^0.45.3", + "@ryanatkn/eslint-config": "^0.9.0", + "@ryanatkn/gro": "^0.185.0", + "@sveltejs/acorn-typescript": "^1.0.8", + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.49.1", + "@sveltejs/package": "^2.5.7", + "@sveltejs/vite-plugin-svelte": "^6.2.1", + "@types/node": "^24.10.1", + "@webref/css": "^8.1.3", + "acorn-jsx": "^5.3.2", + "eslint": "^9.39.1", + "eslint-plugin-svelte": "^3.13.1", + "prettier": "^3.7.4", + "prettier-plugin-svelte": "^3.4.1", + "svelte": "^5.45.6", + "svelte-check": "^4.3.4", + "tslib": "^2.8.1", + "typescript": "^5.9.3", + "typescript-eslint": "^8.48.1", + "vitest": "^4.0.15", + "zimmerframe": "^1.1.4", + "zod": "^4.1.13" + }, + "engines": { + "node": ">=22.15" + }, + "funding": { + "url": "https://www.ryanatkn.com/funding" + }, + "peerDependencies": { + "@fuzdev/fuz_util": ">=0.42.0", + "@sveltejs/acorn-typescript": "^1", + "@webref/css": "^8", + "acorn-jsx": "^5", + "zimmerframe": "^1" + }, + "peerDependenciesMeta": { + "@fuzdev/fuz_util": { + "optional": true + }, + "@sveltejs/acorn-typescript": { + "optional": true + }, + "@webref/css": { + "optional": true + }, + "acorn-jsx": { + "optional": true + }, + "zimmerframe": { + "optional": true + } + } + }, + "node_modules/@babel/code-frame": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", + "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz", + "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-jsx": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fuzdev/fuz_css": { + "resolved": "../..", + "link": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@preact/preset-vite": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@preact/preset-vite/-/preset-vite-2.10.2.tgz", + "integrity": "sha512-K9wHlJOtkE+cGqlyQ5v9kL3Ge0Ql4LlIZjkUTL+1zf3nNdF88F9UZN6VTV8jdzBX9Fl7WSzeNMSDG7qECPmSmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.22.15", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@prefresh/vite": "^2.4.1", + "@rollup/pluginutils": "^4.1.1", + "babel-plugin-transform-hook-names": "^1.0.2", + "debug": "^4.3.4", + "picocolors": "^1.1.1", + "vite-prerender-plugin": "^0.5.3" + }, + "peerDependencies": { + "@babel/core": "7.x", + "vite": "2.x || 3.x || 4.x || 5.x || 6.x || 7.x" + } + }, + "node_modules/@prefresh/babel-plugin": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@prefresh/babel-plugin/-/babel-plugin-0.5.2.tgz", + "integrity": "sha512-AOl4HG6dAxWkJ5ndPHBgBa49oo/9bOiJuRDKHLSTyH+Fd9x00shTXpdiTj1W41l6oQIwUOAgJeHMn4QwIDpHkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@prefresh/core": { + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/@prefresh/core/-/core-1.5.9.tgz", + "integrity": "sha512-IKBKCPaz34OFVC+adiQ2qaTF5qdztO2/4ZPf4KsRTgjKosWqxVXmEbxCiUydYZRY8GVie+DQlKzQr9gt6HQ+EQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "preact": "^10.0.0 || ^11.0.0-0" + } + }, + "node_modules/@prefresh/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@prefresh/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-vq/sIuN5nYfYzvyayXI4C2QkprfNaHUQ9ZX+3xLD8nL3rWyzpxOm1+K7RtMbhd+66QcaISViK7amjnheQ/4WZw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@prefresh/vite": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/@prefresh/vite/-/vite-2.4.11.tgz", + "integrity": "sha512-/XjURQqdRiCG3NpMmWqE9kJwrg9IchIOWHzulCfqg2sRe/8oQ1g5De7xrk9lbqPIQLn7ntBkKdqWXIj4E9YXyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.22.1", + "@prefresh/babel-plugin": "0.5.2", + "@prefresh/core": "^1.5.0", + "@prefresh/utils": "^1.2.0", + "@rollup/pluginutils": "^4.2.1" + }, + "peerDependencies": { + "preact": "^10.4.0 || ^11.0.0-0", + "vite": ">=2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", + "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", + "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", + "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", + "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", + "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", + "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", + "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", + "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", + "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", + "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", + "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", + "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", + "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", + "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", + "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", + "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", + "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", + "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", + "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", + "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", + "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", + "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", + "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", + "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", + "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/babel-plugin-transform-hook-names": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-hook-names/-/babel-plugin-transform-hook-names-1.0.2.tgz", + "integrity": "sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@babel/core": "^7.12.10" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", + "integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001764", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz", + "integrity": "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-html-parser": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", + "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^5.1.0", + "he": "1.2.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/preact": { + "version": "10.28.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.2.tgz", + "integrity": "sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/rollup": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", + "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.55.1", + "@rollup/rollup-android-arm64": "4.55.1", + "@rollup/rollup-darwin-arm64": "4.55.1", + "@rollup/rollup-darwin-x64": "4.55.1", + "@rollup/rollup-freebsd-arm64": "4.55.1", + "@rollup/rollup-freebsd-x64": "4.55.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", + "@rollup/rollup-linux-arm-musleabihf": "4.55.1", + "@rollup/rollup-linux-arm64-gnu": "4.55.1", + "@rollup/rollup-linux-arm64-musl": "4.55.1", + "@rollup/rollup-linux-loong64-gnu": "4.55.1", + "@rollup/rollup-linux-loong64-musl": "4.55.1", + "@rollup/rollup-linux-ppc64-gnu": "4.55.1", + "@rollup/rollup-linux-ppc64-musl": "4.55.1", + "@rollup/rollup-linux-riscv64-gnu": "4.55.1", + "@rollup/rollup-linux-riscv64-musl": "4.55.1", + "@rollup/rollup-linux-s390x-gnu": "4.55.1", + "@rollup/rollup-linux-x64-gnu": "4.55.1", + "@rollup/rollup-linux-x64-musl": "4.55.1", + "@rollup/rollup-openbsd-x64": "4.55.1", + "@rollup/rollup-openharmony-arm64": "4.55.1", + "@rollup/rollup-win32-arm64-msvc": "4.55.1", + "@rollup/rollup-win32-ia32-msvc": "4.55.1", + "@rollup/rollup-win32-x64-gnu": "4.55.1", + "@rollup/rollup-win32-x64-msvc": "4.55.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/simple-code-frame": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/simple-code-frame/-/simple-code-frame-1.3.0.tgz", + "integrity": "sha512-MB4pQmETUBlNs62BBeRjIFGeuy/x6gGKh7+eRUemn1rCFhqo7K+4slPqsyizCbcbYLnaYqaoZ2FWsZ/jN06D8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "kolorist": "^1.6.0" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "1.0.0-pre2", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-1.0.0-pre2.tgz", + "integrity": "sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-prerender-plugin": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/vite-prerender-plugin/-/vite-prerender-plugin-0.5.12.tgz", + "integrity": "sha512-EiwhbMn+flg14EysbLTmZSzq8NGTxhytgK3bf4aGRF1evWLGwZiHiUJ1KZDvbxgKbMf2pG6fJWGEa3UZXOnR1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "kolorist": "^1.8.0", + "magic-string": "0.x >= 0.26.0", + "node-html-parser": "^6.1.12", + "simple-code-frame": "^1.3.0", + "source-map": "^0.7.4", + "stack-trace": "^1.0.0-pre2" + }, + "peerDependencies": { + "vite": "5.x || 6.x || 7.x" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/examples/vite-preact/package.json b/examples/vite-preact/package.json new file mode 100644 index 000000000..9d3c9b493 --- /dev/null +++ b/examples/vite-preact/package.json @@ -0,0 +1,20 @@ +{ + "name": "vite-preact-fuz-css-example", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10" + }, + "devDependencies": { + "@fuzdev/fuz_css": "file:../..", + "@preact/preset-vite": "^2", + "acorn-jsx": "^5", + "typescript": "^5", + "vite": "^6" + } +} diff --git a/examples/vite-preact/src/App.tsx b/examples/vite-preact/src/App.tsx new file mode 100644 index 000000000..b1fc10b6d --- /dev/null +++ b/examples/vite-preact/src/App.tsx @@ -0,0 +1,159 @@ +import {useState} from 'preact/hooks'; + +// Import from node_modules to verify extraction works for dependencies +import { + // Token classes (mix of camelCase and snake_case) + demo_padding_class, + demoShadowClass, + demo_color_class, + // Composite classes + demoBoxClass, + demo_row_class, + demoEllipsisClass, + // Literal classes + demo_display_class, + demoAlignClass, + demo_gap_class, + // Variable patterns + demoClassName, + DEMO_CONSTANT_CLASS, + card_class, + demo_ternary_class, + demo_logical_class, + demoArrayClasses, + // Comment hint examples + from_comment, + arbitrary_literal, +} from '@fuzdev/fuz_css/example_class_utilities.js'; + +export const App = () => { + const [count, setCount] = useState(0); + + return ( +
+
+
+

fuz_css + Preact

+

+ Utility classes generated on-demand via Vite plugin +

+
+ + {/* Responsive layout: column on mobile, row on desktop */} +
+
+

Responsive

+

+ This layout stacks on mobile and becomes a row on medium screens. +

+
+
+

On-demand

+

+ Only the classes you use are included in the bundle. +

+
+
+ + {/* Interactive button with hover states */} +
+

Interactive

+
+ + +
+
+ + {/* Dark mode demo */} +
+

Color Scheme

+
+
+ Adapts to dark mode +
+
+ Different in each scheme +
+
+
+ + {/* Token classes showcase */} +
+

Design Tokens

+
+ {['a', 'b', 'c', 'd', 'e'].map((hue) => ( +
+ {hue.toUpperCase()} +
+ ))} +
+
+ + {/* Classes from node_modules dependency - all unique, verifies extraction */} +
+

From Dependencies

+

+ Classes imported from @fuzdev/fuz_css/example_class_utilities: +

+ + {/* Token classes */} +
+
+ {demo_padding_class} + {demoShadowClass} +
+
+ {demo_color_class} +
+
+ + {/* Composite classes */} +
+
+ {card_class} +
+
+ + {demoEllipsisClass} truncates long text + +
+
+ + {/* Variable patterns - each uses a unique class */} +
+
+ DEMO_CONSTANT_CLASS: {DEMO_CONSTANT_CLASS} +
+
+ demo_ternary_class: {demo_ternary_class} +
+
+ demo_logical_class: {demo_logical_class} +
+
+ demoArrayClasses: [{demoArrayClasses.join(', ')}] +
+
+ from_comment (via @fuz-classes): {from_comment} +
+
+ arbitrary_literal: {arbitrary_literal} +
+
+
+
+
+ ); +}; diff --git a/examples/vite-preact/src/main.tsx b/examples/vite-preact/src/main.tsx new file mode 100644 index 000000000..7e2989347 --- /dev/null +++ b/examples/vite-preact/src/main.tsx @@ -0,0 +1,8 @@ +import '@fuzdev/fuz_css/style.css'; +import '@fuzdev/fuz_css/theme.css'; +import 'virtual:fuz.css'; + +import {render} from 'preact'; +import {App} from './App.tsx'; + +render(, document.getElementById('root')!); diff --git a/examples/vite-preact/src/vite-env.d.ts b/examples/vite-preact/src/vite-env.d.ts new file mode 100644 index 000000000..241d205b0 --- /dev/null +++ b/examples/vite-preact/src/vite-env.d.ts @@ -0,0 +1,6 @@ +/// + +declare module 'virtual:fuz.css' { + const css: string; + export default css; +} diff --git a/examples/vite-preact/tsconfig.json b/examples/vite-preact/tsconfig.json new file mode 100644 index 000000000..79c4a1d61 --- /dev/null +++ b/examples/vite-preact/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/examples/vite-preact/vite.config.ts b/examples/vite-preact/vite.config.ts new file mode 100644 index 000000000..573acdff1 --- /dev/null +++ b/examples/vite-preact/vite.config.ts @@ -0,0 +1,17 @@ +import {defineConfig} from 'vite'; +import preact from '@preact/preset-vite'; +import jsx from 'acorn-jsx'; +import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; + +export default defineConfig({ + plugins: [ + // Plugin order doesn't matter for preact (fuz_css uses enforce: 'pre') + preact(), + vite_plugin_fuz_css({ + acorn_plugins: [jsx()], + // Include dynamically constructed classes that can't be statically extracted + // The example uses `bg_${hue}_5` in a .map() which produces these at runtime + include_classes: ['bg_a_5', 'bg_b_5', 'bg_c_5', 'bg_d_5', 'bg_e_5'], + }), + ], +}); diff --git a/examples/vite-react/index.html b/examples/vite-react/index.html new file mode 100644 index 000000000..7ede35528 --- /dev/null +++ b/examples/vite-react/index.html @@ -0,0 +1,12 @@ + + + + + + fuz_css + React + + +
+ + + diff --git a/examples/vite-react/package-lock.json b/examples/vite-react/package-lock.json new file mode 100644 index 000000000..a0861523d --- /dev/null +++ b/examples/vite-react/package-lock.json @@ -0,0 +1,1909 @@ +{ + "name": "vite-react-fuz-css-example", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vite-react-fuz-css-example", + "dependencies": { + "react": "^19", + "react-dom": "^19" + }, + "devDependencies": { + "@fuzdev/fuz_css": "file:../..", + "@types/react": "^19", + "@types/react-dom": "^19", + "@vitejs/plugin-react": "^5", + "acorn-jsx": "^5", + "typescript": "^5", + "vite": "^6" + } + }, + "../..": { + "name": "@fuzdev/fuz_css", + "version": "0.43.0", + "dev": true, + "license": "MIT", + "devDependencies": { + "@changesets/changelog-git": "^0.2.1", + "@fuzdev/fuz_code": "^0.39.0", + "@fuzdev/fuz_ui": "^0.177.0", + "@fuzdev/fuz_util": "^0.45.3", + "@ryanatkn/eslint-config": "^0.9.0", + "@ryanatkn/gro": "^0.185.0", + "@sveltejs/acorn-typescript": "^1.0.8", + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.49.1", + "@sveltejs/package": "^2.5.7", + "@sveltejs/vite-plugin-svelte": "^6.2.1", + "@types/node": "^24.10.1", + "@webref/css": "^8.1.3", + "acorn-jsx": "^5.3.2", + "eslint": "^9.39.1", + "eslint-plugin-svelte": "^3.13.1", + "prettier": "^3.7.4", + "prettier-plugin-svelte": "^3.4.1", + "svelte": "^5.45.6", + "svelte-check": "^4.3.4", + "tslib": "^2.8.1", + "typescript": "^5.9.3", + "typescript-eslint": "^8.48.1", + "vitest": "^4.0.15", + "zimmerframe": "^1.1.4", + "zod": "^4.1.13" + }, + "engines": { + "node": ">=22.15" + }, + "funding": { + "url": "https://www.ryanatkn.com/funding" + }, + "peerDependencies": { + "@fuzdev/fuz_util": ">=0.42.0", + "@sveltejs/acorn-typescript": "^1", + "@webref/css": "^8", + "acorn-jsx": "^5", + "zimmerframe": "^1" + }, + "peerDependenciesMeta": { + "@fuzdev/fuz_util": { + "optional": true + }, + "@sveltejs/acorn-typescript": { + "optional": true + }, + "@webref/css": { + "optional": true + }, + "acorn-jsx": { + "optional": true + }, + "zimmerframe": { + "optional": true + } + } + }, + "node_modules/@babel/code-frame": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", + "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fuzdev/fuz_css": { + "resolved": "../..", + "link": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", + "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", + "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", + "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", + "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", + "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", + "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", + "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", + "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", + "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", + "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", + "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", + "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", + "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", + "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", + "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", + "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", + "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", + "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", + "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", + "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", + "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", + "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", + "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", + "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", + "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", + "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.8.tgz", + "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.2.tgz", + "integrity": "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.5", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.53", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", + "integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001764", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz", + "integrity": "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.3" + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", + "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.55.1", + "@rollup/rollup-android-arm64": "4.55.1", + "@rollup/rollup-darwin-arm64": "4.55.1", + "@rollup/rollup-darwin-x64": "4.55.1", + "@rollup/rollup-freebsd-arm64": "4.55.1", + "@rollup/rollup-freebsd-x64": "4.55.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", + "@rollup/rollup-linux-arm-musleabihf": "4.55.1", + "@rollup/rollup-linux-arm64-gnu": "4.55.1", + "@rollup/rollup-linux-arm64-musl": "4.55.1", + "@rollup/rollup-linux-loong64-gnu": "4.55.1", + "@rollup/rollup-linux-loong64-musl": "4.55.1", + "@rollup/rollup-linux-ppc64-gnu": "4.55.1", + "@rollup/rollup-linux-ppc64-musl": "4.55.1", + "@rollup/rollup-linux-riscv64-gnu": "4.55.1", + "@rollup/rollup-linux-riscv64-musl": "4.55.1", + "@rollup/rollup-linux-s390x-gnu": "4.55.1", + "@rollup/rollup-linux-x64-gnu": "4.55.1", + "@rollup/rollup-linux-x64-musl": "4.55.1", + "@rollup/rollup-openbsd-x64": "4.55.1", + "@rollup/rollup-openharmony-arm64": "4.55.1", + "@rollup/rollup-win32-arm64-msvc": "4.55.1", + "@rollup/rollup-win32-ia32-msvc": "4.55.1", + "@rollup/rollup-win32-x64-gnu": "4.55.1", + "@rollup/rollup-win32-x64-msvc": "4.55.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/examples/vite-react/package.json b/examples/vite-react/package.json new file mode 100644 index 000000000..dd0fe3921 --- /dev/null +++ b/examples/vite-react/package.json @@ -0,0 +1,23 @@ +{ + "name": "vite-react-fuz-css-example", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19", + "react-dom": "^19" + }, + "devDependencies": { + "@fuzdev/fuz_css": "file:../..", + "@types/react": "^19", + "@types/react-dom": "^19", + "@vitejs/plugin-react": "^5", + "acorn-jsx": "^5", + "typescript": "^5", + "vite": "^6" + } +} diff --git a/examples/vite-react/src/App.tsx b/examples/vite-react/src/App.tsx new file mode 100644 index 000000000..1af323769 --- /dev/null +++ b/examples/vite-react/src/App.tsx @@ -0,0 +1,159 @@ +import {useState} from 'react'; + +// Import from node_modules to verify extraction works for dependencies +import { + // Token classes (mix of camelCase and snake_case) + demo_padding_class, + demoShadowClass, + demo_color_class, + // Composite classes + demoBoxClass, + demo_row_class, + demoEllipsisClass, + // Literal classes + demo_display_class, + demoAlignClass, + demo_gap_class, + // Variable patterns + demoClassName, + DEMO_CONSTANT_CLASS, + card_class, + demo_ternary_class, + demo_logical_class, + demoArrayClasses, + // Comment hint examples + from_comment, + arbitrary_literal, +} from '@fuzdev/fuz_css/example_class_utilities.js'; + +export const App = () => { + const [count, setCount] = useState(0); + + return ( +
+
+
+

fuz_css + React

+

+ Utility classes generated on-demand via Vite plugin +

+
+ + {/* Responsive layout: column on mobile, row on desktop */} +
+
+

Responsive

+

+ This layout stacks on mobile and becomes a row on medium screens. +

+
+
+

On-demand

+

+ Only the classes you use are included in the bundle. +

+
+
+ + {/* Interactive button with hover states */} +
+

Interactive

+
+ + +
+
+ + {/* Dark mode demo */} +
+

Color Scheme

+
+
+ Adapts to dark mode +
+
+ Different in each scheme +
+
+
+ + {/* Token classes showcase */} +
+

Design Tokens

+
+ {['a', 'b', 'c', 'd', 'e'].map((hue) => ( +
+ {hue.toUpperCase()} +
+ ))} +
+
+ + {/* Classes from node_modules dependency - all unique, verifies extraction */} +
+

From Dependencies

+

+ Classes imported from @fuzdev/fuz_css/example_class_utilities: +

+ + {/* Token classes */} +
+
+ {demo_padding_class} + {demoShadowClass} +
+
+ {demo_color_class} +
+
+ + {/* Composite classes */} +
+
+ {card_class} +
+
+ + {demoEllipsisClass} truncates long text + +
+
+ + {/* Variable patterns - each uses a unique class */} +
+
+ DEMO_CONSTANT_CLASS: {DEMO_CONSTANT_CLASS} +
+
+ demo_ternary_class: {demo_ternary_class} +
+
+ demo_logical_class: {demo_logical_class} +
+
+ demoArrayClasses: [{demoArrayClasses.join(', ')}] +
+
+ from_comment (via @fuz-classes): {from_comment} +
+
+ arbitrary_literal: {arbitrary_literal} +
+
+
+
+
+ ); +}; diff --git a/examples/vite-react/src/main.tsx b/examples/vite-react/src/main.tsx new file mode 100644 index 000000000..4f3067a01 --- /dev/null +++ b/examples/vite-react/src/main.tsx @@ -0,0 +1,8 @@ +import '@fuzdev/fuz_css/style.css'; +import '@fuzdev/fuz_css/theme.css'; +import 'virtual:fuz.css'; + +import {createRoot} from 'react-dom/client'; +import {App} from './App.tsx'; + +createRoot(document.getElementById('root')!).render(); diff --git a/examples/vite-react/src/vite-env.d.ts b/examples/vite-react/src/vite-env.d.ts new file mode 100644 index 000000000..241d205b0 --- /dev/null +++ b/examples/vite-react/src/vite-env.d.ts @@ -0,0 +1,6 @@ +/// + +declare module 'virtual:fuz.css' { + const css: string; + export default css; +} diff --git a/examples/vite-react/tsconfig.json b/examples/vite-react/tsconfig.json new file mode 100644 index 000000000..a31bbb0e8 --- /dev/null +++ b/examples/vite-react/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/examples/vite-react/vite.config.ts b/examples/vite-react/vite.config.ts new file mode 100644 index 000000000..0203c41c0 --- /dev/null +++ b/examples/vite-react/vite.config.ts @@ -0,0 +1,17 @@ +import {defineConfig} from 'vite'; +import react from '@vitejs/plugin-react'; +import jsx from 'acorn-jsx'; +import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; + +export default defineConfig({ + plugins: [ + // Plugin order doesn't matter for react (fuz_css uses enforce: 'pre') + react(), + vite_plugin_fuz_css({ + acorn_plugins: [jsx()], + // Include dynamically constructed classes that can't be statically extracted + // The example uses `bg_${hue}_5` in a .map() which produces these at runtime + include_classes: ['bg_a_5', 'bg_b_5', 'bg_c_5', 'bg_d_5', 'bg_e_5'], + }), + ], +}); diff --git a/examples/vite-solid/index.html b/examples/vite-solid/index.html new file mode 100644 index 000000000..7e289f88e --- /dev/null +++ b/examples/vite-solid/index.html @@ -0,0 +1,12 @@ + + + + + + fuz_css + Solid + + +
+ + + diff --git a/examples/vite-solid/package-lock.json b/examples/vite-solid/package-lock.json new file mode 100644 index 000000000..3cd774e75 --- /dev/null +++ b/examples/vite-solid/package-lock.json @@ -0,0 +1,2007 @@ +{ + "name": "vite-solid-fuz-css-example", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vite-solid-fuz-css-example", + "dependencies": { + "solid-js": "^1" + }, + "devDependencies": { + "@fuzdev/fuz_css": "file:../..", + "acorn-jsx": "^5", + "typescript": "^5", + "vite": "^6", + "vite-plugin-solid": "^2" + } + }, + "../..": { + "name": "@fuzdev/fuz_css", + "version": "0.43.0", + "dev": true, + "license": "MIT", + "devDependencies": { + "@changesets/changelog-git": "^0.2.1", + "@fuzdev/fuz_code": "^0.39.0", + "@fuzdev/fuz_ui": "^0.177.0", + "@fuzdev/fuz_util": "^0.45.3", + "@ryanatkn/eslint-config": "^0.9.0", + "@ryanatkn/gro": "^0.185.0", + "@sveltejs/acorn-typescript": "^1.0.8", + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.49.1", + "@sveltejs/package": "^2.5.7", + "@sveltejs/vite-plugin-svelte": "^6.2.1", + "@types/node": "^24.10.1", + "@webref/css": "^8.1.3", + "acorn-jsx": "^5.3.2", + "eslint": "^9.39.1", + "eslint-plugin-svelte": "^3.13.1", + "prettier": "^3.7.4", + "prettier-plugin-svelte": "^3.4.1", + "svelte": "^5.45.6", + "svelte-check": "^4.3.4", + "tslib": "^2.8.1", + "typescript": "^5.9.3", + "typescript-eslint": "^8.48.1", + "vitest": "^4.0.15", + "zimmerframe": "^1.1.4", + "zod": "^4.1.13" + }, + "engines": { + "node": ">=22.15" + }, + "funding": { + "url": "https://www.ryanatkn.com/funding" + }, + "peerDependencies": { + "@fuzdev/fuz_util": ">=0.42.0", + "@sveltejs/acorn-typescript": "^1", + "@webref/css": "^8", + "acorn-jsx": "^5", + "zimmerframe": "^1" + }, + "peerDependenciesMeta": { + "@fuzdev/fuz_util": { + "optional": true + }, + "@sveltejs/acorn-typescript": { + "optional": true + }, + "@webref/css": { + "optional": true + }, + "acorn-jsx": { + "optional": true + }, + "zimmerframe": { + "optional": true + } + } + }, + "node_modules/@babel/code-frame": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", + "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fuzdev/fuz_css": { + "resolved": "../..", + "link": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", + "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", + "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", + "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", + "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", + "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", + "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", + "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", + "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", + "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", + "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", + "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", + "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", + "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", + "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", + "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", + "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", + "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", + "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", + "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", + "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", + "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", + "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", + "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", + "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", + "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/babel-plugin-jsx-dom-expressions": { + "version": "0.40.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.40.3.tgz", + "integrity": "sha512-5HOwwt0BYiv/zxl7j8Pf2bGL6rDXfV6nUhLs8ygBX+EFJXzBPHM/euj9j/6deMZ6wa52Wb2PBaAV5U/jKwIY1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "7.18.6", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.20.7", + "html-entities": "2.3.3", + "parse5": "^7.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.20.12" + } + }, + "node_modules/babel-plugin-jsx-dom-expressions/node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/babel-preset-solid": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.9.10.tgz", + "integrity": "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jsx-dom-expressions": "^0.40.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "solid-js": "^1.9.10" + }, + "peerDependenciesMeta": { + "solid-js": { + "optional": true + } + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", + "integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001764", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz", + "integrity": "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/merge-anything": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-5.1.7.tgz", + "integrity": "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", + "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.55.1", + "@rollup/rollup-android-arm64": "4.55.1", + "@rollup/rollup-darwin-arm64": "4.55.1", + "@rollup/rollup-darwin-x64": "4.55.1", + "@rollup/rollup-freebsd-arm64": "4.55.1", + "@rollup/rollup-freebsd-x64": "4.55.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", + "@rollup/rollup-linux-arm-musleabihf": "4.55.1", + "@rollup/rollup-linux-arm64-gnu": "4.55.1", + "@rollup/rollup-linux-arm64-musl": "4.55.1", + "@rollup/rollup-linux-loong64-gnu": "4.55.1", + "@rollup/rollup-linux-loong64-musl": "4.55.1", + "@rollup/rollup-linux-ppc64-gnu": "4.55.1", + "@rollup/rollup-linux-ppc64-musl": "4.55.1", + "@rollup/rollup-linux-riscv64-gnu": "4.55.1", + "@rollup/rollup-linux-riscv64-musl": "4.55.1", + "@rollup/rollup-linux-s390x-gnu": "4.55.1", + "@rollup/rollup-linux-x64-gnu": "4.55.1", + "@rollup/rollup-linux-x64-musl": "4.55.1", + "@rollup/rollup-openbsd-x64": "4.55.1", + "@rollup/rollup-openharmony-arm64": "4.55.1", + "@rollup/rollup-win32-arm64-msvc": "4.55.1", + "@rollup/rollup-win32-ia32-msvc": "4.55.1", + "@rollup/rollup-win32-x64-gnu": "4.55.1", + "@rollup/rollup-win32-x64-msvc": "4.55.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/seroval": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz", + "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/seroval-plugins": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.3.3.tgz", + "integrity": "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "seroval": "^1.0" + } + }, + "node_modules/solid-js": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.10.tgz", + "integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.0", + "seroval": "~1.3.0", + "seroval-plugins": "~1.3.0" + } + }, + "node_modules/solid-refresh": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/solid-refresh/-/solid-refresh-0.6.3.tgz", + "integrity": "sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.23.6", + "@babel/helper-module-imports": "^7.22.15", + "@babel/types": "^7.23.6" + }, + "peerDependencies": { + "solid-js": "^1.3" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-solid": { + "version": "2.11.10", + "resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.11.10.tgz", + "integrity": "sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.3", + "@types/babel__core": "^7.20.4", + "babel-preset-solid": "^1.8.4", + "merge-anything": "^5.1.7", + "solid-refresh": "^0.6.3", + "vitefu": "^1.0.4" + }, + "peerDependencies": { + "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", + "solid-js": "^1.7.2", + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "@testing-library/jest-dom": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", + "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/examples/vite-solid/package.json b/examples/vite-solid/package.json new file mode 100644 index 000000000..7ac7052fb --- /dev/null +++ b/examples/vite-solid/package.json @@ -0,0 +1,20 @@ +{ + "name": "vite-solid-fuz-css-example", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "solid-js": "^1" + }, + "devDependencies": { + "@fuzdev/fuz_css": "file:../..", + "acorn-jsx": "^5", + "typescript": "^5", + "vite": "^6", + "vite-plugin-solid": "^2" + } +} diff --git a/examples/vite-solid/src/App.tsx b/examples/vite-solid/src/App.tsx new file mode 100644 index 000000000..c45077c9a --- /dev/null +++ b/examples/vite-solid/src/App.tsx @@ -0,0 +1,158 @@ +import {createSignal, For} from 'solid-js'; + +// Import from node_modules to verify extraction works for dependencies +import { + // Token classes (mix of camelCase and snake_case) + demo_padding_class, + demoShadowClass, + demo_color_class, + // Composite classes + demoBoxClass, + demo_row_class, + demoEllipsisClass, + // Literal classes + demo_display_class, + demoAlignClass, + demo_gap_class, + // Variable patterns + demoClassName, + DEMO_CONSTANT_CLASS, + card_class, + demo_ternary_class, + demo_logical_class, + demoArrayClasses, + // Comment hint examples + from_comment, + arbitrary_literal, +} from '@fuzdev/fuz_css/example_class_utilities.js'; + +export const App = () => { + const [count, setCount] = createSignal(0); + + return ( +
+
+
+

fuz_css + Solid

+

+ Utility classes generated on-demand via Vite plugin +

+
+ + {/* Responsive layout: column on mobile, row on desktop */} +
+
+

Responsive

+

+ This layout stacks on mobile and becomes a row on medium screens. +

+
+
+

On-demand

+

+ Only the classes you use are included in the bundle. +

+
+
+ + {/* Interactive button with hover states */} +
+

Interactive

+
+ + +
+
+ + {/* Dark mode demo */} +
+

Color Scheme

+
+
+ Adapts to dark mode +
+
+ Different in each scheme +
+
+
+ + {/* Token classes showcase */} +
+

Design Tokens

+
+ + {(hue) => ( +
+ {hue.toUpperCase()} +
+ )} +
+
+
+ + {/* Classes from node_modules dependency - all unique, verifies extraction */} +
+

From Dependencies

+

+ Classes imported from @fuzdev/fuz_css/example_class_utilities: +

+ + {/* Token classes */} +
+
+ {demo_padding_class} + {demoShadowClass} +
+
+ {demo_color_class} +
+
+ + {/* Composite classes */} +
+
+ {card_class} +
+
+ + {demoEllipsisClass} truncates long text + +
+
+ + {/* Variable patterns - each uses a unique class */} +
+
+ DEMO_CONSTANT_CLASS: {DEMO_CONSTANT_CLASS} +
+
+ demo_ternary_class: {demo_ternary_class} +
+
+ demo_logical_class: {demo_logical_class} +
+
+ demoArrayClasses: [{demoArrayClasses.join(', ')}] +
+
+ from_comment (via @fuz-classes): {from_comment} +
+
+ arbitrary_literal: {arbitrary_literal} +
+
+
+
+
+ ); +}; diff --git a/examples/vite-solid/src/main.tsx b/examples/vite-solid/src/main.tsx new file mode 100644 index 000000000..d4ca9082f --- /dev/null +++ b/examples/vite-solid/src/main.tsx @@ -0,0 +1,8 @@ +import '@fuzdev/fuz_css/style.css'; +import '@fuzdev/fuz_css/theme.css'; +import 'virtual:fuz.css'; + +import {render} from 'solid-js/web'; +import {App} from './App.tsx'; + +render(() => , document.getElementById('root')!); diff --git a/examples/vite-solid/src/vite-env.d.ts b/examples/vite-solid/src/vite-env.d.ts new file mode 100644 index 000000000..241d205b0 --- /dev/null +++ b/examples/vite-solid/src/vite-env.d.ts @@ -0,0 +1,6 @@ +/// + +declare module 'virtual:fuz.css' { + const css: string; + export default css; +} diff --git a/examples/vite-solid/tsconfig.json b/examples/vite-solid/tsconfig.json new file mode 100644 index 000000000..afbd76a06 --- /dev/null +++ b/examples/vite-solid/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/examples/vite-solid/vite.config.ts b/examples/vite-solid/vite.config.ts new file mode 100644 index 000000000..78419e1ab --- /dev/null +++ b/examples/vite-solid/vite.config.ts @@ -0,0 +1,17 @@ +import {defineConfig} from 'vite'; +import solid from 'vite-plugin-solid'; +import jsx from 'acorn-jsx'; +import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; + +export default defineConfig({ + plugins: [ + // fuz_css must be listed first for solid (enforce: 'pre' alone isn't sufficient) + vite_plugin_fuz_css({ + acorn_plugins: [jsx()], + // Include dynamically constructed classes that can't be statically extracted + // The example uses `bg_${hue}_5` in a which produces these at runtime + include_classes: ['bg_a_5', 'bg_b_5', 'bg_c_5', 'bg_d_5', 'bg_e_5'], + }), + solid(), + ], +}); diff --git a/examples/vite-svelte/index.html b/examples/vite-svelte/index.html new file mode 100644 index 000000000..d3652ec98 --- /dev/null +++ b/examples/vite-svelte/index.html @@ -0,0 +1,12 @@ + + + + + + fuz_css + Svelte + + +
+ + + diff --git a/examples/vite-svelte/package-lock.json b/examples/vite-svelte/package-lock.json new file mode 100644 index 000000000..cfa68627e --- /dev/null +++ b/examples/vite-svelte/package-lock.json @@ -0,0 +1,1464 @@ +{ + "name": "vite-svelte-fuz-css-example", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vite-svelte-fuz-css-example", + "dependencies": { + "svelte": "^5" + }, + "devDependencies": { + "@fuzdev/fuz_css": "file:../..", + "@sveltejs/vite-plugin-svelte": "^5", + "typescript": "^5", + "vite": "^6" + } + }, + "../..": { + "name": "@fuzdev/fuz_css", + "version": "0.43.0", + "dev": true, + "license": "MIT", + "devDependencies": { + "@changesets/changelog-git": "^0.2.1", + "@fuzdev/fuz_code": "^0.39.0", + "@fuzdev/fuz_ui": "^0.177.0", + "@fuzdev/fuz_util": "^0.45.3", + "@ryanatkn/eslint-config": "^0.9.0", + "@ryanatkn/gro": "^0.185.0", + "@sveltejs/acorn-typescript": "^1.0.8", + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.49.1", + "@sveltejs/package": "^2.5.7", + "@sveltejs/vite-plugin-svelte": "^6.2.1", + "@types/node": "^24.10.1", + "@webref/css": "^8.1.3", + "acorn-jsx": "^5.3.2", + "eslint": "^9.39.1", + "eslint-plugin-svelte": "^3.13.1", + "prettier": "^3.7.4", + "prettier-plugin-svelte": "^3.4.1", + "svelte": "^5.45.6", + "svelte-check": "^4.3.4", + "tslib": "^2.8.1", + "typescript": "^5.9.3", + "typescript-eslint": "^8.48.1", + "vitest": "^4.0.15", + "zimmerframe": "^1.1.4", + "zod": "^4.1.13" + }, + "engines": { + "node": ">=22.15" + }, + "funding": { + "url": "https://www.ryanatkn.com/funding" + }, + "peerDependencies": { + "@fuzdev/fuz_util": ">=0.42.0", + "@sveltejs/acorn-typescript": "^1", + "@webref/css": "^8", + "acorn-jsx": "^5", + "zimmerframe": "^1" + }, + "peerDependenciesMeta": { + "@fuzdev/fuz_util": { + "optional": true + }, + "@sveltejs/acorn-typescript": { + "optional": true + }, + "@webref/css": { + "optional": true + }, + "acorn-jsx": { + "optional": true + }, + "zimmerframe": { + "optional": true + } + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fuzdev/fuz_css": { + "resolved": "../..", + "link": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", + "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", + "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", + "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", + "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", + "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", + "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", + "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", + "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", + "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", + "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", + "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", + "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", + "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", + "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", + "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", + "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", + "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", + "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", + "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", + "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", + "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", + "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", + "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", + "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", + "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.8.tgz", + "integrity": "sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz", + "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", + "debug": "^4.4.1", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.17", + "vitefu": "^1.0.6" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", + "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.7" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/devalue": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.1.tgz", + "integrity": "sha512-jDwizj+IlEZBunHcOuuFVBnIMPAEHvTsJj0BcIp94xYguLRVBcXO853px/MyIJvbVzWdsGvrRweIUWJw8hBP7A==", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "license": "MIT" + }, + "node_modules/esrap": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.1.tgz", + "integrity": "sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", + "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.55.1", + "@rollup/rollup-android-arm64": "4.55.1", + "@rollup/rollup-darwin-arm64": "4.55.1", + "@rollup/rollup-darwin-x64": "4.55.1", + "@rollup/rollup-freebsd-arm64": "4.55.1", + "@rollup/rollup-freebsd-x64": "4.55.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", + "@rollup/rollup-linux-arm-musleabihf": "4.55.1", + "@rollup/rollup-linux-arm64-gnu": "4.55.1", + "@rollup/rollup-linux-arm64-musl": "4.55.1", + "@rollup/rollup-linux-loong64-gnu": "4.55.1", + "@rollup/rollup-linux-loong64-musl": "4.55.1", + "@rollup/rollup-linux-ppc64-gnu": "4.55.1", + "@rollup/rollup-linux-ppc64-musl": "4.55.1", + "@rollup/rollup-linux-riscv64-gnu": "4.55.1", + "@rollup/rollup-linux-riscv64-musl": "4.55.1", + "@rollup/rollup-linux-s390x-gnu": "4.55.1", + "@rollup/rollup-linux-x64-gnu": "4.55.1", + "@rollup/rollup-linux-x64-musl": "4.55.1", + "@rollup/rollup-openbsd-x64": "4.55.1", + "@rollup/rollup-openharmony-arm64": "4.55.1", + "@rollup/rollup-win32-arm64-msvc": "4.55.1", + "@rollup/rollup-win32-ia32-msvc": "4.55.1", + "@rollup/rollup-win32-x64-gnu": "4.55.1", + "@rollup/rollup-win32-x64-msvc": "4.55.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/svelte": { + "version": "5.46.3", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.46.3.tgz", + "integrity": "sha512-Y5juST3x+/ySty5tYJCVWa6Corkxpt25bUZQHqOceg9xfMUtDsFx6rCsG6cYf1cA6vzDi66HIvaki0byZZX95A==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "acorn": "^8.12.1", + "aria-query": "^5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "devalue": "^5.5.0", + "esm-env": "^1.2.1", + "esrap": "^2.2.1", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", + "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/zimmerframe": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", + "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", + "license": "MIT" + } + } +} diff --git a/examples/vite-svelte/package.json b/examples/vite-svelte/package.json new file mode 100644 index 000000000..866826840 --- /dev/null +++ b/examples/vite-svelte/package.json @@ -0,0 +1,19 @@ +{ + "name": "vite-svelte-fuz-css-example", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "svelte": "^5" + }, + "devDependencies": { + "@fuzdev/fuz_css": "file:../..", + "@sveltejs/vite-plugin-svelte": "^5", + "typescript": "^5", + "vite": "^6" + } +} diff --git a/examples/vite-svelte/src/App.svelte b/examples/vite-svelte/src/App.svelte new file mode 100644 index 000000000..cd3983f07 --- /dev/null +++ b/examples/vite-svelte/src/App.svelte @@ -0,0 +1,152 @@ + + +
+
+
+

fuz_css + Svelte

+

+ Utility classes generated on-demand via Vite plugin +

+
+ + +
+
+

Responsive

+

+ This layout stacks on mobile and becomes a row on medium screens. +

+
+
+

On-demand

+

+ Only the classes you use are included in the bundle. +

+
+
+ + +
+

Interactive

+
+ + +
+
+ + +
+

Color Scheme

+
+
+ Adapts to dark mode +
+
+ Different in each scheme +
+
+
+ + +
+

Design Tokens

+
+ {#each ['a', 'b', 'c', 'd', 'e'] as hue} +
+ {hue.toUpperCase()} +
+ {/each} +
+
+ + +
+

From Dependencies

+

+ Classes imported from @fuzdev/fuz_css/example_class_utilities: +

+ + +
+
+ {demo_padding_class} + {demoShadowClass} +
+
+ {demo_color_class} +
+
+ + +
+
+ {card_class} +
+
+ + {demoEllipsisClass} truncates long text + +
+
+ + +
+
+ DEMO_CONSTANT_CLASS: {DEMO_CONSTANT_CLASS} +
+
+ demo_ternary_class: {demo_ternary_class} +
+
+ demo_logical_class: {demo_logical_class} +
+
+ demoArrayClasses: [{demoArrayClasses.join(', ')}] +
+
+ from_comment (via @fuz-classes): {from_comment} +
+
+ arbitrary_literal: {arbitrary_literal} +
+
+
+
+
diff --git a/examples/vite-svelte/src/main.ts b/examples/vite-svelte/src/main.ts new file mode 100644 index 000000000..f50b05321 --- /dev/null +++ b/examples/vite-svelte/src/main.ts @@ -0,0 +1,8 @@ +import '@fuzdev/fuz_css/style.css'; +import '@fuzdev/fuz_css/theme.css'; +import 'virtual:fuz.css'; + +import {mount} from 'svelte'; +import App from './App.svelte'; + +mount(App, {target: document.getElementById('root')!}); diff --git a/examples/vite-svelte/src/vite-env.d.ts b/examples/vite-svelte/src/vite-env.d.ts new file mode 100644 index 000000000..241d205b0 --- /dev/null +++ b/examples/vite-svelte/src/vite-env.d.ts @@ -0,0 +1,6 @@ +/// + +declare module 'virtual:fuz.css' { + const css: string; + export default css; +} diff --git a/examples/vite-svelte/tsconfig.json b/examples/vite-svelte/tsconfig.json new file mode 100644 index 000000000..394f77eb2 --- /dev/null +++ b/examples/vite-svelte/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/examples/vite-svelte/vite.config.ts b/examples/vite-svelte/vite.config.ts new file mode 100644 index 000000000..07f5973ef --- /dev/null +++ b/examples/vite-svelte/vite.config.ts @@ -0,0 +1,15 @@ +import {defineConfig} from 'vite'; +import {svelte} from '@sveltejs/vite-plugin-svelte'; +import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; + +export default defineConfig({ + plugins: [ + // fuz_css must be listed first for svelte (enforce: 'pre' alone isn't sufficient) + vite_plugin_fuz_css({ + // Include dynamically constructed classes that can't be statically extracted + // The example uses `bg_${hue}_5` in an {#each} which produces these at runtime + include_classes: ['bg_a_5', 'bg_b_5', 'bg_c_5', 'bg_d_5', 'bg_e_5'], + }), + svelte(), + ], +}); diff --git a/src/lib/example_class_utilities.ts b/src/lib/example_class_utilities.ts new file mode 100644 index 000000000..a2765e931 --- /dev/null +++ b/src/lib/example_class_utilities.ts @@ -0,0 +1,111 @@ +/** + * Example CSS class exports demonstrating node_modules extraction. + * + * This module exists to verify that the Vite plugin extracts classes from + * dependencies in node_modules. Each export uses a unique class value + * to verify extraction is working correctly. + * + * **Important:** Variable names must end with `class`, `classes`, or `className` + * for the extractor to detect them (see `CLASS_NAME_PATTERN` in css_class_extractor.ts). + * + * **Class types demonstrated:** + * - Token classes: Map to style variables (`p_lg`, `shadow_sm`) + * - Composite classes: Multi-property shortcuts (`box`, `row`) + * - Literal classes: CSS property:value syntax (`display:flex`) + * + * **Variable patterns demonstrated:** + * - Simple assignment, ternary expressions, logical AND, arrays + * - Various naming conventions (camelCase, snake_case, SCREAMING_SNAKE) + * - Comment hints via `@fuz-classes` + * + * @module + */ + +/* eslint-disable no-constant-condition, @typescript-eslint/no-unnecessary-condition, no-constant-binary-expression */ + +// +// Token classes - map to style variables +// + +/** Padding token - large spacing (snake_case) */ +export const demo_padding_class = 'p_lg'; + +/** Shadow token - small elevation (camelCase) */ +export const demoShadowClass = 'shadow_sm'; + +/** Color token - primary hue intensity 5 (snake_case) */ +export const demo_color_class = 'color_a_5'; + +// +// Composite classes - multi-property shortcuts +// + +/** Layout composite - centered flex container (camelCase) */ +export const demoBoxClass = 'box'; + +/** Layout composite - horizontal flex row (snake_case) */ +export const demo_row_class = 'row'; + +/** Text composite - truncate with ellipsis (camelCase) */ +export const demoEllipsisClass = 'ellipsis'; + +// +// Literal classes - CSS property:value syntax +// + +/** Display literal - flex layout (snake_case) */ +export const demo_display_class = 'display:flex'; + +/** Alignment literal - center items (camelCase) */ +export const demoAlignClass = 'align-items:center'; + +/** Spacing literal - gap between children (snake_case) */ +export const demo_gap_class = 'gap:1rem'; + +// +// Variable patterns and naming conventions +// + +/** camelCase naming - triggers naming-based extraction */ +export const demoClassName = 'column'; + +/** SCREAMING_SNAKE_CASE naming */ +export const DEMO_CONSTANT_CLASS = 'p_md'; + +/** Suffix convention (_class) - triggers naming-based extraction */ +export const card_class = 'pane'; + +/** Ternary expression - both branches should be extracted */ +export const demo_ternary_class = true ? 'bg_d_3' : 'bg_3'; + +/** Logical AND - truthy value should be extracted */ +export const demo_logical_class = true && 'opacity:60%'; + +/** Array - all elements should be extracted */ +export const demoArrayClasses = ['m_xs', 'shadow_xs']; + +// +// Comment hint examples - @fuz-classes directive +// + +// @fuz-classes shadow_lg +/** + * Comment hint - extracted via @fuz-classes, NOT via variable name pattern. + * Variable name `from_comment` doesn't end in class/classes/className. + */ +export const from_comment = 'shadow_lg'; + +// @fuz-classes unknown_not_included +/** + * Unknown class - extracted via @fuz-classes but has no CSS definition. + * This class will be extracted but NOT included in output (no matching token/composite/literal). + */ +export const unknown_extracted = 'unknown_not_included'; + +// @fuz-classes not-real:extracted-but-excluded +/** + * Invalid literal - extracted via @fuz-classes but excluded from CSS output. + * Properties are validated against `@webref/css` data, so `not-real` fails validation. + * This demonstrates that extraction and generation are separate steps. + */ +export const arbitrary_literal = 'not-real:extracted-but-excluded'; diff --git a/src/lib/file_filter.ts b/src/lib/file_filter.ts new file mode 100644 index 000000000..1d6bfe07a --- /dev/null +++ b/src/lib/file_filter.ts @@ -0,0 +1,35 @@ +/** + * File filtering utilities for CSS class extraction. + * + * @module + */ + +/** + * Filter function to determine which files to process for CSS class extraction. + */ +export type FileFilter = (path: string) => boolean; + +/** + * Default file filter for CSS class extraction. + * Includes .svelte, .html, .ts, .js, .tsx, .jsx files. + * Excludes test files and generated files. + */ +export const filter_file_default: FileFilter = (path) => { + if ( + path.includes('.test.') || + path.includes('/test/') || + path.includes('/tests/') || + path.includes('.gen.') + ) { + return false; + } + const ext = path.slice(path.lastIndexOf('.')); + return ( + ext === '.svelte' || + ext === '.html' || + ext === '.ts' || + ext === '.js' || + ext === '.tsx' || + ext === '.jsx' + ); +}; diff --git a/src/lib/gen_fuz_css.ts b/src/lib/gen_fuz_css.ts index 868155129..a5f8f2c51 100644 --- a/src/lib/gen_fuz_css.ts +++ b/src/lib/gen_fuz_css.ts @@ -9,9 +9,9 @@ import {join} from 'node:path'; import type {Gen} from '@ryanatkn/gro/gen.js'; -import type {FileFilter} from '@fuzdev/fuz_util/path.js'; import {map_concurrent, each_concurrent} from '@fuzdev/fuz_util/async.js'; +import {type FileFilter, filter_file_default} from './file_filter.js'; import {extract_css_classes_with_locations, type AcornPlugin} from './css_class_extractor.js'; import {type SourceLocation, type ExtractionDiagnostic, type Diagnostic} from './diagnostics.js'; import {CssClasses} from './css_classes.js'; @@ -166,26 +166,6 @@ export class CssGenerationError extends Error { } } -const filter_file_default: FileFilter = (path) => { - if ( - path.includes('.test.') || - path.includes('/test/') || - path.includes('/tests/') || - path.includes('.gen.') - ) { - return false; - } - const ext = path.slice(path.lastIndexOf('.')); - return ( - ext === '.svelte' || - ext === '.html' || - ext === '.ts' || - ext === '.js' || - ext === '.tsx' || - ext === '.jsx' - ); -}; - export const gen_fuz_css = (options: GenFuzCssOptions = {}): Gen => { const { filter_file = filter_file_default, diff --git a/src/lib/vite_plugin_fuz_css.ts b/src/lib/vite_plugin_fuz_css.ts new file mode 100644 index 000000000..d9e1f1bf8 --- /dev/null +++ b/src/lib/vite_plugin_fuz_css.ts @@ -0,0 +1,500 @@ +/** + * Vite plugin for fuz_css utility class generation. + * + * Uses Vite's transform hook to extract CSS classes from source files + * as they're processed, including node_modules dependencies. + * Generates CSS on-demand via virtual module with HMR support. + * + * @example + * ```ts + * // vite.config.ts + * import {defineConfig} from 'vite'; + * import jsx from 'acorn-jsx'; + * import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; + * + * export default defineConfig({ + * plugins: [ + * vite_plugin_fuz_css({ + * acorn_plugins: [jsx()], + * }), + * ], + * }); + * ``` + * + * @module + */ + +import type {Plugin, ViteDevServer} from 'vite'; +import {join} from 'node:path'; + +import {extract_css_classes_with_locations, type AcornPlugin} from './css_class_extractor.js'; +import {type SourceLocation, type GenerationDiagnostic} from './diagnostics.js'; +import { + generate_classes_css, + type CssClassDefinition, + type CssClassDefinitionInterpreter, +} from './css_class_generation.js'; +import {css_class_definitions} from './css_class_definitions.js'; +import {css_class_interpreters} from './css_class_interpreters.js'; +import {load_css_properties} from './css_literal.js'; +import { + get_cache_path, + load_cached_extraction, + save_cached_extraction, + delete_cached_extraction, + from_cached_extraction, +} from './css_cache.js'; +import {type FileFilter, filter_file_default} from './file_filter.js'; + +/* eslint-disable no-console */ + +const VIRTUAL_ID = 'virtual:fuz.css'; +const RESOLVED_VIRTUAL_ID = '\0virtual:fuz.css'; + +/** + * Skip cache on CI (no point writing cache that won't be reused). + */ +const is_ci = !!process.env.CI; + +/** + * Computes SHA-256 hash of content using Web Crypto API. + * Matches Gro's hashing approach for cache compatibility. + */ +const compute_hash = async (content: string): Promise => { + const encoder = new TextEncoder(); + const buffer = encoder.encode(content); + const digested = await crypto.subtle.digest('SHA-256', buffer); + const bytes = Array.from(new Uint8Array(digested)); + let hex = ''; + for (const h of bytes) { + hex += h.toString(16).padStart(2, '0'); + } + return hex; +}; + +/** + * Options for the fuz_css Vite plugin. + */ +export interface VitePluginFuzCssOptions { + /** + * Filter function to determine which files to extract classes from. + * By default, extracts from .svelte, .html, .ts, .js, .tsx, .jsx files, + * excluding test files and .gen files. + */ + filter_file?: FileFilter; + /** + * Additional class definitions to merge with builtins. + * User definitions take precedence over builtins with the same name. + */ + class_definitions?: Record; + /** + * Custom interpreters for dynamic class generation. + * Replaces the builtin interpreters entirely if provided. + */ + class_interpreters?: Array; + /** + * Classes to always include in the output, regardless of detection. + */ + include_classes?: Iterable; + /** + * Classes to exclude from the output, even if detected. + */ + exclude_classes?: Iterable; + /** + * Additional acorn plugins for parsing. + * Use `acorn-jsx` for React/Preact/Solid projects. + */ + acorn_plugins?: Array; + /** + * How to handle CSS-literal errors during generation. + * - 'log' (default): Log errors, skip invalid classes, continue + * - 'throw': Throw on first error, fail the build + */ + on_error?: 'log' | 'throw'; + /** + * Cache directory relative to project root. + * @default '.fuz/cache/css' + */ + cache_dir?: string; +} + +/** + * Class registry for tracking extracted classes across files. + */ +interface ClassRegistry { + /** file path → extracted classes with locations */ + files: Map>>; + /** file path → content hash for caching */ + hashes: Map; + /** aggregated classes, null = dirty, needs recompute */ + all_classes: Set | null; + /** aggregated class locations (null entry = include_class), null = dirty */ + all_locations: Map | null> | null; +} + +/** + * Creates the fuz_css Vite plugin. + * + * Extracts CSS classes from source files during Vite's transform phase + * and generates optimized CSS via the `virtual:fuz.css` virtual module. + */ +export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plugin => { + const { + filter_file = filter_file_default, + class_definitions: user_class_definitions, + class_interpreters = css_class_interpreters, + include_classes, + exclude_classes, + acorn_plugins, + on_error = 'log', + cache_dir = '.fuz/cache/css', + } = options; + + // Merge class definitions + const all_class_definitions = user_class_definitions + ? {...css_class_definitions, ...user_class_definitions} + : css_class_definitions; + + // Convert to Sets for efficient lookup + const include_set = include_classes ? new Set(include_classes) : null; + const exclude_set = exclude_classes ? new Set(exclude_classes) : null; + + // Plugin state + const registry: ClassRegistry = { + files: new Map(), + hashes: new Map(), + all_classes: null, + all_locations: null, + }; + let virtual_module_loaded = false; + let server: ViteDevServer | null = null; + let css_properties: Set | null = null; + let resolved_cache_dir: string | null = null; + let project_root: string | null = null; + let hmr_timeout: ReturnType | null = null; + + /** Logs a warning message (works in both dev and build) */ + const log_warn = (msg: string): void => { + if (server) { + server.config.logger.warn(msg); + } else { + console.warn(msg); + } + }; + + /** Logs an error message (works in both dev and build) */ + const log_error = (msg: string): void => { + if (server) { + server.config.logger.error(msg); + } else { + console.error(msg); + } + }; + + /** + * Computes cache path for a file. + * Internal files use relative paths, external files use hashed absolute paths. + */ + const get_file_cache_path = async (file_id: string): Promise => { + const is_internal = file_id.startsWith(project_root!); + return is_internal + ? get_cache_path(file_id, resolved_cache_dir!, project_root!) + : join( + resolved_cache_dir!, + '_external', + (await compute_hash(file_id)).slice(0, 16) + '.json', + ); + }; + + /** + * Recomputes aggregated classes from all files. + * Returns locations map with null values for include_classes (no source location). + */ + const get_all_classes = (): { + classes: Set; + locations: Map | null>; + } => { + if (registry.all_classes && registry.all_locations) { + return {classes: registry.all_classes, locations: registry.all_locations}; + } + + const classes: Set = new Set(); + const locations: Map | null> = new Map(); + + // Add include_classes first (with null locations - no source) + if (include_set) { + for (const c of include_set) { + classes.add(c); + locations.set(c, null); + } + } + + // Aggregate from all files + for (const file_classes of registry.files.values()) { + for (const [name, locs] of file_classes) { + classes.add(name); + const existing = locations.get(name); + // Don't overwrite null from include_classes + if (existing === undefined) { + locations.set(name, [...locs]); + } else if (existing !== null) { + existing.push(...locs); + } + } + } + + // Apply excludes + if (exclude_set) { + for (const c of exclude_set) { + classes.delete(c); + locations.delete(c); + } + } + + registry.all_classes = classes; + registry.all_locations = locations; + return {classes, locations}; + }; + + /** + * Generates CSS from the current class registry. + */ + const generate_css = (): string => { + const {classes, locations} = get_all_classes(); + + const result = generate_classes_css({ + class_names: classes, + class_definitions: all_class_definitions, + interpreters: class_interpreters, + css_properties, + class_locations: locations, + }); + + // Handle diagnostics + const errors = result.diagnostics.filter((d: GenerationDiagnostic) => d.level === 'error'); + if (errors.length > 0 && on_error === 'throw') { + throw new Error( + `CSS generation failed with ${errors.length} error(s):\n` + + errors.map((d: GenerationDiagnostic) => ` - ${d.class_name}: ${d.message}`).join('\n'), + ); + } + + // Log warnings/errors + for (const d of result.diagnostics) { + const msg = `[fuz_css] ${d.class_name}: ${d.message}`; + if (d.level === 'error') { + log_error(msg); + } else { + log_warn(msg); + } + } + + return `/* generated by vite_plugin_fuz_css */\n\n${result.css}\n\n/* generated by vite_plugin_fuz_css */`; + }; + + /** + * Invalidates the virtual module and triggers HMR. + * Debounced to avoid spamming updates when multiple files change rapidly. + */ + const invalidate_virtual_module = (): void => { + if (!server) return; + + // Debounce: wait 10ms for more changes before triggering HMR + if (hmr_timeout) { + clearTimeout(hmr_timeout); + } + hmr_timeout = setTimeout(() => { + hmr_timeout = null; + const mod = server!.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ID); + if (mod) { + server!.moduleGraph.invalidateModule(mod); + server!.ws.send({ + type: 'update', + updates: [ + { + type: 'css-update', + path: VIRTUAL_ID, + acceptedPath: VIRTUAL_ID, + timestamp: Date.now(), + }, + ], + }); + } + }, 10); + }; + + return { + name: 'vite-plugin-fuz-css', + // Run before other plugins (like Svelte) to see original source files + enforce: 'pre', + + configResolved(resolved_config) { + const root = resolved_config.root; + project_root = root.endsWith('/') ? root : root + '/'; + resolved_cache_dir = join(root, cache_dir); + }, + + configureServer(dev_server) { + server = dev_server; + + // Handle file deletion - watcher 'unlink' event + dev_server.watcher.on('unlink', (file) => { + if (registry.files.has(file)) { + registry.files.delete(file); + registry.hashes.delete(file); + registry.all_classes = null; + registry.all_locations = null; + + // Delete cache file (fire and forget) + if (!is_ci && resolved_cache_dir && project_root) { + get_file_cache_path(file) + .then((cache_path) => delete_cached_extraction(cache_path)) + .catch(() => { + // Ignore cache deletion errors + }); + } + + if (virtual_module_loaded) { + invalidate_virtual_module(); + } + } + }); + }, + + async buildStart() { + // Load CSS properties for validation + css_properties = await load_css_properties(); + }, + + resolveId(id) { + if (id === VIRTUAL_ID) { + return RESOLVED_VIRTUAL_ID; + } + return undefined; + }, + + load(id) { + if (id === RESOLVED_VIRTUAL_ID) { + virtual_module_loaded = true; + // In dev mode, generate CSS immediately for HMR + // In build mode, return minimal CSS - full CSS appended in generateBundle after all transforms + if (server) { + return generate_css(); + } + // Return empty CSS for build - generateBundle will append the complete CSS + return '/* fuz_css placeholder */'; + } + return undefined; + }, + + generateBundle(_options, bundle) { + // Regenerate CSS with all extracted classes and append to the CSS asset + // This runs after all transforms are complete, so all classes are available + const generated_css = generate_css(); + + // Find the main CSS asset and append our generated CSS + // Vite combines all CSS into one or more asset files + for (const chunk of Object.values(bundle)) { + if ( + chunk.type === 'asset' && + typeof chunk.source === 'string' && + chunk.fileName.endsWith('.css') + ) { + // Append the complete generated CSS to the end + chunk.source = chunk.source + '\n' + generated_css; + break; // Only append to first CSS asset + } + } + }, + + async transform(code, id) { + // Skip non-matching files + if (!filter_file(id)) { + return null; + } + + // Compute content hash + const hash = await compute_hash(code); + const existing_hash = registry.hashes.get(id); + + // Check if unchanged + if (existing_hash === hash) { + return null; + } + + // Try cache (if not CI and we have cache dir) + if (!is_ci && resolved_cache_dir && project_root) { + const cache_path = await get_file_cache_path(id); + const cached = await load_cached_extraction(cache_path); + + if (cached?.content_hash === hash) { + // Cache hit + const {classes} = from_cached_extraction(cached); + if (classes) { + registry.files.set(id, classes); + } else { + registry.files.delete(id); + } + registry.hashes.set(id, hash); + registry.all_classes = null; + registry.all_locations = null; + + if (virtual_module_loaded) { + invalidate_virtual_module(); + } + return null; + } + } + + // Extract classes + const result = extract_css_classes_with_locations(code, { + filename: id, + acorn_plugins, + }); + + // Log extraction diagnostics + if (result.diagnostics) { + for (const d of result.diagnostics) { + const loc = `${d.location.file}:${d.location.line}:${d.location.column}`; + const msg = `[fuz_css] ${loc}: ${d.message}`; + if (d.level === 'error') { + log_error(msg); + } else { + log_warn(msg); + } + } + } + + // Update registry + if (result.classes) { + registry.files.set(id, result.classes); + } else { + registry.files.delete(id); + } + registry.hashes.set(id, hash); + registry.all_classes = null; + registry.all_locations = null; + + // Save to cache (fire and forget - don't block transform) + if (!is_ci && resolved_cache_dir && project_root) { + get_file_cache_path(id) + .then((cache_path) => + save_cached_extraction(cache_path, hash, result.classes, result.diagnostics), + ) + .catch(() => { + // Ignore cache errors + }); + } + + // Trigger HMR if virtual module already loaded + if (virtual_module_loaded) { + invalidate_virtual_module(); + } + + return null; + }, + + // Note: handleHotUpdate not needed - transform hook handles file changes, + // and configureServer's watcher.on('unlink') handles file deletion + }; +}; diff --git a/src/routes/ThemeForm.svelte b/src/routes/ThemeForm.svelte index fa0ec0e84..951dc1283 100644 --- a/src/routes/ThemeForm.svelte +++ b/src/routes/ThemeForm.svelte @@ -75,7 +75,8 @@

variables: {light_count} light, {dark_count} dark

- add a variable
diff --git a/src/routes/docs/classes/+page.svelte b/src/routes/docs/classes/+page.svelte index 1a564a0fe..a6583d6c7 100644 --- a/src/routes/docs/classes/+page.svelte +++ b/src/routes/docs/classes/+page.svelte @@ -517,18 +517,113 @@ ${'<' as string}script> />

The fuz.css file is generated on demand with only the utility classes your code - uses. The main helper is -- for now it must be manually called - unless you use the Gro integration. A Vite plugin - is planned (feel free to open an issue to expedite!). + uses. There are two ways to generate it: the Vite plugin (recommended for + non-Svelte projects) or the Gro generator (recommended for SvelteKit projects).

-

To use with Gro, create src/routes/fuz.gen.css.ts:

- + + +

+ The Vite plugin uses transform-based extraction to generate CSS on-demand. It works with + React, Preact, Solid, Vue, and any other Vite-based framework. +

+ + +

Then import the virtual module in your entry file:

+ );`} + /> +

+ The plugin extracts classes from files as Vite processes them, including from + node_modules dependencies. It supports HMR — changes to classes trigger automatic + CSS updates. +

+

Plugin options

+
    +
  • + acorn_plugins — Required for JSX frameworks. Use acorn-jsx. +
  • +
  • + include_classes — Classes to always include (for dynamic patterns that can't be + statically extracted) +
  • +
  • + exclude_classes — Classes to exclude from output +
  • +
  • + class_definitions — Custom composite class definitions +
  • +
  • + filter_file — Custom filter for which files to process +
  • +
  • + on_error'log' (default) or 'throw' +
  • +
  • + cache_dir — Cache location (default: .fuz/cache/css) +
  • +
+

TypeScript setup

+

Add the virtual module declaration to your vite-env.d.ts:

+ + +declare module 'virtual:fuz.css' { + const css: string; + export default css; +}`} + /> +
+ + + +

+ For SvelteKit projects using Gro, create a + generator file: +

+ +

Then import the generated file in your layout:

+ +${'<' as string}script> + import '@fuzdev/fuz_css/style.css'; + import '@fuzdev/fuz_css/theme.css'; + import '$routes/fuz.css'; // generated by Gro +`} + /> +
diff --git a/src/routes/docs/examples/+page.svelte b/src/routes/docs/examples/+page.svelte new file mode 100644 index 000000000..e52524150 --- /dev/null +++ b/src/routes/docs/examples/+page.svelte @@ -0,0 +1,29 @@ + + + +
+

+ Example projects using the Vite plugin: +

+ +

+ Each example demonstrates token, composite, and literal classes with responsive, hover, and + dark mode modifiers. +

+
+
diff --git a/src/routes/docs/introduction/+page.svelte b/src/routes/docs/introduction/+page.svelte index 170783c08..7a3a54542 100644 --- a/src/routes/docs/introduction/+page.svelte +++ b/src/routes/docs/introduction/+page.svelte @@ -91,7 +91,9 @@ Gro with src/routes/fuz.gen.css.ts using the fuz_css helpers in - . I can add a Vite plugin if there's demand. + . There's also a for non-SvelteKit projects -- see the page.
  • There are not yet tools for optimizing away unused variables or main stylesheet rulesets, so = [ related_modules: [], related_declarations: [], }, + { + name: 'examples', + category: 'guide', + Component: examples, + related_tomes: ['classes'], + related_modules: [], + related_declarations: [], + }, { name: 'semantic', category: 'systems', diff --git a/src/routes/docs/typography/+page.svelte b/src/routes/docs/typography/+page.svelte index bfb249297..3d41e2d0f 100644 --- a/src/routes/docs/typography/+page.svelte +++ b/src/routes/docs/typography/+page.svelte @@ -123,7 +123,7 @@

    Font weight values can be any integer from 1 to 1000.

    There are no variables for but there are - utility classes. + utility classes.

    diff --git a/src/routes/fuz.css b/src/routes/fuz.css index eb37229a7..25da5f952 100644 --- a/src/routes/fuz.css +++ b/src/routes/fuz.css @@ -6,6 +6,11 @@ align-items: center; justify-content: center; } +/* like `.box` but uncentered */ +.column { + display: flex; + flex-direction: column; +} /* can be used to override the direction of a `.box` */ .row { display: flex; @@ -199,6 +204,9 @@ a.chip { .bg { background-color: var(--bg); } +.bg_3 { + background-color: var(--bg_3); +} .fg_1 { background-color: var(--fg_1); } @@ -232,6 +240,9 @@ a.chip { .bg_a_7 { background-color: var(--color_a_7); } +.bg_d_3 { + background-color: var(--color_d_3); +} .outline_color_3 { outline-color: var(--border_color_3); } @@ -491,6 +502,9 @@ a.chip { padding-top: var(--space_xs); padding-bottom: var(--space_xs); } +.m_xs { + margin: var(--space_xs); +} .mt_0 { margin-top: 0; } @@ -557,6 +571,9 @@ a.chip { .gap_lg { gap: var(--space_lg); } +.align-items\:center { + align-items: center; +} .border-bottom-left-radius\:100\% { border-bottom-left-radius: 100%; } @@ -635,6 +652,9 @@ a.chip { .font-weight\:950 { font-weight: 950; } +.gap\:1rem { + gap: 1rem; +} .inset\:0 { inset: 0; } @@ -653,6 +673,9 @@ a.chip { .opacity\:51\% { opacity: 51%; } +.opacity\:60\% { + opacity: 60%; +} .opacity\:79\% { opacity: 79%; } diff --git a/src/routes/library.json b/src/routes/library.json index 5b5fea5dd..c2667c50a 100644 --- a/src/routes/library.json +++ b/src/routes/library.json @@ -266,7 +266,7 @@ } ], "module_comment": "Cache infrastructure for incremental CSS class extraction.\n\nProvides per-file caching with content hash validation to avoid\nre-extracting classes from unchanged files.", - "dependents": ["gen_fuz_css.ts"] + "dependents": ["gen_fuz_css.ts", "vite_plugin_fuz_css.ts"] }, { "path": "css_class_composites.ts", @@ -294,7 +294,7 @@ ], "module_comment": "Built-in CSS class definitions combining token classes and composites.\n\nToken classes map to CSS variables (design tokens).\nFor other CSS properties, use CSS-literal syntax like `display:flex` or `position:absolute`.", "dependencies": ["css_class_composites.ts", "css_class_generators.ts", "variable_data.ts"], - "dependents": ["gen_fuz_css.ts"] + "dependents": ["gen_fuz_css.ts", "vite_plugin_fuz_css.ts"] }, { "path": "css_class_extractor.ts", @@ -495,7 +495,7 @@ } ], "module_comment": "AST-based CSS class extraction for Svelte and TypeScript files.\n\nReplaces regex-based extraction with proper parsing to handle:\n- `class=\"display:flex\"` - string attributes\n- `class={{ active, disabled: !enabled }}` - object attributes (Svelte 5.16+)\n- `class={[cond && 'box', 'display:flex']}` - array attributes (Svelte 5.16+)\n- `class:active={cond}` - class directives\n- `clsx('foo', { bar: true })` - class utility function calls\n- Variables with class-related names\n- `// @fuz-classes class1 class2` - comment hints for dynamic classes", - "dependents": ["gen_fuz_css.ts"] + "dependents": ["gen_fuz_css.ts", "vite_plugin_fuz_css.ts"] }, { "path": "css_class_generation.ts", @@ -747,7 +747,7 @@ ], "module_comment": "CSS class generation utilities.\n\nProduces CSS output from class definitions, handles interpretation of\ndynamic classes, and provides collection management for extracted classes.", "dependencies": ["css_class_resolution.ts", "css_ruleset_parser.ts", "diagnostics.ts"], - "dependents": ["css_class_interpreters.ts", "gen_fuz_css.ts"] + "dependents": ["css_class_interpreters.ts", "gen_fuz_css.ts", "vite_plugin_fuz_css.ts"] }, { "path": "css_class_generators.ts", @@ -1012,7 +1012,7 @@ "css_literal.ts", "css_ruleset_parser.ts" ], - "dependents": ["gen_fuz_css.ts"] + "dependents": ["gen_fuz_css.ts", "vite_plugin_fuz_css.ts"] }, { "path": "css_class_resolution.ts", @@ -1583,7 +1583,7 @@ ], "module_comment": "CSS-literal syntax parser, validator, and interpreter.\n\nEnables writing utility classes using actual CSS syntax:\n\n- `display:flex` → `.display\\:flex { display: flex; }`\n- `hover:opacity:80%` → `.hover\\:opacity\\:80\\%:hover { opacity: 80%; }`\n- `md:dark:hover:before:opacity:80%` → nested CSS with media query, ancestor, state, pseudo-element\n\n@see {@link https://github.com/fuzdev/fuz_css} for documentation", "dependencies": ["modifiers.ts"], - "dependents": ["css_class_interpreters.ts", "gen_fuz_css.ts"] + "dependents": ["css_class_interpreters.ts", "gen_fuz_css.ts", "vite_plugin_fuz_css.ts"] }, { "path": "css_ruleset_parser.ts", @@ -2117,6 +2117,166 @@ "module_comment": "Diagnostic types for CSS class extraction and generation.\n\nProvides a unified diagnostic system across all phases:\n- Extraction: Parsing source files to find class names\n- Generation: Producing CSS output from class definitions", "dependents": ["css_class_generation.ts"] }, + { + "path": "example_class_utilities.ts", + "declarations": [ + { + "name": "demo_padding_class", + "kind": "variable", + "doc_comment": "Padding token - large spacing (snake_case)", + "source_line": 31, + "type_signature": "\"p_lg\"" + }, + { + "name": "demoShadowClass", + "kind": "variable", + "doc_comment": "Shadow token - small elevation (camelCase)", + "source_line": 34, + "type_signature": "\"shadow_sm\"" + }, + { + "name": "demo_color_class", + "kind": "variable", + "doc_comment": "Color token - primary hue intensity 5 (snake_case)", + "source_line": 37, + "type_signature": "\"color_a_5\"" + }, + { + "name": "demoBoxClass", + "kind": "variable", + "doc_comment": "Layout composite - centered flex container (camelCase)", + "source_line": 44, + "type_signature": "\"box\"" + }, + { + "name": "demo_row_class", + "kind": "variable", + "doc_comment": "Layout composite - horizontal flex row (snake_case)", + "source_line": 47, + "type_signature": "\"row\"" + }, + { + "name": "demoEllipsisClass", + "kind": "variable", + "doc_comment": "Text composite - truncate with ellipsis (camelCase)", + "source_line": 50, + "type_signature": "\"ellipsis\"" + }, + { + "name": "demo_display_class", + "kind": "variable", + "doc_comment": "Display literal - flex layout (snake_case)", + "source_line": 57, + "type_signature": "\"display:flex\"" + }, + { + "name": "demoAlignClass", + "kind": "variable", + "doc_comment": "Alignment literal - center items (camelCase)", + "source_line": 60, + "type_signature": "\"align-items:center\"" + }, + { + "name": "demo_gap_class", + "kind": "variable", + "doc_comment": "Spacing literal - gap between children (snake_case)", + "source_line": 63, + "type_signature": "\"gap:1rem\"" + }, + { + "name": "demoClassName", + "kind": "variable", + "doc_comment": "camelCase naming - triggers naming-based extraction", + "source_line": 70, + "type_signature": "\"column\"" + }, + { + "name": "DEMO_CONSTANT_CLASS", + "kind": "variable", + "doc_comment": "SCREAMING_SNAKE_CASE naming", + "source_line": 73, + "type_signature": "\"p_md\"" + }, + { + "name": "card_class", + "kind": "variable", + "doc_comment": "Suffix convention (_class) - triggers naming-based extraction", + "source_line": 76, + "type_signature": "\"pane\"" + }, + { + "name": "demo_ternary_class", + "kind": "variable", + "doc_comment": "Ternary expression - both branches should be extracted", + "source_line": 79, + "type_signature": "\"bg_d_3\" | \"bg_3\"" + }, + { + "name": "demo_logical_class", + "kind": "variable", + "doc_comment": "Logical AND - truthy value should be extracted", + "source_line": 82, + "type_signature": "\"opacity:60%\"" + }, + { + "name": "demoArrayClasses", + "kind": "variable", + "doc_comment": "Array - all elements should be extracted", + "source_line": 85, + "type_signature": "string[]" + }, + { + "name": "from_comment", + "kind": "variable", + "doc_comment": "Comment hint - extracted via", + "source_line": 96, + "type_signature": "\"shadow_lg\"" + }, + { + "name": "unknown_extracted", + "kind": "variable", + "doc_comment": "Unknown class - extracted via", + "source_line": 103, + "type_signature": "\"unknown_not_included\"" + }, + { + "name": "arbitrary_literal", + "kind": "variable", + "doc_comment": "Invalid literal - extracted via", + "source_line": 111, + "type_signature": "\"not-real:extracted-but-excluded\"" + } + ], + "module_comment": "Example CSS class exports demonstrating node_modules extraction.\n\nThis module exists to verify that the Vite plugin extracts classes from\ndependencies in node_modules. Each export uses a unique class value\nto verify extraction is working correctly.\n\n**Important:** Variable names must end with `class`, `classes`, or `className`\nfor the extractor to detect them (see `CLASS_NAME_PATTERN` in css_class_extractor.ts).\n\n**Class types demonstrated:**\n- Token classes: Map to style variables (`p_lg`, `shadow_sm`)\n- Composite classes: Multi-property shortcuts (`box`, `row`)\n- Literal classes: CSS property:value syntax (`display:flex`)\n\n**Variable patterns demonstrated:**\n- Simple assignment, ternary expressions, logical AND, arrays\n- Various naming conventions (camelCase, snake_case, SCREAMING_SNAKE)\n- Comment hints via `@fuz-classes`" + }, + { + "path": "file_filter.ts", + "declarations": [ + { + "name": "FileFilter", + "kind": "type", + "doc_comment": "Filter function to determine which files to process for CSS class extraction.", + "source_line": 10, + "type_signature": "FileFilter" + }, + { + "name": "filter_file_default", + "kind": "function", + "doc_comment": "Default file filter for CSS class extraction.\nIncludes .svelte, .html, .ts, .js, .tsx, .jsx files.\nExcludes test files and generated files.", + "source_line": 17, + "type_signature": "(path: string): boolean", + "return_type": "boolean", + "parameters": [ + { + "name": "path", + "type": "string" + } + ] + } + ], + "module_comment": "File filtering utilities for CSS class extraction.", + "dependents": ["gen_fuz_css.ts", "vite_plugin_fuz_css.ts"] + }, { "path": "gen_fuz_css.ts", "declarations": [ @@ -2227,7 +2387,7 @@ { "name": "gen_fuz_css", "kind": "function", - "source_line": 189, + "source_line": 169, "type_signature": "(options?: GenFuzCssOptions): Gen", "return_type": "Gen", "parameters": [ @@ -2247,7 +2407,8 @@ "css_class_generation.ts", "css_class_interpreters.ts", "css_classes.ts", - "css_literal.ts" + "css_literal.ts", + "file_filter.ts" ] }, { @@ -4840,6 +5001,93 @@ ], "dependencies": ["variable_data.ts"], "dependents": ["theme.ts"] + }, + { + "path": "vite_plugin_fuz_css.ts", + "declarations": [ + { + "name": "VitePluginFuzCssOptions", + "kind": "type", + "doc_comment": "Options for the fuz_css Vite plugin.", + "source_line": 78, + "type_signature": "VitePluginFuzCssOptions", + "properties": [ + { + "name": "filter_file", + "kind": "variable", + "type_signature": "FileFilter", + "doc_comment": "Filter function to determine which files to extract classes from.\nBy default, extracts from .svelte, .html, .ts, .js, .tsx, .jsx files,\nexcluding test files and .gen files." + }, + { + "name": "class_definitions", + "kind": "variable", + "type_signature": "Record", + "doc_comment": "Additional class definitions to merge with builtins.\nUser definitions take precedence over builtins with the same name." + }, + { + "name": "class_interpreters", + "kind": "variable", + "type_signature": "Array", + "doc_comment": "Custom interpreters for dynamic class generation.\nReplaces the builtin interpreters entirely if provided." + }, + { + "name": "include_classes", + "kind": "variable", + "type_signature": "Iterable", + "doc_comment": "Classes to always include in the output, regardless of detection." + }, + { + "name": "exclude_classes", + "kind": "variable", + "type_signature": "Iterable", + "doc_comment": "Classes to exclude from the output, even if detected." + }, + { + "name": "acorn_plugins", + "kind": "variable", + "type_signature": "Array", + "doc_comment": "Additional acorn plugins for parsing.\nUse `acorn-jsx` for React/Preact/Solid projects." + }, + { + "name": "on_error", + "kind": "variable", + "type_signature": "'log' | 'throw'", + "doc_comment": "How to handle CSS-literal errors during generation.\n- 'log' (default): Log errors, skip invalid classes, continue\n- 'throw': Throw on first error, fail the build" + }, + { + "name": "cache_dir", + "kind": "variable", + "type_signature": "string", + "doc_comment": "Cache directory relative to project root." + } + ] + }, + { + "name": "vite_plugin_fuz_css", + "kind": "function", + "doc_comment": "Creates the fuz_css Vite plugin.\n\nExtracts CSS classes from source files during Vite's transform phase\nand generates optimized CSS via the `virtual:fuz.css` virtual module.", + "source_line": 141, + "type_signature": "(options?: VitePluginFuzCssOptions): Plugin$1", + "return_type": "Plugin$1", + "parameters": [ + { + "name": "options", + "type": "VitePluginFuzCssOptions", + "default_value": "{}" + } + ] + } + ], + "module_comment": "Vite plugin for fuz_css utility class generation.\n\nUses Vite's transform hook to extract CSS classes from source files\nas they're processed, including node_modules dependencies.\nGenerates CSS on-demand via virtual module with HMR support.\n\n@example\n```ts\n// vite.config.ts\nimport {defineConfig} from 'vite';\nimport jsx from 'acorn-jsx';\nimport {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js';\n\nexport default defineConfig({\n plugins: [\n vite_plugin_fuz_css({\n acorn_plugins: [jsx()],\n }),\n ],\n});\n```", + "dependencies": [ + "css_cache.ts", + "css_class_definitions.ts", + "css_class_extractor.ts", + "css_class_generation.ts", + "css_class_interpreters.ts", + "css_literal.ts", + "file_filter.ts" + ] } ] } diff --git a/src/test/vite_plugin_examples.test.ts b/src/test/vite_plugin_examples.test.ts new file mode 100644 index 000000000..569fd7f65 --- /dev/null +++ b/src/test/vite_plugin_examples.test.ts @@ -0,0 +1,212 @@ +/** + * Integration tests for Vite plugin examples. + * + * Builds each example project and verifies that: + * 1. The build completes successfully + * 2. All expected CSS classes are extracted (no missing) + * 3. All examples produce the same set of classes (consistency) + * + * These tests are slower due to npm install + vite build. + * Skip with: SKIP_EXAMPLE_TESTS=1 gro test + * + * @module + */ + +import {test, expect, describe, beforeAll} from 'vitest'; +import {join} from 'node:path'; +import {readdir, readFile} from 'node:fs/promises'; +import {execSync} from 'node:child_process'; + +// Skip if SKIP_EXAMPLE_TESTS is set +const SKIP = !!process.env.SKIP_EXAMPLE_TESTS; + +const EXAMPLES_DIR = join(process.cwd(), 'examples'); + +/** + * All CSS classes that should be extracted from the examples. + * This is the single source of truth - all examples should produce this exact set. + * Sorted alphabetically for consistent comparison. + */ +const EXPECTED_CLASSES = [ + // From example_class_utilities.ts - Token classes + 'color_a_5', + 'p_lg', + 'p_md', // DEMO_CONSTANT + 'shadow_sm', + // From example_class_utilities.ts - Composite classes + 'box', + 'column', // demoClassName + 'ellipsis', + 'pane', // card_class + 'row', + // From example_class_utilities.ts - Literal classes + 'align-items:center', + 'display:flex', + 'gap:1rem', + 'opacity:60%', // demo_logical + // From example_class_utilities.ts - Variable patterns + 'bg_3', // demo_ternary (false branch) + 'bg_d_3', // demo_ternary (true branch) + 'm_xs', // demoArrayClasses[0] + // Note: 'not-real:but-still-included' is extracted via @fuz-classes but excluded + // from CSS output because 'not-real' fails @webref/css property validation + 'shadow_lg', // from_comment via @fuz-classes + 'shadow_xs', // demoArrayClasses[1] + // From App - Layout + 'gap_lg', + 'gap_md', + 'max-width:600px', + 'min-height:100vh', + 'p_xl', + 'text-align:center', + 'width:100%', + // From App - Typography + 'font_size_lg', + 'font_size_sm', + 'font_size_xl3', + 'text_color_5', + 'text_color_6', + // From App - Responsive + 'md:gap_lg', + 'md:row', + // From App - Interactive + 'border_radius_sm', + 'gap_sm', + 'hover:bg_a_5', + 'hover:bg_b_5', + 'hover:color:white', + 'px_lg', + // From App - Dark mode + 'bg_a_5', + 'bg_b_5', + 'color:white', + 'dark:bg_a_3', + 'dark:bg_b_3', + // From App - Other + 'bg_1', + 'bg_2', + 'border_radius_md', + 'border_radius_xs', + 'flex-wrap:wrap', + 'flex:1', + 'gap_xs', + 'justify-content:center', + // From App - Dynamic hue loop (bg_${hue}_5 where hue is a, b, c, d, e) + // Note: bg_a_5 and bg_b_5 are already listed above + 'bg_c_5', + 'bg_d_5', + 'bg_e_5', +].sort(); + +/** + * Finds the CSS file in Vite's build output. + */ +const find_css_file = async (dist_dir: string): Promise => { + const assets_dir = join(dist_dir, 'assets'); + try { + const files = await readdir(assets_dir); + const css_file = files.find((f) => f.endsWith('.css')); + return css_file ? join(assets_dir, css_file) : null; + } catch { + return null; + } +}; + +/** + * Builds an example project. + */ +const build_example = (example_name: string): void => { + const example_dir = join(EXAMPLES_DIR, example_name); + execSync('npm install', {cwd: example_dir, stdio: 'pipe'}); + execSync('npm run build', {cwd: example_dir, stdio: 'pipe'}); +}; + +/** + * Reads the generated CSS from an example's dist folder. + */ +const read_generated_css = async (example_name: string): Promise => { + const dist_dir = join(EXAMPLES_DIR, example_name, 'dist'); + const css_path = await find_css_file(dist_dir); + if (!css_path) { + throw new Error(`No CSS file found in ${dist_dir}/assets`); + } + return readFile(css_path, 'utf8'); +}; + +/** + * Extracts the fuz_css generated portion from the full CSS. + * Returns the CSS between the marker comments. + */ +const extract_fuz_css = (css: string): string | null => { + const marker = '/* generated by vite_plugin_fuz_css */'; + const start_idx = css.indexOf(marker); + const end_idx = css.lastIndexOf(marker); + if (start_idx === -1 || end_idx === -1 || start_idx === end_idx) { + return null; + } + return css.slice(start_idx, end_idx + marker.length); +}; + +/** + * Extracts class names from CSS content. + * Handles escaped characters in class names (colons, percent signs). + */ +const extract_class_names = (css: string): Array => { + const classes: Set = new Set(); + // Match class selectors: .classname followed by space, comma, colon, or brace + // Class names can contain escaped characters like \: and \% + const pattern = /\.([a-zA-Z_][a-zA-Z0-9_-]*(?:\\[:%][a-zA-Z0-9_%-]*)*)/g; + let match; + while ((match = pattern.exec(css)) !== null) { + // Unescape CSS escape sequences: \: -> :, \% -> % + const class_name = match[1]!.replace(/\\([:%])/g, '$1'); + classes.add(class_name); + } + return [...classes].sort(); +}; + +/** + * Creates a test suite for an example. + */ +const create_example_tests = (example_name: string, app_file: string): void => { + describe.skipIf(SKIP)(`${example_name} example`, () => { + let css: string; + let fuz_css: string | null; + let extracted_classes: Array; + + beforeAll(async () => { + build_example(example_name); + css = await read_generated_css(example_name); + fuz_css = extract_fuz_css(css); + extracted_classes = fuz_css ? extract_class_names(fuz_css) : []; + }, 120_000); // 2 minute timeout for install + build + + test('generates fuz_css section', () => { + expect(fuz_css, 'CSS should contain fuz_css marker comments').not.toBeNull(); + }); + + test(`extracts all expected classes from ${app_file} and dependencies`, () => { + const missing = EXPECTED_CLASSES.filter((cls) => !extracted_classes.includes(cls)); + expect(missing, `Missing classes: ${missing.join(', ')}`).toEqual([]); + }); + + test('produces exactly the expected classes (no extra, no missing)', () => { + // Filter extracted classes to only those in our expected set + // (there may be additional classes from composite expansions) + const relevant = extracted_classes.filter((cls) => EXPECTED_CLASSES.includes(cls)); + expect(relevant).toEqual(EXPECTED_CLASSES); + }); + + test('generates valid CSS without errors', () => { + expect(css).not.toContain('undefined'); + expect(css).not.toContain('[object Object]'); + expect(css).not.toContain('NaN'); + }); + }); +}; + +// Create test suites for each example +create_example_tests('vite-react', 'App.tsx'); +create_example_tests('vite-preact', 'App.tsx'); +create_example_tests('vite-solid', 'App.tsx'); +create_example_tests('vite-svelte', 'App.svelte'); From c906c10ab2592536cebe3b01baf944f421f93bda Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 14 Jan 2026 08:01:21 -0500 Subject: [PATCH 073/138] wip --- examples/vite-preact/src/App.tsx | 42 ++++++++++---------- examples/vite-react/src/App.tsx | 42 ++++++++++---------- examples/vite-solid/src/App.tsx | 42 ++++++++++---------- examples/vite-svelte/src/App.svelte | 42 ++++++++++---------- src/lib/css_class_extractor.ts | 2 +- src/lib/example_class_utilities.ts | 49 ++++++++++++------------ src/routes/fuz.css | 13 ++++--- src/routes/library.json | 42 ++++++++++---------- src/test/css_class_extractor.jsx.test.ts | 22 +++++++++++ src/test/css_class_extractor.test.ts | 24 ++++++++++++ src/test/vite_plugin_examples.test.ts | 13 +++++-- 11 files changed, 195 insertions(+), 138 deletions(-) diff --git a/examples/vite-preact/src/App.tsx b/examples/vite-preact/src/App.tsx index b1fc10b6d..967cddf3c 100644 --- a/examples/vite-preact/src/App.tsx +++ b/examples/vite-preact/src/App.tsx @@ -2,18 +2,18 @@ import {useState} from 'preact/hooks'; // Import from node_modules to verify extraction works for dependencies import { - // Token classes (mix of camelCase and snake_case) - demo_padding_class, + // Token classes + demoPaddingClass, demoShadowClass, - demo_color_class, + demoColorClass, // Composite classes demoBoxClass, - demo_row_class, + demoRowClass, demoEllipsisClass, // Literal classes - demo_display_class, - demoAlignClass, - demo_gap_class, + demoJustifyClass, + demoTextTransformClass, + demoGapClass, // Variable patterns demoClassName, DEMO_CONSTANT_CLASS, @@ -22,8 +22,8 @@ import { demo_logical_class, demoArrayClasses, // Comment hint examples - from_comment, - arbitrary_literal, + fromComment, + arbitraryLiteral, } from '@fuzdev/fuz_css/example_class_utilities.js'; export const App = () => { @@ -110,21 +110,21 @@ export const App = () => {

    {/* Token classes */} -
    -
    - {demo_padding_class} + {demoShadowClass} +
    +
    + {demoPaddingClass} + {demoShadowClass}
    -
    - {demo_color_class} +
    + {demoColorClass}
    {/* Composite classes */} -
    -
    +
    +
    {card_class}
    -
    +
    {demoEllipsisClass} truncates long text @@ -145,11 +145,11 @@ export const App = () => {
    demoArrayClasses: [{demoArrayClasses.join(', ')}]
    -
    - from_comment (via @fuz-classes): {from_comment} +
    + fromComment (via @fuz-classes): {fromComment}
    -
    - arbitrary_literal: {arbitrary_literal} +
    + arbitraryLiteral: {arbitraryLiteral}
    diff --git a/examples/vite-react/src/App.tsx b/examples/vite-react/src/App.tsx index 1af323769..3e65514c3 100644 --- a/examples/vite-react/src/App.tsx +++ b/examples/vite-react/src/App.tsx @@ -2,18 +2,18 @@ import {useState} from 'react'; // Import from node_modules to verify extraction works for dependencies import { - // Token classes (mix of camelCase and snake_case) - demo_padding_class, + // Token classes + demoPaddingClass, demoShadowClass, - demo_color_class, + demoColorClass, // Composite classes demoBoxClass, - demo_row_class, + demoRowClass, demoEllipsisClass, // Literal classes - demo_display_class, - demoAlignClass, - demo_gap_class, + demoJustifyClass, + demoTextTransformClass, + demoGapClass, // Variable patterns demoClassName, DEMO_CONSTANT_CLASS, @@ -22,8 +22,8 @@ import { demo_logical_class, demoArrayClasses, // Comment hint examples - from_comment, - arbitrary_literal, + fromComment, + arbitraryLiteral, } from '@fuzdev/fuz_css/example_class_utilities.js'; export const App = () => { @@ -110,21 +110,21 @@ export const App = () => {

    {/* Token classes */} -
    -
    - {demo_padding_class} + {demoShadowClass} +
    +
    + {demoPaddingClass} + {demoShadowClass}
    -
    - {demo_color_class} +
    + {demoColorClass}
    {/* Composite classes */} -
    -
    +
    +
    {card_class}
    -
    +
    {demoEllipsisClass} truncates long text @@ -145,11 +145,11 @@ export const App = () => {
    demoArrayClasses: [{demoArrayClasses.join(', ')}]
    -
    - from_comment (via @fuz-classes): {from_comment} +
    + fromComment (via @fuz-classes): {fromComment}
    -
    - arbitrary_literal: {arbitrary_literal} +
    + arbitraryLiteral: {arbitraryLiteral}
    diff --git a/examples/vite-solid/src/App.tsx b/examples/vite-solid/src/App.tsx index c45077c9a..e250d6a6b 100644 --- a/examples/vite-solid/src/App.tsx +++ b/examples/vite-solid/src/App.tsx @@ -2,18 +2,18 @@ import {createSignal, For} from 'solid-js'; // Import from node_modules to verify extraction works for dependencies import { - // Token classes (mix of camelCase and snake_case) - demo_padding_class, + // Token classes + demoPaddingClass, demoShadowClass, - demo_color_class, + demoColorClass, // Composite classes demoBoxClass, - demo_row_class, + demoRowClass, demoEllipsisClass, // Literal classes - demo_display_class, - demoAlignClass, - demo_gap_class, + demoJustifyClass, + demoTextTransformClass, + demoGapClass, // Variable patterns demoClassName, DEMO_CONSTANT_CLASS, @@ -22,8 +22,8 @@ import { demo_logical_class, demoArrayClasses, // Comment hint examples - from_comment, - arbitrary_literal, + fromComment, + arbitraryLiteral, } from '@fuzdev/fuz_css/example_class_utilities.js'; export const App = () => { @@ -109,21 +109,21 @@ export const App = () => {

    {/* Token classes */} -
    -
    - {demo_padding_class} + {demoShadowClass} +
    +
    + {demoPaddingClass} + {demoShadowClass}
    -
    - {demo_color_class} +
    + {demoColorClass}
    {/* Composite classes */} -
    -
    +
    +
    {card_class}
    -
    +
    {demoEllipsisClass} truncates long text @@ -144,11 +144,11 @@ export const App = () => {
    demoArrayClasses: [{demoArrayClasses.join(', ')}]
    -
    - from_comment (via @fuz-classes): {from_comment} +
    + fromComment (via @fuz-classes): {fromComment}
    -
    - arbitrary_literal: {arbitrary_literal} +
    + arbitraryLiteral: {arbitraryLiteral}
    diff --git a/examples/vite-svelte/src/App.svelte b/examples/vite-svelte/src/App.svelte index cd3983f07..a06b84ae6 100644 --- a/examples/vite-svelte/src/App.svelte +++ b/examples/vite-svelte/src/App.svelte @@ -1,18 +1,18 @@ +
    +`; + const result = extract_from_svelte(source); + class_names_equal(result, ['btn-list', 'card-list-a', 'card-list-b']); + }); + + test('extracts classes from variables ending in classLists or class_lists', () => { + const source = ` + +
    +`; + const result = extract_from_svelte(source); + class_names_equal(result, ['btn-lists-a', 'btn-lists-b', 'card-lists']); + }); + test('extracts classes from $derived rune', () => { const source = ` -
    -
    -
    -

    fuz_css + Svelte

    -

    - Utility classes generated on-demand via Vite plugin -

    +
    +
    +
    +

    fuz_css + Svelte

    +

    Utility classes generated on-demand via Vite plugin

    -
    -
    -

    Responsive

    -

    - This layout stacks on mobile and becomes a row on medium screens. -

    +
    +
    +

    Responsive

    +

    .display:flex .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    -
    -

    On-demand

    -

    - Only the classes you use are included in the bundle. -

    +
    +

    On-demand

    +

    Only classes used are bundled

    -
    -

    Interactive

    -
    - - -
    -
    - - -
    -

    Color Scheme

    -
    -
    - Adapts to dark mode -
    -
    - Different in each scheme -
    -
    +
    +

    Interactive

    +

    Hover modifiers like .hover:border_color_b change styles on hover

    + +
    -
    -

    Design Tokens

    -
    +
    +

    Design tokens

    +

    .p_md for padding, .color_bg_5 for text color

    +
    {#each ['a', 'b', 'c', 'd', 'e'] as hue} -
    - {hue.toUpperCase()} +
    + .bg_{hue}_5
    {/each}
    - -
    -

    From Dependencies

    -

    - Classes imported from @fuzdev/fuz_css/example_class_utilities: -

    + +
    +

    Class types

    - -
    -
    - {demoPaddingClass} + {demoShadowClass} -
    -
    - {demoColorClass} +
    +

    Token classes

    +
    .pl_xl5 .font_size_lg
    +
    .shadow_sm
    +
    .color_a_5
    +
    + +
    +

    Composite classes

    +
    .box
    +
    + .ellipsis — this text truncates with ellipsis when it overflows
    - -
    -
    - - {demoEllipsisClass} truncates long text - +
    +

    Literal classes

    +
    .opacity:60%
    +
    .color:var(--color_j_5)
    +
    .box-shadow:0~4px~8px~rgb(0,0,0,0.2) (~ encodes spaces)
    +
    + left + .display:flex .justify-content:space-between + right
    +
    - -
    -
    demoClass: {demoClass}
    -
    demo_class: {demo_class}
    -
    demoClasses: {demoClasses}
    -
    demo_classes: {demo_classes}
    -
    demoClassName: {demoClassName}
    -
    demo_class_name: {demo_class_name}
    -
    demoClassNames: {demoClassNames}
    -
    demo_class_names: {demo_class_names}
    -
    demoClassList: {demoClassList}
    -
    demo_class_list: {demo_class_list}
    -
    demoClassLists: {demoClassLists}
    -
    demo_class_lists: {demo_class_lists}
    -
    DEMO_CLASS: {DEMO_CLASS}
    + +
    +

    From dependencies

    +

    Classes imported from @fuzdev/fuz_css/example_class_utilities.js

    + +
    +

    Naming patterns

    +
    demoClass: .{demoClass}
    +
    demo_class: .{demo_class}
    +
    demoClasses: .mb_xs3 .ml_xs
    +
    demo_classes: .mb_xs2 .ml_sm
    +
    demoClassName: .{demoClassName}
    +
    demo_class_name: .{demo_class_name}
    +
    demoClassNames: .mb_md .ml_md
    +
    demo_class_names: .mb_lg .ml_lg
    +
    demoClassList: .{demoClassList}
    +
    demo_class_list: .{demo_class_list}
    +
    demoClassLists: .mb_xl3 .ml_xl
    +
    demo_class_lists: .mb_xl4 .ml_xl2
    +
    DEMO_CLASS: .{DEMO_CLASS}
    - -
    -
    ternaryClass: {ternaryClass}
    -
    logicalClass: {logicalClass}
    -
    - arrayClasses: [{arrayClasses.join(', ')}] +
    +

    Expression patterns

    +
    + {"true ? 'mt_xs' : 'mt_sm'"} → .{ternaryClass} (both branches extracted) +
    +
    + {"true && 'mt_md'"} → .{logicalClass} +
    +
    + {"['mt_lg', 'mt_xl']"} → .{arrayClasses.join(', .')}
    - -
    -
    fromComment: {fromComment}
    -
    arbitraryLiteral: {arbitraryLiteral}
    +
    +

    Comment hints

    +
    + // @fuz-classes {fromComment} → .{fromComment} +
    +
    + // @fuz-classes {unknownExtracted} → extracted but excluded (no matching definition) +
    +
    + // @fuz-classes {arbitraryLiteral} → extracted but excluded (invalid property, not in @webref/css) +
    diff --git a/src/lib/css_class_generation.ts b/src/lib/css_class_generation.ts index ee30fb72d..5251297c1 100644 --- a/src/lib/css_class_generation.ts +++ b/src/lib/css_class_generation.ts @@ -17,6 +17,7 @@ import { } from './diagnostics.js'; import {parse_ruleset, is_single_selector_ruleset} from './css_ruleset_parser.js'; import {resolve_class_definition} from './css_class_resolution.js'; +import {get_modifier} from './modifiers.js'; // // CSS Utilities @@ -142,12 +143,31 @@ export const generate_classes_css = ( indexes.set(keys[i]!, i); } - // If any classes are unknown, just put them at the end + // Helper to get the maximum state modifier order from a class name + // This ensures proper cascade: hover (5) comes before active (6) + const get_state_modifier_order = (class_name: string): number => { + const parts = class_name.split(':'); + let max_order = 0; + for (const part of parts.slice(0, -1)) { + // Check each potential modifier prefix + const modifier = get_modifier(part); + if (modifier?.type === 'state' && modifier.order !== undefined) { + max_order = Math.max(max_order, modifier.order); + } + } + return max_order; + }; + + // Sort classes: first by definition index, then by state modifier order, then alphabetically const sorted_classes = (Array.isArray(class_names) ? class_names : Array.from(class_names)).sort( (a, b) => { const index_a = indexes.get(a) ?? Number.MAX_VALUE; const index_b = indexes.get(b) ?? Number.MAX_VALUE; if (index_a !== index_b) return index_a - index_b; + // For classes with modifiers, sort by state modifier order (for proper cascade) + const order_a = get_state_modifier_order(a); + const order_b = get_state_modifier_order(b); + if (order_a !== order_b) return order_a - order_b; return a.localeCompare(b); // alphabetic tiebreaker for stable sort }, ); diff --git a/src/lib/example_class_utilities.ts b/src/lib/example_class_utilities.ts index 6e9cd0d54..c3c349fff 100644 --- a/src/lib/example_class_utilities.ts +++ b/src/lib/example_class_utilities.ts @@ -2,22 +2,20 @@ * Example CSS class exports demonstrating node_modules extraction. * * This module exists to verify that the Vite plugin extracts classes from - * dependencies in node_modules. Each export uses a unique class value - * to verify extraction is working correctly. + * dependencies in node_modules. The exports test specific extraction patterns + * that require being in a separate module. * * **Important:** Variable names must match `CLASS_NAME_PATTERN` in css_class_extractor.ts. * Supported suffixes: `class`, `classes`, `className`, `classNames`, `classList`, `classLists` * (also snake_case variants like `class_name`, `class_names`, `class_list`, `class_lists`). * - * **Class types demonstrated:** - * - Token classes: Map to style variables (`p_lg`, `shadow_sm`) - * - Composite classes: Multi-property shortcuts (`box`, `row`) - * - Literal classes: CSS property:value syntax (`justify-content:space-between`) + * **Patterns demonstrated:** + * - Naming patterns: All CLASS_NAME_PATTERN suffix variants + * - Expression patterns: Ternary, logical AND, arrays + * - Comment hints: `@fuz-classes` directive * - * **Variable patterns demonstrated:** - * - Simple assignment, ternary expressions, logical AND, arrays - * - Various naming conventions (camelCase, snake_case, SCREAMING_SNAKE) - * - Comment hints via `@fuz-classes` + * Token, composite, and literal classes are demonstrated inline in the examples + * since they don't require special extraction testing. * * @module */ @@ -25,46 +23,7 @@ /* eslint-disable no-constant-condition, @typescript-eslint/no-unnecessary-condition, no-constant-binary-expression */ // -// Token classes - map to style variables -// - -/** Padding token - large spacing */ -export const demoPaddingClass = 'p_lg'; - -/** Shadow token - small elevation */ -export const demoShadowClass = 'shadow_sm'; - -/** Color token - primary hue intensity 5 */ -export const demoColorClass = 'color_a_5'; - -// -// Composite classes - multi-property shortcuts -// - -/** Layout composite - centered flex container */ -export const demoBoxClass = 'box'; - -/** Layout composite - horizontal flex row */ -export const demoRowClass = 'row'; - -/** Text composite - truncate with ellipsis */ -export const demoEllipsisClass = 'ellipsis'; - -// -// Literal classes - CSS property:value syntax -// - -/** Justify literal - space-between distribution */ -export const demoJustifyClass = 'justify-content:space-between'; - -/** Text literal - uppercase transform */ -export const demoTextTransformClass = 'text-transform:uppercase'; - -/** Spacing literal - gap between children */ -export const demoGapClass = 'gap:1rem'; - -// -// Naming patterns - all CLASS_NAME_PATTERN suffix variants (mb_* incrementing) +// Naming patterns - all CLASS_NAME_PATTERN suffix variants (mb_* + ml_* for plurals) // /** `*Class` suffix (camelCase) */ @@ -73,11 +32,11 @@ export const demoClass = 'mb_xs5'; /** `*_class` suffix (snake_case) */ export const demo_class = 'mb_xs4'; -/** `*Classes` suffix (camelCase) */ -export const demoClasses = 'mb_xs3'; +/** `*Classes` suffix (camelCase) - plural, multiple classes */ +export const demoClasses = 'mb_xs3 ml_xs'; -/** `*_classes` suffix (snake_case) */ -export const demo_classes = 'mb_xs2'; +/** `*_classes` suffix (snake_case) - plural, multiple classes */ +export const demo_classes = 'mb_xs2 ml_sm'; /** `*ClassName` suffix (camelCase) */ export const demoClassName = 'mb_xs'; @@ -85,11 +44,11 @@ export const demoClassName = 'mb_xs'; /** `*class_name` suffix (snake_case) */ export const demo_class_name = 'mb_sm'; -/** `*ClassNames` suffix (camelCase) */ -export const demoClassNames = 'mb_md'; +/** `*ClassNames` suffix (camelCase) - plural, multiple classes */ +export const demoClassNames = 'mb_md ml_md'; -/** `*class_names` suffix (snake_case) */ -export const demo_class_names = 'mb_lg'; +/** `*class_names` suffix (snake_case) - plural, multiple classes */ +export const demo_class_names = 'mb_lg ml_lg'; /** `*ClassList` suffix (camelCase) */ export const demoClassList = 'mb_xl'; @@ -97,11 +56,11 @@ export const demoClassList = 'mb_xl'; /** `*class_list` suffix (snake_case) */ export const demo_class_list = 'mb_xl2'; -/** `*ClassLists` suffix (camelCase) */ -export const demoClassLists = 'mb_xl3'; +/** `*ClassLists` suffix (camelCase) - plural, multiple classes */ +export const demoClassLists = 'mb_xl3 ml_xl'; -/** `*class_lists` suffix (snake_case) */ -export const demo_class_lists = 'mb_xl4'; +/** `*class_lists` suffix (snake_case) - plural, multiple classes */ +export const demo_class_lists = 'mb_xl4 ml_xl2'; /** `SCREAMING_SNAKE_CASE` naming */ export const DEMO_CLASS = 'mb_xl5'; diff --git a/src/lib/modifiers.ts b/src/lib/modifiers.ts index 104ed11dc..6963a6674 100644 --- a/src/lib/modifiers.ts +++ b/src/lib/modifiers.ts @@ -65,14 +65,14 @@ export const MODIFIERS: Array = [ {name: 'dark', type: 'ancestor', css: ':root.dark'}, {name: 'light', type: 'ancestor', css: ':root.light'}, - // State modifiers - interaction - {name: 'hover', type: 'state', css: ':hover'}, - {name: 'focus', type: 'state', css: ':focus'}, - {name: 'focus-visible', type: 'state', css: ':focus-visible'}, - {name: 'focus-within', type: 'state', css: ':focus-within'}, - {name: 'active', type: 'state', css: ':active'}, - {name: 'visited', type: 'state', css: ':visited'}, - {name: 'target', type: 'state', css: ':target'}, + // State modifiers - interaction (ordered for proper cascade: LVFHA) + {name: 'visited', type: 'state', css: ':visited', order: 1}, + {name: 'focus-within', type: 'state', css: ':focus-within', order: 2}, + {name: 'focus', type: 'state', css: ':focus', order: 3}, + {name: 'focus-visible', type: 'state', css: ':focus-visible', order: 4}, + {name: 'hover', type: 'state', css: ':hover', order: 5}, + {name: 'active', type: 'state', css: ':active', order: 6}, + {name: 'target', type: 'state', css: ':target', order: 7}, // State modifiers - form states {name: 'disabled', type: 'state', css: ':disabled'}, diff --git a/src/test/css_class_generation.test.ts b/src/test/css_class_generation.test.ts index 130b149db..4966b5a96 100644 --- a/src/test/css_class_generation.test.ts +++ b/src/test/css_class_generation.test.ts @@ -1197,6 +1197,73 @@ describe('modified_class_interpreter', () => { }); }); + describe('state modifier ordering for cascade', () => { + test('hover classes come before active classes in output (LVFHA order)', () => { + const result = generate_classes_css({ + class_names: ['active:border_color_a', 'hover:border_color_b'], + class_definitions: css_class_definitions, + interpreters: [modified_class_interpreter], + css_properties: null, + }); + + // Find positions of hover and active classes in the output + const hover_pos = result.css.indexOf('.hover\\:border_color_b'); + const active_pos = result.css.indexOf('.active\\:border_color_a'); + + expect(hover_pos).toBeGreaterThan(-1); + expect(active_pos).toBeGreaterThan(-1); + // Hover should come BEFORE active for proper cascade (active overrides hover) + expect(hover_pos).toBeLessThan(active_pos); + }); + + test('visited < focus < hover < active ordering', () => { + const result = generate_classes_css({ + class_names: [ + 'active:p_xl', + 'hover:p_lg', + 'focus:p_md', + 'visited:p_sm', + ], + class_definitions: css_class_definitions, + interpreters: [modified_class_interpreter], + css_properties: null, + }); + + const visited_pos = result.css.indexOf('.visited\\:p_sm'); + const focus_pos = result.css.indexOf('.focus\\:p_md'); + const hover_pos = result.css.indexOf('.hover\\:p_lg'); + const active_pos = result.css.indexOf('.active\\:p_xl'); + + // All should be present + expect(visited_pos).toBeGreaterThan(-1); + expect(focus_pos).toBeGreaterThan(-1); + expect(hover_pos).toBeGreaterThan(-1); + expect(active_pos).toBeGreaterThan(-1); + + // Order should be: visited < focus < hover < active + expect(visited_pos).toBeLessThan(focus_pos); + expect(focus_pos).toBeLessThan(hover_pos); + expect(hover_pos).toBeLessThan(active_pos); + }); + + test('non-interaction states use alphabetical order', () => { + const result = generate_classes_css({ + class_names: ['odd:p_md', 'even:p_lg', 'first:p_sm'], + class_definitions: css_class_definitions, + interpreters: [modified_class_interpreter], + css_properties: null, + }); + + const even_pos = result.css.indexOf('.even\\:p_lg'); + const first_pos = result.css.indexOf('.first\\:p_sm'); + const odd_pos = result.css.indexOf('.odd\\:p_md'); + + // Alphabetical: even < first < odd + expect(even_pos).toBeLessThan(first_pos); + expect(first_pos).toBeLessThan(odd_pos); + }); + }); + describe('skip warnings', () => { test('before:chevron emits warning for skipped pseudo-element rule', () => { const result = generate_classes_css({ diff --git a/src/test/vite_plugin_examples.test.ts b/src/test/vite_plugin_examples.test.ts index d07d55fc0..55c252cf1 100644 --- a/src/test/vite_plugin_examples.test.ts +++ b/src/test/vite_plugin_examples.test.ts @@ -35,32 +35,36 @@ if (!SKIP) { * Sorted alphabetically for consistent comparison. */ const EXPECTED_CLASSES = [ - // From example_class_utilities.ts - Token classes + // From App - Class Types section 'color_a_5', - 'p_lg', + 'p_xl5', 'shadow_sm', - // From example_class_utilities.ts - Composite classes 'box', 'ellipsis', - 'row', - // From example_class_utilities.ts - Literal classes + 'display:flex', 'gap:1rem', 'justify-content:space-between', 'text-transform:uppercase', - // From example_class_utilities.ts - Naming patterns (mb_* incrementing) + // From example_class_utilities.ts - Naming patterns (mb_* + ml_* for plurals) 'mb_xs5', // demoClass 'mb_xs4', // demo_class - 'mb_xs3', // demoClasses - 'mb_xs2', // demo_classes + 'mb_xs3', // demoClasses (+ ml_xs) + 'mb_xs2', // demo_classes (+ ml_sm) 'mb_xs', // demoClassName 'mb_sm', // demo_class_name - 'mb_md', // demoClassNames - 'mb_lg', // demo_class_names + 'mb_md', // demoClassNames (+ ml_md) + 'mb_lg', // demo_class_names (+ ml_lg) 'mb_xl', // demoClassList 'mb_xl2', // demo_class_list - 'mb_xl3', // demoClassLists - 'mb_xl4', // demo_class_lists + 'mb_xl3', // demoClassLists (+ ml_xl) + 'mb_xl4', // demo_class_lists (+ ml_xl2) 'mb_xl5', // DEMO_CLASS + 'ml_xs', // demoClasses (plural) + 'ml_sm', // demo_classes (plural) + 'ml_md', // demoClassNames (plural) + 'ml_lg', // demo_class_names (plural) + 'ml_xl', // demoClassLists (plural) + 'ml_xl2', // demo_class_lists (plural) // From example_class_utilities.ts - Expression patterns (mt_* incrementing) 'mt_xs', // ternaryClass (true branch) 'mt_sm', // ternaryClass (false branch) @@ -72,49 +76,35 @@ const EXPECTED_CLASSES = [ // from CSS output because 'not-real' fails @webref/css property validation 'shadow_lg', // fromComment via @fuz-classes // From App - Layout + 'column', 'gap_lg', 'gap_md', - 'max-width:600px', - 'min-height:100vh', + 'gap_sm', + 'max-width:800px', 'p_xl', 'text-align:center', 'width:100%', - // From App - Typography - 'font_size_lg', - 'font_size_sm', - 'font_size_xl3', - 'text_color_5', - 'text_color_6', // From App - Responsive + 'flex:1', 'md:gap_lg', 'md:row', - // From App - Interactive - 'border_radius_sm', - 'gap_sm', - 'hover:bg_a_5', - 'hover:bg_b_5', - 'hover:color:white', - 'px_lg', - // From App - Dark mode + // From App - Interactive (hover/active state modifiers) + 'hover:border_color_b', + 'hover:outline_color_b', + 'active:border_color_d', + 'active:outline_color_d', + 'hover:border_color_e', + 'hover:outline_color_e', + 'active:border_color_h', + 'active:outline_color_h', + // From App - Design Tokens (bg_${hue}_5 where hue is a, b, c, d, e) 'bg_a_5', 'bg_b_5', - 'color:white', - 'dark:bg_a_3', - 'dark:bg_b_3', - // From App - Other - 'bg_1', - 'bg_2', - 'border_radius_md', - 'border_radius_xs', - 'flex-wrap:wrap', - 'flex:1', - 'gap_xs', - 'justify-content:center', - // From App - Dynamic hue loop (bg_${hue}_5 where hue is a, b, c, d, e) - // Note: bg_a_5 and bg_b_5 are already listed above 'bg_c_5', 'bg_d_5', 'bg_e_5', + 'color:white', + 'p_md', ].sort(); /** From 79281eb0a062aeaf4258a4e9a9040983abac01c8 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 14 Jan 2026 11:34:03 -0500 Subject: [PATCH 077/138] wip --- examples/vite-preact/src/App.tsx | 65 ++++------ examples/vite-react/src/App.tsx | 65 ++++------ examples/vite-solid/src/App.tsx | 67 ++++------ examples/vite-svelte/src/App.svelte | 65 ++++------ src/lib/example_class_utilities.ts | 29 +++-- src/routes/fuz.css | 24 ++-- src/routes/library.json | 180 +++++++++----------------- src/test/vite_plugin_examples.test.ts | 77 ++++++----- 8 files changed, 240 insertions(+), 332 deletions(-) diff --git a/examples/vite-preact/src/App.tsx b/examples/vite-preact/src/App.tsx index 669026bb5..e94482db6 100644 --- a/examples/vite-preact/src/App.tsx +++ b/examples/vite-preact/src/App.tsx @@ -20,6 +20,7 @@ import { ternaryClass, logicalClass, arrayClasses, + objectClasses, // Comment hint examples fromComment, unknownExtracted, @@ -30,7 +31,7 @@ export const App = () => { const [count, setCount] = useState(0); return ( -
    +

    fuz_css + Preact

    @@ -38,39 +39,31 @@ export const App = () => {
    {/* Responsive layout: column on mobile, row on desktop */} -
    +

    Responsive

    -

    .display:flex .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    +

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    -

    On-demand

    -

    Only classes used are bundled

    +

    Try it

    +

    Resize the window to see the layout switch from column to row

    {/* Interactive button with hover states */}

    Interactive

    -

    Hover modifiers like .hover:border_color_b change styles on hover

    - - -
    - - {/* Token classes showcase */} -
    -

    Design tokens

    -

    .p_md for padding, .color_bg_5 for text color

    -
    - {['a', 'b', 'c', 'd', 'e'].map((hue) => ( -
    - .bg_{hue}_5 -
    - ))} +
    + + .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d +
    +
    + + .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h
    @@ -80,9 +73,9 @@ export const App = () => {

    Token classes

    +
    .p_md .bg_d_2
    .pl_xl5 .font_size_lg
    .shadow_sm
    -
    .color_a_5
    @@ -98,11 +91,6 @@ export const App = () => {
    .opacity:60%
    .color:var(--color_j_5)
    .box-shadow:0~4px~8px~rgb(0,0,0,0.2) (~ encodes spaces)
    -
    - left - .display:flex .justify-content:space-between - right -
    @@ -115,17 +103,17 @@ export const App = () => {

    Naming patterns

    demoClass: .{demoClass}
    demo_class: .{demo_class}
    -
    demoClasses: .mb_xs3 .ml_xs
    -
    demo_classes: .mb_xs2 .ml_sm
    +
    DEMO_CLASS: .{DEMO_CLASS}
    +
    demoClasses: .mb_xs2 .ml_xs
    +
    demo_classes: .mb_xs .ml_sm
    demoClassName: .{demoClassName}
    demo_class_name: .{demo_class_name}
    -
    demoClassNames: .mb_md .ml_md
    -
    demo_class_names: .mb_lg .ml_lg
    +
    demoClassNames: .mb_lg .ml_md
    +
    demo_class_names: .mb_xl .ml_lg
    demoClassList: .{demoClassList}
    demo_class_list: .{demo_class_list}
    -
    demoClassLists: .mb_xl3 .ml_xl
    -
    demo_class_lists: .mb_xl4 .ml_xl2
    -
    DEMO_CLASS: .{DEMO_CLASS}
    +
    demoClassLists: .mb_xl4 .ml_xl
    +
    demo_class_lists: .mb_xl5 .ml_xl2
    @@ -139,6 +127,9 @@ export const App = () => {
    {`['mt_lg', 'mt_xl']`} → .{arrayClasses.join(', .')}
    +
    + {`{ mt_xl2: 'mt_xl2', mt_xl3: 'mt_xl3' }`} → keys extracted from object +
    diff --git a/examples/vite-react/src/App.tsx b/examples/vite-react/src/App.tsx index c8d0c6b6b..db8780f27 100644 --- a/examples/vite-react/src/App.tsx +++ b/examples/vite-react/src/App.tsx @@ -20,6 +20,7 @@ import { ternaryClass, logicalClass, arrayClasses, + objectClasses, // Comment hint examples fromComment, unknownExtracted, @@ -30,7 +31,7 @@ export const App = () => { const [count, setCount] = useState(0); return ( -
    +

    fuz_css + React

    @@ -38,39 +39,31 @@ export const App = () => {
    {/* Responsive layout: column on mobile, row on desktop */} -
    +

    Responsive

    -

    .display:flex .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    +

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    -

    On-demand

    -

    Only classes used are bundled

    +

    Try it

    +

    Resize the window to see the layout switch from column to row

    {/* Interactive button with hover states */}

    Interactive

    -

    Hover modifiers like .hover:border_color_b change styles on hover

    - - -
    - - {/* Token classes showcase */} -
    -

    Design tokens

    -

    .p_md for padding, .color_bg_5 for text color

    -
    - {['a', 'b', 'c', 'd', 'e'].map((hue) => ( -
    - .bg_{hue}_5 -
    - ))} +
    + + .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d +
    +
    + + .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h
    @@ -80,9 +73,9 @@ export const App = () => {

    Token classes

    +
    .p_md .bg_d_2
    .pl_xl5 .font_size_lg
    .shadow_sm
    -
    .color_a_5
    @@ -98,11 +91,6 @@ export const App = () => {
    .opacity:60%
    .color:var(--color_j_5)
    .box-shadow:0~4px~8px~rgb(0,0,0,0.2) (~ encodes spaces)
    -
    - left - .display:flex .justify-content:space-between - right -
    @@ -115,17 +103,17 @@ export const App = () => {

    Naming patterns

    demoClass: .{demoClass}
    demo_class: .{demo_class}
    -
    demoClasses: .mb_xs3 .ml_xs
    -
    demo_classes: .mb_xs2 .ml_sm
    +
    DEMO_CLASS: .{DEMO_CLASS}
    +
    demoClasses: .mb_xs2 .ml_xs
    +
    demo_classes: .mb_xs .ml_sm
    demoClassName: .{demoClassName}
    demo_class_name: .{demo_class_name}
    -
    demoClassNames: .mb_md .ml_md
    -
    demo_class_names: .mb_lg .ml_lg
    +
    demoClassNames: .mb_lg .ml_md
    +
    demo_class_names: .mb_xl .ml_lg
    demoClassList: .{demoClassList}
    demo_class_list: .{demo_class_list}
    -
    demoClassLists: .mb_xl3 .ml_xl
    -
    demo_class_lists: .mb_xl4 .ml_xl2
    -
    DEMO_CLASS: .{DEMO_CLASS}
    +
    demoClassLists: .mb_xl4 .ml_xl
    +
    demo_class_lists: .mb_xl5 .ml_xl2
    @@ -139,6 +127,9 @@ export const App = () => {
    {`['mt_lg', 'mt_xl']`} → .{arrayClasses.join(', .')}
    +
    + {`{ mt_xl2: 'mt_xl2', mt_xl3: 'mt_xl3' }`} → keys extracted from object +
    diff --git a/examples/vite-solid/src/App.tsx b/examples/vite-solid/src/App.tsx index ea1738b80..c71d05617 100644 --- a/examples/vite-solid/src/App.tsx +++ b/examples/vite-solid/src/App.tsx @@ -20,6 +20,7 @@ import { ternaryClass, logicalClass, arrayClasses, + objectClasses, // Comment hint examples fromComment, unknownExtracted, @@ -30,7 +31,7 @@ export const App = () => { const [count, setCount] = createSignal(0); return ( -
    +

    fuz_css + Solid

    @@ -38,41 +39,31 @@ export const App = () => {
    {/* Responsive layout: column on mobile, row on desktop */} -
    +

    Responsive

    -

    .display:flex .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    +

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    -

    On-demand

    -

    Only classes used are bundled

    +

    Try it

    +

    Resize the window to see the layout switch from column to row

    {/* Interactive button with hover states */}

    Interactive

    -

    Hover modifiers like .hover:border_color_b change styles on hover

    - - -
    - - {/* Token classes showcase */} -
    -

    Design tokens

    -

    .p_md for padding, .color_bg_5 for text color

    -
    - - {(hue) => ( -
    - .bg_{hue}_5 -
    - )} -
    +
    + + .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d +
    +
    + + .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h
    @@ -82,9 +73,9 @@ export const App = () => {

    Token classes

    +
    .p_md .bg_d_2
    .pl_xl5 .font_size_lg
    .shadow_sm
    -
    .color_a_5
    @@ -100,11 +91,6 @@ export const App = () => {
    .opacity:60%
    .color:var(--color_j_5)
    .box-shadow:0~4px~8px~rgb(0,0,0,0.2) (~ encodes spaces)
    -
    - left - .display:flex .justify-content:space-between - right -
    @@ -117,17 +103,17 @@ export const App = () => {

    Naming patterns

    demoClass: .{demoClass}
    demo_class: .{demo_class}
    -
    demoClasses: .mb_xs3 .ml_xs
    -
    demo_classes: .mb_xs2 .ml_sm
    +
    DEMO_CLASS: .{DEMO_CLASS}
    +
    demoClasses: .mb_xs2 .ml_xs
    +
    demo_classes: .mb_xs .ml_sm
    demoClassName: .{demoClassName}
    demo_class_name: .{demo_class_name}
    -
    demoClassNames: .mb_md .ml_md
    -
    demo_class_names: .mb_lg .ml_lg
    +
    demoClassNames: .mb_lg .ml_md
    +
    demo_class_names: .mb_xl .ml_lg
    demoClassList: .{demoClassList}
    demo_class_list: .{demo_class_list}
    -
    demoClassLists: .mb_xl3 .ml_xl
    -
    demo_class_lists: .mb_xl4 .ml_xl2
    -
    DEMO_CLASS: .{DEMO_CLASS}
    +
    demoClassLists: .mb_xl4 .ml_xl
    +
    demo_class_lists: .mb_xl5 .ml_xl2
    @@ -141,6 +127,9 @@ export const App = () => {
    {`['mt_lg', 'mt_xl']`} → .{arrayClasses.join(', .')}
    +
    + {`{ mt_xl2: 'mt_xl2', mt_xl3: 'mt_xl3' }`} → keys extracted from object +
    diff --git a/examples/vite-svelte/src/App.svelte b/examples/vite-svelte/src/App.svelte index a0d3f13a7..cad880bc4 100644 --- a/examples/vite-svelte/src/App.svelte +++ b/examples/vite-svelte/src/App.svelte @@ -19,6 +19,7 @@ ternaryClass, logicalClass, arrayClasses, + objectClasses, // Comment hint examples fromComment, unknownExtracted, @@ -28,7 +29,7 @@ let count = $state(0); -
    +

    fuz_css + Svelte

    @@ -36,39 +37,31 @@
    -
    +

    Responsive

    -

    .display:flex .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    +

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    -

    On-demand

    -

    Only classes used are bundled

    +

    Try it

    +

    Resize the window to see the layout switch from column to row

    Interactive

    -

    Hover modifiers like .hover:border_color_b change styles on hover

    - - -
    - - -
    -

    Design tokens

    -

    .p_md for padding, .color_bg_5 for text color

    -
    - {#each ['a', 'b', 'c', 'd', 'e'] as hue} -
    - .bg_{hue}_5 -
    - {/each} +
    + + .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d +
    +
    + + .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h
    @@ -78,9 +71,9 @@

    Token classes

    +
    .p_md .bg_d_2
    .pl_xl5 .font_size_lg
    .shadow_sm
    -
    .color_a_5
    @@ -96,11 +89,6 @@
    .opacity:60%
    .color:var(--color_j_5)
    .box-shadow:0~4px~8px~rgb(0,0,0,0.2) (~ encodes spaces)
    -
    - left - .display:flex .justify-content:space-between - right -
    @@ -113,17 +101,17 @@

    Naming patterns

    demoClass: .{demoClass}
    demo_class: .{demo_class}
    -
    demoClasses: .mb_xs3 .ml_xs
    -
    demo_classes: .mb_xs2 .ml_sm
    +
    DEMO_CLASS: .{DEMO_CLASS}
    +
    demoClasses: .mb_xs2 .ml_xs
    +
    demo_classes: .mb_xs .ml_sm
    demoClassName: .{demoClassName}
    demo_class_name: .{demo_class_name}
    -
    demoClassNames: .mb_md .ml_md
    -
    demo_class_names: .mb_lg .ml_lg
    +
    demoClassNames: .mb_lg .ml_md
    +
    demo_class_names: .mb_xl .ml_lg
    demoClassList: .{demoClassList}
    demo_class_list: .{demo_class_list}
    -
    demoClassLists: .mb_xl3 .ml_xl
    -
    demo_class_lists: .mb_xl4 .ml_xl2
    -
    DEMO_CLASS: .{DEMO_CLASS}
    +
    demoClassLists: .mb_xl4 .ml_xl
    +
    demo_class_lists: .mb_xl5 .ml_xl2
    @@ -137,6 +125,9 @@
    {"['mt_lg', 'mt_xl']"} → .{arrayClasses.join(', .')}
    +
    + {`{ mt_xl2: 'mt_xl2', mt_xl3: 'mt_xl3' }`} → keys extracted from object +
    diff --git a/src/lib/example_class_utilities.ts b/src/lib/example_class_utilities.ts index c3c349fff..7f76300c9 100644 --- a/src/lib/example_class_utilities.ts +++ b/src/lib/example_class_utilities.ts @@ -32,38 +32,38 @@ export const demoClass = 'mb_xs5'; /** `*_class` suffix (snake_case) */ export const demo_class = 'mb_xs4'; +/** `SCREAMING_SNAKE_CASE` naming */ +export const DEMO_CLASS = 'mb_xs3'; + /** `*Classes` suffix (camelCase) - plural, multiple classes */ -export const demoClasses = 'mb_xs3 ml_xs'; +export const demoClasses = 'mb_xs2 ml_xs'; /** `*_classes` suffix (snake_case) - plural, multiple classes */ -export const demo_classes = 'mb_xs2 ml_sm'; +export const demo_classes = 'mb_xs ml_sm'; /** `*ClassName` suffix (camelCase) */ -export const demoClassName = 'mb_xs'; +export const demoClassName = 'mb_sm'; /** `*class_name` suffix (snake_case) */ -export const demo_class_name = 'mb_sm'; +export const demo_class_name = 'mb_md'; /** `*ClassNames` suffix (camelCase) - plural, multiple classes */ -export const demoClassNames = 'mb_md ml_md'; +export const demoClassNames = 'mb_lg ml_md'; /** `*class_names` suffix (snake_case) - plural, multiple classes */ -export const demo_class_names = 'mb_lg ml_lg'; +export const demo_class_names = 'mb_xl ml_lg'; /** `*ClassList` suffix (camelCase) */ -export const demoClassList = 'mb_xl'; +export const demoClassList = 'mb_xl2'; /** `*class_list` suffix (snake_case) */ -export const demo_class_list = 'mb_xl2'; +export const demo_class_list = 'mb_xl3'; /** `*ClassLists` suffix (camelCase) - plural, multiple classes */ -export const demoClassLists = 'mb_xl3 ml_xl'; +export const demoClassLists = 'mb_xl4 ml_xl'; /** `*class_lists` suffix (snake_case) - plural, multiple classes */ -export const demo_class_lists = 'mb_xl4 ml_xl2'; - -/** `SCREAMING_SNAKE_CASE` naming */ -export const DEMO_CLASS = 'mb_xl5'; +export const demo_class_lists = 'mb_xl5 ml_xl2'; // // Expression patterns - ternary, logical AND, array (mt_* incrementing) @@ -78,6 +78,9 @@ export const logicalClass = true && 'mt_md'; /** Array - all elements extracted */ export const arrayClasses = ['mt_lg', 'mt_xl']; +/** Object - keys extracted as class names */ +export const objectClasses = {mt_xl2: 'mt_xl2', mt_xl3: 'mt_xl3'}; + // // Comment hint examples - @fuz-classes directive // diff --git a/src/routes/fuz.css b/src/routes/fuz.css index 1da1da159..98ec7dc65 100644 --- a/src/routes/fuz.css +++ b/src/routes/fuz.css @@ -571,9 +571,24 @@ a.chip { .mb_xl9 { margin-bottom: var(--space_xl9); } +.ml_xs { + margin-left: var(--space_xs); +} .ml_sm { margin-left: var(--space_sm); } +.ml_md { + margin-left: var(--space_md); +} +.ml_lg { + margin-left: var(--space_lg); +} +.ml_xl { + margin-left: var(--space_xl); +} +.ml_xl2 { + margin-left: var(--space_xl2); +} .mx_auto { margin-left: auto; margin-right: auto; @@ -670,15 +685,9 @@ a.chip { .font-weight\:950 { font-weight: 950; } -.gap\:1rem { - gap: 1rem; -} .inset\:0 { inset: 0; } -.justify-content\:space-between { - justify-content: space-between; -} .opacity\:0 { opacity: 0; } @@ -709,9 +718,6 @@ a.chip { .text-align\:center { text-align: center; } -.text-transform\:uppercase { - text-transform: uppercase; -} .white-space\:nowrap { white-space: nowrap; } diff --git a/src/routes/library.json b/src/routes/library.json index 4d8bc2f8e..24098171e 100644 --- a/src/routes/library.json +++ b/src/routes/library.json @@ -507,7 +507,7 @@ "examples": [ "escape_css_selector('display:flex') // 'display\\\\:flex'\nescape_css_selector('opacity:80%') // 'opacity\\\\:80\\\\%'\nescape_css_selector('nth-child(2n)') // 'nth-child\\\\(2n\\\\)'" ], - "source_line": 34, + "source_line": 35, "type_signature": "(name: string): string", "return_type": "string", "parameters": [ @@ -520,7 +520,7 @@ { "name": "CssClassDefinitionBase", "kind": "type", - "source_line": 42, + "source_line": 43, "type_signature": "CssClassDefinitionBase", "properties": [ { @@ -534,7 +534,7 @@ "name": "CssClassDefinitionComposition", "kind": "type", "doc_comment": "Pure utility composition (classes only).", - "source_line": 47, + "source_line": 48, "type_signature": "CssClassDefinitionComposition", "extends": ["CssClassDefinitionBase"], "properties": [ @@ -559,7 +559,7 @@ "name": "CssClassDefinitionDeclaration", "kind": "type", "doc_comment": "Custom CSS declaration (optionally seeded with classes).", - "source_line": 54, + "source_line": 55, "type_signature": "CssClassDefinitionDeclaration", "extends": ["CssClassDefinitionBase"], "properties": [ @@ -584,7 +584,7 @@ "name": "CssClassDefinitionRuleset", "kind": "type", "doc_comment": "Full ruleset with selectors.", - "source_line": 61, + "source_line": 62, "type_signature": "CssClassDefinitionRuleset", "extends": ["CssClassDefinitionBase"], "properties": [ @@ -609,21 +609,21 @@ "name": "CssClassDefinitionStatic", "kind": "type", "doc_comment": "Static definitions (not interpreter-based).", - "source_line": 68, + "source_line": 69, "type_signature": "CssClassDefinitionStatic" }, { "name": "CssClassDefinition", "kind": "type", "doc_comment": "Full union including interpreters.", - "source_line": 74, + "source_line": 75, "type_signature": "CssClassDefinition" }, { "name": "CssClassInterpreterContext", "kind": "type", "doc_comment": "Context passed to CSS class interpreters.\nProvides access to logging, diagnostics collection, and the class registry.", - "source_line": 80, + "source_line": 81, "type_signature": "CssClassInterpreterContext", "properties": [ { @@ -656,7 +656,7 @@ "name": "CssClassDefinitionInterpreter", "kind": "type", "doc_comment": "Interpreter for dynamic CSS class generation based on pattern matching.", - "source_line": 92, + "source_line": 93, "type_signature": "CssClassDefinitionInterpreter", "extends": ["CssClassDefinitionBase"], "properties": [ @@ -677,7 +677,7 @@ "name": "GenerateClassesCssResult", "kind": "type", "doc_comment": "Result from CSS class generation.", - "source_line": 107, + "source_line": 108, "type_signature": "GenerateClassesCssResult", "properties": [ { @@ -695,7 +695,7 @@ { "name": "GenerateClassesCssOptions", "kind": "type", - "source_line": 112, + "source_line": 113, "type_signature": "GenerateClassesCssOptions", "properties": [ { @@ -734,7 +734,7 @@ { "name": "generate_classes_css", "kind": "function", - "source_line": 122, + "source_line": 123, "type_signature": "(options: GenerateClassesCssOptions): GenerateClassesCssResult", "return_type": "GenerateClassesCssResult", "parameters": [ @@ -746,7 +746,12 @@ } ], "module_comment": "CSS class generation utilities.\n\nProduces CSS output from class definitions, handles interpretation of\ndynamic classes, and provides collection management for extracted classes.", - "dependencies": ["css_class_resolution.ts", "css_ruleset_parser.ts", "diagnostics.ts"], + "dependencies": [ + "css_class_resolution.ts", + "css_ruleset_parser.ts", + "diagnostics.ts", + "modifiers.ts" + ], "dependents": ["css_class_interpreters.ts", "gen_fuz_css.ts", "vite_plugin_fuz_css.ts"] }, { @@ -2120,204 +2125,141 @@ { "path": "example_class_utilities.ts", "declarations": [ - { - "name": "demoPaddingClass", - "kind": "variable", - "doc_comment": "Padding token - large spacing", - "source_line": 32, - "type_signature": "\"p_lg\"" - }, - { - "name": "demoShadowClass", - "kind": "variable", - "doc_comment": "Shadow token - small elevation", - "source_line": 35, - "type_signature": "\"shadow_sm\"" - }, - { - "name": "demoColorClass", - "kind": "variable", - "doc_comment": "Color token - primary hue intensity 5", - "source_line": 38, - "type_signature": "\"color_a_5\"" - }, - { - "name": "demoBoxClass", - "kind": "variable", - "doc_comment": "Layout composite - centered flex container", - "source_line": 45, - "type_signature": "\"box\"" - }, - { - "name": "demoRowClass", - "kind": "variable", - "doc_comment": "Layout composite - horizontal flex row", - "source_line": 48, - "type_signature": "\"row\"" - }, - { - "name": "demoEllipsisClass", - "kind": "variable", - "doc_comment": "Text composite - truncate with ellipsis", - "source_line": 51, - "type_signature": "\"ellipsis\"" - }, - { - "name": "demoJustifyClass", - "kind": "variable", - "doc_comment": "Justify literal - space-between distribution", - "source_line": 58, - "type_signature": "\"justify-content:space-between\"" - }, - { - "name": "demoTextTransformClass", - "kind": "variable", - "doc_comment": "Text literal - uppercase transform", - "source_line": 61, - "type_signature": "\"text-transform:uppercase\"" - }, - { - "name": "demoGapClass", - "kind": "variable", - "doc_comment": "Spacing literal - gap between children", - "source_line": 64, - "type_signature": "\"gap:1rem\"" - }, { "name": "demoClass", "kind": "variable", "doc_comment": "`*Class` suffix (camelCase)", - "source_line": 71, + "source_line": 30, "type_signature": "\"mb_xs5\"" }, { "name": "demo_class", "kind": "variable", "doc_comment": "`*_class` suffix (snake_case)", - "source_line": 74, + "source_line": 33, "type_signature": "\"mb_xs4\"" }, { - "name": "demoClasses", + "name": "DEMO_CLASS", "kind": "variable", - "doc_comment": "`*Classes` suffix (camelCase)", - "source_line": 77, + "doc_comment": "`SCREAMING_SNAKE_CASE` naming", + "source_line": 36, "type_signature": "\"mb_xs3\"" }, + { + "name": "demoClasses", + "kind": "variable", + "doc_comment": "`*Classes` suffix (camelCase) - plural, multiple classes", + "source_line": 39, + "type_signature": "\"mb_xs2 ml_xs\"" + }, { "name": "demo_classes", "kind": "variable", - "doc_comment": "`*_classes` suffix (snake_case)", - "source_line": 80, - "type_signature": "\"mb_xs2\"" + "doc_comment": "`*_classes` suffix (snake_case) - plural, multiple classes", + "source_line": 42, + "type_signature": "\"mb_xs ml_sm\"" }, { "name": "demoClassName", "kind": "variable", "doc_comment": "`*ClassName` suffix (camelCase)", - "source_line": 83, - "type_signature": "\"mb_xs\"" + "source_line": 45, + "type_signature": "\"mb_sm\"" }, { "name": "demo_class_name", "kind": "variable", "doc_comment": "`*class_name` suffix (snake_case)", - "source_line": 86, - "type_signature": "\"mb_sm\"" + "source_line": 48, + "type_signature": "\"mb_md\"" }, { "name": "demoClassNames", "kind": "variable", - "doc_comment": "`*ClassNames` suffix (camelCase)", - "source_line": 89, - "type_signature": "\"mb_md\"" + "doc_comment": "`*ClassNames` suffix (camelCase) - plural, multiple classes", + "source_line": 51, + "type_signature": "\"mb_lg ml_md\"" }, { "name": "demo_class_names", "kind": "variable", - "doc_comment": "`*class_names` suffix (snake_case)", - "source_line": 92, - "type_signature": "\"mb_lg\"" + "doc_comment": "`*class_names` suffix (snake_case) - plural, multiple classes", + "source_line": 54, + "type_signature": "\"mb_xl ml_lg\"" }, { "name": "demoClassList", "kind": "variable", "doc_comment": "`*ClassList` suffix (camelCase)", - "source_line": 95, - "type_signature": "\"mb_xl\"" + "source_line": 57, + "type_signature": "\"mb_xl2\"" }, { "name": "demo_class_list", "kind": "variable", "doc_comment": "`*class_list` suffix (snake_case)", - "source_line": 98, - "type_signature": "\"mb_xl2\"" + "source_line": 60, + "type_signature": "\"mb_xl3\"" }, { "name": "demoClassLists", "kind": "variable", - "doc_comment": "`*ClassLists` suffix (camelCase)", - "source_line": 101, - "type_signature": "\"mb_xl3\"" + "doc_comment": "`*ClassLists` suffix (camelCase) - plural, multiple classes", + "source_line": 63, + "type_signature": "\"mb_xl4 ml_xl\"" }, { "name": "demo_class_lists", "kind": "variable", - "doc_comment": "`*class_lists` suffix (snake_case)", - "source_line": 104, - "type_signature": "\"mb_xl4\"" - }, - { - "name": "DEMO_CLASS", - "kind": "variable", - "doc_comment": "`SCREAMING_SNAKE_CASE` naming", - "source_line": 107, - "type_signature": "\"mb_xl5\"" + "doc_comment": "`*class_lists` suffix (snake_case) - plural, multiple classes", + "source_line": 66, + "type_signature": "\"mb_xl5 ml_xl2\"" }, { "name": "ternaryClass", "kind": "variable", "doc_comment": "Ternary expression - both branches extracted", - "source_line": 114, + "source_line": 73, "type_signature": "\"mt_xs\" | \"mt_sm\"" }, { "name": "logicalClass", "kind": "variable", "doc_comment": "Logical AND - truthy value extracted", - "source_line": 117, + "source_line": 76, "type_signature": "\"mt_md\"" }, { "name": "arrayClasses", "kind": "variable", "doc_comment": "Array - all elements extracted", - "source_line": 120, + "source_line": 79, "type_signature": "string[]" }, { "name": "fromComment", "kind": "variable", "doc_comment": "Comment hint - extracted via", - "source_line": 131, + "source_line": 90, "type_signature": "\"shadow_lg\"" }, { "name": "unknownExtracted", "kind": "variable", "doc_comment": "Unknown class - extracted via", - "source_line": 138, + "source_line": 97, "type_signature": "\"unknown_not_included\"" }, { "name": "arbitraryLiteral", "kind": "variable", "doc_comment": "Invalid literal - extracted via", - "source_line": 146, + "source_line": 105, "type_signature": "\"not-real:extracted-but-excluded\"" } ], - "module_comment": "Example CSS class exports demonstrating node_modules extraction.\n\nThis module exists to verify that the Vite plugin extracts classes from\ndependencies in node_modules. Each export uses a unique class value\nto verify extraction is working correctly.\n\n**Important:** Variable names must match `CLASS_NAME_PATTERN` in css_class_extractor.ts.\nSupported suffixes: `class`, `classes`, `className`, `classNames`, `classList`, `classLists`\n(also snake_case variants like `class_name`, `class_names`, `class_list`, `class_lists`).\n\n**Class types demonstrated:**\n- Token classes: Map to style variables (`p_lg`, `shadow_sm`)\n- Composite classes: Multi-property shortcuts (`box`, `row`)\n- Literal classes: CSS property:value syntax (`justify-content:space-between`)\n\n**Variable patterns demonstrated:**\n- Simple assignment, ternary expressions, logical AND, arrays\n- Various naming conventions (camelCase, snake_case, SCREAMING_SNAKE)\n- Comment hints via `@fuz-classes`" + "module_comment": "Example CSS class exports demonstrating node_modules extraction.\n\nThis module exists to verify that the Vite plugin extracts classes from\ndependencies in node_modules. The exports test specific extraction patterns\nthat require being in a separate module.\n\n**Important:** Variable names must match `CLASS_NAME_PATTERN` in css_class_extractor.ts.\nSupported suffixes: `class`, `classes`, `className`, `classNames`, `classList`, `classLists`\n(also snake_case variants like `class_name`, `class_names`, `class_list`, `class_lists`).\n\n**Patterns demonstrated:**\n- Naming patterns: All CLASS_NAME_PATTERN suffix variants\n- Expression patterns: Ternary, logical AND, arrays\n- Comment hints: `@fuz-classes` directive\n\nToken, composite, and literal classes are demonstrated inline in the examples\nsince they don't require special extraction testing." }, { "path": "file_filter.ts", @@ -2650,7 +2592,7 @@ } ], "module_comment": "Declarative modifier definitions for CSS-literal syntax.\n\nModifiers enable responsive, state-based, and contextual styling:\n- Media modifiers: `md:`, `print:`, `motion-safe:`\n- Ancestor modifiers: `dark:`, `light:`\n- State modifiers: `hover:`, `focus:`, `disabled:`\n- Pseudo-element modifiers: `before:`, `after:`\n\n@see {@link https://github.com/fuzdev/fuz_css} for documentation", - "dependents": ["css_literal.ts"] + "dependents": ["css_class_generation.ts", "css_literal.ts"] }, { "path": "theme.gen.css.ts", diff --git a/src/test/vite_plugin_examples.test.ts b/src/test/vite_plugin_examples.test.ts index 55c252cf1..4e058b900 100644 --- a/src/test/vite_plugin_examples.test.ts +++ b/src/test/vite_plugin_examples.test.ts @@ -35,30 +35,33 @@ if (!SKIP) { * Sorted alphabetically for consistent comparison. */ const EXPECTED_CLASSES = [ - // From App - Class Types section - 'color_a_5', - 'p_xl5', + // From App - Class Types section (Token classes) + 'p_md', // also used in main wrapper + 'bg_d_2', + 'pl_xl5', + 'font_size_lg', 'shadow_sm', + // From App - Class Types section (Composite classes) 'box', 'ellipsis', - 'display:flex', - 'gap:1rem', - 'justify-content:space-between', - 'text-transform:uppercase', + // From App - Class Types section (Literal classes) + 'opacity:60%', + 'color:var(--color_j_5)', + 'box-shadow:0~4px~8px~rgb(0,0,0,0.2)', // From example_class_utilities.ts - Naming patterns (mb_* + ml_* for plurals) 'mb_xs5', // demoClass 'mb_xs4', // demo_class - 'mb_xs3', // demoClasses (+ ml_xs) - 'mb_xs2', // demo_classes (+ ml_sm) - 'mb_xs', // demoClassName - 'mb_sm', // demo_class_name - 'mb_md', // demoClassNames (+ ml_md) - 'mb_lg', // demo_class_names (+ ml_lg) - 'mb_xl', // demoClassList - 'mb_xl2', // demo_class_list - 'mb_xl3', // demoClassLists (+ ml_xl) - 'mb_xl4', // demo_class_lists (+ ml_xl2) - 'mb_xl5', // DEMO_CLASS + 'mb_xs3', // DEMO_CLASS + 'mb_xs2', // demoClasses (+ ml_xs) + 'mb_xs', // demo_classes (+ ml_sm) + 'mb_sm', // demoClassName + 'mb_md', // demo_class_name + 'mb_lg', // demoClassNames (+ ml_md) + 'mb_xl', // demo_class_names (+ ml_lg) + 'mb_xl2', // demoClassList + 'mb_xl3', // demo_class_list + 'mb_xl4', // demoClassLists (+ ml_xl) + 'mb_xl5', // demo_class_lists (+ ml_xl2) 'ml_xs', // demoClasses (plural) 'ml_sm', // demo_classes (plural) 'ml_md', // demoClassNames (plural) @@ -71,40 +74,32 @@ const EXPECTED_CLASSES = [ 'mt_md', // logicalClass 'mt_lg', // arrayClasses[0] 'mt_xl', // arrayClasses[1] + 'mt_xl2', // objectClasses key + 'mt_xl3', // objectClasses key // From example_class_utilities.ts - Comment hints // Note: 'not-real:extracted-but-excluded' is extracted via @fuz-classes but excluded // from CSS output because 'not-real' fails @webref/css property validation 'shadow_lg', // fromComment via @fuz-classes // From App - Layout + 'md:p_xl', 'column', 'gap_lg', - 'gap_md', - 'gap_sm', - 'max-width:800px', - 'p_xl', 'text-align:center', - 'width:100%', // From App - Responsive - 'flex:1', + 'gap_md', + 'md:flex-direction:row', 'md:gap_lg', - 'md:row', + 'flex:1', // From App - Interactive (hover/active state modifiers) + 'row', 'hover:border_color_b', 'hover:outline_color_b', 'active:border_color_d', 'active:outline_color_d', - 'hover:border_color_e', - 'hover:outline_color_e', + 'hover:border_color_g', + 'hover:outline_color_g', 'active:border_color_h', 'active:outline_color_h', - // From App - Design Tokens (bg_${hue}_5 where hue is a, b, c, d, e) - 'bg_a_5', - 'bg_b_5', - 'bg_c_5', - 'bg_d_5', - 'bg_e_5', - 'color:white', - 'p_md', ].sort(); /** @@ -158,17 +153,17 @@ const extract_fuz_css = (css: string): string | null => { /** * Extracts class names from CSS content. - * Handles escaped characters in class names (colons, percent signs). + * Handles escaped characters in class names (colons, percent signs, parens, tildes, commas, dots). */ const extract_class_names = (css: string): Array => { const classes: Set = new Set(); - // Match class selectors: .classname followed by space, comma, colon, or brace - // Class names can contain escaped characters like \: and \% - const pattern = /\.([a-zA-Z_][a-zA-Z0-9_-]*(?:\\[:%][a-zA-Z0-9_%-]*)*)/g; + // Match class selectors: .classname + // Class names can contain escaped characters like \: \% \( \) \~ \, \. + const pattern = /\.([a-zA-Z_][a-zA-Z0-9_-]*(?:\\[:%()~,.][-a-zA-Z0-9_(),%~.]*)*)/g; let match; while ((match = pattern.exec(css)) !== null) { - // Unescape CSS escape sequences: \: -> :, \% -> % - const class_name = match[1]!.replace(/\\([:%])/g, '$1'); + // Unescape CSS escape sequences: \: -> :, \% -> %, \( -> (, etc. + const class_name = match[1]!.replace(/\\([:%()~,.])/g, '$1'); classes.add(class_name); } return [...classes].sort(); From cd858c05f28a372816fcf6cb3706e197155f3106 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 14 Jan 2026 12:14:45 -0500 Subject: [PATCH 078/138] wip --- examples/vite-preact/package-lock.json | 248 +++++++++---------- examples/vite-preact/package.json | 2 +- examples/vite-preact/vite.config.ts | 3 - examples/vite-react/package-lock.json | 248 +++++++++---------- examples/vite-react/package.json | 2 +- examples/vite-react/vite.config.ts | 3 - examples/vite-solid/package-lock.json | 248 +++++++++---------- examples/vite-solid/package.json | 2 +- examples/vite-solid/vite.config.ts | 3 - examples/vite-svelte/package-lock.json | 329 ++++++++++++------------- examples/vite-svelte/package.json | 4 +- examples/vite-svelte/vite.config.ts | 6 +- src/lib/vite_plugin_fuz_css.ts | 5 +- src/test/vite_plugin_examples.test.ts | 56 ++++- 14 files changed, 577 insertions(+), 582 deletions(-) diff --git a/examples/vite-preact/package-lock.json b/examples/vite-preact/package-lock.json index 50ca6c6b5..5c05c23ce 100644 --- a/examples/vite-preact/package-lock.json +++ b/examples/vite-preact/package-lock.json @@ -13,7 +13,7 @@ "@preact/preset-vite": "^2", "acorn-jsx": "^5", "typescript": "^5", - "vite": "^6" + "vite": "^7" } }, "../..": { @@ -396,9 +396,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", "cpu": [ "ppc64" ], @@ -413,9 +413,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", "cpu": [ "arm" ], @@ -430,9 +430,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", "cpu": [ "arm64" ], @@ -447,9 +447,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", "cpu": [ "x64" ], @@ -464,9 +464,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ "arm64" ], @@ -481,9 +481,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", "cpu": [ "x64" ], @@ -498,9 +498,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", "cpu": [ "arm64" ], @@ -515,9 +515,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", "cpu": [ "x64" ], @@ -532,9 +532,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", "cpu": [ "arm" ], @@ -549,9 +549,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", "cpu": [ "arm64" ], @@ -566,9 +566,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", "cpu": [ "ia32" ], @@ -583,9 +583,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", "cpu": [ "loong64" ], @@ -600,9 +600,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", "cpu": [ "mips64el" ], @@ -617,9 +617,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", "cpu": [ "ppc64" ], @@ -634,9 +634,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", "cpu": [ "riscv64" ], @@ -651,9 +651,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", "cpu": [ "s390x" ], @@ -668,9 +668,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -685,9 +685,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", "cpu": [ "arm64" ], @@ -702,9 +702,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", "cpu": [ "x64" ], @@ -719,9 +719,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", "cpu": [ "arm64" ], @@ -736,9 +736,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", "cpu": [ "x64" ], @@ -753,9 +753,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", "cpu": [ "arm64" ], @@ -770,9 +770,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", "cpu": [ "x64" ], @@ -787,9 +787,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", "cpu": [ "arm64" ], @@ -804,9 +804,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", "cpu": [ "ia32" ], @@ -821,9 +821,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -1566,9 +1566,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1579,32 +1579,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/escalade": { @@ -2024,24 +2024,24 @@ } }, "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -2050,14 +2050,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", - "less": "*", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" diff --git a/examples/vite-preact/package.json b/examples/vite-preact/package.json index 9d3c9b493..a386926a6 100644 --- a/examples/vite-preact/package.json +++ b/examples/vite-preact/package.json @@ -15,6 +15,6 @@ "@preact/preset-vite": "^2", "acorn-jsx": "^5", "typescript": "^5", - "vite": "^6" + "vite": "^7" } } diff --git a/examples/vite-preact/vite.config.ts b/examples/vite-preact/vite.config.ts index 573acdff1..88f82c483 100644 --- a/examples/vite-preact/vite.config.ts +++ b/examples/vite-preact/vite.config.ts @@ -9,9 +9,6 @@ export default defineConfig({ preact(), vite_plugin_fuz_css({ acorn_plugins: [jsx()], - // Include dynamically constructed classes that can't be statically extracted - // The example uses `bg_${hue}_5` in a .map() which produces these at runtime - include_classes: ['bg_a_5', 'bg_b_5', 'bg_c_5', 'bg_d_5', 'bg_e_5'], }), ], }); diff --git a/examples/vite-react/package-lock.json b/examples/vite-react/package-lock.json index a0861523d..a5f331f71 100644 --- a/examples/vite-react/package-lock.json +++ b/examples/vite-react/package-lock.json @@ -16,7 +16,7 @@ "@vitejs/plugin-react": "^5", "acorn-jsx": "^5", "typescript": "^5", - "vite": "^6" + "vite": "^7" } }, "../..": { @@ -366,9 +366,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", "cpu": [ "ppc64" ], @@ -383,9 +383,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", "cpu": [ "arm" ], @@ -400,9 +400,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", "cpu": [ "arm64" ], @@ -417,9 +417,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", "cpu": [ "x64" ], @@ -434,9 +434,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ "arm64" ], @@ -451,9 +451,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", "cpu": [ "x64" ], @@ -468,9 +468,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", "cpu": [ "arm64" ], @@ -485,9 +485,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", "cpu": [ "x64" ], @@ -502,9 +502,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", "cpu": [ "arm" ], @@ -519,9 +519,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", "cpu": [ "arm64" ], @@ -536,9 +536,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", "cpu": [ "ia32" ], @@ -553,9 +553,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", "cpu": [ "loong64" ], @@ -570,9 +570,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", "cpu": [ "mips64el" ], @@ -587,9 +587,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", "cpu": [ "ppc64" ], @@ -604,9 +604,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", "cpu": [ "riscv64" ], @@ -621,9 +621,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", "cpu": [ "s390x" ], @@ -638,9 +638,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -655,9 +655,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", "cpu": [ "arm64" ], @@ -672,9 +672,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", "cpu": [ "x64" ], @@ -689,9 +689,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", "cpu": [ "arm64" ], @@ -706,9 +706,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", "cpu": [ "x64" ], @@ -723,9 +723,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", "cpu": [ "arm64" ], @@ -740,9 +740,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", "cpu": [ "x64" ], @@ -757,9 +757,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", "cpu": [ "arm64" ], @@ -774,9 +774,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", "cpu": [ "ia32" ], @@ -791,9 +791,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -1440,9 +1440,9 @@ "license": "ISC" }, "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1453,32 +1453,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/escalade": { @@ -1824,24 +1824,24 @@ } }, "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -1850,14 +1850,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", - "less": "*", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" diff --git a/examples/vite-react/package.json b/examples/vite-react/package.json index dd0fe3921..30f1fb351 100644 --- a/examples/vite-react/package.json +++ b/examples/vite-react/package.json @@ -18,6 +18,6 @@ "@vitejs/plugin-react": "^5", "acorn-jsx": "^5", "typescript": "^5", - "vite": "^6" + "vite": "^7" } } diff --git a/examples/vite-react/vite.config.ts b/examples/vite-react/vite.config.ts index 0203c41c0..fa39ab941 100644 --- a/examples/vite-react/vite.config.ts +++ b/examples/vite-react/vite.config.ts @@ -9,9 +9,6 @@ export default defineConfig({ react(), vite_plugin_fuz_css({ acorn_plugins: [jsx()], - // Include dynamically constructed classes that can't be statically extracted - // The example uses `bg_${hue}_5` in a .map() which produces these at runtime - include_classes: ['bg_a_5', 'bg_b_5', 'bg_c_5', 'bg_d_5', 'bg_e_5'], }), ], }); diff --git a/examples/vite-solid/package-lock.json b/examples/vite-solid/package-lock.json index 3cd774e75..933c9490d 100644 --- a/examples/vite-solid/package-lock.json +++ b/examples/vite-solid/package-lock.json @@ -12,7 +12,7 @@ "@fuzdev/fuz_css": "file:../..", "acorn-jsx": "^5", "typescript": "^5", - "vite": "^6", + "vite": "^7", "vite-plugin-solid": "^2" } }, @@ -347,9 +347,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", "cpu": [ "ppc64" ], @@ -364,9 +364,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", "cpu": [ "arm" ], @@ -381,9 +381,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", "cpu": [ "arm64" ], @@ -398,9 +398,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", "cpu": [ "x64" ], @@ -415,9 +415,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ "arm64" ], @@ -432,9 +432,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", "cpu": [ "x64" ], @@ -449,9 +449,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", "cpu": [ "arm64" ], @@ -466,9 +466,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", "cpu": [ "x64" ], @@ -483,9 +483,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", "cpu": [ "arm" ], @@ -500,9 +500,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", "cpu": [ "arm64" ], @@ -517,9 +517,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", "cpu": [ "ia32" ], @@ -534,9 +534,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", "cpu": [ "loong64" ], @@ -551,9 +551,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", "cpu": [ "mips64el" ], @@ -568,9 +568,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", "cpu": [ "ppc64" ], @@ -585,9 +585,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", "cpu": [ "riscv64" ], @@ -602,9 +602,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", "cpu": [ "s390x" ], @@ -619,9 +619,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -636,9 +636,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", "cpu": [ "arm64" ], @@ -653,9 +653,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", "cpu": [ "x64" ], @@ -670,9 +670,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", "cpu": [ "arm64" ], @@ -687,9 +687,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", "cpu": [ "x64" ], @@ -704,9 +704,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", "cpu": [ "arm64" ], @@ -721,9 +721,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", "cpu": [ "x64" ], @@ -738,9 +738,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", "cpu": [ "arm64" ], @@ -755,9 +755,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", "cpu": [ "ia32" ], @@ -772,9 +772,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -1434,9 +1434,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1447,32 +1447,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/escalade": { @@ -1877,24 +1877,24 @@ } }, "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -1903,14 +1903,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", - "less": "*", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" diff --git a/examples/vite-solid/package.json b/examples/vite-solid/package.json index 7ac7052fb..3c521ae07 100644 --- a/examples/vite-solid/package.json +++ b/examples/vite-solid/package.json @@ -14,7 +14,7 @@ "@fuzdev/fuz_css": "file:../..", "acorn-jsx": "^5", "typescript": "^5", - "vite": "^6", + "vite": "^7", "vite-plugin-solid": "^2" } } diff --git a/examples/vite-solid/vite.config.ts b/examples/vite-solid/vite.config.ts index 78419e1ab..2b31a7fad 100644 --- a/examples/vite-solid/vite.config.ts +++ b/examples/vite-solid/vite.config.ts @@ -8,9 +8,6 @@ export default defineConfig({ // fuz_css must be listed first for solid (enforce: 'pre' alone isn't sufficient) vite_plugin_fuz_css({ acorn_plugins: [jsx()], - // Include dynamically constructed classes that can't be statically extracted - // The example uses `bg_${hue}_5` in a which produces these at runtime - include_classes: ['bg_a_5', 'bg_b_5', 'bg_c_5', 'bg_d_5', 'bg_e_5'], }), solid(), ], diff --git a/examples/vite-svelte/package-lock.json b/examples/vite-svelte/package-lock.json index cfa68627e..6dd736dc6 100644 --- a/examples/vite-svelte/package-lock.json +++ b/examples/vite-svelte/package-lock.json @@ -10,9 +10,9 @@ }, "devDependencies": { "@fuzdev/fuz_css": "file:../..", - "@sveltejs/vite-plugin-svelte": "^5", + "@sveltejs/vite-plugin-svelte": "^6", "typescript": "^5", - "vite": "^6" + "vite": "^7" } }, "../..": { @@ -80,9 +80,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", "cpu": [ "ppc64" ], @@ -97,9 +97,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", "cpu": [ "arm" ], @@ -114,9 +114,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", "cpu": [ "arm64" ], @@ -131,9 +131,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", "cpu": [ "x64" ], @@ -148,9 +148,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ "arm64" ], @@ -165,9 +165,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", "cpu": [ "x64" ], @@ -182,9 +182,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", "cpu": [ "arm64" ], @@ -199,9 +199,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", "cpu": [ "x64" ], @@ -216,9 +216,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", "cpu": [ "arm" ], @@ -233,9 +233,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", "cpu": [ "arm64" ], @@ -250,9 +250,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", "cpu": [ "ia32" ], @@ -267,9 +267,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", "cpu": [ "loong64" ], @@ -284,9 +284,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", "cpu": [ "mips64el" ], @@ -301,9 +301,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", "cpu": [ "ppc64" ], @@ -318,9 +318,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", "cpu": [ "riscv64" ], @@ -335,9 +335,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", "cpu": [ "s390x" ], @@ -352,9 +352,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -369,9 +369,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", "cpu": [ "arm64" ], @@ -386,9 +386,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", "cpu": [ "x64" ], @@ -403,9 +403,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", "cpu": [ "arm64" ], @@ -420,9 +420,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", "cpu": [ "x64" ], @@ -437,9 +437,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", "cpu": [ "arm64" ], @@ -454,9 +454,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", "cpu": [ "x64" ], @@ -471,9 +471,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", "cpu": [ "arm64" ], @@ -488,9 +488,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", "cpu": [ "ia32" ], @@ -505,9 +505,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -930,43 +930,42 @@ } }, "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz", - "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.2.4.tgz", + "integrity": "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==", "dev": true, "license": "MIT", "dependencies": { - "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", - "debug": "^4.4.1", + "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0", "deepmerge": "^4.3.1", - "kleur": "^4.1.5", - "magic-string": "^0.30.17", - "vitefu": "^1.0.6" + "magic-string": "^0.30.21", + "obug": "^2.1.0", + "vitefu": "^1.1.1" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22" + "node": "^20.19 || ^22.12 || >=24" }, "peerDependencies": { "svelte": "^5.0.0", - "vite": "^6.0.0" + "vite": "^6.3.0 || ^7.0.0" } }, "node_modules/@sveltejs/vite-plugin-svelte-inspector": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", - "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-5.0.2.tgz", + "integrity": "sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.3.7" + "obug": "^2.1.0" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22" + "node": "^20.19 || ^22.12 || >=24" }, "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0", "svelte": "^5.0.0", - "vite": "^6.0.0" + "vite": "^6.3.0 || ^7.0.0" } }, "node_modules/@types/estree": { @@ -1014,24 +1013,6 @@ "node": ">=6" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -1049,9 +1030,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1062,32 +1043,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/esm-env": { @@ -1147,16 +1128,6 @@ "@types/estree": "^1.0.6" } }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", @@ -1172,13 +1143,6 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -1198,6 +1162,17 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1360,24 +1335,24 @@ } }, "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -1386,14 +1361,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", - "less": "*", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" diff --git a/examples/vite-svelte/package.json b/examples/vite-svelte/package.json index 866826840..6595c48c4 100644 --- a/examples/vite-svelte/package.json +++ b/examples/vite-svelte/package.json @@ -12,8 +12,8 @@ }, "devDependencies": { "@fuzdev/fuz_css": "file:../..", - "@sveltejs/vite-plugin-svelte": "^5", + "@sveltejs/vite-plugin-svelte": "^6", "typescript": "^5", - "vite": "^6" + "vite": "^7" } } diff --git a/examples/vite-svelte/vite.config.ts b/examples/vite-svelte/vite.config.ts index 07f5973ef..d94ba0216 100644 --- a/examples/vite-svelte/vite.config.ts +++ b/examples/vite-svelte/vite.config.ts @@ -5,11 +5,7 @@ import {vite_plugin_fuz_css} from '@fuzdev/fuz_css/vite_plugin_fuz_css.js'; export default defineConfig({ plugins: [ // fuz_css must be listed first for svelte (enforce: 'pre' alone isn't sufficient) - vite_plugin_fuz_css({ - // Include dynamically constructed classes that can't be statically extracted - // The example uses `bg_${hue}_5` in an {#each} which produces these at runtime - include_classes: ['bg_a_5', 'bg_b_5', 'bg_c_5', 'bg_d_5', 'bg_e_5'], - }), + vite_plugin_fuz_css(), svelte(), ], }); diff --git a/src/lib/vite_plugin_fuz_css.ts b/src/lib/vite_plugin_fuz_css.ts index d9e1f1bf8..b1ee2ad85 100644 --- a/src/lib/vite_plugin_fuz_css.ts +++ b/src/lib/vite_plugin_fuz_css.ts @@ -48,6 +48,9 @@ import {type FileFilter, filter_file_default} from './file_filter.js'; /* eslint-disable no-console */ +/** Marker comment used to delimit generated CSS in the output. */ +export const FUZ_CSS_MARKER = '/* generated by vite_plugin_fuz_css */'; + const VIRTUAL_ID = 'virtual:fuz.css'; const RESOLVED_VIRTUAL_ID = '\0virtual:fuz.css'; @@ -289,7 +292,7 @@ export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plug } } - return `/* generated by vite_plugin_fuz_css */\n\n${result.css}\n\n/* generated by vite_plugin_fuz_css */`; + return `${FUZ_CSS_MARKER}\n\n${result.css}\n\n${FUZ_CSS_MARKER}`; }; /** diff --git a/src/test/vite_plugin_examples.test.ts b/src/test/vite_plugin_examples.test.ts index 4e058b900..b145b7654 100644 --- a/src/test/vite_plugin_examples.test.ts +++ b/src/test/vite_plugin_examples.test.ts @@ -4,7 +4,8 @@ * Builds each example project and verifies that: * 1. The build completes successfully * 2. All expected CSS classes are extracted (no missing) - * 3. All examples produce the same set of classes (consistency) + * 3. No unexpected classes are generated (no extra) + * 4. All examples produce the same set of classes (consistency) * * These tests are slower due to npm install + vite build. * Skip with: SKIP_EXAMPLE_TESTS=1 gro test @@ -17,6 +18,8 @@ import {join} from 'node:path'; import {readdir, readFile} from 'node:fs/promises'; import {execSync} from 'node:child_process'; +import {FUZ_CSS_MARKER} from '$lib/vite_plugin_fuz_css.js'; + // Skip if SKIP_EXAMPLE_TESTS is set const SKIP = !!process.env.SKIP_EXAMPLE_TESTS; @@ -56,7 +59,7 @@ const EXPECTED_CLASSES = [ 'mb_xs', // demo_classes (+ ml_sm) 'mb_sm', // demoClassName 'mb_md', // demo_class_name - 'mb_lg', // demoClassNames (+ ml_md) + 'mb_lg', // demoClassNames (+ ml_md), also used in Interactive row wrapper 'mb_xl', // demo_class_names (+ ml_lg) 'mb_xl2', // demoClassList 'mb_xl3', // demo_class_list @@ -118,11 +121,17 @@ const find_css_file = async (dist_dir: string): Promise => { /** * Builds an example project. + * @throws Error if build fails with details about the failure */ const build_example = (example_name: string): void => { const example_dir = join(EXAMPLES_DIR, example_name); - execSync('npm install', {cwd: example_dir, stdio: 'pipe'}); - execSync('npm run build', {cwd: example_dir, stdio: 'pipe'}); + try { + execSync('npm install', {cwd: example_dir, stdio: 'pipe'}); + execSync('npm run build', {cwd: example_dir, stdio: 'pipe'}); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + throw new Error(`Failed to build ${example_name}: ${message}`); + } }; /** @@ -142,13 +151,12 @@ const read_generated_css = async (example_name: string): Promise => { * Returns the CSS between the marker comments. */ const extract_fuz_css = (css: string): string | null => { - const marker = '/* generated by vite_plugin_fuz_css */'; - const start_idx = css.indexOf(marker); - const end_idx = css.lastIndexOf(marker); + const start_idx = css.indexOf(FUZ_CSS_MARKER); + const end_idx = css.lastIndexOf(FUZ_CSS_MARKER); if (start_idx === -1 || end_idx === -1 || start_idx === end_idx) { return null; } - return css.slice(start_idx, end_idx + marker.length); + return css.slice(start_idx, end_idx + FUZ_CSS_MARKER.length); }; /** @@ -169,6 +177,9 @@ const extract_class_names = (css: string): Array => { return [...classes].sort(); }; +/** Store extracted classes per example for cross-example consistency test */ +const example_results: Map> = new Map(); + /** * Creates a test suite for an example. */ @@ -183,6 +194,8 @@ const create_example_tests = (example_name: string, app_file: string): void => { css = await read_generated_css(example_name); fuz_css = extract_fuz_css(css); extracted_classes = fuz_css ? extract_class_names(fuz_css) : []; + // Store for cross-example comparison + example_results.set(example_name, extracted_classes); }, 120_000); // 2 minute timeout for install + build test('generates fuz_css section', () => { @@ -194,11 +207,9 @@ const create_example_tests = (example_name: string, app_file: string): void => { expect(missing, `Missing classes: ${missing.join(', ')}`).toEqual([]); }); - test('produces exactly the expected classes (no extra, no missing)', () => { - // Filter extracted classes to only those in our expected set - // (there may be additional classes from composite expansions) - const relevant = extracted_classes.filter((cls) => EXPECTED_CLASSES.includes(cls)); - expect(relevant).toEqual(EXPECTED_CLASSES); + test('does not generate unexpected classes', () => { + const extra = extracted_classes.filter((cls) => !EXPECTED_CLASSES.includes(cls)); + expect(extra, `Unexpected classes: ${extra.join(', ')}`).toEqual([]); }); test('generates valid CSS without errors', () => { @@ -214,3 +225,22 @@ create_example_tests('vite-react', 'App.tsx'); create_example_tests('vite-preact', 'App.tsx'); create_example_tests('vite-solid', 'App.tsx'); create_example_tests('vite-svelte', 'App.svelte'); + +// Cross-example consistency test +describe.skipIf(SKIP)('cross-example consistency', () => { + test('all examples produce the same classes', () => { + const examples = [...example_results.keys()]; + expect(examples.length, 'Should have results from all 4 examples').toBe(4); + + const first_example = examples[0]!; + const first_classes = example_results.get(first_example)!; + + for (const example of examples.slice(1)) { + const classes = example_results.get(example)!; + expect( + classes, + `${example} should produce same classes as ${first_example}`, + ).toEqual(first_classes); + } + }); +}); From 56e60ad24def192fb71f3a93e8b52936ef3a655d Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 14 Jan 2026 12:43:52 -0500 Subject: [PATCH 079/138] wip --- src/lib/css_cache.ts | 5 +++++ src/lib/gen_fuz_css.ts | 5 +++-- src/lib/vite_plugin_fuz_css.ts | 5 +++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/lib/css_cache.ts b/src/lib/css_cache.ts index e98cad97b..a90e3bf32 100644 --- a/src/lib/css_cache.ts +++ b/src/lib/css_cache.ts @@ -12,6 +12,11 @@ import {dirname, join} from 'node:path'; import type {SourceLocation, ExtractionDiagnostic} from './diagnostics.js'; +/** + * Default cache directory relative to project root. + */ +export const DEFAULT_CACHE_DIR = '.fuz/cache/css'; + /** * Cache version. Bump when any of these change: * - `CachedExtraction` schema diff --git a/src/lib/gen_fuz_css.ts b/src/lib/gen_fuz_css.ts index a5f8f2c51..0cef34343 100644 --- a/src/lib/gen_fuz_css.ts +++ b/src/lib/gen_fuz_css.ts @@ -24,6 +24,7 @@ import {css_class_definitions} from './css_class_definitions.js'; import {css_class_interpreters} from './css_class_interpreters.js'; import {load_css_properties} from './css_literal.js'; import { + DEFAULT_CACHE_DIR, get_cache_path, load_cached_extraction, save_cached_extraction, @@ -101,7 +102,7 @@ export interface GenFuzCssOptions { exclude_classes?: Iterable; /** * Cache directory relative to project_root. - * @default '.fuz/cache/css' + * @default DEFAULT_CACHE_DIR */ cache_dir?: string; /** @@ -175,7 +176,7 @@ export const gen_fuz_css = (options: GenFuzCssOptions = {}): Gen => { on_error = 'log', include_classes, exclude_classes, - cache_dir = '.fuz/cache/css', + cache_dir = DEFAULT_CACHE_DIR, project_root: project_root_option, concurrency = DEFAULT_CONCURRENCY, cache_io_concurrency = DEFAULT_CACHE_IO_CONCURRENCY, diff --git a/src/lib/vite_plugin_fuz_css.ts b/src/lib/vite_plugin_fuz_css.ts index b1ee2ad85..e2b83da32 100644 --- a/src/lib/vite_plugin_fuz_css.ts +++ b/src/lib/vite_plugin_fuz_css.ts @@ -38,6 +38,7 @@ import {css_class_definitions} from './css_class_definitions.js'; import {css_class_interpreters} from './css_class_interpreters.js'; import {load_css_properties} from './css_literal.js'; import { + DEFAULT_CACHE_DIR, get_cache_path, load_cached_extraction, save_cached_extraction, @@ -116,7 +117,7 @@ export interface VitePluginFuzCssOptions { on_error?: 'log' | 'throw'; /** * Cache directory relative to project root. - * @default '.fuz/cache/css' + * @default DEFAULT_CACHE_DIR */ cache_dir?: string; } @@ -150,7 +151,7 @@ export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plug exclude_classes, acorn_plugins, on_error = 'log', - cache_dir = '.fuz/cache/css', + cache_dir = DEFAULT_CACHE_DIR, } = options; // Merge class definitions From 288bedc47fd783606a0aa9c9f266edc941984a8b Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Wed, 14 Jan 2026 13:18:07 -0500 Subject: [PATCH 080/138] wip --- CLAUDE.md | 30 +++- examples/vite-preact/src/App.tsx | 77 +++++---- examples/vite-react/src/App.tsx | 77 +++++---- examples/vite-solid/src/App.tsx | 77 +++++---- examples/vite-svelte/src/App.svelte | 112 ++++++++----- src/lib/css_cache.ts | 15 ++ src/lib/diagnostics.ts | 32 ++++ src/lib/gen_fuz_css.ts | 70 ++++---- src/lib/vite_plugin_fuz_css.ts | 57 ++++--- src/routes/fuz.css | 3 + src/routes/library.json | 131 ++++++++++----- src/test/css_class_generation.test.ts | 7 +- src/test/diagnostics.test.ts | 220 ++++++++++++++++++++++++++ src/test/vite_plugin_examples.test.ts | 14 +- 14 files changed, 668 insertions(+), 254 deletions(-) create mode 100644 src/test/diagnostics.test.ts diff --git a/CLAUDE.md b/CLAUDE.md index b7589b334..1138d1857 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -36,12 +36,38 @@ gro build # build the package for production ### Smart utility class generation -Two generators available: +Two generators available, both using AST-based extraction ([css_class_extractor.ts](src/lib/css_class_extractor.ts)) and per-file caching with content hash validation: 1. **Gro generator** - [gen_fuz_css.ts](src/lib/gen_fuz_css.ts) for SvelteKit projects using Gro 2. **Vite plugin** - [vite_plugin_fuz_css.ts](src/lib/vite_plugin_fuz_css.ts) for Svelte/React/Preact/Solid via `virtual:fuz.css` -Both use AST-based extraction ([css_class_extractor.ts](src/lib/css_class_extractor.ts)) and output only CSS for classes actually used. Supports Svelte 5.16+ class syntax, JSX `className`, clsx/cn calls, and `// @fuz-classes` comment hints. +Both output only CSS for classes actually used. Supports Svelte 5.16+ class syntax, JSX `className`, clsx/cn calls, and `// @fuz-classes` comment hints. + +**Shared options (both generators):** + +- `filter_file` - Which files to extract from (default: `.svelte`, `.html`, `.ts`, `.js`, `.tsx`, `.jsx`, excluding tests/gen files) +- `class_definitions` - Additional definitions to merge with builtins (user takes precedence) +- `class_interpreters` - Custom interpreters (replaces builtins if provided) +- `include_classes` - Classes to always include (for dynamic class names) +- `exclude_classes` - Classes to exclude (filter false positives) +- `acorn_plugins` - Additional acorn plugins (use `acorn-jsx` for React/Preact/Solid) +- `on_error` - `'log'` (default) or `'throw'` for CSS-literal errors +- `cache_dir` - Cache directory (default: `.fuz/cache/css`) + +**Gro-only options:** + +- `include_stats` - Include file statistics in output +- `project_root` - Project root directory (default: `process.cwd()`) +- `concurrency` - Max concurrent file processing (default: 8) +- `cache_io_concurrency` - Max concurrent cache I/O (default: 50) + +**Key implementation differences:** + +- **HMR**: Vite plugin has HMR with 10ms debouncing; Gro regenerates on file change +- **Cache writes**: Vite uses fire-and-forget; Gro awaits with concurrency control +- **External files**: Both use hashed paths in `_external/` subdirectory for files outside project root (e.g., symlinked deps with pnpm) +- **Error types**: Both throw `CssGenerationError` with `diagnostics` property for programmatic error access +- **CI behavior**: Both skip cache writes on CI ### Three class types diff --git a/examples/vite-preact/src/App.tsx b/examples/vite-preact/src/App.tsx index e94482db6..9c10a6203 100644 --- a/examples/vite-preact/src/App.tsx +++ b/examples/vite-preact/src/App.tsx @@ -31,42 +31,13 @@ export const App = () => { const [count, setCount] = useState(0); return ( -
    +

    fuz_css + Preact

    -

    Utility classes generated on-demand via Vite plugin

    +

    Utility classes generated on-demand via Vite plugin (docs, source)

    - {/* Responsive layout: column on mobile, row on desktop */} -
    -
    -

    Responsive

    -

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    -
    -
    -

    Try it

    -

    Resize the window to see the layout switch from column to row

    -
    -
    - - {/* Interactive button with hover states */} -
    -

    Interactive

    -
    - - .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d -
    -
    - - .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h -
    -
    - {/* Class types */}

    Class types

    @@ -94,10 +65,44 @@ export const App = () => {
    - {/* Classes from node_modules dependency - verifies extraction */} + {/* Modifiers */} +
    +

    Modifiers

    + +
    +

    Responsive

    +
    +
    +

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    +
    +
    +

    Resize the window to see the layout switch from column to row

    +
    +
    +

    .min-width(543px):font_size_lg — arbitrary breakpoint

    +
    + +
    +

    Interactive

    +
    + + .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d +
    +
    + + .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h +
    +
    +
    + + {/* Extraction */}
    -

    From dependencies

    -

    Classes imported from @fuzdev/fuz_css/example_class_utilities.js

    +

    Extraction

    +

    Classes detected via naming conventions, expressions, and comments (examples imported from node_modules to verify dependency scanning)

    Naming patterns

    @@ -145,6 +150,10 @@ export const App = () => {
    + +
    +

    This demos a subset of features.
    See the docs and source code for more.

    +
    ); diff --git a/examples/vite-react/src/App.tsx b/examples/vite-react/src/App.tsx index db8780f27..83155dce6 100644 --- a/examples/vite-react/src/App.tsx +++ b/examples/vite-react/src/App.tsx @@ -31,42 +31,13 @@ export const App = () => { const [count, setCount] = useState(0); return ( -
    +

    fuz_css + React

    -

    Utility classes generated on-demand via Vite plugin

    +

    Utility classes generated on-demand via Vite plugin (docs, source)

    - {/* Responsive layout: column on mobile, row on desktop */} -
    -
    -

    Responsive

    -

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    -
    -
    -

    Try it

    -

    Resize the window to see the layout switch from column to row

    -
    -
    - - {/* Interactive button with hover states */} -
    -

    Interactive

    -
    - - .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d -
    -
    - - .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h -
    -
    - {/* Class types */}

    Class types

    @@ -94,10 +65,44 @@ export const App = () => {
    - {/* Classes from node_modules dependency - verifies extraction */} + {/* Modifiers */} +
    +

    Modifiers

    + +
    +

    Responsive

    +
    +
    +

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    +
    +
    +

    Resize the window to see the layout switch from column to row

    +
    +
    +

    .min-width(543px):font_size_lg — arbitrary breakpoint

    +
    + +
    +

    Interactive

    +
    + + .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d +
    +
    + + .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h +
    +
    +
    + + {/* Extraction */}
    -

    From dependencies

    -

    Classes imported from @fuzdev/fuz_css/example_class_utilities.js

    +

    Extraction

    +

    Classes detected via naming conventions, expressions, and comments (examples imported from node_modules to verify dependency scanning)

    Naming patterns

    @@ -145,6 +150,10 @@ export const App = () => {
    + +
    +

    This demos a subset of features.
    See the docs and source code for more.

    +
    ); diff --git a/examples/vite-solid/src/App.tsx b/examples/vite-solid/src/App.tsx index c71d05617..19354ba8b 100644 --- a/examples/vite-solid/src/App.tsx +++ b/examples/vite-solid/src/App.tsx @@ -31,42 +31,13 @@ export const App = () => { const [count, setCount] = createSignal(0); return ( -
    +

    fuz_css + Solid

    -

    Utility classes generated on-demand via Vite plugin

    +

    Utility classes generated on-demand via Vite plugin (docs, source)

    - {/* Responsive layout: column on mobile, row on desktop */} -
    -
    -

    Responsive

    -

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    -
    -
    -

    Try it

    -

    Resize the window to see the layout switch from column to row

    -
    -
    - - {/* Interactive button with hover states */} -
    -

    Interactive

    -
    - - .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d -
    -
    - - .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h -
    -
    - {/* Class types */}

    Class types

    @@ -94,10 +65,44 @@ export const App = () => {
    - {/* Classes from node_modules dependency - verifies extraction */} + {/* Modifiers */} +
    +

    Modifiers

    + +
    +

    Responsive

    +
    +
    +

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    +
    +
    +

    Resize the window to see the layout switch from column to row

    +
    +
    +

    .min-width(543px):font_size_lg — arbitrary breakpoint

    +
    + +
    +

    Interactive

    +
    + + .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d +
    +
    + + .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h +
    +
    +
    + + {/* Extraction */}
    -

    From dependencies

    -

    Classes imported from @fuzdev/fuz_css/example_class_utilities.js

    +

    Extraction

    +

    Classes detected via naming conventions, expressions, and comments (examples imported from node_modules to verify dependency scanning)

    Naming patterns

    @@ -145,6 +150,10 @@ export const App = () => {
    + +
    +

    This demos a subset of features.
    See the docs and source code for more.

    +
    ); diff --git a/examples/vite-svelte/src/App.svelte b/examples/vite-svelte/src/App.svelte index cad880bc4..fb2eceef6 100644 --- a/examples/vite-svelte/src/App.svelte +++ b/examples/vite-svelte/src/App.svelte @@ -29,42 +29,17 @@ let count = $state(0); -
    +

    fuz_css + Svelte

    -

    Utility classes generated on-demand via Vite plugin

    +

    + Utility classes generated on-demand via Vite plugin (docs, source) +

    - -
    -
    -

    Responsive

    -

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    -
    -
    -

    Try it

    -

    Resize the window to see the layout switch from column to row

    -
    -
    - - -
    -

    Interactive

    -
    - - .hover:border_color_b .hover:outline_color_b .active:border_color_d .active:outline_color_d -
    -
    - - .hover:border_color_g .hover:outline_color_g .active:border_color_h .active:outline_color_h -
    -
    -

    Class types

    @@ -88,14 +63,68 @@

    Literal classes

    .opacity:60%
    .color:var(--color_j_5)
    -
    .box-shadow:0~4px~8px~rgb(0,0,0,0.2) (~ encodes spaces)
    +
    + .box-shadow:0~4px~8px~rgb(0,0,0,0.2) (~ encodes spaces) +
    - +
    -

    From dependencies

    -

    Classes imported from @fuzdev/fuz_css/example_class_utilities.js

    +

    Modifiers

    + +
    +

    Responsive

    +
    +
    +

    .column .gap_md on mobile, .md:flex-direction:row .md:gap_lg on medium+ screens

    +
    +
    +

    Resize the window to see the layout switch from column to row

    +
    +
    +

    + .min-width(543px):font_size_lg — arbitrary breakpoint +

    +
    + +
    +

    Interactive

    +
    + + .hover:border_color_b .hover:outline_color_b .active:border_color_d + .active:outline_color_d +
    +
    + + .hover:border_color_g .hover:outline_color_g .active:border_color_h + .active:outline_color_h +
    +
    +
    + + +
    +

    Extraction

    +

    + Classes detected via naming conventions, expressions, and comments (examples imported from node_modules to verify dependency scanning) +

    Naming patterns

    @@ -139,9 +168,20 @@ // @fuz-classes {unknownExtracted} → extracted but excluded (no matching definition)
    - // @fuz-classes {arbitraryLiteral} → extracted but excluded (invalid property, not in @webref/css) + // @fuz-classes {arbitraryLiteral} → extracted but excluded (invalid property, + not in @webref/css)
    + +
    +

    + This demos a subset of features.
    See the + docs + and + source code for + more. +

    +
    diff --git a/src/lib/css_cache.ts b/src/lib/css_cache.ts index a90e3bf32..7274385f2 100644 --- a/src/lib/css_cache.ts +++ b/src/lib/css_cache.ts @@ -12,6 +12,21 @@ import {dirname, join} from 'node:path'; import type {SourceLocation, ExtractionDiagnostic} from './diagnostics.js'; +/** + * Computes SHA-256 hash of content using Web Crypto API. + */ +export const compute_hash = async (content: string): Promise => { + const encoder = new TextEncoder(); + const buffer = encoder.encode(content); + const digested = await crypto.subtle.digest('SHA-256', buffer); + const bytes = Array.from(new Uint8Array(digested)); + let hex = ''; + for (const h of bytes) { + hex += h.toString(16).padStart(2, '0'); + } + return hex; +}; + /** * Default cache directory relative to project root. */ diff --git a/src/lib/diagnostics.ts b/src/lib/diagnostics.ts index 79782039e..7b84e6c80 100644 --- a/src/lib/diagnostics.ts +++ b/src/lib/diagnostics.ts @@ -94,3 +94,35 @@ export const create_generation_diagnostic = ( suggestion: diagnostic.suggestion ?? null, locations, }); + +/** + * Formats a diagnostic for display. + */ +export const format_diagnostic = (d: Diagnostic): string => { + const suggestion = d.suggestion ? ` (${d.suggestion})` : ''; + if (d.phase === 'extraction') { + return ` - ${d.location.file}:${d.location.line}:${d.location.column}: ${d.message}${suggestion}`; + } + const loc = d.locations?.[0]; + const location_str = loc ? `${loc.file}:${loc.line}:${loc.column}: ` : ''; + return ` - ${location_str}${d.class_name}: ${d.message}${suggestion}`; +}; + +/** + * Error thrown when CSS generation encounters errors and `on_error: 'throw'` is set. + * Contains the full diagnostics array for programmatic access. + */ +export class CssGenerationError extends Error { + diagnostics: Array; + + constructor(diagnostics: Array) { + const error_count = diagnostics.filter((d) => d.level === 'error').length; + const message = `CSS generation failed with ${error_count} error${error_count === 1 ? '' : 's'}:\n${diagnostics + .filter((d) => d.level === 'error') + .map(format_diagnostic) + .join('\n')}`; + super(message); + this.name = 'CssGenerationError'; + this.diagnostics = diagnostics; + } +} diff --git a/src/lib/gen_fuz_css.ts b/src/lib/gen_fuz_css.ts index 0cef34343..62a15161b 100644 --- a/src/lib/gen_fuz_css.ts +++ b/src/lib/gen_fuz_css.ts @@ -13,7 +13,13 @@ import {map_concurrent, each_concurrent} from '@fuzdev/fuz_util/async.js'; import {type FileFilter, filter_file_default} from './file_filter.js'; import {extract_css_classes_with_locations, type AcornPlugin} from './css_class_extractor.js'; -import {type SourceLocation, type ExtractionDiagnostic, type Diagnostic} from './diagnostics.js'; +import { + type SourceLocation, + type ExtractionDiagnostic, + type Diagnostic, + format_diagnostic, + CssGenerationError, +} from './diagnostics.js'; import {CssClasses} from './css_classes.js'; import { generate_classes_css, @@ -30,6 +36,7 @@ import { save_cached_extraction, delete_cached_extraction, from_cached_extraction, + compute_hash, } from './css_cache.js'; /** @@ -55,6 +62,22 @@ const DEFAULT_CONCURRENCY = 8; */ const DEFAULT_CACHE_IO_CONCURRENCY = 50; +/** + * Computes cache path for a file. + * Internal files use relative paths mirroring source tree. + * External files (outside project root) use hashed absolute paths in `_external/`. + */ +const get_file_cache_path = async ( + file_id: string, + cache_dir: string, + project_root: string, +): Promise => { + const is_internal = file_id.startsWith(project_root); + return is_internal + ? get_cache_path(file_id, cache_dir, project_root) + : join(cache_dir, '_external', (await compute_hash(file_id)).slice(0, 16) + '.json'); +}; + /** * Result from extracting CSS classes from a single file. * Used internally during parallel extraction with caching. @@ -118,7 +141,7 @@ export interface GenFuzCssOptions { concurrency?: number; /** * Max concurrent cache writes and deletes (I/O-bound). - * @default 20 + * @default 50 */ cache_io_concurrency?: number; /** @@ -136,42 +159,11 @@ export interface GenFuzCssOptions { acorn_plugins?: Array; } -/** - * Formats a diagnostic for display. - */ -const format_diagnostic = (d: Diagnostic): string => { - const suggestion = d.suggestion ? ` (${d.suggestion})` : ''; - if (d.phase === 'extraction') { - return ` - ${d.location.file}:${d.location.line}:${d.location.column}: ${d.message}${suggestion}`; - } - const loc = d.locations?.[0]; - const location_str = loc ? `${loc.file}:${loc.line}:${loc.column}: ` : ''; - return ` - ${location_str}${d.class_name}: ${d.message}${suggestion}`; -}; - -/** - * Error thrown when CSS-literal generation encounters errors and `on_error: 'throw'` is set. - */ -export class CssGenerationError extends Error { - diagnostics: Array; - - constructor(diagnostics: Array) { - const error_count = diagnostics.filter((d) => d.level === 'error').length; - const message = `CSS generation failed with ${error_count} error${error_count === 1 ? '' : 's'}:\n${diagnostics - .filter((d) => d.level === 'error') - .map(format_diagnostic) - .join('\n')}`; - super(message); - this.name = 'CssGenerationError'; - this.diagnostics = diagnostics; - } -} - export const gen_fuz_css = (options: GenFuzCssOptions = {}): Gen => { const { filter_file = filter_file_default, include_stats = false, - class_definitions = css_class_definitions, + class_definitions: user_class_definitions, class_interpreters = css_class_interpreters, on_error = 'log', include_classes, @@ -263,7 +255,7 @@ export const gen_fuz_css = (options: GenFuzCssOptions = {}): Gen => { nodes, async (node): Promise => { current_paths.add(node.id); - const cache_path = get_cache_path(node.id, resolved_cache_dir, project_root); + const cache_path = await get_file_cache_path(node.id, resolved_cache_dir, project_root); // Try cache (skip on CI) if (!is_ci) { @@ -332,7 +324,7 @@ export const gen_fuz_css = (options: GenFuzCssOptions = {}): Gen => { await each_concurrent( paths_to_delete, async (path) => { - const cache_path = get_cache_path(path, resolved_cache_dir, project_root); + const cache_path = await get_file_cache_path(path, resolved_cache_dir, project_root); await delete_cached_extraction(cache_path); }, cache_io_concurrency, @@ -372,8 +364,10 @@ export const gen_fuz_css = (options: GenFuzCssOptions = {}): Gen => { log.info(` Unique CSS classes found: ${all_classes.size}`); } - // Merge builtins with user definitions (user definitions take precedence) - const all_class_definitions = {...css_class_definitions, ...class_definitions}; + // Merge class definitions (user definitions take precedence) + const all_class_definitions = user_class_definitions + ? {...css_class_definitions, ...user_class_definitions} + : css_class_definitions; const result = generate_classes_css({ class_names: all_classes, diff --git a/src/lib/vite_plugin_fuz_css.ts b/src/lib/vite_plugin_fuz_css.ts index e2b83da32..39a69bd4b 100644 --- a/src/lib/vite_plugin_fuz_css.ts +++ b/src/lib/vite_plugin_fuz_css.ts @@ -28,7 +28,12 @@ import type {Plugin, ViteDevServer} from 'vite'; import {join} from 'node:path'; import {extract_css_classes_with_locations, type AcornPlugin} from './css_class_extractor.js'; -import {type SourceLocation, type GenerationDiagnostic} from './diagnostics.js'; +import { + type SourceLocation, + type ExtractionDiagnostic, + type Diagnostic, + CssGenerationError, +} from './diagnostics.js'; import { generate_classes_css, type CssClassDefinition, @@ -44,6 +49,7 @@ import { save_cached_extraction, delete_cached_extraction, from_cached_extraction, + compute_hash, } from './css_cache.js'; import {type FileFilter, filter_file_default} from './file_filter.js'; @@ -60,22 +66,6 @@ const RESOLVED_VIRTUAL_ID = '\0virtual:fuz.css'; */ const is_ci = !!process.env.CI; -/** - * Computes SHA-256 hash of content using Web Crypto API. - * Matches Gro's hashing approach for cache compatibility. - */ -const compute_hash = async (content: string): Promise => { - const encoder = new TextEncoder(); - const buffer = encoder.encode(content); - const digested = await crypto.subtle.digest('SHA-256', buffer); - const bytes = Array.from(new Uint8Array(digested)); - let hex = ''; - for (const h of bytes) { - hex += h.toString(16).padStart(2, '0'); - } - return hex; -}; - /** * Options for the fuz_css Vite plugin. */ @@ -128,6 +118,8 @@ export interface VitePluginFuzCssOptions { interface ClassRegistry { /** file path → extracted classes with locations */ files: Map>>; + /** file path → extraction diagnostics */ + diagnostics: Map>; /** file path → content hash for caching */ hashes: Map; /** aggregated classes, null = dirty, needs recompute */ @@ -166,6 +158,7 @@ export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plug // Plugin state const registry: ClassRegistry = { files: new Map(), + diagnostics: new Map(), hashes: new Map(), all_classes: null, all_locations: null, @@ -274,16 +267,19 @@ export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plug class_locations: locations, }); - // Handle diagnostics - const errors = result.diagnostics.filter((d: GenerationDiagnostic) => d.level === 'error'); + // Collect all diagnostics: extraction + generation + const all_diagnostics: Array = [ + ...Array.from(registry.diagnostics.values()).flat(), + ...result.diagnostics, + ]; + + // Handle errors + const errors = all_diagnostics.filter((d) => d.level === 'error'); if (errors.length > 0 && on_error === 'throw') { - throw new Error( - `CSS generation failed with ${errors.length} error(s):\n` + - errors.map((d: GenerationDiagnostic) => ` - ${d.class_name}: ${d.message}`).join('\n'), - ); + throw new CssGenerationError(all_diagnostics); } - // Log warnings/errors + // Log generation warnings/errors (extraction diagnostics already logged in transform) for (const d of result.diagnostics) { const msg = `[fuz_css] ${d.class_name}: ${d.message}`; if (d.level === 'error') { @@ -345,6 +341,7 @@ export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plug dev_server.watcher.on('unlink', (file) => { if (registry.files.has(file)) { registry.files.delete(file); + registry.diagnostics.delete(file); registry.hashes.delete(file); registry.all_classes = null; registry.all_locations = null; @@ -433,12 +430,17 @@ export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plug if (cached?.content_hash === hash) { // Cache hit - const {classes} = from_cached_extraction(cached); + const {classes, diagnostics} = from_cached_extraction(cached); if (classes) { registry.files.set(id, classes); } else { registry.files.delete(id); } + if (diagnostics && diagnostics.length > 0) { + registry.diagnostics.set(id, diagnostics); + } else { + registry.diagnostics.delete(id); + } registry.hashes.set(id, hash); registry.all_classes = null; registry.all_locations = null; @@ -475,6 +477,11 @@ export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plug } else { registry.files.delete(id); } + if (result.diagnostics && result.diagnostics.length > 0) { + registry.diagnostics.set(id, result.diagnostics); + } else { + registry.diagnostics.delete(id); + } registry.hashes.set(id, hash); registry.all_classes = null; registry.all_locations = null; diff --git a/src/routes/fuz.css b/src/routes/fuz.css index 98ec7dc65..34eaad8c5 100644 --- a/src/routes/fuz.css +++ b/src/routes/fuz.css @@ -517,6 +517,9 @@ a.chip { .mt_xl2 { margin-top: var(--space_xl2); } +.mt_xl3 { + margin-top: var(--space_xl3); +} .mt_xl4 { margin-top: var(--space_xl4); } diff --git a/src/routes/library.json b/src/routes/library.json index 24098171e..e8a61349f 100644 --- a/src/routes/library.json +++ b/src/routes/library.json @@ -131,11 +131,32 @@ { "path": "css_cache.ts", "declarations": [ + { + "name": "compute_hash", + "kind": "function", + "doc_comment": "Computes SHA-256 hash of content using Web Crypto API.", + "source_line": 18, + "type_signature": "(content: string): Promise", + "return_type": "Promise", + "parameters": [ + { + "name": "content", + "type": "string" + } + ] + }, + { + "name": "DEFAULT_CACHE_DIR", + "kind": "variable", + "doc_comment": "Default cache directory relative to project root.", + "source_line": 33, + "type_signature": "\".fuz/cache/css\"" + }, { "name": "CachedExtraction", "kind": "type", "doc_comment": "Cached extraction result for a single file.\nUses `null` instead of empty arrays to avoid allocation overhead.", - "source_line": 29, + "source_line": 49, "type_signature": "CachedExtraction", "properties": [ { @@ -168,7 +189,7 @@ "name": "get_cache_path", "kind": "function", "doc_comment": "Computes the cache file path for a source file.\nCache structure mirrors source tree: `src/lib/Foo.svelte` → `.fuz/cache/css/src/lib/Foo.svelte.json`", - "source_line": 48, + "source_line": 68, "type_signature": "(source_path: string, cache_dir: string, project_root: string): string", "return_type": "string", "parameters": [ @@ -193,7 +214,7 @@ "name": "load_cached_extraction", "kind": "function", "doc_comment": "Loads a cached extraction result from disk.\nReturns `null` if the cache is missing, corrupted, or has a version mismatch.\nThis makes the cache self-healing: any error triggers re-extraction.", - "source_line": 67, + "source_line": 87, "type_signature": "(cache_path: string): Promise", "return_type": "Promise", "parameters": [ @@ -208,7 +229,7 @@ "name": "save_cached_extraction", "kind": "function", "doc_comment": "Saves an extraction result to the cache.\nUses atomic write (temp file + rename) for crash safety.\nConverts empty arrays to null to avoid allocation overhead on load.", - "source_line": 97, + "source_line": 117, "type_signature": "(cache_path: string, content_hash: string, classes: Map | null, diagnostics: ExtractionDiagnostic[] | null): Promise<...>", "return_type": "Promise", "parameters": [ @@ -238,7 +259,7 @@ "name": "delete_cached_extraction", "kind": "function", "doc_comment": "Deletes a cached extraction file.\nSilently succeeds if the file doesn't exist.", - "source_line": 128, + "source_line": 148, "type_signature": "(cache_path: string): Promise", "return_type": "Promise", "parameters": [ @@ -253,7 +274,7 @@ "name": "from_cached_extraction", "kind": "function", "doc_comment": "Converts a cached extraction back to the runtime format.\nPreserves null semantics (null = empty).", - "source_line": 140, + "source_line": 160, "type_signature": "(cached: CachedExtraction): { classes: Map | null; diagnostics: ExtractionDiagnostic[] | null; }", "return_type": "{ classes: Map | null; diagnostics: ExtractionDiagnostic[] | null; }", "parameters": [ @@ -2117,10 +2138,50 @@ "description": "- Source locations where the class was used" } ] + }, + { + "name": "format_diagnostic", + "kind": "function", + "doc_comment": "Formats a diagnostic for display.", + "source_line": 101, + "type_signature": "(d: Diagnostic): string", + "return_type": "string", + "parameters": [ + { + "name": "d", + "type": "Diagnostic" + } + ] + }, + { + "name": "CssGenerationError", + "kind": "class", + "doc_comment": "Error thrown when CSS generation encounters errors and `on_error: 'throw'` is set.\nContains the full diagnostics array for programmatic access.", + "source_line": 115, + "extends": ["Error"], + "implements": [], + "members": [ + { + "name": "diagnostics", + "kind": "variable", + "type_signature": "Array" + }, + { + "name": "constructor", + "kind": "constructor", + "type_signature": "(diagnostics: Diagnostic[]): CssGenerationError", + "parameters": [ + { + "name": "diagnostics", + "type": "Diagnostic[]" + } + ] + } + ] } ], "module_comment": "Diagnostic types for CSS class extraction and generation.\n\nProvides a unified diagnostic system across all phases:\n- Extraction: Parsing source files to find class names\n- Generation: Producing CSS output from class definitions", - "dependents": ["css_class_generation.ts"] + "dependents": ["css_class_generation.ts", "gen_fuz_css.ts", "vite_plugin_fuz_css.ts"] }, { "path": "example_class_utilities.ts", @@ -2237,25 +2298,32 @@ "source_line": 79, "type_signature": "string[]" }, + { + "name": "objectClasses", + "kind": "variable", + "doc_comment": "Object - keys extracted as class names", + "source_line": 82, + "type_signature": "{ mt_xl2: string; mt_xl3: string; }" + }, { "name": "fromComment", "kind": "variable", "doc_comment": "Comment hint - extracted via", - "source_line": 90, + "source_line": 93, "type_signature": "\"shadow_lg\"" }, { "name": "unknownExtracted", "kind": "variable", "doc_comment": "Unknown class - extracted via", - "source_line": 97, + "source_line": 100, "type_signature": "\"unknown_not_included\"" }, { "name": "arbitraryLiteral", "kind": "variable", "doc_comment": "Invalid literal - extracted via", - "source_line": 105, + "source_line": 108, "type_signature": "\"not-real:extracted-but-excluded\"" } ], @@ -2295,7 +2363,7 @@ { "name": "GenFuzCssOptions", "kind": "type", - "source_line": 73, + "source_line": 97, "type_signature": "GenFuzCssOptions", "properties": [ { @@ -2370,36 +2438,10 @@ } ] }, - { - "name": "CssGenerationError", - "kind": "class", - "doc_comment": "Error thrown when CSS-literal generation encounters errors and `on_error: 'throw'` is set.", - "source_line": 154, - "extends": ["Error"], - "implements": [], - "members": [ - { - "name": "diagnostics", - "kind": "variable", - "type_signature": "Array" - }, - { - "name": "constructor", - "kind": "constructor", - "type_signature": "(diagnostics: Diagnostic[]): CssGenerationError", - "parameters": [ - { - "name": "diagnostics", - "type": "Diagnostic[]" - } - ] - } - ] - }, { "name": "gen_fuz_css", "kind": "function", - "source_line": 169, + "source_line": 162, "type_signature": "(options?: GenFuzCssOptions): Gen", "return_type": "Gen", "parameters": [ @@ -2420,6 +2462,7 @@ "css_class_interpreters.ts", "css_classes.ts", "css_literal.ts", + "diagnostics.ts", "file_filter.ts" ] }, @@ -5017,11 +5060,18 @@ { "path": "vite_plugin_fuz_css.ts", "declarations": [ + { + "name": "FUZ_CSS_MARKER", + "kind": "variable", + "doc_comment": "Marker comment used to delimit generated CSS in the output.", + "source_line": 59, + "type_signature": "\"/* generated by vite_plugin_fuz_css */\"" + }, { "name": "VitePluginFuzCssOptions", "kind": "type", "doc_comment": "Options for the fuz_css Vite plugin.", - "source_line": 78, + "source_line": 72, "type_signature": "VitePluginFuzCssOptions", "properties": [ { @@ -5078,7 +5128,7 @@ "name": "vite_plugin_fuz_css", "kind": "function", "doc_comment": "Creates the fuz_css Vite plugin.\n\nExtracts CSS classes from source files during Vite's transform phase\nand generates optimized CSS via the `virtual:fuz.css` virtual module.", - "source_line": 141, + "source_line": 137, "type_signature": "(options?: VitePluginFuzCssOptions): Plugin$1", "return_type": "Plugin$1", "parameters": [ @@ -5098,6 +5148,7 @@ "css_class_generation.ts", "css_class_interpreters.ts", "css_literal.ts", + "diagnostics.ts", "file_filter.ts" ] } diff --git a/src/test/css_class_generation.test.ts b/src/test/css_class_generation.test.ts index 4966b5a96..6388b4931 100644 --- a/src/test/css_class_generation.test.ts +++ b/src/test/css_class_generation.test.ts @@ -1218,12 +1218,7 @@ describe('modified_class_interpreter', () => { test('visited < focus < hover < active ordering', () => { const result = generate_classes_css({ - class_names: [ - 'active:p_xl', - 'hover:p_lg', - 'focus:p_md', - 'visited:p_sm', - ], + class_names: ['active:p_xl', 'hover:p_lg', 'focus:p_md', 'visited:p_sm'], class_definitions: css_class_definitions, interpreters: [modified_class_interpreter], css_properties: null, diff --git a/src/test/diagnostics.test.ts b/src/test/diagnostics.test.ts new file mode 100644 index 000000000..de4815c6a --- /dev/null +++ b/src/test/diagnostics.test.ts @@ -0,0 +1,220 @@ +import {test, expect, describe} from 'vitest'; + +import { + format_diagnostic, + CssGenerationError, + type ExtractionDiagnostic, + type GenerationDiagnostic, +} from '$lib/diagnostics.js'; + +describe('format_diagnostic', () => { + test('formats extraction diagnostic with location', () => { + const diagnostic: ExtractionDiagnostic = { + phase: 'extraction', + level: 'warning', + message: 'test warning message', + suggestion: null, + location: {file: 'src/lib/Button.svelte', line: 10, column: 5}, + }; + + const result = format_diagnostic(diagnostic); + expect(result).toBe(' - src/lib/Button.svelte:10:5: test warning message'); + }); + + test('formats extraction diagnostic with suggestion', () => { + const diagnostic: ExtractionDiagnostic = { + phase: 'extraction', + level: 'error', + message: 'deprecated syntax', + suggestion: 'use the new syntax instead', + location: {file: 'app.ts', line: 1, column: 1}, + }; + + const result = format_diagnostic(diagnostic); + expect(result).toBe(' - app.ts:1:1: deprecated syntax (use the new syntax instead)'); + }); + + test('formats generation diagnostic with location', () => { + const diagnostic: GenerationDiagnostic = { + phase: 'generation', + level: 'error', + message: 'unknown CSS property', + suggestion: null, + class_name: 'invalid:value', + locations: [{file: 'src/App.svelte', line: 5, column: 12}], + }; + + const result = format_diagnostic(diagnostic); + expect(result).toBe(' - src/App.svelte:5:12: invalid:value: unknown CSS property'); + }); + + test('formats generation diagnostic without location (from include_classes)', () => { + const diagnostic: GenerationDiagnostic = { + phase: 'generation', + level: 'error', + message: 'invalid class', + suggestion: null, + class_name: 'bad_class', + locations: null, + }; + + const result = format_diagnostic(diagnostic); + expect(result).toBe(' - bad_class: invalid class'); + }); + + test('formats generation diagnostic with suggestion', () => { + const diagnostic: GenerationDiagnostic = { + phase: 'generation', + level: 'warning', + message: 'unknown property', + suggestion: 'did you mean "color"?', + class_name: 'colour:red', + locations: [{file: 'test.ts', line: 1, column: 1}], + }; + + const result = format_diagnostic(diagnostic); + expect(result).toBe(` - test.ts:1:1: colour:red: unknown property (did you mean "color"?)`); + }); + + test('formats generation diagnostic with empty locations array', () => { + const diagnostic: GenerationDiagnostic = { + phase: 'generation', + level: 'error', + message: 'test error', + suggestion: null, + class_name: 'test_class', + locations: [], + }; + + const result = format_diagnostic(diagnostic); + expect(result).toBe(' - test_class: test error'); + }); +}); + +describe('CssGenerationError', () => { + test('creates error with single error diagnostic', () => { + const diagnostics: Array = [ + { + phase: 'generation', + level: 'error', + message: 'unknown property', + suggestion: null, + class_name: 'bad:class', + locations: [{file: 'app.ts', line: 1, column: 1}], + }, + ]; + + const error = new CssGenerationError(diagnostics); + + expect(error.name).toBe('CssGenerationError'); + expect(error.diagnostics).toBe(diagnostics); + expect(error.message).toContain('CSS generation failed with 1 error'); + expect(error.message).toContain('bad:class'); + }); + + test('creates error with multiple error diagnostics', () => { + const diagnostics: Array = [ + { + phase: 'generation', + level: 'error', + message: 'error one', + suggestion: null, + class_name: 'class_a', + locations: null, + }, + { + phase: 'generation', + level: 'error', + message: 'error two', + suggestion: null, + class_name: 'class_b', + locations: null, + }, + ]; + + const error = new CssGenerationError(diagnostics); + + expect(error.message).toContain('CSS generation failed with 2 errors'); + expect(error.message).toContain('class_a'); + expect(error.message).toContain('class_b'); + }); + + test('excludes warnings from error message', () => { + const diagnostics: Array = [ + { + phase: 'generation', + level: 'error', + message: 'this is an error', + suggestion: null, + class_name: 'error_class', + locations: null, + }, + { + phase: 'generation', + level: 'warning', + message: 'this is a warning', + suggestion: null, + class_name: 'warning_class', + locations: null, + }, + ]; + + const error = new CssGenerationError(diagnostics); + + expect(error.message).toContain('1 error'); + expect(error.message).toContain('error_class'); + expect(error.message).not.toContain('warning_class'); + // But diagnostics array still contains both + expect(error.diagnostics).toHaveLength(2); + }); + + test('handles mixed extraction and generation diagnostics', () => { + const diagnostics = [ + { + phase: 'extraction' as const, + level: 'error' as const, + message: 'extraction error', + suggestion: null, + location: {file: 'test.ts', line: 1, column: 1}, + }, + { + phase: 'generation' as const, + level: 'error' as const, + message: 'generation error', + suggestion: null, + class_name: 'gen_class', + locations: null, + }, + ]; + + const error = new CssGenerationError(diagnostics); + + expect(error.message).toContain('2 errors'); + expect(error.message).toContain('extraction error'); + expect(error.message).toContain('gen_class'); + }); + + test('is instanceof Error', () => { + const error = new CssGenerationError([]); + expect(error).toBeInstanceOf(Error); + expect(error).toBeInstanceOf(CssGenerationError); + }); + + test('handles zero errors gracefully', () => { + const diagnostics: Array = [ + { + phase: 'generation', + level: 'warning', + message: 'just a warning', + suggestion: null, + class_name: 'warn_class', + locations: null, + }, + ]; + + const error = new CssGenerationError(diagnostics); + + expect(error.message).toContain('0 errors'); + expect(error.diagnostics).toHaveLength(1); + }); +}); diff --git a/src/test/vite_plugin_examples.test.ts b/src/test/vite_plugin_examples.test.ts index b145b7654..3f75050e6 100644 --- a/src/test/vite_plugin_examples.test.ts +++ b/src/test/vite_plugin_examples.test.ts @@ -84,7 +84,11 @@ const EXPECTED_CLASSES = [ // from CSS output because 'not-real' fails @webref/css property validation 'shadow_lg', // fromComment via @fuz-classes // From App - Layout - 'md:p_xl', + 'max-width:1000px', + 'mx_auto', + 'px_md', + 'md:px_xl', + 'py_xl7', 'column', 'gap_lg', 'text-align:center', @@ -92,6 +96,7 @@ const EXPECTED_CLASSES = [ 'gap_md', 'md:flex-direction:row', 'md:gap_lg', + 'min-width(543px):font_size_lg', 'flex:1', // From App - Interactive (hover/active state modifiers) 'row', @@ -237,10 +242,9 @@ describe.skipIf(SKIP)('cross-example consistency', () => { for (const example of examples.slice(1)) { const classes = example_results.get(example)!; - expect( - classes, - `${example} should produce same classes as ${first_example}`, - ).toEqual(first_classes); + expect(classes, `${example} should produce same classes as ${first_example}`).toEqual( + first_classes, + ); } }); }); From 72c48056b91cd907fae02f00deab06ca9f94dd54 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Thu, 15 Jan 2026 07:29:52 -0500 Subject: [PATCH 081/138] wip --- src/routes/docs/classes/+page.svelte | 82 ++++++++++++++-------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/routes/docs/classes/+page.svelte b/src/routes/docs/classes/+page.svelte index a6583d6c7..f95029133 100644 --- a/src/routes/docs/classes/+page.svelte +++ b/src/routes/docs/classes/+page.svelte @@ -176,14 +176,14 @@ export const gen = gen_fuz_css({

    What classes can reference

    • - Token classes (p_lg, color_a_5) — resolved to + Token classes (p_lg, color_a_5) - resolved to their declarations
    • - Composites with declaration — the declaration is included + Composites with declaration - the declaration is included
    • - Composites with classes — recursively resolved + Composites with classes - recursively resolved

    @@ -490,9 +490,9 @@ card: {classes: ['card_base'], declaration: 'border: 1px solid var(--border_colo `} +`} />

    Usage tracking works for variables inside clsx(), arrays, ternaries, and logical expressions within class attributes. Note that standalone clsx() calls outside - class attributes don't trigger tracking — use the naming convention for those cases. + class attributes don't trigger tracking - use the naming convention for those cases.

    @@ -868,22 +868,22 @@ export const gen = gen_fuz_css({
  • - + - + - + - + @@ -949,7 +949,7 @@ export const gen = gen_fuz_css({ To enable JSX support for React/Preact/Solid/etc, install acorn-jsx and pass it to the generator:

    - + Supported JSX patterns:

    • - className="..." and class="..." — static strings + className="..." and class="..." - static strings
    • - {'className={clsx(...)}'} — utility function calls + {'className={clsx(...)}'} - utility function calls
    • - {'className={cond ? "a" : "b"}'} — ternary and logical expressions + {'className={cond ? "a" : "b"}'} - ternary and logical expressions
    • - {'classList={{active: cond}}'} — Solid's classList (static keys) + {'classList={{active: cond}}'} - Solid's classList (static keys)
    • usage tracking: variables in className, class, @@ -981,7 +981,7 @@ export const gen = gen_fuz_css({
    ;`} From 472d2a1107b59f65d9abb10517bb4f890dd13cf5 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Thu, 15 Jan 2026 08:00:48 -0500 Subject: [PATCH 082/138] wip --- src/routes/docs/classes/+page.svelte | 88 +++++++++++++++------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/src/routes/docs/classes/+page.svelte b/src/routes/docs/classes/+page.svelte index f95029133..ab4aafeea 100644 --- a/src/routes/docs/classes/+page.svelte +++ b/src/routes/docs/classes/+page.svelte @@ -68,7 +68,7 @@
  • .top|bottom|left|right_xs5-xl15
  • .inset_xs5-xl15
  • -
    th
    React / JSX fullwith acorn-jsx plugin — classNamewith acorn-jsx plugin - className
    Preact fullwith acorn-jsx plugin — classwith acorn-jsx plugin - class
    Solid fullwith acorn-jsx plugin — class, classListwith acorn-jsx plugin - class, classList
    Vue JSX fullwith acorn-jsx plugin — classwith acorn-jsx plugin - class
    Vue SFC
    + content={`
    - +
    - +
    Date: Fri, 16 Jan 2026 14:13:11 -0500 Subject: [PATCH 096/138] wip --- src/routes/docs/introduction/+page.svelte | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/routes/docs/introduction/+page.svelte b/src/routes/docs/introduction/+page.svelte index f498cd1d3..13fbb5a1c 100644 --- a/src/routes/docs/introduction/+page.svelte +++ b/src/routes/docs/introduction/+page.svelte @@ -39,8 +39,7 @@ import '@fuzdev/fuz_css/theme.css'; // or bring your own`}
  • minimal dependencies, all optional -- none needed if you only use the stylesheets
  • exports a reset stylesheet with defaults that styles HTML elements, - see , and also exports the underlying data, helpers, and - types for open-ended usage + and also exports the underlying data, helpers, and types for open-ended usage
  • supports with a basic theme stylesheet,
  • uses its own concept of style , a specialization of CSS - custom properties and design tokens that integrate with the other systems (e.g. themes are - groups of variables, and token classes use variables) + custom properties and design tokens that integrate with the other systems (e.g. the reset + stylesheet and token classes use variables, and themes are groups of variables)
  • the stylesheets work with any framework and plain HTML; utility class generation supports - Svelte, JSX, and TypeScript/JS -- see - framework support and + Svelte, JSX, and TypeScript/JS -- see the utility class + framework support, and for + the companion Svelte integration see Themed in - fuz_ui for Svelte integration + fuz_ui
  • see the Date: Fri, 16 Jan 2026 14:20:17 -0500 Subject: [PATCH 097/138] wip --- src/routes/docs/classes/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/docs/classes/+page.svelte b/src/routes/docs/classes/+page.svelte index a9b2793c7..3a492f2a2 100644 --- a/src/routes/docs/classes/+page.svelte +++ b/src/routes/docs/classes/+page.svelte @@ -16,7 +16,7 @@

    fuz_css has two categories of CSS classes: utilities and builtins. Builtins are baked into the - main stylesheet; utilities are optional and require build tool integration. + main stylesheet; utility classes have 3 types, are optional, and require build tool integration.

    From 8b1337269a54a5583fe2d6ae04161abc513513c6 Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Sat, 17 Jan 2026 11:12:54 -0500 Subject: [PATCH 098/138] wip --- CLAUDE.md | 5 ++- README.md | 14 ++++---- package.json | 4 +-- src/routes/+page.svelte | 4 +-- src/routes/Introduction.svelte | 8 ++--- src/routes/docs/classes/+page.svelte | 48 +++++++++++++++++++++------- src/routes/library.json | 4 +-- 7 files changed, 58 insertions(+), 29 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index fab6af6ec..b0b9f6ebb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,9 @@ # fuz_css framework and design system -CSS framework and design system built on **semantic styles** and **style variables** (design tokens as CSS custom properties). Early alpha with breaking changes ahead. +CSS framework and design system for semantic HTML for semantic HTML. +It styles HTML elements by default and integrates +custom properties, themes, and utility classes into a complete system. +Early alpha with breaking changes ahead. For code style, see the `fuz-stack` skill. For UI components (themes, color scheme controls), see `@fuzdev/fuz_ui`. diff --git a/README.md b/README.md index 5ba0a12df..1835d4be9 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,20 @@ [a fuzzy tuft of green moss](https://css.fuz.dev/) -> CSS framework and design system 🌿 CSS with more utility +> CSS with more utility 🪴 + +fuz_css is a CSS framework and design system for semantic HTML. +It styles elements by default and +integrates custom properties, themes, and utility classes into a complete system. +It's Svelte-first but works with plain HTML/JS/TS, React, Preact, Solid, and other JSX frameworks. -fuz_css is a CSS framework and design system built around semantic styles and style variables. It's in early alpha with breaking changes ahead. +Feedback and design input in +the [discussions](https://github.com/fuzdev/fuz_css/discussions). View the [docs](https://css.fuz.dev/docs) at [css.fuz.dev](https://css.fuz.dev/). More about the stack at [fuz.dev](https://www.fuz.dev/) -Interested in helping? We welcome feedback and design input in -the [issues](https://github.com/fuzdev/fuz_css/issues) -and [discussions](https://github.com/fuzdev/fuz_css/discussions). - ## License [🐦](https://wikipedia.org/wiki/Free_and_open-source_software) [MIT](LICENSE) diff --git a/package.json b/package.json index b12a7f7d4..cd7d7a3ba 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "@fuzdev/fuz_css", "version": "0.43.0", - "description": "CSS framework and design system", + "description": "CSS framework and design system for semantic HTML", "motto": "CSS with more utility", - "glyph": "🌿", + "glyph": "🪴", "logo": "logo.svg", "logo_alt": "a fuzzy tuft of green moss", "license": "MIT", diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 1c335bd9f..cfa61896d 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -17,7 +17,7 @@

    fuz_css

    -
    CSS with more utility 🌿
    +
    CSS with more utility 🪴
  • @@ -26,7 +26,7 @@
    - docs{#snippet icon()}🌿{/snippet} + docs{#snippet icon()}🪴{/snippet}
    fuz_css is part of the Fuz stack,
    see diff --git a/src/routes/Introduction.svelte b/src/routes/Introduction.svelte index adfe70166..154718471 100644 --- a/src/routes/Introduction.svelte +++ b/src/routes/Introduction.svelte @@ -5,10 +5,10 @@

    - fuz_css is a framework and design system built on semantic styles and style variables. It styles - HTML elements by default and integrates custom properties, themes, and utility classes into a - complete system. It's Svelte-first but works with plain HTML/JS/TS, React, Preact, Solid, and - other JSX frameworks. For more see the + fuz_css is a CSS framework and design system for semantic HTML. It styles elements by default and + integrates custom properties, themes, and utility classes into a complete system. It's + Svelte-first but works with plain HTML/JS/TS, React, Preact, Solid, and other JSX frameworks. For + more see the framework support docs, and for the companion Svelte components, see fuz_ui.

    diff --git a/src/routes/docs/classes/+page.svelte b/src/routes/docs/classes/+page.svelte index 3a492f2a2..430f64bb6 100644 --- a/src/routes/docs/classes/+page.svelte +++ b/src/routes/docs/classes/+page.svelte @@ -121,15 +121,17 @@

    - Multi-property groups for repeated patterns. Composites can define custom CSS, compose - existing classes, or both. + Composites bundle multiple CSS declarations into a single class name. They have four forms: + raw CSS declarations, composition of other classes, a combination of both, or full rulesets + as an escape hatch for multi-selector patterns (hover states, child selectors, etc.).

    -

    Three definition forms

    +

    Four definition forms

    = { // 1. declaration only - custom CSS properties centered: { declaration: \` @@ -150,6 +152,22 @@ export const custom_composites = { classes: ['box'], declaration: 'text-align: center;', }, + + // 4. ruleset - full CSS with multiple selectors + // (cannot be composed with \`classes\` due to complex edge cases) + centered: { + ruleset: \` + .centered { + display: flex; + align-items: center; + justify-content: center; + } + /* any selector: .centered > *, .centered:hover .foo, etc */ + .centered:focus-within { + outline: 2px solid var(--color_a_5); + } + \`, + }, };`} />

    Register custom composites with the plugin or generator:

    @@ -184,7 +202,7 @@ export const gen = gen_fuz_css({

    Composites can reference other composites, enabling layered abstractions:

    = { spacing: {classes: ['p_lg', 'gap_md']}, surface: {classes: ['bg_1', 'border_radius_md', 'shadow_sm']}, panel: {classes: ['spacing', 'surface']}, // combines both @@ -208,10 +226,11 @@ export const gen = gen_fuz_css({

    - Not allowed: Ruleset-based composites (those with multiple selectors like - .clickable) cannot be referenced in classes because their - multi-selector CSS can't be inlined into a single rule. Use declaration for custom - CSS or apply ruleset classes separately in your markup. + Not allowed: Composites with ruleset cannot be referenced in + classes because they define their own selectors. The classes + property merges declarations into a single rule, but edge cases like + .clickable:hover {'{ ... }'} can't be flattened that way. Apply ruleset classes directly + in markup alongside other classes.

    @@ -79,7 +79,7 @@ export const App = () => {

    Resize the window to see the layout switch from column to row

    -

    .min-width(543px):font_size_lg — arbitrary breakpoint

    +

    .min-width(543px):font_size_lg -- arbitrary breakpoint

    diff --git a/examples/vite-react/src/App.tsx b/examples/vite-react/src/App.tsx index 83155dce6..96cb513a2 100644 --- a/examples/vite-react/src/App.tsx +++ b/examples/vite-react/src/App.tsx @@ -53,7 +53,7 @@ export const App = () => {

    Composite classes

    .box
    - .ellipsis — this text truncates with ellipsis when it overflows + .ellipsis -- this text truncates with ellipsis when it overflows
    @@ -79,7 +79,7 @@ export const App = () => {

    Resize the window to see the layout switch from column to row

    -

    .min-width(543px):font_size_lg — arbitrary breakpoint

    +

    .min-width(543px):font_size_lg -- arbitrary breakpoint

    diff --git a/examples/vite-solid/src/App.tsx b/examples/vite-solid/src/App.tsx index 19354ba8b..6364fe910 100644 --- a/examples/vite-solid/src/App.tsx +++ b/examples/vite-solid/src/App.tsx @@ -53,7 +53,7 @@ export const App = () => {

    Composite classes

    .box
    - .ellipsis — this text truncates with ellipsis when it overflows + .ellipsis -- this text truncates with ellipsis when it overflows
    @@ -79,7 +79,7 @@ export const App = () => {

    Resize the window to see the layout switch from column to row

    -

    .min-width(543px):font_size_lg — arbitrary breakpoint

    +

    .min-width(543px):font_size_lg -- arbitrary breakpoint

    diff --git a/examples/vite-svelte/src/App.svelte b/examples/vite-svelte/src/App.svelte index fb2eceef6..a52f0e705 100644 --- a/examples/vite-svelte/src/App.svelte +++ b/examples/vite-svelte/src/App.svelte @@ -55,7 +55,7 @@

    Composite classes

    .box
    - .ellipsis — this text truncates with ellipsis when it overflows + .ellipsis -- this text truncates with ellipsis when it overflows
    @@ -84,7 +84,7 @@

    - .min-width(543px):font_size_lg — arbitrary breakpoint + .min-width(543px):font_size_lg -- arbitrary breakpoint

    diff --git a/src/routes/docs/classes/+page.svelte b/src/routes/docs/classes/+page.svelte index 430f64bb6..84cb8f4c0 100644 --- a/src/routes/docs/classes/+page.svelte +++ b/src/routes/docs/classes/+page.svelte @@ -153,8 +153,7 @@ export const custom_composites: Record = { declaration: 'text-align: center;', }, - // 4. ruleset - full CSS with multiple selectors - // (cannot be composed with \`classes\` due to complex edge cases) + // 4. ruleset - full CSS with multiple selectors (not composable) centered: { ruleset: \` .centered { @@ -228,18 +227,19 @@ export const gen = gen_fuz_css({

    Not allowed: Composites with ruleset cannot be referenced in classes because they define their own selectors. The classes - property merges declarations into a single rule, but edge cases like - .clickable:hover {'{ ... }'} can't be flattened that way. Apply ruleset classes directly - in markup alongside other classes. + property merges declarations into a single rule, but multi-selector patterns like + .clickable:hover {'{ ... }'} cannot be inlined. Apply ruleset classes directly in + markup alongside other classes.

    @@ -267,12 +267,13 @@ export const gen = gen_fuz_css({

    Modifiers

    - Composites with classes or declaration support all modifiers. The resolved - declarations are combined and wrapped: + All composite forms support modifiers. For classes and declaration + composites, declarations are combined and wrapped. For ruleset composites, + modifiers are applied to each selector (with smart conflict detection):

    -
    `} +
    `} />

    Builtin composites

    From 316d0f26f8dc4961e11c0c0ca19b1b5e2bf2adbe Mon Sep 17 00:00:00 2001 From: Ryan Atkinson Date: Sun, 18 Jan 2026 07:51:50 -0500 Subject: [PATCH 101/138] wip --- src/lib/diagnostics.ts | 23 +++++++++---- src/lib/gen_fuz_css.ts | 29 ++++++++++++---- src/lib/vite_plugin_fuz_css.ts | 48 ++++++++++++++++++-------- src/routes/docs/classes/+page.svelte | 50 +++++++++++++++++++++++----- src/routes/library.json | 24 +++++++++---- src/test/diagnostics.test.ts | 19 ++++++++--- 6 files changed, 149 insertions(+), 44 deletions(-) diff --git a/src/lib/diagnostics.ts b/src/lib/diagnostics.ts index 7b84e6c80..37ca9a780 100644 --- a/src/lib/diagnostics.ts +++ b/src/lib/diagnostics.ts @@ -109,18 +109,29 @@ export const format_diagnostic = (d: Diagnostic): string => { }; /** - * Error thrown when CSS generation encounters errors and `on_error: 'throw'` is set. + * Error thrown when CSS generation encounters errors or warnings + * (depending on `on_error` and `on_warning` settings). * Contains the full diagnostics array for programmatic access. */ export class CssGenerationError extends Error { diagnostics: Array; constructor(diagnostics: Array) { - const error_count = diagnostics.filter((d) => d.level === 'error').length; - const message = `CSS generation failed with ${error_count} error${error_count === 1 ? '' : 's'}:\n${diagnostics - .filter((d) => d.level === 'error') - .map(format_diagnostic) - .join('\n')}`; + const errors = diagnostics.filter((d) => d.level === 'error'); + const warnings = diagnostics.filter((d) => d.level === 'warning'); + + const parts: Array = []; + if (errors.length > 0) { + parts.push(`${errors.length} error${errors.length === 1 ? '' : 's'}`); + } + if (warnings.length > 0) { + parts.push(`${warnings.length} warning${warnings.length === 1 ? '' : 's'}`); + } + + const summary = parts.length > 0 ? parts.join(' and ') : '0 issues'; + const formatted = diagnostics.map(format_diagnostic).join('\n'); + const message = `CSS generation failed with ${summary}:\n${formatted}`; + super(message); this.name = 'CssGenerationError'; this.diagnostics = diagnostics; diff --git a/src/lib/gen_fuz_css.ts b/src/lib/gen_fuz_css.ts index 792f3d0a7..3e37ca09a 100644 --- a/src/lib/gen_fuz_css.ts +++ b/src/lib/gen_fuz_css.ts @@ -116,10 +116,19 @@ export interface GenFuzCssOptions { class_interpreters?: Array; /** * How to handle CSS-literal errors during generation. - * - 'log' (default): Log errors, skip invalid classes, continue + * - 'log': Log errors, skip invalid classes, continue * - 'throw': Throw on first error, fail the build + * @default 'throw' in CI, 'log' otherwise */ on_error?: 'log' | 'throw'; + /** + * How to handle warnings during generation. + * - 'log': Log warnings, continue + * - 'throw': Throw on first warning, fail the build + * - 'ignore': Suppress warnings entirely + * @default 'log' + */ + on_warning?: 'log' | 'throw' | 'ignore'; /** * Classes to always include in the output, regardless of whether they're detected in source files. * Useful for dynamically generated class names that can't be statically extracted. @@ -173,7 +182,8 @@ export const gen_fuz_css = (options: GenFuzCssOptions = {}): Gen => { include_builtin_definitions = true, class_definitions: user_class_definitions, class_interpreters = css_class_interpreters, - on_error = 'log', + on_error = is_ci ? 'throw' : 'log', + on_warning = 'log', include_classes, exclude_classes, cache_dir = DEFAULT_CACHE_DIR, @@ -401,15 +411,22 @@ export const gen_fuz_css = (options: GenFuzCssOptions = {}): Gen => { const errors = all_diagnostics.filter((d) => d.level === 'error'); const warnings = all_diagnostics.filter((d) => d.level === 'warning'); - // Log all warnings using consistent format - for (const warning of warnings) { - log.warn(format_diagnostic(warning)); + // Handle warnings based on on_warning setting + if (warnings.length > 0) { + if (on_warning === 'throw') { + throw new CssGenerationError(warnings); + } else if (on_warning === 'log') { + for (const warning of warnings) { + log.warn(format_diagnostic(warning)); + } + } + // 'ignore' - do nothing } // Handle errors based on on_error setting if (errors.length > 0) { if (on_error === 'throw') { - throw new CssGenerationError(all_diagnostics); + throw new CssGenerationError(errors); } // 'log' mode - errors are already logged by interpret_css_literal log.warn( diff --git a/src/lib/vite_plugin_fuz_css.ts b/src/lib/vite_plugin_fuz_css.ts index 973694305..c40a477d4 100644 --- a/src/lib/vite_plugin_fuz_css.ts +++ b/src/lib/vite_plugin_fuz_css.ts @@ -108,10 +108,19 @@ export interface VitePluginFuzCssOptions { acorn_plugins?: Array; /** * How to handle CSS-literal errors during generation. - * - 'log' (default): Log errors, skip invalid classes, continue + * - 'log': Log errors, skip invalid classes, continue * - 'throw': Throw on first error, fail the build + * @default 'throw' in CI, 'log' otherwise */ on_error?: 'log' | 'throw'; + /** + * How to handle warnings during generation. + * - 'log': Log warnings, continue + * - 'throw': Throw on first warning, fail the build + * - 'ignore': Suppress warnings entirely + * @default 'log' + */ + on_warning?: 'log' | 'throw' | 'ignore'; /** * Cache directory relative to project root. * @default DEFAULT_CACHE_DIR @@ -150,7 +159,8 @@ export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plug include_classes, exclude_classes, acorn_plugins, - on_error = 'log', + on_error = is_ci ? 'throw' : 'log', + on_warning = 'log', cache_dir = DEFAULT_CACHE_DIR, } = options; @@ -286,19 +296,30 @@ export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plug ...result.diagnostics, ]; - // Handle errors + // Separate errors and warnings const errors = all_diagnostics.filter((d) => d.level === 'error'); - if (errors.length > 0 && on_error === 'throw') { - throw new CssGenerationError(all_diagnostics); + const warnings = all_diagnostics.filter((d) => d.level === 'warning'); + + // Handle warnings based on on_warning setting + if (warnings.length > 0) { + if (on_warning === 'throw') { + throw new CssGenerationError(warnings); + } else if (on_warning === 'log') { + for (const d of result.diagnostics.filter((d) => d.level === 'warning')) { + log_warn(`[fuz_css] ${d.class_name}: ${d.message}`); + } + } + // 'ignore' - do nothing } - // Log generation warnings/errors (extraction diagnostics already logged in transform) - for (const d of result.diagnostics) { - const msg = `[fuz_css] ${d.class_name}: ${d.message}`; - if (d.level === 'error') { - log_error(msg); - } else { - log_warn(msg); + // Handle errors based on on_error setting + if (errors.length > 0) { + if (on_error === 'throw') { + throw new CssGenerationError(errors); + } + // Log errors (extraction diagnostics already logged in transform) + for (const d of result.diagnostics.filter((d) => d.level === 'error')) { + log_error(`[fuz_css] ${d.class_name}: ${d.message}`); } } @@ -478,9 +499,10 @@ export const vite_plugin_fuz_css = (options: VitePluginFuzCssOptions = {}): Plug const msg = `[fuz_css] ${loc}: ${d.message}`; if (d.level === 'error') { log_error(msg); - } else { + } else if (on_warning === 'log') { log_warn(msg); } + // 'ignore' and 'throw' (handled at generation time) - don't log here } } diff --git a/src/routes/docs/classes/+page.svelte b/src/routes/docs/classes/+page.svelte index 84cb8f4c0..9e65441a5 100644 --- a/src/routes/docs/classes/+page.svelte +++ b/src/routes/docs/classes/+page.svelte @@ -239,7 +239,8 @@ export const gen = gen_fuz_css({ needs.

    - Circular references produce: Circular reference detected: card → panel → card. + Circular references produce: Circular reference detected: card → panel → card.

    @@ -268,8 +269,8 @@ export const gen = gen_fuz_css({

    Modifiers

    All composite forms support modifiers. For classes and declaration - composites, declarations are combined and wrapped. For ruleset composites, - modifiers are applied to each selector (with smart conflict detection): + composites, declarations are combined and wrapped. For ruleset composites, modifiers + are applied to each selector (with smart conflict detection):

    @@ -546,7 +547,7 @@ export const gen = gen_fuz_css({ -
    +
    @@ -554,6 +555,15 @@ export const gen = gen_fuz_css({