frutjam 2.7.1-beta.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +117 -19
- package/dist/base/reboot/index.js +5 -0
- package/dist/base/reboot/object.js +1 -0
- package/dist/base/tokens/index.js +5 -0
- package/dist/base/tokens/object.js +1 -0
- package/dist/base.css +4 -0
- package/dist/components/accordion/index.js +7 -0
- package/dist/components/accordion/object.js +1 -0
- package/dist/components/accordion.css +2 -0
- package/dist/components/alert/index.js +7 -0
- package/dist/components/alert/object.js +1 -0
- package/dist/components/alert.css +2 -0
- package/dist/components/avatar/index.js +7 -0
- package/dist/components/avatar/object.js +1 -0
- package/dist/components/avatar.css +2 -0
- package/dist/components/badge/index.js +7 -0
- package/dist/components/badge/object.js +1 -0
- package/dist/components/badge.css +2 -0
- package/dist/components/breadcrumb/index.js +7 -0
- package/dist/components/breadcrumb/object.js +1 -0
- package/dist/components/breadcrumb.css +2 -0
- package/dist/components/button/index.js +7 -0
- package/dist/components/button/object.js +1 -0
- package/dist/components/button.css +4 -0
- package/dist/components/card/index.js +7 -0
- package/dist/components/card/object.js +1 -0
- package/dist/components/card.css +2 -0
- package/dist/components/carousel/index.js +7 -0
- package/dist/components/carousel/object.js +1 -0
- package/dist/components/carousel.css +2 -0
- package/dist/components/chat/index.js +7 -0
- package/dist/components/chat/object.js +1 -0
- package/dist/components/chat.css +2 -0
- package/dist/components/checkbox/index.js +7 -0
- package/dist/components/checkbox/object.js +1 -0
- package/dist/components/checkbox.css +2 -0
- package/dist/components/collapsible/index.js +7 -0
- package/dist/components/collapsible/object.js +1 -0
- package/dist/components/collapsible.css +2 -0
- package/dist/components/combobox/index.js +7 -0
- package/dist/components/combobox/object.js +1 -0
- package/dist/components/combobox.css +2 -0
- package/dist/components/countdown/index.js +7 -0
- package/dist/components/countdown/object.js +1 -0
- package/dist/components/countdown.css +2 -0
- package/dist/components/diff/index.js +7 -0
- package/dist/components/diff/object.js +1 -0
- package/dist/components/diff.css +2 -0
- package/dist/components/divider/index.js +7 -0
- package/dist/components/divider/object.js +1 -0
- package/dist/components/divider.css +2 -0
- package/dist/components/drawer/index.js +7 -0
- package/dist/components/drawer/object.js +1 -0
- package/dist/components/drawer.css +2 -0
- package/dist/components/footer/index.js +7 -0
- package/dist/components/footer/object.js +1 -0
- package/dist/components/footer.css +2 -0
- package/dist/components/header/index.js +7 -0
- package/dist/components/header/object.js +1 -0
- package/dist/components/header.css +2 -0
- package/dist/components/hero/index.js +7 -0
- package/dist/components/hero/object.js +1 -0
- package/dist/components/hero.css +2 -0
- package/dist/components/indicator/index.js +7 -0
- package/dist/components/indicator/object.js +1 -0
- package/dist/components/indicator.css +2 -0
- package/dist/components/input/index.js +7 -0
- package/dist/components/input/object.js +1 -0
- package/dist/components/input.css +2 -0
- package/dist/components/join/index.js +7 -0
- package/dist/components/join/object.js +1 -0
- package/dist/components/join.css +2 -0
- package/dist/components/kbd/index.js +7 -0
- package/dist/components/kbd/object.js +1 -0
- package/dist/components/kbd.css +2 -0
- package/dist/components/link/index.js +7 -0
- package/dist/components/link/object.js +1 -0
- package/dist/components/link.css +2 -0
- package/dist/components/loading/index.js +7 -0
- package/dist/components/loading/object.js +1 -0
- package/dist/components/loading.css +2 -0
- package/dist/components/mask/index.js +7 -0
- package/dist/components/mask/object.js +1 -0
- package/dist/components/mask.css +2 -0
- package/dist/components/menu/index.js +7 -0
- package/dist/components/menu/object.js +1 -0
- package/dist/components/menu.css +2 -0
- package/dist/components/modal/index.js +7 -0
- package/dist/components/modal/object.js +1 -0
- package/dist/components/modal.css +2 -0
- package/dist/components/navbar/index.js +7 -0
- package/dist/components/navbar/object.js +1 -0
- package/dist/components/navbar.css +2 -0
- package/dist/components/popover/index.js +7 -0
- package/dist/components/popover/object.js +1 -0
- package/dist/components/popover.css +2 -0
- package/dist/components/progress/index.js +7 -0
- package/dist/components/progress/object.js +1 -0
- package/dist/components/progress.css +2 -0
- package/dist/components/radial-progress/index.js +7 -0
- package/dist/components/radial-progress/object.js +1 -0
- package/dist/components/radial-progress.css +2 -0
- package/dist/components/radio/index.js +7 -0
- package/dist/components/radio/object.js +1 -0
- package/dist/components/radio.css +2 -0
- package/dist/components/range/index.js +7 -0
- package/dist/components/range/object.js +1 -0
- package/dist/components/range.css +2 -0
- package/dist/components/rating/index.js +7 -0
- package/dist/components/rating/object.js +1 -0
- package/dist/components/rating.css +2 -0
- package/dist/components/select/index.js +7 -0
- package/dist/components/select/object.js +1 -0
- package/dist/components/select.css +2 -0
- package/dist/components/sidebar/index.js +7 -0
- package/dist/components/sidebar/object.js +1 -0
- package/dist/components/sidebar.css +2 -0
- package/dist/components/skeleton/index.js +7 -0
- package/dist/components/skeleton/object.js +1 -0
- package/dist/components/skeleton.css +2 -0
- package/dist/components/stat/index.js +7 -0
- package/dist/components/stat/object.js +1 -0
- package/dist/components/stat.css +2 -0
- package/dist/components/status/index.js +7 -0
- package/dist/components/status/object.js +1 -0
- package/dist/components/status.css +2 -0
- package/dist/components/steps/index.js +7 -0
- package/dist/components/steps/object.js +1 -0
- package/dist/components/steps.css +2 -0
- package/dist/components/surface/index.js +7 -0
- package/dist/components/surface/object.js +1 -0
- package/dist/components/surface.css +2 -0
- package/dist/components/swap/index.js +7 -0
- package/dist/components/swap/object.js +1 -0
- package/dist/components/swap.css +2 -0
- package/dist/components/table/index.js +7 -0
- package/dist/components/table/object.js +1 -0
- package/dist/components/table.css +2 -0
- package/dist/components/tabs/index.js +7 -0
- package/dist/components/tabs/object.js +1 -0
- package/dist/components/tabs.css +2 -0
- package/dist/components/tag/index.js +7 -0
- package/dist/components/tag/object.js +1 -0
- package/dist/components/tag.css +2 -0
- package/dist/components/textarea/index.js +7 -0
- package/dist/components/textarea/object.js +1 -0
- package/dist/components/textarea.css +2 -0
- package/dist/components/timeline/index.js +7 -0
- package/dist/components/timeline/object.js +1 -0
- package/dist/components/timeline.css +2 -0
- package/dist/components/toast/index.js +7 -0
- package/dist/components/toast/object.js +1 -0
- package/dist/components/toast.css +2 -0
- package/dist/components/toggle/index.js +7 -0
- package/dist/components/toggle/object.js +1 -0
- package/dist/components/toggle.css +2 -0
- package/dist/components/tooltip/index.js +7 -0
- package/dist/components/tooltip/object.js +1 -0
- package/dist/components/tooltip.css +2 -0
- package/dist/frutjam.min.css +6 -5
- package/dist/functions/addPrefix.js +14 -0
- package/dist/plugin.js +146 -0
- package/dist/themes/darkberry/index.js +5 -0
- package/dist/themes/darkberry/object.js +1 -0
- package/dist/themes/darkberry.css +2 -0
- package/dist/themes/snowberry/index.js +5 -0
- package/dist/themes/snowberry/object.js +1 -0
- package/dist/themes/snowberry.css +2 -0
- package/dist/utilities/headings/index.js +7 -0
- package/dist/utilities/headings/object.js +1 -0
- package/dist/utilities/headings.css +2 -0
- package/dist/utilities/para/index.js +7 -0
- package/dist/utilities/para/object.js +1 -0
- package/dist/utilities/para.css +2 -0
- package/dist/utilities/typography/index.js +7 -0
- package/dist/utilities/typography/object.js +1 -0
- package/dist/utilities/typography.css +2 -0
- package/dist/utilities/wrapper/index.js +7 -0
- package/dist/utilities/wrapper/object.js +1 -0
- package/dist/utilities/wrapper.css +2 -0
- package/index.js +272 -0
- package/package.json +51 -40
- package/packages/js/carousel.js +19 -0
- package/packages/js/collapsible.js +8 -0
- package/packages/js/combobox.js +79 -0
- package/packages/js/drawer.js +1 -0
- package/packages/js/index.js +8 -0
- package/packages/js/modal.js +8 -0
- package/packages/js/tabs.js +33 -0
- package/packages/js/toast.js +19 -0
- package/packages/js/tooltip.js +8 -0
- package/packages/react/index.js +8 -0
- package/packages/react/useCarousel.js +23 -0
- package/packages/react/useCollapsible.js +12 -0
- package/packages/react/useCombobox.js +69 -0
- package/packages/react/useDrawer.js +1 -0
- package/packages/react/useModal.js +12 -0
- package/packages/react/useTabs.js +23 -0
- package/packages/react/useToast.js +27 -0
- package/packages/react/useTooltip.js +12 -0
- package/dist/frutjam.local.css +0 -2
- package/dist/frutjam.min.css.map +0 -1
- package/dist/frutjam.min.js +0 -3
- package/dist/frutjam.min.js.LICENSE.txt +0 -1
- package/dist/frutjam.min.js.map +0 -1
- package/dist/frutjam.safelist.local.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {"@layer theme":{":is([data-theme=\"darkberry\"], [data-theme=\"dark\"])":{"--scheme-color":"dark","--border-radius":"0.25rem","--color-base":"oklch(10.889% 0.00301 17.398)","--color-on-base":"oklch(98% 0.01 270)","--color-neutral":"oklch(85% 0 0)","--color-on-neutral":"oklch(20% 0 0)","--color-primary":"oklch(66.385% 0.18368 285.592)","--color-on-primary":"oklch(10% 0.01 270)","--color-secondary":"oklch(65% 0.18 220)","--color-on-secondary":"oklch(10% 0.01 220)","--color-accent":"oklch(75% 0.18 50)","--color-on-accent":"oklch(10% 0.01 50)","--color-info":"oklch(91.67% .077 205.04)","--color-on-info":"oklch(10% 0.01 250)","--color-success":"oklch(65% 0.18 140)","--color-on-success":"oklch(10% 0.01 140)","--color-warning":"oklch(75% 0.20 85)","--color-on-warning":"oklch(10% 0.01 85)","--color-error":"oklch(60% 0.22 30)","--color-on-error":"oklch(10% 0.01 30)"}}};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! frutjam v3.0.0 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
|
+
@layer theme{:is([data-theme=darkberry],[data-theme=dark]){--scheme-color:dark;--border-radius:0.25rem;--color-base:oklch(10.889% 0.00301 17.398);--color-on-base:oklch(98% 0.01 270);--color-neutral:oklch(85% 0 0);--color-on-neutral:oklch(20% 0 0);--color-primary:oklch(66.385% 0.18368 285.592);--color-on-primary:oklch(10% 0.01 270);--color-secondary:oklch(65% 0.18 220);--color-on-secondary:oklch(10% 0.01 220);--color-accent:oklch(75% 0.18 50);--color-on-accent:oklch(10% 0.01 50);--color-info:oklch(91.67% .077 205.04);--color-on-info:oklch(10% 0.01 250);--color-success:oklch(65% 0.18 140);--color-on-success:oklch(10% 0.01 140);--color-warning:oklch(75% 0.20 85);--color-on-warning:oklch(10% 0.01 85);--color-error:oklch(60% 0.22 30);--color-on-error:oklch(10% 0.01 30)}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {"@layer theme":{":root:not([data-theme]), :is([data-theme=\"snowberry\"], [data-theme=\"light\"])":{"--scheme-color":"light","--border-radius":"0.25rem","--color-base":"oklch(1 0 0)","--color-on-base":"oklch(0.22 0 0)","--color-neutral":"oklch(0.15 0 0)","--color-on-neutral":"oklch(1 0 0)","--color-primary":"oklch(51.1% 0.262 276.966)","--color-on-primary":"oklch(96.2% 0.018 272.314)","--color-secondary":"oklch(0.591 0.293 322.896)","--color-on-secondary":"oklch(1 0 0)","--color-accent":"oklch(0.541 0.281 293.009)","--color-on-accent":"oklch(1 0 0)","--color-info":"oklch(0.685 0.169 237.323)","--color-on-info":"oklch(0.15 0 0)","--color-success":"oklch(0.792 0.209 151.711)","--color-on-success":"oklch(0.15 0 0)","--color-warning":"oklch(0.852 0.199 91.936)","--color-on-warning":"oklch(0.15 0 0)","--color-error":"oklch(0.577 0.245 27.325)","--color-on-error":"oklch(1 0 0)"}}};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! frutjam v3.0.0 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
|
+
@layer theme{:is([data-theme=snowberry],[data-theme=light]),:root:not([data-theme]){--scheme-color:light;--border-radius:0.25rem;--color-base:oklch(1 0 0);--color-on-base:oklch(0.22 0 0);--color-neutral:oklch(0.15 0 0);--color-on-neutral:oklch(1 0 0);--color-primary:oklch(51.1% 0.262 276.966);--color-on-primary:oklch(96.2% 0.018 272.314);--color-secondary:oklch(0.591 0.293 322.896);--color-on-secondary:oklch(1 0 0);--color-accent:oklch(0.541 0.281 293.009);--color-on-accent:oklch(1 0 0);--color-info:oklch(0.685 0.169 237.323);--color-on-info:oklch(0.15 0 0);--color-success:oklch(0.792 0.209 151.711);--color-on-success:oklch(0.15 0 0);--color-warning:oklch(0.852 0.199 91.936);--color-on-warning:oklch(0.15 0 0);--color-error:oklch(0.577 0.245 27.325);--color-on-error:oklch(1 0 0)}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {".heading-2xl":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-2xl)","line-height":1.15},".heading-3xl":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-3xl)","line-height":1.15},".heading-4xl":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-4xl)","line-height":1.15},".heading-5xl":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-5xl)","line-height":1.15},".heading-6xl":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-6xl)","line-height":1.15},".heading-7xl":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-7xl)","line-height":1.15},".heading-8xl":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-8xl)","line-height":1.15},".heading-9xl":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-9xl)","line-height":1.15},".heading-lg":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-lg)","line-height":1.15},".heading-md":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","line-height":1.15,"font-size":"var(--text-base)"},".heading-sm":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-sm)","line-height":1.15},".heading-xl":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-xl)","line-height":1.15},".heading-xs":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-xs)","line-height":1.15},".heading":{"color":"var(--color-on-base)","font-weight":"bold","text-wrap-style":"balance","font-size":"var(--text-base)","line-height":1.15}};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! frutjam v3.0.0 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
|
+
/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */.heading-2xl{font-size:var(--text-base);font-size:var(--text-2xl)}.heading-2xl,.heading-3xl{color:var(--color-on-base);font-weight:700;line-height:1.15;text-wrap-style:balance}.heading-3xl{font-size:var(--text-base);font-size:var(--text-3xl)}.heading-4xl{font-size:var(--text-base);font-size:var(--text-4xl)}.heading-4xl,.heading-5xl{color:var(--color-on-base);font-weight:700;line-height:1.15;text-wrap-style:balance}.heading-5xl{font-size:var(--text-base);font-size:var(--text-5xl)}.heading-6xl{font-size:var(--text-base);font-size:var(--text-6xl)}.heading-6xl,.heading-7xl{color:var(--color-on-base);font-weight:700;line-height:1.15;text-wrap-style:balance}.heading-7xl{font-size:var(--text-base);font-size:var(--text-7xl)}.heading-8xl{font-size:var(--text-base);font-size:var(--text-8xl)}.heading-8xl,.heading-9xl{color:var(--color-on-base);font-weight:700;line-height:1.15;text-wrap-style:balance}.heading-9xl{font-size:var(--text-base);font-size:var(--text-9xl)}.heading-lg{font-size:var(--text-base);font-size:var(--text-lg)}.heading-lg,.heading-md{color:var(--color-on-base);font-weight:700;line-height:1.15;text-wrap-style:balance}.heading-md{font-size:var(--text-base)}.heading-sm{font-size:var(--text-base);font-size:var(--text-sm)}.heading-sm,.heading-xl{color:var(--color-on-base);font-weight:700;line-height:1.15;text-wrap-style:balance}.heading-xl{font-size:var(--text-base);font-size:var(--text-xl)}.heading-xs{font-size:var(--text-base);font-size:var(--text-xs)}.heading,.heading-xs{color:var(--color-on-base);font-weight:700;line-height:1.15;text-wrap-style:balance}.heading{font-size:var(--text-base)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {".para-2xl":{"text-wrap-style":"pretty","font-size":"var(--text-2xl)","line-height":1.6},".para-3xl":{"text-wrap-style":"pretty","font-size":"var(--text-3xl)","line-height":1.6},".para-4xl":{"text-wrap-style":"pretty","font-size":"var(--text-4xl)","line-height":1.6},".para-5xl":{"text-wrap-style":"pretty","font-size":"var(--text-5xl)","line-height":1.6},".para-6xl":{"text-wrap-style":"pretty","font-size":"var(--text-6xl)","line-height":1.6},".para-7xl":{"text-wrap-style":"pretty","font-size":"var(--text-7xl)","line-height":1.6},".para-8xl":{"text-wrap-style":"pretty","font-size":"var(--text-8xl)","line-height":1.6},".para-9xl":{"text-wrap-style":"pretty","font-size":"var(--text-9xl)","line-height":1.6},".para-lg":{"text-wrap-style":"pretty","font-size":"var(--text-lg)","line-height":1.6},".para-md":{"text-wrap-style":"pretty","line-height":1.6,"font-size":"var(--text-base)"},".para-sm":{"text-wrap-style":"pretty","font-size":"var(--text-sm)","line-height":1.6},".para-xl":{"text-wrap-style":"pretty","font-size":"var(--text-xl)","line-height":1.6},".para-xs":{"text-wrap-style":"pretty","font-size":"var(--text-xs)","line-height":1.6},".para":{"text-wrap-style":"pretty","font-size":"var(--text-base)","line-height":1.6}};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! frutjam v3.0.0 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
|
+
/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */.para-2xl{font-size:var(--text-base);font-size:var(--text-2xl)}.para-2xl,.para-3xl{line-height:1.6;text-wrap-style:pretty}.para-3xl{font-size:var(--text-base);font-size:var(--text-3xl)}.para-4xl{font-size:var(--text-base);font-size:var(--text-4xl)}.para-4xl,.para-5xl{line-height:1.6;text-wrap-style:pretty}.para-5xl{font-size:var(--text-base);font-size:var(--text-5xl)}.para-6xl{font-size:var(--text-base);font-size:var(--text-6xl)}.para-6xl,.para-7xl{line-height:1.6;text-wrap-style:pretty}.para-7xl{font-size:var(--text-base);font-size:var(--text-7xl)}.para-8xl{font-size:var(--text-base);font-size:var(--text-8xl)}.para-8xl,.para-9xl{line-height:1.6;text-wrap-style:pretty}.para-9xl{font-size:var(--text-base);font-size:var(--text-9xl)}.para-lg{font-size:var(--text-base);font-size:var(--text-lg)}.para-lg,.para-md{line-height:1.6;text-wrap-style:pretty}.para-md{font-size:var(--text-base)}.para-sm{font-size:var(--text-base);font-size:var(--text-sm)}.para-sm,.para-xl{line-height:1.6;text-wrap-style:pretty}.para-xl{font-size:var(--text-base);font-size:var(--text-xl)}.para-xs{font-size:var(--text-base);font-size:var(--text-xs)}.para,.para-xs{line-height:1.6;text-wrap-style:pretty}.para{font-size:var(--text-base)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {".prose-frutjam":{"--tw-prose-body":"var(--color-body)","--tw-prose-headings":"var(--color-on-base)","--tw-prose-lead":"var(--color-on-neutral)","--tw-prose-bold":"var(--color-on-base)","--tw-prose-links":"var(--color-primary)","--tw-prose-counters":"var(--color-on-neutral)","--tw-prose-bullets":"var(--color-neutral)","--tw-prose-hr":"var(--color-base-soft)","--tw-prose-quotes":"var(--color-on-base)","--tw-prose-quote-borders":"var(--color-primary)","--tw-prose-code":"var(--color-on-base)","--tw-prose-pre-code":"var(--color-base)","--tw-prose-pre-bg":"var(--color-on-base)","--tw-prose-th-borders":"var(--color-base-soft)","--tw-prose-td-borders":"var(--color-base-soft)","--tw-prose-captions":"var(--color-on-neutral)","--tw-prose-kbd":"var(--color-body)","--tw-prose-invert-body":"var(--color-on-neutral)","--tw-prose-invert-headings":"var(--color-on-base)","--tw-prose-invert-links":"var(--color-primary)"}};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! frutjam v3.0.0 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
|
+
.prose-frutjam{--tw-prose-body:var(--color-body);--tw-prose-headings:var(--color-on-base);--tw-prose-lead:var(--color-on-neutral);--tw-prose-bold:var(--color-on-base);--tw-prose-links:var(--color-primary);--tw-prose-counters:var(--color-on-neutral);--tw-prose-bullets:var(--color-neutral);--tw-prose-hr:var(--color-base-soft);--tw-prose-quotes:var(--color-on-base);--tw-prose-quote-borders:var(--color-primary);--tw-prose-code:var(--color-on-base);--tw-prose-pre-code:var(--color-base);--tw-prose-pre-bg:var(--color-on-base);--tw-prose-th-borders:var(--color-base-soft);--tw-prose-td-borders:var(--color-base-soft);--tw-prose-captions:var(--color-on-neutral);--tw-prose-kbd:var(--color-body);--tw-prose-invert-body:var(--color-on-neutral);--tw-prose-invert-headings:var(--color-on-base);--tw-prose-invert-links:var(--color-primary)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default {".wrapper-full":{"width":"100%","max-width":"100%","box-sizing":"border-box","margin-inline":"auto","padding-inline":"1rem","@media (width >= 40rem)":{"padding-inline":"2rem"},"@media (width >= 64rem)":{"padding-inline":"4rem"}},".wrapper-2xl":{"box-sizing":"border-box","max-width":"1536px","margin-inline":"auto","padding-inline":"1rem","@media (width >= 40rem)":{"padding-inline":"2rem"},"@media (width >= 64rem)":{"padding-inline":"4rem"}},".wrapper-lg":{"box-sizing":"border-box","max-width":"1024px","margin-inline":"auto","padding-inline":"1rem","@media (width >= 40rem)":{"padding-inline":"2rem"},"@media (width >= 64rem)":{"padding-inline":"4rem"}},".wrapper-md":{"box-sizing":"border-box","max-width":"768px","margin-inline":"auto","padding-inline":"1rem","@media (width >= 40rem)":{"padding-inline":"2rem"},"@media (width >= 64rem)":{"padding-inline":"4rem"}},".wrapper-sm":{"box-sizing":"border-box","max-width":"640px","margin-inline":"auto","padding-inline":"1rem","@media (width >= 40rem)":{"padding-inline":"2rem"},"@media (width >= 64rem)":{"padding-inline":"4rem"}},".wrapper-xl":{"box-sizing":"border-box","max-width":"1280px","margin-inline":"auto","padding-inline":"1rem","@media (width >= 40rem)":{"padding-inline":"2rem"},"@media (width >= 64rem)":{"padding-inline":"4rem"}},".wrapper-xs":{"box-sizing":"border-box","max-width":"320px","margin-inline":"auto","padding-inline":"1rem","@media (width >= 40rem)":{"padding-inline":"2rem"},"@media (width >= 64rem)":{"padding-inline":"4rem"}},".wrapper":{"box-sizing":"border-box","margin-inline":"auto","padding-inline":"1rem","@media (width >= 40rem)":{"padding-inline":"2rem"},"@media (width >= 64rem)":{"padding-inline":"4rem"}}};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! frutjam v3.0.0 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
|
+
/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */.wrapper-full{box-sizing:border-box;margin-inline:auto;max-width:100%;padding-inline:1rem;width:100%;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-2xl{box-sizing:border-box;margin-inline:auto;max-width:1536px;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-lg{box-sizing:border-box;margin-inline:auto;max-width:1024px;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-md{box-sizing:border-box;margin-inline:auto;max-width:768px;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-sm{box-sizing:border-box;margin-inline:auto;max-width:640px;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-xl{box-sizing:border-box;margin-inline:auto;max-width:1280px;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-xs{box-sizing:border-box;margin-inline:auto;max-width:320px;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper{box-sizing:border-box;margin-inline:auto;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}
|
package/index.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, statSync, existsSync } from "fs"
|
|
2
|
+
import { join, dirname, basename, extname } from "path"
|
|
3
|
+
import { fileURLToPath } from "url"
|
|
4
|
+
import postcss from "postcss"
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
7
|
+
const __dir = dirname(__filename)
|
|
8
|
+
const srcDir = join(__dir, "src")
|
|
9
|
+
const VERSION = JSON.parse(readFileSync(join(__dir, "package.json"), "utf8")).version
|
|
10
|
+
|
|
11
|
+
// ── Keys that must be injected after Tailwind processes layers ───────────────
|
|
12
|
+
// These files conflict with @layer utilities from Tailwind plugins (e.g. typography),
|
|
13
|
+
// so they are injected via OnceExit into @layer utilities (or root if not found).
|
|
14
|
+
const LATE_INJECT = new Set(['typography'])
|
|
15
|
+
|
|
16
|
+
// ── Registry (built once at startup, not per build) ──────────────────────────
|
|
17
|
+
|
|
18
|
+
function buildRegistry() {
|
|
19
|
+
const registry = {}
|
|
20
|
+
|
|
21
|
+
// Components: src/components/*/base.css — keyed by folder name
|
|
22
|
+
const componentsDir = join(srcDir, "components")
|
|
23
|
+
for (const name of readdirSync(componentsDir)) {
|
|
24
|
+
const entry = join(componentsDir, name, "base.css")
|
|
25
|
+
if (statSync(join(componentsDir, name)).isDirectory() && existsSync(entry)) {
|
|
26
|
+
registry[name] = entry
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Utilities: src/utilities/*.css — keyed by filename without extension
|
|
31
|
+
const utilitiesDir = join(srcDir, "utilities")
|
|
32
|
+
for (const file of readdirSync(utilitiesDir)) {
|
|
33
|
+
if (extname(file) === ".css") {
|
|
34
|
+
registry[basename(file, ".css")] = join(utilitiesDir, file)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return registry
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const REGISTRY = buildRegistry()
|
|
42
|
+
|
|
43
|
+
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
function readFile(p) { return readFileSync(p, "utf8") }
|
|
46
|
+
|
|
47
|
+
function parseList(val) {
|
|
48
|
+
if (!val) return []
|
|
49
|
+
if (Array.isArray(val)) return val.map(s => s.trim()).filter(Boolean)
|
|
50
|
+
return String(val).split(",").map(s => s.trim()).filter(Boolean)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function applyPrefix(css, prefix) {
|
|
54
|
+
if (!prefix) return css
|
|
55
|
+
|
|
56
|
+
css = css.replace(
|
|
57
|
+
/@utility\s+([\w-]+\*?)\s*\{/g,
|
|
58
|
+
(_, name) => `@utility ${prefix}-${name} {`
|
|
59
|
+
)
|
|
60
|
+
css = css.replace(
|
|
61
|
+
/@apply\s+([^;{}\n]+)/g,
|
|
62
|
+
(_, classes) => `@apply ${classes.trim().split(/\s+/).map(c => `${prefix}-${c}`).join(' ')}`
|
|
63
|
+
)
|
|
64
|
+
css = css.replace(
|
|
65
|
+
/\/\*[\s\S]*?\*\/|"[^"]*"|'[^']*'|\.(([a-z][a-z0-9]*-?)+)/g,
|
|
66
|
+
(match, name) => name ? `.${prefix}-${name}` : match
|
|
67
|
+
)
|
|
68
|
+
return css
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function buildUtilityMap(css) {
|
|
72
|
+
const map = new Map()
|
|
73
|
+
const pattern = /@utility\s+([\w-]+(?:\s*\*)?)\s*\{/g
|
|
74
|
+
let match
|
|
75
|
+
while ((match = pattern.exec(css)) !== null) {
|
|
76
|
+
const name = match[1].trim()
|
|
77
|
+
if (map.has(name)) continue
|
|
78
|
+
let depth = 0, bodyStart = -1
|
|
79
|
+
for (let i = match.index + match[0].length - 1; i < css.length; i++) {
|
|
80
|
+
if (css[i] === '{') {
|
|
81
|
+
if (depth === 0) bodyStart = i + 1
|
|
82
|
+
depth++
|
|
83
|
+
} else if (css[i] === '}') {
|
|
84
|
+
if (--depth === 0) { map.set(name, css.slice(bodyStart, i)); break }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return map
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function resolveCopy(css, source = css) {
|
|
92
|
+
const map = source instanceof Map ? source : buildUtilityMap(source)
|
|
93
|
+
return css.replace(/@copy\s+([\w-]+)\s*;/g, (original, name) => map.get(name) ?? original)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function resolveImports(css, baseDir) {
|
|
97
|
+
return css.replace(
|
|
98
|
+
/@import\s+["']([^"']+)["'];?\s*/g,
|
|
99
|
+
(_, importPath) => {
|
|
100
|
+
const fullPath = join(baseDir, importPath)
|
|
101
|
+
const importedDir = dirname(fullPath)
|
|
102
|
+
const importedCSS = readFile(fullPath)
|
|
103
|
+
return resolveImports(importedCSS, importedDir)
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function buildCustomThemes(themes) {
|
|
109
|
+
if (!themes || Object.keys(themes).length === 0) return ""
|
|
110
|
+
|
|
111
|
+
return Object.entries(themes)
|
|
112
|
+
.map(([name, vars]) => {
|
|
113
|
+
const varString = Object.entries(vars)
|
|
114
|
+
.map(([k, v]) => ` ${k}: ${v};`)
|
|
115
|
+
.join("\n")
|
|
116
|
+
return `[data-theme="${name}"] {\n${varString}\n}`
|
|
117
|
+
})
|
|
118
|
+
.join("\n\n")
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ── Base layers (inlined — no entry CSS files needed) ───────────────────────
|
|
122
|
+
|
|
123
|
+
const BASE_FULL = [
|
|
124
|
+
"base/reboot.css",
|
|
125
|
+
"theme/base.css",
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
const BASE_CORE = [
|
|
129
|
+
"base/variants.css",
|
|
130
|
+
"base/tokens.css",
|
|
131
|
+
"theme/base.css",
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
// ── Build ────────────────────────────────────────────────────────────────────
|
|
135
|
+
|
|
136
|
+
function buildCSS(prefix, themes, reset, rootSelector, include, exclude) {
|
|
137
|
+
// Resolve which components+utilities to include
|
|
138
|
+
let keys = Object.keys(REGISTRY)
|
|
139
|
+
if (include.length > 0) {
|
|
140
|
+
keys = include.filter(k => REGISTRY[k])
|
|
141
|
+
} else if (exclude.length > 0) {
|
|
142
|
+
const excludeSet = new Set(exclude)
|
|
143
|
+
keys = keys.filter(k => !excludeSet.has(k))
|
|
144
|
+
}
|
|
145
|
+
// LATE_INJECT keys are handled separately via OnceExit — skip them here
|
|
146
|
+
keys = keys.filter(k => !LATE_INJECT.has(k))
|
|
147
|
+
|
|
148
|
+
// Base layer (full with reboot, or core without)
|
|
149
|
+
const baseFiles = reset ? BASE_FULL : BASE_CORE
|
|
150
|
+
const baseCss = baseFiles
|
|
151
|
+
.map(f => resolveImports(readFile(join(srcDir, f)), join(srcDir, dirname(f))))
|
|
152
|
+
.join("\n")
|
|
153
|
+
|
|
154
|
+
// Components + utilities
|
|
155
|
+
const modulesCss = keys
|
|
156
|
+
.map(k => resolveImports(readFile(REGISTRY[k]), dirname(REGISTRY[k])))
|
|
157
|
+
.join("\n")
|
|
158
|
+
|
|
159
|
+
const combined = baseCss + "\n" + modulesCss
|
|
160
|
+
const utilMap = buildUtilityMap(combined)
|
|
161
|
+
let css = resolveCopy(combined, utilMap)
|
|
162
|
+
|
|
163
|
+
if (rootSelector !== ":root") {
|
|
164
|
+
css = css.replace(/:root\b/g, rootSelector)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
css = applyPrefix(css, prefix)
|
|
168
|
+
|
|
169
|
+
const customThemes = buildCustomThemes(themes)
|
|
170
|
+
if (customThemes) css += "\n\n" + customThemes
|
|
171
|
+
|
|
172
|
+
return { css, utilMap }
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function buildLateCSS(prefix, include, exclude, utilMap = new Map()) {
|
|
176
|
+
let keys = [...LATE_INJECT].filter(k => REGISTRY[k])
|
|
177
|
+
if (include.length > 0) {
|
|
178
|
+
keys = keys.filter(k => include.includes(k))
|
|
179
|
+
} else if (exclude.length > 0) {
|
|
180
|
+
const excludeSet = new Set(exclude)
|
|
181
|
+
keys = keys.filter(k => !excludeSet.has(k))
|
|
182
|
+
}
|
|
183
|
+
if (keys.length === 0) return ""
|
|
184
|
+
const raw = keys
|
|
185
|
+
.map(k => resolveImports(readFile(REGISTRY[k]), dirname(REGISTRY[k])))
|
|
186
|
+
.join("\n")
|
|
187
|
+
const css = resolveCopy(raw, utilMap)
|
|
188
|
+
return applyPrefix(css, prefix)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ── Plugin ───────────────────────────────────────────────────────────────────
|
|
192
|
+
|
|
193
|
+
function parseAtPluginOptions(atRule) {
|
|
194
|
+
const opts = {}
|
|
195
|
+
atRule.each(node => {
|
|
196
|
+
if (node.type !== "decl") return
|
|
197
|
+
let val = node.value.trim()
|
|
198
|
+
if (val === "true") val = true
|
|
199
|
+
else if (val === "false") val = false
|
|
200
|
+
else if (
|
|
201
|
+
(val.startsWith('"') && val.endsWith('"')) ||
|
|
202
|
+
(val.startsWith("'") && val.endsWith("'"))
|
|
203
|
+
) val = val.slice(1, -1)
|
|
204
|
+
opts[node.prop.trim()] = val
|
|
205
|
+
})
|
|
206
|
+
return opts
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export { buildUtilityMap, resolveCopy }
|
|
210
|
+
|
|
211
|
+
export default function frutjam(options = {}) {
|
|
212
|
+
let _lateCss = ""
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
postcssPlugin: "frutjam",
|
|
216
|
+
Once(root) {
|
|
217
|
+
// Collect @plugin "frutjam" { ... } blocks from the CSS
|
|
218
|
+
const atPluginNodes = []
|
|
219
|
+
root.each(node => {
|
|
220
|
+
if (
|
|
221
|
+
node.type === "atrule" &&
|
|
222
|
+
node.name === "plugin" &&
|
|
223
|
+
/^["']frutjam["']/.test(node.params.trim()) &&
|
|
224
|
+
node.nodes
|
|
225
|
+
) atPluginNodes.push(node)
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
// CSS-level options override factory options
|
|
229
|
+
let cssOptions = {}
|
|
230
|
+
for (const node of atPluginNodes) {
|
|
231
|
+
Object.assign(cssOptions, parseAtPluginOptions(node))
|
|
232
|
+
node.remove()
|
|
233
|
+
}
|
|
234
|
+
const merged = { ...options, ...cssOptions }
|
|
235
|
+
|
|
236
|
+
const prefix = typeof merged.prefix === "string" ? merged.prefix.trim() : ""
|
|
237
|
+
const themes = typeof merged.themes === "object" ? merged.themes : {}
|
|
238
|
+
const reset = merged.reset !== false
|
|
239
|
+
const rootSelector = typeof merged.root === "string" ? merged.root : ":root"
|
|
240
|
+
const logs = merged.logs !== false
|
|
241
|
+
const include = parseList(merged.include)
|
|
242
|
+
const exclude = parseList(merged.exclude)
|
|
243
|
+
|
|
244
|
+
const { css, utilMap } = buildCSS(prefix, themes, reset, rootSelector, include, exclude)
|
|
245
|
+
root.append(postcss.parse(css).nodes)
|
|
246
|
+
_lateCss = buildLateCSS(prefix, include, exclude, utilMap)
|
|
247
|
+
if (logs) {
|
|
248
|
+
const d = "\x1b[2m", r = "\x1b[0m"
|
|
249
|
+
const badge = "\x1b[46m\x1b[30m frutjam \x1b[0m"
|
|
250
|
+
console.log("\n" + badge + " " + d + "v" + VERSION + r + "\n")
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
OnceExit(root) {
|
|
254
|
+
if (!_lateCss) return
|
|
255
|
+
// Inject into @layer utilities if it exists (correct cascade layer),
|
|
256
|
+
// otherwise append to root (unlayered CSS beats all @layer rules).
|
|
257
|
+
let utilLayer = null
|
|
258
|
+
root.each(node => {
|
|
259
|
+
if (node.type === "atrule" && node.name === "layer" && node.params === "utilities" && node.nodes) {
|
|
260
|
+
utilLayer = node
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
const nodes = postcss.parse(_lateCss).nodes
|
|
264
|
+
if (utilLayer) {
|
|
265
|
+
utilLayer.append(nodes)
|
|
266
|
+
} else {
|
|
267
|
+
root.append(nodes)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
frutjam.postcss = true
|
package/package.json
CHANGED
|
@@ -1,42 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frutjam",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A utility-first CSS
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "A utility-first CSS UI Library for Tailwind CSS",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./dist/plugin.js",
|
|
8
|
+
"./postcss": "./index.js",
|
|
9
|
+
"./js": "./packages/js/index.js",
|
|
10
|
+
"./js/*": "./packages/js/*.js",
|
|
11
|
+
"./react": "./packages/react/index.js",
|
|
12
|
+
"./react/*": "./packages/react/*.js",
|
|
13
|
+
"./components/*": "./dist/components/*/index.js",
|
|
14
|
+
"./utilities/*": "./dist/utilities/*/index.js",
|
|
15
|
+
"./themes/*": "./dist/themes/*/index.js",
|
|
16
|
+
"./base/tokens": "./dist/base/tokens/index.js",
|
|
17
|
+
"./base/reboot": "./dist/base/reboot/index.js",
|
|
18
|
+
"./functions/addPrefix": "./dist/functions/addPrefix.js"
|
|
19
|
+
},
|
|
9
20
|
"files": [
|
|
21
|
+
"index.js",
|
|
10
22
|
"dist/",
|
|
11
|
-
"
|
|
12
|
-
"LICENSE"
|
|
23
|
+
"packages/"
|
|
13
24
|
],
|
|
25
|
+
"style": "./dist/frutjam.min.css",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"clean": "rimraf ./dist",
|
|
28
|
+
"build:cdn": "node scripts/build-cdn.mjs",
|
|
29
|
+
"build:plugin": "node scripts/build-plugin.mjs",
|
|
30
|
+
"build": "rimraf ./dist && node scripts/build-cdn.mjs && node scripts/build-plugin.mjs",
|
|
31
|
+
"prepublishOnly": "rimraf ./dist && node scripts/build-cdn.mjs && node scripts/build-plugin.mjs",
|
|
32
|
+
"postversion": "git push origin main --tags"
|
|
33
|
+
},
|
|
34
|
+
"funding": "https://ko-fi.com/nezanuha",
|
|
14
35
|
"repository": {
|
|
15
36
|
"type": "git",
|
|
16
37
|
"url": "git+https://github.com/nezanuha/frutjam.git"
|
|
17
38
|
},
|
|
18
|
-
"exports": {
|
|
19
|
-
".": "./dist/frutjam.local.css",
|
|
20
|
-
"./safelist": "./dist/frutjam.safelist.local.css"
|
|
21
|
-
},
|
|
22
|
-
"scripts": {
|
|
23
|
-
"clean": "rimraf ./dist",
|
|
24
|
-
"dev": "webpack serve --config scripts/webpack.config.dev.js --mode=development",
|
|
25
|
-
"build:local": "node scripts/build-local.mjs && node scripts/build-safelist-local.mjs",
|
|
26
|
-
"build:browser": "webpack --config scripts/webpack.config.prod.js --mode=production",
|
|
27
|
-
"build": "npm run clean && npm run build:browser && npm run build:local",
|
|
28
|
-
"prepublishOnly": "npm run build"
|
|
29
|
-
},
|
|
30
39
|
"publishConfig": {
|
|
31
|
-
"
|
|
32
|
-
"
|
|
40
|
+
"access": "public",
|
|
41
|
+
"provenance": true
|
|
33
42
|
},
|
|
34
43
|
"keywords": [
|
|
35
44
|
"frutjam",
|
|
36
45
|
"tailwindcss",
|
|
46
|
+
"tailwind css plugin",
|
|
37
47
|
"UI Library",
|
|
38
48
|
"tailwind",
|
|
39
|
-
"taiwind css",
|
|
40
49
|
"components",
|
|
41
50
|
"tailwind components",
|
|
42
51
|
"tailwind component library",
|
|
@@ -49,11 +58,11 @@
|
|
|
49
58
|
"tailwind django",
|
|
50
59
|
"tailwind rails",
|
|
51
60
|
"tailwind laravel",
|
|
52
|
-
"tailwind css plugin",
|
|
53
61
|
"component library",
|
|
54
62
|
"tailwind themes",
|
|
55
63
|
"css library",
|
|
56
64
|
"theme",
|
|
65
|
+
"design system",
|
|
57
66
|
"front-end",
|
|
58
67
|
"framework",
|
|
59
68
|
"W3C standards",
|
|
@@ -68,23 +77,25 @@
|
|
|
68
77
|
"bugs": {
|
|
69
78
|
"url": "https://github.com/nezanuha/frutjam/issues"
|
|
70
79
|
},
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
|
|
80
|
+
"engines": {
|
|
81
|
+
"node": ">=18"
|
|
82
|
+
},
|
|
83
|
+
"peerDependencies": {
|
|
84
|
+
"tailwindcss": "^4.0.0",
|
|
85
|
+
"react": ">=18"
|
|
86
|
+
},
|
|
87
|
+
"peerDependenciesMeta": {
|
|
88
|
+
"react": {
|
|
89
|
+
"optional": true
|
|
90
|
+
}
|
|
74
91
|
},
|
|
75
92
|
"devDependencies": {
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"postcss": "^8.5.
|
|
80
|
-
"postcss-
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"rimraf": "^6.0.1",
|
|
84
|
-
"style-loader": "^4.0.0",
|
|
85
|
-
"webpack": "^5.102.1",
|
|
86
|
-
"webpack-cli": "^6.0.1",
|
|
87
|
-
"webpack-dev-server": "^5.2.2",
|
|
88
|
-
"webpack-remove-empty-scripts": "^1.1.1"
|
|
93
|
+
"@tailwindcss/postcss": "^4.2.4",
|
|
94
|
+
"autoprefixer": "^10.5.0",
|
|
95
|
+
"cssnano": "^7.1.7",
|
|
96
|
+
"postcss": "^8.5.13",
|
|
97
|
+
"postcss-js": "^5.1.0",
|
|
98
|
+
"rimraf": "^6.1.3",
|
|
99
|
+
"tailwindcss": "^4.2.4"
|
|
89
100
|
}
|
|
90
101
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function createCarousel(el) {
|
|
2
|
+
const getItems = () => Array.from(el.querySelectorAll('.carousel-item'))
|
|
3
|
+
let current = 0
|
|
4
|
+
|
|
5
|
+
function goTo(index) {
|
|
6
|
+
const items = getItems()
|
|
7
|
+
if (!items.length) return
|
|
8
|
+
current = Math.max(0, Math.min(index, items.length - 1))
|
|
9
|
+
items[current].scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
goTo,
|
|
14
|
+
next: () => goTo(current + 1),
|
|
15
|
+
prev: () => goTo(current - 1),
|
|
16
|
+
current: () => current,
|
|
17
|
+
count: () => getItems().length,
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function createCollapsible(el) {
|
|
2
|
+
return {
|
|
3
|
+
open: () => el.classList.add('collapsible-open'),
|
|
4
|
+
close: () => el.classList.remove('collapsible-open'),
|
|
5
|
+
toggle: () => el.classList.toggle('collapsible-open'),
|
|
6
|
+
isOpen: () => el.classList.contains('collapsible-open'),
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export function createCombobox(el) {
|
|
2
|
+
const input = el.querySelector('input')
|
|
3
|
+
let activeIndex = -1
|
|
4
|
+
|
|
5
|
+
const allOptions = () => Array.from(el.querySelectorAll('[role="option"], .combobox-option'))
|
|
6
|
+
const visibleOptions = () => allOptions().filter((o) => !o.hidden)
|
|
7
|
+
|
|
8
|
+
function open() {
|
|
9
|
+
el.classList.add('combobox-open')
|
|
10
|
+
input?.setAttribute('aria-expanded', 'true')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function close() {
|
|
14
|
+
el.classList.remove('combobox-open')
|
|
15
|
+
input?.setAttribute('aria-expanded', 'false')
|
|
16
|
+
highlight(-1)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function toggle() {
|
|
20
|
+
el.classList.contains('combobox-open') ? close() : open()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function filter(query) {
|
|
24
|
+
allOptions().forEach((opt) => {
|
|
25
|
+
opt.hidden = !opt.textContent.toLowerCase().includes(query.toLowerCase())
|
|
26
|
+
})
|
|
27
|
+
highlight(-1)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function highlight(index) {
|
|
31
|
+
const opts = visibleOptions()
|
|
32
|
+
opts.forEach((o) => o.classList.remove('combobox-option-active'))
|
|
33
|
+
if (index >= 0 && opts[index]) {
|
|
34
|
+
opts[index].classList.add('combobox-option-active')
|
|
35
|
+
opts[index].scrollIntoView({ block: 'nearest' })
|
|
36
|
+
}
|
|
37
|
+
activeIndex = index
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function select(opt) {
|
|
41
|
+
if (input) input.value = opt.textContent.trim()
|
|
42
|
+
el.dispatchEvent(new CustomEvent('fj:select', { detail: { value: opt.dataset.value ?? opt.textContent.trim() } }))
|
|
43
|
+
close()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
input?.addEventListener('input', (e) => {
|
|
47
|
+
open()
|
|
48
|
+
filter(e.target.value)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
input?.addEventListener('keydown', (e) => {
|
|
52
|
+
const opts = visibleOptions()
|
|
53
|
+
if (e.key === 'ArrowDown') {
|
|
54
|
+
e.preventDefault()
|
|
55
|
+
if (!el.classList.contains('combobox-open')) { open(); return }
|
|
56
|
+
highlight(Math.min(activeIndex + 1, opts.length - 1))
|
|
57
|
+
} else if (e.key === 'ArrowUp') {
|
|
58
|
+
e.preventDefault()
|
|
59
|
+
highlight(Math.max(activeIndex - 1, 0))
|
|
60
|
+
} else if (e.key === 'Enter' && activeIndex >= 0) {
|
|
61
|
+
e.preventDefault()
|
|
62
|
+
select(opts[activeIndex])
|
|
63
|
+
} else if (e.key === 'Escape') {
|
|
64
|
+
close()
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
el.addEventListener('click', (e) => {
|
|
69
|
+
const opt = e.target.closest('[role="option"], .combobox-option')
|
|
70
|
+
if (opt) { select(opt); return }
|
|
71
|
+
if (e.target === input) open()
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
document.addEventListener('click', (e) => {
|
|
75
|
+
if (!el.contains(e.target)) close()
|
|
76
|
+
}, { capture: true })
|
|
77
|
+
|
|
78
|
+
return { open, close, toggle, filter }
|
|
79
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createModal as createDrawer } from './modal.js'
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createModal } from './modal.js'
|
|
2
|
+
export { createDrawer } from './drawer.js'
|
|
3
|
+
export { createCollapsible } from './collapsible.js'
|
|
4
|
+
export { createTooltip } from './tooltip.js'
|
|
5
|
+
export { createTabs } from './tabs.js'
|
|
6
|
+
export { createToastManager } from './toast.js'
|
|
7
|
+
export { createCarousel } from './carousel.js'
|
|
8
|
+
export { createCombobox } from './combobox.js'
|