defuss-shadcn 0.6.4 → 0.7.14
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/AGENTS.md +877 -0
- package/ARCH.md +130 -0
- package/LICENSE +22 -0
- package/Makefile +55 -0
- package/README.md +176 -40
- package/bun.lock +340 -0
- package/dist/components/accordion/accordion.css +82 -0
- package/dist/components/accordion/accordion.js +138 -0
- package/dist/components/accordion/component-skill.md +165 -0
- package/dist/components/alert/alert.css +67 -0
- package/dist/components/alert/component-skill.md +56 -0
- package/dist/components/alert-dialog/alert-dialog.css +136 -0
- package/dist/components/alert-dialog/alert-dialog.js +132 -0
- package/dist/components/alert-dialog/component-skill.md +56 -0
- package/dist/components/avatar/avatar.css +93 -0
- package/dist/components/avatar/avatar.js +126 -0
- package/dist/components/avatar/component-skill.md +72 -0
- package/dist/components/badge/badge.css +30 -0
- package/dist/components/badge/component-skill.md +40 -0
- package/dist/components/breadcrumb/breadcrumb.css +47 -0
- package/dist/components/breadcrumb/component-skill.md +111 -0
- package/dist/components/button/button.css +141 -0
- package/dist/components/button/component-skill.md +82 -0
- package/dist/components/button-group/button-group.css +98 -0
- package/dist/components/button-group/component-skill.md +67 -0
- package/dist/components/calendar/calendar.css +187 -0
- package/dist/components/calendar/calendar.js +261 -0
- package/dist/components/calendar/component-skill.md +75 -0
- package/dist/components/card/card.css +55 -0
- package/dist/components/card/component-skill.md +121 -0
- package/dist/components/carousel/carousel.css +153 -0
- package/dist/components/carousel/carousel.js +276 -0
- package/dist/components/carousel/component-skill.md +167 -0
- package/dist/components/checkbox/checkbox.css +121 -0
- package/dist/components/checkbox/component-skill.md +100 -0
- package/dist/components/collapsible/collapsible.css +109 -0
- package/dist/components/collapsible/component-skill.md +32 -0
- package/dist/components/color-picker/color-picker.css +42 -0
- package/dist/components/color-picker/color-picker.js +111 -0
- package/dist/components/color-picker/component-skill.md +43 -0
- package/dist/components/combobox/combobox.css +177 -0
- package/dist/components/combobox/combobox.js +231 -0
- package/dist/components/combobox/component-skill.md +168 -0
- package/dist/components/command/command.css +73 -0
- package/dist/components/command/command.js +219 -0
- package/dist/components/command/component-skill.md +103 -0
- package/dist/components/context-menu/component-skill.md +35 -0
- package/dist/components/context-menu/context-menu.css +75 -0
- package/dist/components/context-menu/context-menu.js +137 -0
- package/dist/components/date-picker/component-skill.md +40 -0
- package/dist/components/date-picker/date-picker.css +60 -0
- package/dist/components/dialog/component-skill.md +110 -0
- package/dist/components/dialog/dialog.css +73 -0
- package/dist/components/dialog/dialog.js +125 -0
- package/dist/components/dropdown/component-skill.md +162 -0
- package/dist/components/dropdown/dropdown.css +148 -0
- package/dist/components/dropdown/dropdown.js +206 -0
- package/dist/components/file-input/component-skill.md +37 -0
- package/dist/components/file-input/file-input.css +66 -0
- package/dist/components/form/component-skill.md +134 -0
- package/dist/components/form/form.css +135 -0
- package/dist/components/icon/component-skill.md +159 -0
- package/dist/components/icon/icon.css +53 -0
- package/dist/components/image/component-skill.md +184 -0
- package/dist/components/image/image.css +174 -0
- package/dist/components/image/image.js +218 -0
- package/dist/components/input/component-skill.md +137 -0
- package/dist/components/input/input.css +153 -0
- package/dist/components/label/component-skill.md +98 -0
- package/dist/components/label/label.css +56 -0
- package/dist/components/navigation-menu/component-skill.md +88 -0
- package/dist/components/navigation-menu/navigation-menu.css +59 -0
- package/dist/components/navigation-menu/navigation-menu.js +119 -0
- package/dist/components/number-input/component-skill.md +41 -0
- package/dist/components/number-input/number-input.css +86 -0
- package/dist/components/number-input/number-input.js +124 -0
- package/dist/components/pagination/component-skill.md +109 -0
- package/dist/components/pagination/pagination.css +51 -0
- package/dist/components/popover/component-skill.md +90 -0
- package/dist/components/popover/popover.css +87 -0
- package/dist/components/popover/popover.js +114 -0
- package/dist/components/progress/component-skill.md +28 -0
- package/dist/components/progress/progress.css +76 -0
- package/dist/components/radio/component-skill.md +140 -0
- package/dist/components/radio/radio.css +210 -0
- package/dist/components/scroll-area/component-skill.md +44 -0
- package/dist/components/scroll-area/scroll-area.css +21 -0
- package/dist/components/select/component-skill.md +69 -0
- package/dist/components/select/select.css +69 -0
- package/dist/components/separator/component-skill.md +93 -0
- package/dist/components/separator/separator.css +65 -0
- package/dist/components/sheet/component-skill.md +121 -0
- package/dist/components/sheet/sheet.css +222 -0
- package/dist/components/sheet/sheet.js +125 -0
- package/dist/components/sidebar/component-skill.md +188 -0
- package/dist/components/sidebar/sidebar.css +352 -0
- package/dist/components/sidebar/sidebar.js +144 -0
- package/dist/components/skeleton/component-skill.md +34 -0
- package/dist/components/skeleton/skeleton.css +43 -0
- package/dist/components/slider/component-skill.md +122 -0
- package/dist/components/slider/slider.css +178 -0
- package/dist/components/slider/slider.js +118 -0
- package/dist/components/sortable/component-skill.md +138 -0
- package/dist/components/sortable/sortable.css +131 -0
- package/dist/components/sortable/sortable.js +301 -0
- package/dist/components/spinner/component-skill.md +34 -0
- package/dist/components/spinner/spinner.css +48 -0
- package/dist/components/statistic/component-skill.md +45 -0
- package/dist/components/statistic/statistic.css +53 -0
- package/dist/components/steps/component-skill.md +183 -0
- package/dist/components/steps/steps.css +95 -0
- package/dist/components/switch/component-skill.md +77 -0
- package/dist/components/switch/switch.css +153 -0
- package/dist/components/table/component-skill.md +51 -0
- package/dist/components/table/table.css +135 -0
- package/dist/components/tabs/component-skill.md +166 -0
- package/dist/components/tabs/tabs.css +123 -0
- package/dist/components/tabs/tabs.js +177 -0
- package/dist/components/textarea/component-skill.md +41 -0
- package/dist/components/textarea/textarea.css +82 -0
- package/dist/components/timeline/component-skill.md +45 -0
- package/dist/components/timeline/timeline.css +78 -0
- package/dist/components/toast/component-skill.md +140 -0
- package/dist/components/toast/toast.css +214 -0
- package/dist/components/toast/toast.js +225 -0
- package/dist/components/toggle/component-skill.md +100 -0
- package/dist/components/toggle/toggle.css +116 -0
- package/dist/components/toggle/toggle.js +112 -0
- package/dist/components/toggle-group/component-skill.md +164 -0
- package/dist/components/toggle-group/toggle-group.css +125 -0
- package/dist/components/toggle-group/toggle-group.js +167 -0
- package/dist/components/toolbar/component-skill.md +83 -0
- package/dist/components/toolbar/toolbar.css +39 -0
- package/dist/components/toolbar/toolbar.js +146 -0
- package/dist/components/tooltip/component-skill.md +108 -0
- package/dist/components/tooltip/tooltip.css +119 -0
- package/dist/components/tooltip/tooltip.js +174 -0
- package/dist/components/tree-view/component-skill.md +63 -0
- package/dist/components/tree-view/tree-view.css +156 -0
- package/dist/components/tree-view/tree-view.js +164 -0
- package/dist/components/typography/component-skill.md +111 -0
- package/dist/components/typography/typography.css +152 -0
- package/dist/documentation/accessibility.html +454 -0
- package/dist/documentation/accordion.html +937 -0
- package/dist/documentation/alert-dialog.html +560 -0
- package/dist/documentation/alert.html +377 -0
- package/dist/documentation/animations.html +398 -0
- package/dist/documentation/avatar.html +600 -0
- package/dist/documentation/badge.html +380 -0
- package/dist/documentation/breadcrumb.html +420 -0
- package/dist/documentation/button-group.html +503 -0
- package/dist/documentation/button.html +629 -0
- package/dist/documentation/calendar.html +733 -0
- package/dist/documentation/card.html +556 -0
- package/dist/documentation/carousel.html +984 -0
- package/dist/documentation/cascade-layers.html +437 -0
- package/dist/documentation/changelog.html +385 -0
- package/dist/documentation/checkbox.html +565 -0
- package/dist/documentation/collapsible.html +407 -0
- package/dist/documentation/color-picker.html +384 -0
- package/dist/documentation/combobox.html +894 -0
- package/dist/documentation/command.html +579 -0
- package/dist/documentation/component-skills.html +294 -0
- package/dist/documentation/context-menu.html +407 -0
- package/dist/documentation/css/docs-theme.css +41 -0
- package/dist/documentation/css/docs-utilities.css +63 -0
- package/dist/documentation/css/layout.css +788 -0
- package/dist/documentation/dark-mode.html +334 -0
- package/dist/documentation/data-attribute-api.html +503 -0
- package/dist/documentation/date-picker.html +318 -0
- package/dist/documentation/dialog.html +781 -0
- package/dist/documentation/dropdown.html +927 -0
- package/dist/documentation/es-modules.html +394 -0
- package/dist/documentation/favicon.svg +12 -0
- package/dist/documentation/file-input.html +319 -0
- package/dist/documentation/fonts/fraunces-300.woff2 +0 -0
- package/dist/documentation/fonts/fraunces-300i.woff2 +0 -0
- package/dist/documentation/fonts/fraunces-400.woff2 +0 -0
- package/dist/documentation/fonts/fraunces-400i.woff2 +0 -0
- package/dist/documentation/fonts/fraunces-500.woff2 +0 -0
- package/dist/documentation/fonts/geist-300.woff2 +0 -0
- package/dist/documentation/fonts/geist-400.woff2 +0 -0
- package/dist/documentation/fonts/geist-500.woff2 +0 -0
- package/dist/documentation/fonts/geist-600.woff2 +0 -0
- package/dist/documentation/fonts/geist-mono-400.woff2 +0 -0
- package/dist/documentation/fonts/geist-mono-500.woff2 +0 -0
- package/dist/documentation/form.html +832 -0
- package/dist/documentation/icon.html +623 -0
- package/dist/documentation/image.html +557 -0
- package/dist/documentation/index.html +303 -0
- package/dist/documentation/input.html +742 -0
- package/dist/documentation/installation.html +230 -0
- package/dist/documentation/js/layout.js +663 -0
- package/dist/documentation/js/shiki-highlight.js +69 -0
- package/dist/documentation/js/site.js +281 -0
- package/dist/documentation/js/theme-switcher.js +143 -0
- package/dist/documentation/js/themes.js +1660 -0
- package/dist/documentation/label.html +480 -0
- package/dist/documentation/native-web-apis.html +285 -0
- package/dist/documentation/navigation-menu.html +507 -0
- package/dist/documentation/number-input.html +429 -0
- package/dist/documentation/pagination.html +501 -0
- package/dist/documentation/popover.html +561 -0
- package/dist/documentation/progress.html +360 -0
- package/dist/documentation/radio.html +786 -0
- package/dist/documentation/scroll-area.html +248 -0
- package/dist/documentation/select.html +378 -0
- package/dist/documentation/separator.html +520 -0
- package/dist/documentation/sheet.html +948 -0
- package/dist/documentation/sidebar.html +933 -0
- package/dist/documentation/skeleton.html +307 -0
- package/dist/documentation/slider.html +683 -0
- package/dist/documentation/sortable.html +897 -0
- package/dist/documentation/spinner.html +315 -0
- package/dist/documentation/statistic.html +416 -0
- package/dist/documentation/steps.html +748 -0
- package/dist/documentation/switch.html +538 -0
- package/dist/documentation/table.html +480 -0
- package/dist/documentation/tabs.html +940 -0
- package/dist/documentation/textarea.html +343 -0
- package/dist/documentation/theming.html +320 -0
- package/dist/documentation/timeline.html +401 -0
- package/dist/documentation/toast.html +844 -0
- package/dist/documentation/toggle-group.html +839 -0
- package/dist/documentation/toggle.html +611 -0
- package/dist/documentation/toolbar.html +487 -0
- package/dist/documentation/tooltip.html +802 -0
- package/dist/documentation/tree-view.html +610 -0
- package/dist/documentation/typography.html +645 -0
- package/dist/robots.txt +4 -0
- package/dist/sitemap.xml +72 -0
- package/dist/theme/default-semantic-tokens.css +137 -0
- package/docs/components/accordion/accordion.css +82 -0
- package/docs/components/accordion/accordion.js +138 -0
- package/docs/components/accordion/component-skill.md +165 -0
- package/docs/components/alert/alert.css +67 -0
- package/docs/components/alert/component-skill.md +56 -0
- package/docs/components/alert-dialog/alert-dialog.css +136 -0
- package/docs/components/alert-dialog/alert-dialog.js +132 -0
- package/docs/components/alert-dialog/component-skill.md +56 -0
- package/docs/components/avatar/avatar.css +93 -0
- package/docs/components/avatar/avatar.js +126 -0
- package/docs/components/avatar/component-skill.md +72 -0
- package/docs/components/badge/badge.css +30 -0
- package/docs/components/badge/component-skill.md +40 -0
- package/docs/components/breadcrumb/breadcrumb.css +47 -0
- package/docs/components/breadcrumb/component-skill.md +111 -0
- package/docs/components/button/button.css +141 -0
- package/docs/components/button/component-skill.md +82 -0
- package/docs/components/button-group/button-group.css +98 -0
- package/docs/components/button-group/component-skill.md +67 -0
- package/docs/components/calendar/calendar.css +187 -0
- package/docs/components/calendar/calendar.js +261 -0
- package/docs/components/calendar/component-skill.md +75 -0
- package/docs/components/card/card.css +55 -0
- package/docs/components/card/component-skill.md +121 -0
- package/docs/components/carousel/carousel.css +153 -0
- package/docs/components/carousel/carousel.js +276 -0
- package/docs/components/carousel/component-skill.md +167 -0
- package/docs/components/checkbox/checkbox.css +121 -0
- package/docs/components/checkbox/component-skill.md +100 -0
- package/docs/components/collapsible/collapsible.css +109 -0
- package/docs/components/collapsible/component-skill.md +32 -0
- package/docs/components/color-picker/color-picker.css +42 -0
- package/docs/components/color-picker/color-picker.js +111 -0
- package/docs/components/color-picker/component-skill.md +43 -0
- package/docs/components/combobox/combobox.css +177 -0
- package/docs/components/combobox/combobox.js +231 -0
- package/docs/components/combobox/component-skill.md +168 -0
- package/docs/components/command/command.css +73 -0
- package/docs/components/command/command.js +219 -0
- package/docs/components/command/component-skill.md +103 -0
- package/docs/components/context-menu/component-skill.md +35 -0
- package/docs/components/context-menu/context-menu.css +75 -0
- package/docs/components/context-menu/context-menu.js +137 -0
- package/docs/components/date-picker/component-skill.md +40 -0
- package/docs/components/date-picker/date-picker.css +60 -0
- package/docs/components/dialog/component-skill.md +110 -0
- package/docs/components/dialog/dialog.css +73 -0
- package/docs/components/dialog/dialog.js +125 -0
- package/docs/components/dropdown/component-skill.md +162 -0
- package/docs/components/dropdown/dropdown.css +148 -0
- package/docs/components/dropdown/dropdown.js +206 -0
- package/docs/components/file-input/component-skill.md +37 -0
- package/docs/components/file-input/file-input.css +66 -0
- package/docs/components/form/component-skill.md +134 -0
- package/docs/components/form/form.css +135 -0
- package/docs/components/icon/component-skill.md +159 -0
- package/docs/components/icon/icon.css +53 -0
- package/docs/components/image/component-skill.md +184 -0
- package/docs/components/image/image.css +174 -0
- package/docs/components/image/image.js +218 -0
- package/docs/components/input/component-skill.md +137 -0
- package/docs/components/input/input.css +153 -0
- package/docs/components/label/component-skill.md +98 -0
- package/docs/components/label/label.css +56 -0
- package/docs/components/navigation-menu/component-skill.md +88 -0
- package/docs/components/navigation-menu/navigation-menu.css +59 -0
- package/docs/components/navigation-menu/navigation-menu.js +119 -0
- package/docs/components/number-input/component-skill.md +41 -0
- package/docs/components/number-input/number-input.css +86 -0
- package/docs/components/number-input/number-input.js +124 -0
- package/docs/components/pagination/component-skill.md +109 -0
- package/docs/components/pagination/pagination.css +51 -0
- package/docs/components/popover/component-skill.md +90 -0
- package/docs/components/popover/popover.css +87 -0
- package/docs/components/popover/popover.js +114 -0
- package/docs/components/progress/component-skill.md +28 -0
- package/docs/components/progress/progress.css +76 -0
- package/docs/components/radio/component-skill.md +140 -0
- package/docs/components/radio/radio.css +210 -0
- package/docs/components/scroll-area/component-skill.md +44 -0
- package/docs/components/scroll-area/scroll-area.css +21 -0
- package/docs/components/select/component-skill.md +69 -0
- package/docs/components/select/select.css +69 -0
- package/docs/components/separator/component-skill.md +93 -0
- package/docs/components/separator/separator.css +65 -0
- package/docs/components/sheet/component-skill.md +121 -0
- package/docs/components/sheet/sheet.css +222 -0
- package/docs/components/sheet/sheet.js +125 -0
- package/docs/components/sidebar/component-skill.md +188 -0
- package/docs/components/sidebar/sidebar.css +352 -0
- package/docs/components/sidebar/sidebar.js +144 -0
- package/docs/components/skeleton/component-skill.md +34 -0
- package/docs/components/skeleton/skeleton.css +43 -0
- package/docs/components/slider/component-skill.md +122 -0
- package/docs/components/slider/slider.css +178 -0
- package/docs/components/slider/slider.js +118 -0
- package/docs/components/sortable/component-skill.md +138 -0
- package/docs/components/sortable/sortable.css +131 -0
- package/docs/components/sortable/sortable.js +301 -0
- package/docs/components/spinner/component-skill.md +34 -0
- package/docs/components/spinner/spinner.css +48 -0
- package/docs/components/statistic/component-skill.md +45 -0
- package/docs/components/statistic/statistic.css +53 -0
- package/docs/components/steps/component-skill.md +183 -0
- package/docs/components/steps/steps.css +95 -0
- package/docs/components/switch/component-skill.md +77 -0
- package/docs/components/switch/switch.css +153 -0
- package/docs/components/table/component-skill.md +51 -0
- package/docs/components/table/table.css +135 -0
- package/docs/components/tabs/component-skill.md +166 -0
- package/docs/components/tabs/tabs.css +123 -0
- package/docs/components/tabs/tabs.js +177 -0
- package/docs/components/textarea/component-skill.md +41 -0
- package/docs/components/textarea/textarea.css +82 -0
- package/docs/components/timeline/component-skill.md +45 -0
- package/docs/components/timeline/timeline.css +78 -0
- package/docs/components/toast/component-skill.md +140 -0
- package/docs/components/toast/toast.css +214 -0
- package/docs/components/toast/toast.js +225 -0
- package/docs/components/toggle/component-skill.md +100 -0
- package/docs/components/toggle/toggle.css +116 -0
- package/docs/components/toggle/toggle.js +112 -0
- package/docs/components/toggle-group/component-skill.md +164 -0
- package/docs/components/toggle-group/toggle-group.css +125 -0
- package/docs/components/toggle-group/toggle-group.js +167 -0
- package/docs/components/toolbar/component-skill.md +83 -0
- package/docs/components/toolbar/toolbar.css +39 -0
- package/docs/components/toolbar/toolbar.js +146 -0
- package/docs/components/tooltip/component-skill.md +108 -0
- package/docs/components/tooltip/tooltip.css +119 -0
- package/docs/components/tooltip/tooltip.js +174 -0
- package/docs/components/tree-view/component-skill.md +63 -0
- package/docs/components/tree-view/tree-view.css +156 -0
- package/docs/components/tree-view/tree-view.js +164 -0
- package/docs/components/typography/component-skill.md +111 -0
- package/docs/components/typography/typography.css +152 -0
- package/docs/documentation/accessibility.html +454 -0
- package/docs/documentation/accordion.html +937 -0
- package/docs/documentation/alert-dialog.html +560 -0
- package/docs/documentation/alert.html +377 -0
- package/docs/documentation/animations.html +398 -0
- package/docs/documentation/avatar.html +600 -0
- package/docs/documentation/badge.html +380 -0
- package/docs/documentation/breadcrumb.html +420 -0
- package/docs/documentation/button-group.html +503 -0
- package/docs/documentation/button.html +629 -0
- package/docs/documentation/calendar.html +733 -0
- package/docs/documentation/card.html +556 -0
- package/docs/documentation/carousel.html +984 -0
- package/docs/documentation/cascade-layers.html +437 -0
- package/docs/documentation/changelog.html +385 -0
- package/docs/documentation/checkbox.html +565 -0
- package/docs/documentation/collapsible.html +407 -0
- package/docs/documentation/color-picker.html +384 -0
- package/docs/documentation/combobox.html +894 -0
- package/docs/documentation/command.html +579 -0
- package/docs/documentation/component-skills.html +294 -0
- package/docs/documentation/context-menu.html +407 -0
- package/docs/documentation/css/docs-theme.css +41 -0
- package/docs/documentation/css/docs-utilities.css +63 -0
- package/docs/documentation/css/layout.css +788 -0
- package/docs/documentation/dark-mode.html +334 -0
- package/docs/documentation/data-attribute-api.html +503 -0
- package/docs/documentation/date-picker.html +318 -0
- package/docs/documentation/dialog.html +781 -0
- package/docs/documentation/dropdown.html +927 -0
- package/docs/documentation/es-modules.html +394 -0
- package/docs/documentation/favicon.svg +12 -0
- package/docs/documentation/file-input.html +319 -0
- package/docs/documentation/fonts/fraunces-300.woff2 +0 -0
- package/docs/documentation/fonts/fraunces-300i.woff2 +0 -0
- package/docs/documentation/fonts/fraunces-400.woff2 +0 -0
- package/docs/documentation/fonts/fraunces-400i.woff2 +0 -0
- package/docs/documentation/fonts/fraunces-500.woff2 +0 -0
- package/docs/documentation/fonts/geist-300.woff2 +0 -0
- package/docs/documentation/fonts/geist-400.woff2 +0 -0
- package/docs/documentation/fonts/geist-500.woff2 +0 -0
- package/docs/documentation/fonts/geist-600.woff2 +0 -0
- package/docs/documentation/fonts/geist-mono-400.woff2 +0 -0
- package/docs/documentation/fonts/geist-mono-500.woff2 +0 -0
- package/docs/documentation/form.html +832 -0
- package/docs/documentation/icon.html +623 -0
- package/docs/documentation/image.html +557 -0
- package/docs/documentation/index.html +303 -0
- package/docs/documentation/input.html +742 -0
- package/docs/documentation/installation.html +230 -0
- package/docs/documentation/js/layout.js +663 -0
- package/docs/documentation/js/shiki-highlight.js +69 -0
- package/docs/documentation/js/site.js +281 -0
- package/docs/documentation/js/theme-switcher.js +143 -0
- package/docs/documentation/js/themes.js +1660 -0
- package/docs/documentation/label.html +480 -0
- package/docs/documentation/native-web-apis.html +285 -0
- package/docs/documentation/navigation-menu.html +507 -0
- package/docs/documentation/number-input.html +429 -0
- package/docs/documentation/pagination.html +501 -0
- package/docs/documentation/popover.html +561 -0
- package/docs/documentation/progress.html +360 -0
- package/docs/documentation/radio.html +786 -0
- package/docs/documentation/scroll-area.html +248 -0
- package/docs/documentation/select.html +378 -0
- package/docs/documentation/separator.html +520 -0
- package/docs/documentation/sheet.html +948 -0
- package/docs/documentation/sidebar.html +933 -0
- package/docs/documentation/skeleton.html +307 -0
- package/docs/documentation/slider.html +683 -0
- package/docs/documentation/sortable.html +897 -0
- package/docs/documentation/spinner.html +315 -0
- package/docs/documentation/statistic.html +416 -0
- package/docs/documentation/steps.html +748 -0
- package/docs/documentation/switch.html +538 -0
- package/docs/documentation/table.html +480 -0
- package/docs/documentation/tabs.html +940 -0
- package/docs/documentation/textarea.html +343 -0
- package/docs/documentation/theming.html +320 -0
- package/docs/documentation/timeline.html +401 -0
- package/docs/documentation/toast.html +844 -0
- package/docs/documentation/toggle-group.html +839 -0
- package/docs/documentation/toggle.html +611 -0
- package/docs/documentation/toolbar.html +487 -0
- package/docs/documentation/tooltip.html +802 -0
- package/docs/documentation/tree-view.html +610 -0
- package/docs/documentation/typography.html +645 -0
- package/docs/robots.txt +4 -0
- package/docs/sitemap.xml +72 -0
- package/docs/theme/default-semantic-tokens.css +137 -0
- package/package.json +34 -73
- package/scripts/build.ts +60 -0
- package/scripts/create-screenshots.ts +226 -0
- package/scripts/deploy.sh +164 -0
- package/scripts/lib/audit.ts +127 -0
- package/scripts/lib/inputs.ts +76 -0
- package/scripts/lib/snippets.ts +57 -0
- package/scripts/push.sh +34 -0
- package/scripts/sync-css-snippets.ts +54 -0
- package/scripts/sync-docs.ts +31 -0
- package/scripts/sync-js-snippets.ts +47 -0
- package/scripts/verify.ts +686 -0
- package/src/components/accordion/accordion.css +82 -0
- package/src/components/accordion/accordion.ts +94 -0
- package/src/components/accordion/component-skill.md +165 -0
- package/src/components/alert/alert.css +67 -0
- package/src/components/alert/component-skill.md +56 -0
- package/src/components/alert-dialog/alert-dialog.css +136 -0
- package/src/components/alert-dialog/alert-dialog.ts +92 -0
- package/src/components/alert-dialog/component-skill.md +56 -0
- package/src/components/avatar/avatar.css +93 -0
- package/src/components/avatar/avatar.ts +84 -0
- package/src/components/avatar/component-skill.md +72 -0
- package/src/components/badge/badge.css +30 -0
- package/src/components/badge/component-skill.md +40 -0
- package/src/components/breadcrumb/breadcrumb.css +47 -0
- package/src/components/breadcrumb/component-skill.md +111 -0
- package/src/components/button/button.css +141 -0
- package/src/components/button/component-skill.md +82 -0
- package/src/components/button-group/button-group.css +98 -0
- package/src/components/button-group/component-skill.md +67 -0
- package/src/components/calendar/calendar.css +187 -0
- package/src/components/calendar/calendar.ts +219 -0
- package/src/components/calendar/component-skill.md +75 -0
- package/src/components/card/card.css +55 -0
- package/src/components/card/component-skill.md +121 -0
- package/src/components/carousel/carousel.css +153 -0
- package/src/components/carousel/carousel.ts +236 -0
- package/src/components/carousel/component-skill.md +167 -0
- package/src/components/checkbox/checkbox.css +121 -0
- package/src/components/checkbox/component-skill.md +100 -0
- package/src/components/collapsible/collapsible.css +109 -0
- package/src/components/collapsible/component-skill.md +32 -0
- package/src/components/color-picker/color-picker.css +42 -0
- package/src/components/color-picker/color-picker.ts +72 -0
- package/src/components/color-picker/component-skill.md +43 -0
- package/src/components/combobox/combobox.css +177 -0
- package/src/components/combobox/combobox.ts +149 -0
- package/src/components/combobox/component-skill.md +168 -0
- package/src/components/command/command.css +73 -0
- package/src/components/command/command.ts +161 -0
- package/src/components/command/component-skill.md +103 -0
- package/src/components/context-menu/component-skill.md +35 -0
- package/src/components/context-menu/context-menu.css +75 -0
- package/src/components/context-menu/context-menu.ts +96 -0
- package/src/components/date-picker/component-skill.md +40 -0
- package/src/components/date-picker/date-picker.css +60 -0
- package/src/components/dialog/component-skill.md +110 -0
- package/src/components/dialog/dialog.css +73 -0
- package/src/components/dialog/dialog.ts +81 -0
- package/src/components/dropdown/component-skill.md +162 -0
- package/src/components/dropdown/dropdown.css +148 -0
- package/src/components/dropdown/dropdown.ts +132 -0
- package/src/components/file-input/component-skill.md +37 -0
- package/src/components/file-input/file-input.css +66 -0
- package/src/components/form/component-skill.md +134 -0
- package/src/components/form/form.css +135 -0
- package/src/components/icon/component-skill.md +159 -0
- package/src/components/icon/icon.css +53 -0
- package/src/components/image/component-skill.md +184 -0
- package/src/components/image/image.css +174 -0
- package/src/components/image/image.ts +181 -0
- package/src/components/input/component-skill.md +137 -0
- package/src/components/input/input.css +153 -0
- package/src/components/label/component-skill.md +98 -0
- package/src/components/label/label.css +56 -0
- package/src/components/navigation-menu/component-skill.md +88 -0
- package/src/components/navigation-menu/navigation-menu.css +59 -0
- package/src/components/navigation-menu/navigation-menu.ts +78 -0
- package/src/components/number-input/component-skill.md +41 -0
- package/src/components/number-input/number-input.css +86 -0
- package/src/components/number-input/number-input.ts +81 -0
- package/src/components/pagination/component-skill.md +109 -0
- package/src/components/pagination/pagination.css +51 -0
- package/src/components/popover/component-skill.md +90 -0
- package/src/components/popover/popover.css +87 -0
- package/src/components/popover/popover.ts +73 -0
- package/src/components/progress/component-skill.md +28 -0
- package/src/components/progress/progress.css +76 -0
- package/src/components/radio/component-skill.md +140 -0
- package/src/components/radio/radio.css +210 -0
- package/src/components/scroll-area/component-skill.md +44 -0
- package/src/components/scroll-area/scroll-area.css +21 -0
- package/src/components/select/component-skill.md +69 -0
- package/src/components/select/select.css +69 -0
- package/src/components/separator/component-skill.md +93 -0
- package/src/components/separator/separator.css +65 -0
- package/src/components/sheet/component-skill.md +121 -0
- package/src/components/sheet/sheet.css +222 -0
- package/src/components/sheet/sheet.ts +81 -0
- package/src/components/sidebar/component-skill.md +188 -0
- package/src/components/sidebar/sidebar.css +352 -0
- package/src/components/sidebar/sidebar.ts +109 -0
- package/src/components/skeleton/component-skill.md +34 -0
- package/src/components/skeleton/skeleton.css +43 -0
- package/src/components/slider/component-skill.md +122 -0
- package/src/components/slider/slider.css +178 -0
- package/src/components/slider/slider.ts +79 -0
- package/src/components/sortable/component-skill.md +138 -0
- package/src/components/sortable/sortable.css +131 -0
- package/src/components/sortable/sortable.ts +269 -0
- package/src/components/spinner/component-skill.md +34 -0
- package/src/components/spinner/spinner.css +48 -0
- package/src/components/statistic/component-skill.md +45 -0
- package/src/components/statistic/statistic.css +53 -0
- package/src/components/steps/component-skill.md +183 -0
- package/src/components/steps/steps.css +95 -0
- package/src/components/switch/component-skill.md +77 -0
- package/src/components/switch/switch.css +153 -0
- package/src/components/table/component-skill.md +51 -0
- package/src/components/table/table.css +135 -0
- package/src/components/tabs/component-skill.md +166 -0
- package/src/components/tabs/tabs.css +123 -0
- package/src/components/tabs/tabs.ts +129 -0
- package/src/components/textarea/component-skill.md +41 -0
- package/src/components/textarea/textarea.css +82 -0
- package/src/components/timeline/component-skill.md +45 -0
- package/src/components/timeline/timeline.css +78 -0
- package/src/components/toast/component-skill.md +140 -0
- package/src/components/toast/toast.css +214 -0
- package/src/components/toast/toast.ts +159 -0
- package/src/components/toggle/component-skill.md +100 -0
- package/src/components/toggle/toggle.css +116 -0
- package/src/components/toggle/toggle.ts +73 -0
- package/src/components/toggle-group/component-skill.md +164 -0
- package/src/components/toggle-group/toggle-group.css +125 -0
- package/src/components/toggle-group/toggle-group.ts +131 -0
- package/src/components/toolbar/component-skill.md +83 -0
- package/src/components/toolbar/toolbar.css +39 -0
- package/src/components/toolbar/toolbar.ts +109 -0
- package/src/components/tooltip/component-skill.md +108 -0
- package/src/components/tooltip/tooltip.css +119 -0
- package/src/components/tooltip/tooltip.ts +135 -0
- package/src/components/tree-view/component-skill.md +63 -0
- package/src/components/tree-view/tree-view.css +156 -0
- package/src/components/tree-view/tree-view.ts +118 -0
- package/src/components/typography/component-skill.md +111 -0
- package/src/components/typography/typography.css +152 -0
- package/src/documentation/accessibility.html +454 -0
- package/src/documentation/accordion.html +937 -0
- package/src/documentation/alert-dialog.html +560 -0
- package/src/documentation/alert.html +377 -0
- package/src/documentation/animations.html +398 -0
- package/src/documentation/avatar.html +600 -0
- package/src/documentation/badge.html +380 -0
- package/src/documentation/breadcrumb.html +420 -0
- package/src/documentation/button-group.html +503 -0
- package/src/documentation/button.html +629 -0
- package/src/documentation/calendar.html +733 -0
- package/src/documentation/card.html +556 -0
- package/src/documentation/carousel.html +984 -0
- package/src/documentation/cascade-layers.html +437 -0
- package/src/documentation/changelog.html +385 -0
- package/src/documentation/checkbox.html +565 -0
- package/src/documentation/collapsible.html +407 -0
- package/src/documentation/color-picker.html +384 -0
- package/src/documentation/combobox.html +894 -0
- package/src/documentation/command.html +579 -0
- package/src/documentation/component-skills.html +294 -0
- package/src/documentation/context-menu.html +407 -0
- package/src/documentation/css/docs-theme.css +41 -0
- package/src/documentation/css/docs-utilities.css +63 -0
- package/src/documentation/css/layout.css +788 -0
- package/src/documentation/dark-mode.html +334 -0
- package/src/documentation/data-attribute-api.html +503 -0
- package/src/documentation/date-picker.html +318 -0
- package/src/documentation/dialog.html +781 -0
- package/src/documentation/dropdown.html +927 -0
- package/src/documentation/es-modules.html +394 -0
- package/src/documentation/favicon.svg +12 -0
- package/src/documentation/file-input.html +319 -0
- package/src/documentation/fonts/fraunces-300.woff2 +0 -0
- package/src/documentation/fonts/fraunces-300i.woff2 +0 -0
- package/src/documentation/fonts/fraunces-400.woff2 +0 -0
- package/src/documentation/fonts/fraunces-400i.woff2 +0 -0
- package/src/documentation/fonts/fraunces-500.woff2 +0 -0
- package/src/documentation/fonts/geist-300.woff2 +0 -0
- package/src/documentation/fonts/geist-400.woff2 +0 -0
- package/src/documentation/fonts/geist-500.woff2 +0 -0
- package/src/documentation/fonts/geist-600.woff2 +0 -0
- package/src/documentation/fonts/geist-mono-400.woff2 +0 -0
- package/src/documentation/fonts/geist-mono-500.woff2 +0 -0
- package/src/documentation/form.html +832 -0
- package/src/documentation/icon.html +623 -0
- package/src/documentation/image.html +557 -0
- package/src/documentation/index.html +303 -0
- package/src/documentation/input.html +742 -0
- package/src/documentation/installation.html +230 -0
- package/src/documentation/js/layout.ts +685 -0
- package/src/documentation/js/shiki-highlight.ts +83 -0
- package/src/documentation/js/site.ts +296 -0
- package/src/documentation/js/theme-switcher.ts +158 -0
- package/src/documentation/js/themes.ts +1661 -0
- package/src/documentation/label.html +480 -0
- package/src/documentation/native-web-apis.html +285 -0
- package/src/documentation/navigation-menu.html +507 -0
- package/src/documentation/number-input.html +429 -0
- package/src/documentation/pagination.html +501 -0
- package/src/documentation/popover.html +561 -0
- package/src/documentation/progress.html +360 -0
- package/src/documentation/radio.html +786 -0
- package/src/documentation/scroll-area.html +248 -0
- package/src/documentation/select.html +378 -0
- package/src/documentation/separator.html +520 -0
- package/src/documentation/sheet.html +948 -0
- package/src/documentation/sidebar.html +933 -0
- package/src/documentation/skeleton.html +307 -0
- package/src/documentation/slider.html +683 -0
- package/src/documentation/sortable.html +897 -0
- package/src/documentation/spinner.html +315 -0
- package/src/documentation/statistic.html +416 -0
- package/src/documentation/steps.html +748 -0
- package/src/documentation/switch.html +538 -0
- package/src/documentation/table.html +480 -0
- package/src/documentation/tabs.html +940 -0
- package/src/documentation/textarea.html +343 -0
- package/src/documentation/theming.html +320 -0
- package/src/documentation/timeline.html +401 -0
- package/src/documentation/toast.html +844 -0
- package/src/documentation/toggle-group.html +839 -0
- package/src/documentation/toggle.html +611 -0
- package/src/documentation/toolbar.html +487 -0
- package/src/documentation/tooltip.html +802 -0
- package/src/documentation/tree-view.html +610 -0
- package/src/documentation/typography.html +645 -0
- package/src/robots.txt +4 -0
- package/src/shared/state-api.ts +43 -0
- package/src/sitemap.xml +72 -0
- package/src/theme/default-semantic-tokens.css +137 -0
- package/src/types/defuss-shadcn.d.ts +67 -0
- package/tests/e2e/accordion.e2e-fixture.html +152 -0
- package/tests/e2e/accordion.e2e.ts +186 -0
- package/tests/e2e/alert-dialog.e2e-fixture.html +28 -0
- package/tests/e2e/alert-dialog.e2e.ts +131 -0
- package/tests/e2e/alert.e2e-fixture.html +27 -0
- package/tests/e2e/alert.e2e.ts +37 -0
- package/tests/e2e/avatar.e2e-fixture.html +31 -0
- package/tests/e2e/avatar.e2e.ts +129 -0
- package/tests/e2e/badge.e2e-fixture.html +17 -0
- package/tests/e2e/badge.e2e.ts +35 -0
- package/tests/e2e/breadcrumb.e2e-fixture.html +21 -0
- package/tests/e2e/breadcrumb.e2e.ts +31 -0
- package/tests/e2e/button-group.e2e-fixture.html +28 -0
- package/tests/e2e/button-group.e2e.ts +51 -0
- package/tests/e2e/button.e2e-fixture.html +29 -0
- package/tests/e2e/button.e2e.ts +80 -0
- package/tests/e2e/calendar.e2e-fixture.html +22 -0
- package/tests/e2e/calendar.e2e.ts +193 -0
- package/tests/e2e/card.e2e-fixture.html +28 -0
- package/tests/e2e/card.e2e.ts +50 -0
- package/tests/e2e/carousel.e2e-fixture.html +34 -0
- package/tests/e2e/carousel.e2e.ts +160 -0
- package/tests/e2e/checkbox.e2e-fixture.html +41 -0
- package/tests/e2e/checkbox.e2e.ts +75 -0
- package/tests/e2e/collapsible.e2e-fixture.html +27 -0
- package/tests/e2e/collapsible.e2e.ts +36 -0
- package/tests/e2e/color-picker.e2e-fixture.html +24 -0
- package/tests/e2e/color-picker.e2e.ts +113 -0
- package/tests/e2e/combobox.e2e-fixture.html +58 -0
- package/tests/e2e/combobox.e2e.ts +217 -0
- package/tests/e2e/command.e2e-fixture.html +40 -0
- package/tests/e2e/command.e2e.ts +142 -0
- package/tests/e2e/context-menu.e2e-fixture.html +22 -0
- package/tests/e2e/context-menu.e2e.ts +143 -0
- package/tests/e2e/date-picker.e2e-fixture.html +14 -0
- package/tests/e2e/date-picker.e2e.ts +19 -0
- package/tests/e2e/dialog.e2e-fixture.html +39 -0
- package/tests/e2e/dialog.e2e.ts +141 -0
- package/tests/e2e/dropdown.e2e-fixture.html +41 -0
- package/tests/e2e/dropdown.e2e.ts +207 -0
- package/tests/e2e/file-input.e2e-fixture.html +14 -0
- package/tests/e2e/file-input.e2e.ts +33 -0
- package/tests/e2e/form.e2e-fixture.html +35 -0
- package/tests/e2e/form.e2e.ts +41 -0
- package/tests/e2e/icon.e2e-fixture.html +19 -0
- package/tests/e2e/icon.e2e.ts +44 -0
- package/tests/e2e/image.e2e-fixture.html +36 -0
- package/tests/e2e/image.e2e.ts +164 -0
- package/tests/e2e/input.e2e-fixture.html +18 -0
- package/tests/e2e/input.e2e.ts +61 -0
- package/tests/e2e/label.e2e-fixture.html +21 -0
- package/tests/e2e/label.e2e.ts +32 -0
- package/tests/e2e/lib/css-smoke.ts +91 -0
- package/tests/e2e/navigation-menu.e2e-fixture.html +37 -0
- package/tests/e2e/navigation-menu.e2e.ts +131 -0
- package/tests/e2e/number-input.e2e-fixture.html +25 -0
- package/tests/e2e/number-input.e2e.ts +139 -0
- package/tests/e2e/pagination.e2e-fixture.html +22 -0
- package/tests/e2e/pagination.e2e.ts +46 -0
- package/tests/e2e/popover.e2e-fixture.html +45 -0
- package/tests/e2e/popover.e2e.ts +141 -0
- package/tests/e2e/progress.e2e-fixture.html +15 -0
- package/tests/e2e/progress.e2e.ts +39 -0
- package/tests/e2e/radio.e2e-fixture.html +43 -0
- package/tests/e2e/radio.e2e.ts +75 -0
- package/tests/e2e/run.ts +32 -0
- package/tests/e2e/scroll-area.e2e-fixture.html +15 -0
- package/tests/e2e/scroll-area.e2e.ts +29 -0
- package/tests/e2e/select.e2e-fixture.html +28 -0
- package/tests/e2e/select.e2e.ts +51 -0
- package/tests/e2e/separator.e2e-fixture.html +24 -0
- package/tests/e2e/separator.e2e.ts +37 -0
- package/tests/e2e/server.ts +42 -0
- package/tests/e2e/sheet.e2e-fixture.html +56 -0
- package/tests/e2e/sheet.e2e.ts +195 -0
- package/tests/e2e/sidebar.e2e-fixture.html +39 -0
- package/tests/e2e/sidebar.e2e.ts +141 -0
- package/tests/e2e/skeleton.e2e-fixture.html +14 -0
- package/tests/e2e/skeleton.e2e.ts +30 -0
- package/tests/e2e/slider.e2e-fixture.html +23 -0
- package/tests/e2e/slider.e2e.ts +158 -0
- package/tests/e2e/sortable.e2e-fixture.html +25 -0
- package/tests/e2e/sortable.e2e.ts +191 -0
- package/tests/e2e/spinner.e2e-fixture.html +16 -0
- package/tests/e2e/spinner.e2e.ts +40 -0
- package/tests/e2e/statistic.e2e-fixture.html +25 -0
- package/tests/e2e/statistic.e2e.ts +38 -0
- package/tests/e2e/steps.e2e-fixture.html +40 -0
- package/tests/e2e/steps.e2e.ts +56 -0
- package/tests/e2e/switch.e2e-fixture.html +17 -0
- package/tests/e2e/switch.e2e.ts +68 -0
- package/tests/e2e/table.e2e-fixture.html +35 -0
- package/tests/e2e/table.e2e.ts +44 -0
- package/tests/e2e/tabs.e2e-fixture.html +34 -0
- package/tests/e2e/tabs.e2e.ts +142 -0
- package/tests/e2e/textarea.e2e-fixture.html +15 -0
- package/tests/e2e/textarea.e2e.ts +41 -0
- package/tests/e2e/timeline.e2e-fixture.html +27 -0
- package/tests/e2e/timeline.e2e.ts +39 -0
- package/tests/e2e/toast.e2e-fixture.html +29 -0
- package/tests/e2e/toast.e2e.ts +184 -0
- package/tests/e2e/toggle-group.e2e-fixture.html +45 -0
- package/tests/e2e/toggle-group.e2e.ts +169 -0
- package/tests/e2e/toggle.e2e-fixture.html +20 -0
- package/tests/e2e/toggle.e2e.ts +136 -0
- package/tests/e2e/toolbar.e2e-fixture.html +42 -0
- package/tests/e2e/toolbar.e2e.ts +161 -0
- package/tests/e2e/tooltip.e2e-fixture.html +43 -0
- package/tests/e2e/tooltip.e2e.ts +151 -0
- package/tests/e2e/tree-view.e2e-fixture.html +45 -0
- package/tests/e2e/tree-view.e2e.ts +206 -0
- package/tests/e2e/typography.e2e-fixture.html +24 -0
- package/tests/e2e/typography.e2e.ts +70 -0
- package/tests/helpers.ts +68 -0
- package/tests/ui.test.ts +83 -0
- package/tsconfig.json +25 -0
- package/tsconfig.scripts.json +18 -0
- package/tsconfig.test.json +14 -0
- package/vite.config.ts +22 -0
- package/vitest.config.ts +23 -0
- package/dist/css/shadcn.cdn.css +0 -4336
- package/dist/css/shadcn.cdn.min.css +0 -2
- package/dist/index.cjs +0 -6408
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -527
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.mts +0 -527
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs +0 -6285
- package/dist/index.mjs.map +0 -1
package/AGENTS.md
ADDED
|
@@ -0,0 +1,877 @@
|
|
|
1
|
+
# defuss-shadcn — Maintainer Instructions
|
|
2
|
+
|
|
3
|
+
Scratch space: throwaway scripts, probes and scaffolds go in the repo-local
|
|
4
|
+
`tmp/` (gitignored) — never `/tmp` or other machine-specific locations. This
|
|
5
|
+
keeps everything relative to the repo root (see the `portable paths` verify
|
|
6
|
+
check) and inspectable. **Write the file with the file-writing tool and run it
|
|
7
|
+
with `bun tmp/<script>.ts` from the repo root** — do not build scripts through
|
|
8
|
+
`python3 - <<'PY'`/heredoc rewrites, which get permission-blocked and are
|
|
9
|
+
harder to iterate on than editing the file directly.
|
|
10
|
+
|
|
11
|
+
Long-running commands: always run e2e tests, screenshot generation, builds and
|
|
12
|
+
browser tooling with a **timeout** (execute_command's `timeout` parameter, or
|
|
13
|
+
`--timeout`/`PAGE_TIMEOUT_MS` inside the scripts). A stalled Chromium session
|
|
14
|
+
must surface as a failure with output, never as an agent hanging forever.
|
|
15
|
+
|
|
16
|
+
You are working on the **defuss-shadcn** design system repo.
|
|
17
|
+
The consumer-facing system lives in `dist/` — **it is generated**: edit sources in
|
|
18
|
+
`src/` (`bun run build` compiles `.ts` → `.js` and copies everything else 1:1).
|
|
19
|
+
`docs/` is also generated: a 1:1 mirror of `dist/` (whole tree — Pages pages reference
|
|
20
|
+
`../components/…` siblings) published by GitHub Pages; refresh it with `bun run docs`
|
|
21
|
+
(`make build` does this automatically and `verify` fails if the mirror drifts). Never
|
|
22
|
+
edit `docs/` directly — like `dist/`, it is deleted and rebuilt on every `bun run docs`.
|
|
23
|
+
Never edit `dist/` directly; it is deleted and rebuilt on every build.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Project structure
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
defuss-shadcn/
|
|
31
|
+
├── dist/ ← the distributable (drop into any project)
|
|
32
|
+
│ ├── theme/default-semantic-tokens.css ← design tokens (source of truth for colors, radius, shadows)
|
|
33
|
+
│ ├── components/ ← self-contained component folders
|
|
34
|
+
│ │ └── {name}/
|
|
35
|
+
│ │ ├── component-skill.md ← component skill (HTML structure & ARIA reference)
|
|
36
|
+
│ │ ├── {name}.css ← component stylesheet (edit directly)
|
|
37
|
+
│ │ └── {name}.js ← interaction JS (only for interactive components)
|
|
38
|
+
│ └── documentation/ ← reference implementations + public website
|
|
39
|
+
│ ├── *.html ← one page per component + overview pages
|
|
40
|
+
│ ├── css/docs-utilities.css ← hand-written utility classes for doc pages
|
|
41
|
+
│ ├── css/docs-theme.css ← doc-site font overrides (not part of the system)
|
|
42
|
+
│ ├── css/layout.css ← doc-site layout (not part of the system)
|
|
43
|
+
│ ├── js/layout.js ← SPA router, <site-header>/<site-nav> web components
|
|
44
|
+
│ ├── js/site.js ← doc-site-only JS (tabs, copy buttons, skill modal, code collapse)
|
|
45
|
+
│ ├── js/shiki-highlight.js ← Shiki-based syntax highlighting (ES module, CDN)
|
|
46
|
+
│ ├── js/themes.js ← tweakcn color theme presets (global THEMES array)
|
|
47
|
+
│ └── js/theme-switcher.js ← applies theme overrides to CSS custom properties
|
|
48
|
+
│
|
|
49
|
+
├── .github/
|
|
50
|
+
│ ├── instructions/ ← auto-attached instruction files for Copilot
|
|
51
|
+
│ │ ├── documentation.instructions.md
|
|
52
|
+
│ │ ├── specifications.instructions.md
|
|
53
|
+
│ │ └── tokens.instructions.md
|
|
54
|
+
│ └── prompts/ ← reusable prompt files
|
|
55
|
+
│ └── component-review.prompt.md
|
|
56
|
+
│
|
|
57
|
+
├── screenshots/ ← generated default-state PNGs per component in light/ + dark/ (`bun run screenshots`, gitignored)
|
|
58
|
+
├── scripts/ ← build & maintenance scripts (no one-shot migrations)
|
|
59
|
+
│ ├── build.ts ← src/ → dist/ (tsc type-strip + copy everything else 1:1)
|
|
60
|
+
│ ├── verify.ts ← static consistency gate (runs at end of build; `bun run verify`)
|
|
61
|
+
│ ├── sync-docs.ts ← mirror dist/ → docs/ for GitHub Pages (`bun run docs`)
|
|
62
|
+
│ ├── create-screenshots.ts ← parallel default-state screenshots for agent inspection
|
|
63
|
+
│ ├── lib/audit.ts ← undefined-utility audit (used by verify)
|
|
64
|
+
│ ├── lib/snippets.ts ← shared snippet drift/replace logic (syncers + verify)
|
|
65
|
+
│ ├── sync-css-snippets.ts ← re-embed component CSS into doc pages after edits
|
|
66
|
+
│ ├── sync-js-snippets.ts ← re-embed component JS into doc pages after edits
|
|
67
|
+
│ ├── push.sh ← commit + push dev → main (non-release)
|
|
68
|
+
│ └── deploy.sh ← release: version bump, changelog, tag, GitHub release
|
|
69
|
+
├── tests/ ← UI tests (Vitest browser mode + Playwright)
|
|
70
|
+
│ ├── helpers.ts ← loads real doc pages in a same-origin iframe
|
|
71
|
+
│ ├── ui.test.ts ← end-to-end tests of the actual site UI
|
|
72
|
+
│ └── e2e/ ← per-component smoke tests (plain Playwright)
|
|
73
|
+
│ ├── run.ts ← `bun run e2e` runner: every *.e2e.ts file
|
|
74
|
+
│ ├── server.ts ← Bun static server exposing /dist and /tests/e2e
|
|
75
|
+
│ └── accordion.e2e-{fixture.html,ts} ← fixture + test for one component
|
|
76
|
+
├── vitest.config.ts ← browser-mode test config (root = repo root)
|
|
77
|
+
├── Makefile ← setup / dev / test / e2e / build shortcuts (wrappers for bun scripts)
|
|
78
|
+
│
|
|
79
|
+
└── AGENTS.md ← this file (maintainer instructions)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Critical rules
|
|
85
|
+
|
|
86
|
+
### The verifier is authoritative
|
|
87
|
+
|
|
88
|
+
`bun run verify` is the single source of truth for "is this done?". Its
|
|
89
|
+
output — including every `fix:` line it prints on failure — overrides any
|
|
90
|
+
interpretation of this file: when prose and verifier disagree, the verifier
|
|
91
|
+
wins and its `fix:` line is the work to do. A build is only ever as good as
|
|
92
|
+
its last green `verify` run; there is no flag that skips the gate. (The
|
|
93
|
+
warn-ratchets it still reports, e.g. `STATE_API_LEGACY`, are named migration
|
|
94
|
+
debt with an explicit removal path — not permission to ignore them.) The
|
|
95
|
+
full rationale lives in [ARCH.md](ARCH.md).
|
|
96
|
+
|
|
97
|
+
### Native web platform first
|
|
98
|
+
|
|
99
|
+
Every component starts from a native HTML element or browser API. If the browser
|
|
100
|
+
can do it, we don't write JavaScript for it.
|
|
101
|
+
|
|
102
|
+
**HTML elements & attributes**
|
|
103
|
+
|
|
104
|
+
- Use `<dialog>` for modals — not divs with JS show/hide
|
|
105
|
+
- Use `popover` API for dropdowns, tooltips, toasts — not JS positioning
|
|
106
|
+
- Use `popover="hint"` for tooltips — not `popover="auto"` (hints don't
|
|
107
|
+
close other popovers)
|
|
108
|
+
- Use `<details>/<summary>` for accordions — not JS toggle logic
|
|
109
|
+
- Use `<details name="group">` for exclusive (single-open) accordions — not
|
|
110
|
+
JS that closes siblings
|
|
111
|
+
- Use `commandfor` / `command` attributes for declarative button→dialog/popover
|
|
112
|
+
triggers — not JS click handlers that call `showModal()` or `togglePopover()`
|
|
113
|
+
- Use `<progress>` for completion indicators — not div-based progress bars
|
|
114
|
+
- Use `<meter>` for scalar values in a range — not custom gauge components
|
|
115
|
+
- Use `<output>` for computed/live results — not manual `aria-live` regions
|
|
116
|
+
- Use `inert` attribute to disable interaction on background content — not
|
|
117
|
+
JS focus traps or `aria-hidden` toggling
|
|
118
|
+
- Use `loading="lazy"` for images/iframes — not JS lazy load libraries
|
|
119
|
+
- Use `autofocus` in dialogs/popovers — not JS `.focus()` calls
|
|
120
|
+
- Use `inputmode` for mobile keyboard hints — not separate input types
|
|
121
|
+
- Use `enterkeyhint` for mobile Enter key labels (`search`, `send`, `go`)
|
|
122
|
+
- Use `autocomplete` with proper field names — not custom autofill
|
|
123
|
+
- Use `<datalist>` for native type-ahead suggestions — not custom dropdowns
|
|
124
|
+
- Use `fetchpriority` for resource priority hints (`high`/`low`)
|
|
125
|
+
- Use `disabled` / `readonly` for native form states — not JS class toggling
|
|
126
|
+
|
|
127
|
+
**CSS**
|
|
128
|
+
|
|
129
|
+
- Use `@starting-style` + `transition-behavior: allow-discrete` for
|
|
130
|
+
enter/exit animations on `display: none` elements — not JS class toggling
|
|
131
|
+
- Use CSS anchor positioning for popover placement — not Floating UI / Popper
|
|
132
|
+
- Use `::backdrop` + `backdrop-filter` for dialog/sheet overlays — not
|
|
133
|
+
JS-managed overlay divs or canvas blur
|
|
134
|
+
- Use `:has()` for parent-state reactions — not JS class propagation
|
|
135
|
+
- Use `:focus-visible` for keyboard-only focus rings — not JS focus detection
|
|
136
|
+
- Use `:user-valid` / `:user-invalid` for post-interaction validation
|
|
137
|
+
styling — not JS blur listeners with class toggling
|
|
138
|
+
- Use `field-sizing: content` for auto-growing textareas — not JS resize
|
|
139
|
+
- Use `oklch()` and relative color syntax for wide-gamut, derived colors — not
|
|
140
|
+
hardcoded hex/hsl palettes
|
|
141
|
+
- Use `color-mix(in oklch, ...)` for hover/disabled color derivation — not
|
|
142
|
+
Sass `darken()`/`lighten()` or hardcoded variants
|
|
143
|
+
- Use `light-dark()` for inline dark mode values — not media queries or
|
|
144
|
+
class toggles when `color-scheme` is already set
|
|
145
|
+
- Use `color-scheme` property for dark mode browser defaults — not all-manual
|
|
146
|
+
dark overrides on every native element
|
|
147
|
+
- Use `accent-color` for theming native form controls — not custom replacements
|
|
148
|
+
- Use `text-wrap: balance` for headings and labels — not JS text-balancing
|
|
149
|
+
- Use `text-wrap: pretty` for body text orphan prevention — not manual ` `
|
|
150
|
+
- Use `overscroll-behavior: contain` on scroll containers inside overlays — not
|
|
151
|
+
JS scroll-lock libraries
|
|
152
|
+
- Use `scroll-snap` for carousel/slider snap points — not JS snap calculations
|
|
153
|
+
- Use `scrollbar-gutter: stable` to prevent layout shift from scrollbars — not
|
|
154
|
+
padding hacks
|
|
155
|
+
- Use individual transform properties (`rotate`, `scale`, `translate`) — not
|
|
156
|
+
compound `transform` strings
|
|
157
|
+
- Use CSS nesting, `@layer`, container queries — not preprocessors
|
|
158
|
+
- Use `aspect-ratio` for intrinsic ratios — not padding-bottom hacks
|
|
159
|
+
- Use `content-visibility` for expand/collapse transitions — not JS lazy rendering
|
|
160
|
+
- Use `interpolate-size: allow-keywords` for animating to `auto` height — not
|
|
161
|
+
JS measurement or `max-height` hacks
|
|
162
|
+
- Use `@property` for typed, animatable custom properties — not JS animation
|
|
163
|
+
of CSS values
|
|
164
|
+
- Use scroll-driven animations (`animation-timeline: scroll()` / `view()`) for
|
|
165
|
+
scroll-linked effects — not scroll listeners or IntersectionObserver
|
|
166
|
+
- Use View Transitions API for smooth DOM state changes — not JS crossfades
|
|
167
|
+
- Use `@supports` for CSS feature detection — not Modernizr or JS detection
|
|
168
|
+
- Use logical properties (`margin-inline`, `padding-block`) for RTL support — not
|
|
169
|
+
separate LTR/RTL stylesheets
|
|
170
|
+
- Use subgrid for aligned child layouts — not manually synchronized columns
|
|
171
|
+
- Use dynamic viewport units (`dvh`, `svh`, `lvh`) — not JS `innerHeight` hacks
|
|
172
|
+
- Use CSS math functions (`clamp()`, `min()`, `max()`) for responsive sizing — not
|
|
173
|
+
JS resize calculations
|
|
174
|
+
- Use `:is()` / `:where()` for selector grouping — not repeated selectors
|
|
175
|
+
- Use `hanging-punctuation` for optical quote alignment — not negative text-indent
|
|
176
|
+
- Use `@layer` + descriptive prefixed class names (`card-header`, `slider-track`) for
|
|
177
|
+
style scoping — not `@scope` (generic class names lose context for AI generation)
|
|
178
|
+
or Shadow DOM
|
|
179
|
+
- Use `@media (scripting)` for no-JS progressive enhancement — not `<noscript>` alone
|
|
180
|
+
|
|
181
|
+
**Accessibility (REQUIRED)**
|
|
182
|
+
|
|
183
|
+
- Use `prefers-reduced-motion: reduce` to suppress/simplify all animations — not
|
|
184
|
+
ignoring motion preferences (this is an accessibility requirement, not optional)
|
|
185
|
+
- Use `prefers-contrast: more` to increase contrast when requested
|
|
186
|
+
- Use `forced-colors: active` to support Windows High Contrast Mode with system colors
|
|
187
|
+
- Use `prefers-color-scheme` for automatic dark mode defaults
|
|
188
|
+
|
|
189
|
+
**JavaScript (only when HTML/CSS cannot express it)**
|
|
190
|
+
|
|
191
|
+
- Use Web Animations API (`el.animate()`) for imperative animations — not CSS
|
|
192
|
+
class toggling when JS needs to coordinate timing
|
|
193
|
+
- Use `Intl` APIs (`DateTimeFormat`, `NumberFormat`, `RelativeTimeFormat`,
|
|
194
|
+
`ListFormat`) for locale-aware formatting — not moment.js or date-fns
|
|
195
|
+
- Use native Drag and Drop API for reordering — not SortableJS or drag libraries
|
|
196
|
+
- Use `CustomEvent` for component-to-component communication — not framework
|
|
197
|
+
event systems
|
|
198
|
+
- Use `element.checkVisibility()` for visibility detection — not manual
|
|
199
|
+
offset calculations
|
|
200
|
+
- Use `IntersectionObserver` for viewport-entry detection — not scroll listeners
|
|
201
|
+
with `getBoundingClientRect()`
|
|
202
|
+
- Use `ResizeObserver` for element size changes — not window resize listeners
|
|
203
|
+
- Use `MutationObserver` for DOM change reactions — not polling loops
|
|
204
|
+
- Use `navigator.clipboard` for clipboard access — not `document.execCommand('copy')`
|
|
205
|
+
- Use `CloseWatcher` for platform close signals in custom UI — not manual
|
|
206
|
+
Escape key listeners
|
|
207
|
+
- Use `AbortController` for canceling fetches/listeners — not boolean flags
|
|
208
|
+
- Use `FormData` for form serialization — not manual value collection loops
|
|
209
|
+
- Use `structuredClone()` for deep cloning — not `JSON.parse(JSON.stringify())`
|
|
210
|
+
- Use `ElementInternals` for custom form elements — not hidden input proxies
|
|
211
|
+
- Use Navigation API for SPA routing — not History API hacks
|
|
212
|
+
|
|
213
|
+
JavaScript is only for behavior that HTML and CSS cannot express: keyboard
|
|
214
|
+
navigation patterns, focus management, and state coordination between elements.
|
|
215
|
+
Use modern ECMAScript (ES modules, arrow functions, `const`/`let`, etc.) —
|
|
216
|
+
no libraries, no frameworks.
|
|
217
|
+
|
|
218
|
+
All `querySelectorAll` loops that add event listeners **must** guard against
|
|
219
|
+
double-initialization using `:not([data-init])` in the selector and setting
|
|
220
|
+
`element.dataset.init = ''` as the first line inside the loop.
|
|
221
|
+
|
|
222
|
+
Component JS files wrap initialization in an `init()` function, call it once,
|
|
223
|
+
then use a `MutationObserver` to auto-initialize new elements after SPA
|
|
224
|
+
navigation or dynamic DOM changes:
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
function init() {
|
|
228
|
+
document.querySelectorAll('.my-component:not([data-init])').forEach((el) => {
|
|
229
|
+
el.dataset.init = '';
|
|
230
|
+
el.addEventListener('click', () => { /* … */ });
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
init();
|
|
235
|
+
new MutationObserver(init).observe(document, { childList: true, subtree: true });
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
For document-level event delegation (no per-element loop), use a global flag:
|
|
239
|
+
```js
|
|
240
|
+
if (!document.__myComponentInit) {
|
|
241
|
+
document.__myComponentInit = true;
|
|
242
|
+
document.addEventListener('click', (e) => { /* … */ });
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### No window globals (REQUIRED)
|
|
247
|
+
|
|
248
|
+
Never define or read application globals on `window` — use `globalThis`, and keep
|
|
249
|
+
every name under the single namespace `globalThis._defussShadcn`:
|
|
250
|
+
|
|
251
|
+
```js
|
|
252
|
+
globalThis._defussShadcn = globalThis._defussShadcn || {}; // idempotent bootstrap
|
|
253
|
+
globalThis._defussShadcn.toast = { show, success, dismiss }; // public imperative API
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
- Components expose their State API as `_defussShadcn.{name}Api` / `{name}States`
|
|
257
|
+
(see "State API" below); a component's additional public imperative API lives
|
|
258
|
+
under `_defussShadcn.{name}` — never as a bare global. Example: the toast
|
|
259
|
+
factory is `_defussShadcn.toast.show(...)`, **not** `window.toast = { … }`.
|
|
260
|
+
- Doc-site-only scripts (not shipped) share the same discipline under
|
|
261
|
+
`_defussShadcn.docs` (theme registry, SPA hooks: `THEMES`, `applyTheme`,
|
|
262
|
+
`onPageReady`, …).
|
|
263
|
+
- Third-party CDN globals (`lucide`, `marked`) are owned by their vendors — read
|
|
264
|
+
them via `globalThis.*`; never assign to `window`.
|
|
265
|
+
|
|
266
|
+
**Why:** `window` is a browser-only alias; `globalThis` is the one canonical
|
|
267
|
+
global object and works unchanged in Workers and other runtimes (see the
|
|
268
|
+
isomorphic rule). Scoping everything under `_defussShadcn` keeps a
|
|
269
|
+
copy-paste/CDN-shipped system collision-free on hosts we do not control.
|
|
270
|
+
`scripts/verify.ts` fails the build on any `window.x =` assignment in `src/`.
|
|
271
|
+
|
|
272
|
+
### Each component is a self-contained folder
|
|
273
|
+
|
|
274
|
+
Each component at `dist/components/{name}/` contains:
|
|
275
|
+
- `component-skill.md` — component skill: HTML structure, attributes, ARIA, and usage notes
|
|
276
|
+
- `{name}.css` — the component stylesheet (edit directly)
|
|
277
|
+
- `{name}.js` — interaction JS (only for interactive components, edit directly)
|
|
278
|
+
|
|
279
|
+
The component skill `.md` file documents **how to build the HTML**. The `.css` and `.js` files
|
|
280
|
+
are the actual implementation — edit them directly, no build step needed.
|
|
281
|
+
|
|
282
|
+
### State API (REQUIRED for every JS component)
|
|
283
|
+
|
|
284
|
+
Components with a `.js` file have observable UI states (open/closed, collapsed,
|
|
285
|
+
selected…). Every such component must expose its states **by name** so agents and
|
|
286
|
+
tests can drive them without knowing the implementation:
|
|
287
|
+
|
|
288
|
+
```js
|
|
289
|
+
document.querySelector('#x').api.setState('open', { /* config */ });
|
|
290
|
+
document.querySelector('#x').api.getState(); // → { name: 'open', config: { … } }
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Required shape of `{name}.js`** (verify.ts enforces these markers by regex;
|
|
294
|
+
`accordion.ts` and `dialog.ts` are the reference implementations):
|
|
295
|
+
|
|
296
|
+
1. **Preamble** — import the shared helper (single source in
|
|
297
|
+
`src/shared/state-api.ts`; `build.ts` inlines it into the shipped `.js`,
|
|
298
|
+
so dist components stay isolated single files):
|
|
299
|
+
```js
|
|
300
|
+
import { defussGlobals } from '../../shared/state-api.js';
|
|
301
|
+
const _defussShadcn = defussGlobals();
|
|
302
|
+
```
|
|
303
|
+
2. **State list** — `const {name}States = ['default', …]` — `'default'` must be
|
|
304
|
+
the first entry and always be one of the declared states. Every component
|
|
305
|
+
starts in its `default` state unless markup declares otherwise.
|
|
306
|
+
3. **`triggerStateChange(el, stateName, config)`** — the only function that
|
|
307
|
+
touches the DOM for a state change; `switch`/dispatch over the declared states.
|
|
308
|
+
4. **Registry API** — `export const {name}Api = { setState(el, name, config), getState(el) }`
|
|
309
|
+
with the element passed explicitly; reject unknown state names by throwing.
|
|
310
|
+
Register both globals:
|
|
311
|
+
```js
|
|
312
|
+
globalThis._defussShadcn.{name}Api = {name}Api;
|
|
313
|
+
globalThis._defussShadcn.{name}States = {name}States;
|
|
314
|
+
```
|
|
315
|
+
5. **Per-instance binding** inside `init()`, on each element the component
|
|
316
|
+
initializes (state lives **on the element** — `dataset.stateName` +
|
|
317
|
+
`_stateConfig` — never in module scope; 26 components share one page and each
|
|
318
|
+
instance may hold a different state):
|
|
319
|
+
```js
|
|
320
|
+
el.api = {
|
|
321
|
+
setState: (stateName, config) => {name}Api.setState(el, stateName, config),
|
|
322
|
+
getState: () => {name}Api.getState(el),
|
|
323
|
+
};
|
|
324
|
+
```
|
|
325
|
+
6. **Document the states** in the component skill (`component-skill.md` →
|
|
326
|
+
`## States` section): state names, meaning, and one `api.setState(...)` example.
|
|
327
|
+
7. **Every state must be visually verifiable** — four artifacts cover each
|
|
328
|
+
declared state (verify.ts parses `{name}States = [...]` and checks all four):
|
|
329
|
+
- **Doc page**: `src/documentation/{name}.html` has a `States` section with
|
|
330
|
+
`<code>{state}</code>` per state, AND the state-bearing demo element
|
|
331
|
+
carries `data-state-demo` (the anchor `create-screenshots.ts` drives via
|
|
332
|
+
`api.setState()` to capture `screenshots/{mode}/{name}-{state}.png`)
|
|
333
|
+
- **Screenshots**: one PNG per state per mode (light + dark), default state
|
|
334
|
+
as `{name}.png` from the first `.preview`
|
|
335
|
+
- **Skill**: the state name appears in the `## States` section
|
|
336
|
+
- **E2E**: the state name string appears in `{name}.e2e.ts` (a
|
|
337
|
+
`setState(name)` assertion)
|
|
338
|
+
Adding a state without all four fails the build.
|
|
339
|
+
|
|
340
|
+
Types for the globals live in `src/types/defuss-shadcn.d.ts` — extend it when the
|
|
341
|
+
contract grows; never re-declare the globals inside a component file.
|
|
342
|
+
|
|
343
|
+
`scripts/verify.ts` checks all markers for every new JS component (hard fail).
|
|
344
|
+
Legacy components in its `STATE_API_LEGACY` list warn only until migrated —
|
|
345
|
+
remove a name from the list in the same commit that migrates the component.
|
|
346
|
+
|
|
347
|
+
### Tokens are the source of truth for design values
|
|
348
|
+
|
|
349
|
+
`dist/theme/default-semantic-tokens.css` defines all CSS custom properties. These must match
|
|
350
|
+
the shape of tweakcn.com theme exports so themes are drop-in compatible.
|
|
351
|
+
|
|
352
|
+
The token file provides:
|
|
353
|
+
- Color pairs (surface + foreground) for light and dark modes
|
|
354
|
+
- `--radius` (base) — derived values (`--radius-sm/md/lg/xl`) are computed in the token file
|
|
355
|
+
- Shadow scale and composition tokens
|
|
356
|
+
- Font stacks (generic — overridden by doc site)
|
|
357
|
+
- Spacing and tracking
|
|
358
|
+
|
|
359
|
+
#### Tokens & Theme
|
|
360
|
+
|
|
361
|
+
##### Token boundary rule (CRITICAL)
|
|
362
|
+
|
|
363
|
+
**Components must only use the tokens that exist in the TweakCN export shape.**
|
|
364
|
+
|
|
365
|
+
- `default-semantic-tokens.css` defines the complete set of available CSS custom properties.
|
|
366
|
+
- No new custom properties may be added to `default-semantic-tokens.css` beyond what TweakCN provides.
|
|
367
|
+
- Components CSS (`dist/components/{name}/{name}.css`)
|
|
368
|
+
must reference only these tokens via `var(--*)`.
|
|
369
|
+
- If a component needs a color that has no token (e.g., status colors like
|
|
370
|
+
green/amber/blue), use a hardcoded CSS value directly in the component CSS.
|
|
371
|
+
Do NOT invent a new `--*` token for it.
|
|
372
|
+
|
|
373
|
+
###### Why
|
|
374
|
+
TweakCN themes are drop-in replacements. If we add tokens that TweakCN doesn't
|
|
375
|
+
export, swapping a theme will leave those tokens undefined and break components.
|
|
376
|
+
The token file must be a pure subset of what TweakCN produces.
|
|
377
|
+
|
|
378
|
+
###### Allowed token list (exhaustive)
|
|
379
|
+
|
|
380
|
+
**Color pairs** (surface + foreground):
|
|
381
|
+
`--background`, `--foreground`, `--card`, `--card-foreground`, `--popover`,
|
|
382
|
+
`--popover-foreground`, `--primary`, `--primary-foreground`, `--secondary`,
|
|
383
|
+
`--secondary-foreground`, `--muted`, `--muted-foreground`, `--accent`,
|
|
384
|
+
`--accent-foreground`, `--destructive`, `--destructive-foreground`
|
|
385
|
+
|
|
386
|
+
**Utility tokens**: `--border`, `--input`, `--ring`
|
|
387
|
+
|
|
388
|
+
**Sidebar tokens**: `--sidebar`, `--sidebar-foreground`, `--sidebar-primary`,
|
|
389
|
+
`--sidebar-primary-foreground`, `--sidebar-accent`, `--sidebar-accent-foreground`,
|
|
390
|
+
`--sidebar-border`, `--sidebar-ring`
|
|
391
|
+
|
|
392
|
+
**Chart tokens**: `--chart-1` through `--chart-5`
|
|
393
|
+
|
|
394
|
+
**Typography**: `--font-sans`, `--font-serif`, `--font-mono`
|
|
395
|
+
|
|
396
|
+
**Radius**: `--radius` (base), `--radius-sm`, `--radius-md`, `--radius-lg`, `--radius-xl` (derived)
|
|
397
|
+
|
|
398
|
+
**Shadow scale**: `--shadow-2xs` through `--shadow-2xl`
|
|
399
|
+
|
|
400
|
+
**Spacing**: `--spacing`
|
|
401
|
+
|
|
402
|
+
**Tracking**: `--tracking-normal`
|
|
403
|
+
|
|
404
|
+
**Nothing else.** If a value is not on this list, it cannot be a `var(--*)` reference
|
|
405
|
+
in component CSS. Use a literal CSS value instead.
|
|
406
|
+
|
|
407
|
+
###### Token shape (tweakcn compatible)
|
|
408
|
+
|
|
409
|
+
`dist/theme/default-semantic-tokens.css` must match the shape of theme exports from tweakcn.com:
|
|
410
|
+
|
|
411
|
+
###### `:root` block provides:
|
|
412
|
+
- Color pairs: `--primary` / `--primary-foreground` (and all other semantic pairs)
|
|
413
|
+
- Utility tokens: `--border`, `--input`, `--ring`
|
|
414
|
+
- Sidebar tokens: `--sidebar`, `--sidebar-foreground`, etc.
|
|
415
|
+
- Chart tokens: `--chart-1` through `--chart-5`
|
|
416
|
+
- Font stacks: `--font-sans`, `--font-serif`, `--font-mono` (generic defaults)
|
|
417
|
+
- Base radius: `--radius`
|
|
418
|
+
- Derived radius: `--radius-sm`, `--radius-md`, `--radius-lg`, `--radius-xl` (computed from `var(--radius)`)
|
|
419
|
+
- Shadow scale: `--shadow-2xs` through `--shadow-2xl`
|
|
420
|
+
- Spacing: `--spacing`
|
|
421
|
+
- Tracking: `--tracking-normal`
|
|
422
|
+
|
|
423
|
+
###### `.dark` block overrides:
|
|
424
|
+
- All color pairs for dark mode
|
|
425
|
+
- Same tokens, different values
|
|
426
|
+
|
|
427
|
+
###### Derived radius values
|
|
428
|
+
|
|
429
|
+
Tweakcn themes provide `--radius` and derived values. The derived values use additive offsets:
|
|
430
|
+
```css
|
|
431
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
432
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
433
|
+
--radius-lg: var(--radius);
|
|
434
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
These exist as real CSS custom properties because component CSS uses `var(--radius-md)` directly.
|
|
438
|
+
|
|
439
|
+
### Documentation site architecture
|
|
440
|
+
|
|
441
|
+
The doc site dev server runs on `http://localhost:3000/` via `bun run dev` (Vite).
|
|
442
|
+
When testing, use the existing dev server — don't start a new one.
|
|
443
|
+
|
|
444
|
+
The doc site is a **SPA-style multi-page app**. `layout.js` loads synchronously in
|
|
445
|
+
`<head>` and provides:
|
|
446
|
+
|
|
447
|
+
- `<site-header>` — renders the fixed header (logo, GitHub link, dark mode toggle)
|
|
448
|
+
- `<site-nav>` — renders the sidebar from a centralized `NAV` array, auto-detecting the active page
|
|
449
|
+
- **SPA router** — intercepts nav clicks, fetches HTML, swaps `<main>` content
|
|
450
|
+
without full-page reloads (uses View Transitions API for smooth crossfade)
|
|
451
|
+
|
|
452
|
+
**Sidebar nav is centralized in `layout.js`.** To add or reorder nav links, edit
|
|
453
|
+
the `NAV` array and the `BUILT` set in that one file — individual HTML pages
|
|
454
|
+
do not contain nav markup.
|
|
455
|
+
|
|
456
|
+
Each HTML page duplicates the full list of component CSS `<link>` tags in `<head>`
|
|
457
|
+
and component JS `<script>` tags at end of `<body>`. When adding a new component,
|
|
458
|
+
these imports must be added to **every** HTML file.
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## Adding a new component
|
|
463
|
+
|
|
464
|
+
### Reference sites (REQUIRED)
|
|
465
|
+
|
|
466
|
+
Before writing any component skill or documentation page, **fetch and review** the component on these sites:
|
|
467
|
+
|
|
468
|
+
#### Feature checklist (what to build)
|
|
469
|
+
1. **shadcn/ui** → `https://ui.shadcn.com/docs/components/{name}`
|
|
470
|
+
2. **Basecoat UI** → `https://basecoatui.com/components/{name}/`
|
|
471
|
+
|
|
472
|
+
These define the completeness bar. Every variant, size, state, and composition pattern
|
|
473
|
+
shown on those pages must be accounted for in the component skill and doc page — adapted
|
|
474
|
+
to our semantic HTML / CSS custom property / vanilla JS model. Do not copy their markup;
|
|
475
|
+
use them as a feature checklist.
|
|
476
|
+
|
|
477
|
+
#### Native implementation (how to build it)
|
|
478
|
+
3. **WAI-ARIA APG** → `https://www.w3.org/WAI/ARIA/apg/patterns/{name}/` — canonical keyboard navigation and ARIA patterns
|
|
479
|
+
4. **MDN Web Docs** → `https://developer.mozilla.org/` — authoritative reference for HTML elements, CSS properties, and JS APIs
|
|
480
|
+
5. **Open UI** → `https://open-ui.org` — W3C community group defining native component standards
|
|
481
|
+
6. **Base UI** → `https://base-ui.com/react/components/{name}` — headless component architecture (closest to our approach in spirit)
|
|
482
|
+
|
|
483
|
+
Always prefer native browser APIs over JS workarounds. Check MDN for the latest
|
|
484
|
+
support status of newer APIs (`popover`, anchor positioning, `@starting-style`, etc.).
|
|
485
|
+
|
|
486
|
+
### Steps
|
|
487
|
+
|
|
488
|
+
1. **Create the component folder** → `dist/components/{name}/`
|
|
489
|
+
|
|
490
|
+
2. **Write the component skill** → `dist/components/{name}/component-skill.md`
|
|
491
|
+
- Follow the template: Native basis → Native Web APIs → Structure → Variants → Sizes → ARIA → Notes
|
|
492
|
+
- Documents the HTML pattern, not CSS/JS (those are the actual files)
|
|
493
|
+
- Cross-check variants, sizes, and states against the reference sites above
|
|
494
|
+
|
|
495
|
+
3. **Write the CSS** → `dist/components/{name}/{name}.css`
|
|
496
|
+
- Edit directly — no build step
|
|
497
|
+
|
|
498
|
+
4. **Write the JS** (if interactive) → `dist/components/{name}/{name}.js`
|
|
499
|
+
- Plain ES module — wrap initialization in an `init()` function
|
|
500
|
+
- Call `init()` immediately, then add `new MutationObserver(init).observe(document, { childList: true, subtree: true });`
|
|
501
|
+
- This auto-initializes new elements after SPA navigation or dynamic DOM changes
|
|
502
|
+
- No `export`, no `window.onPageReady` — just the init function + MutationObserver
|
|
503
|
+
|
|
504
|
+
5. **Create the doc page** → `dist/documentation/{name}.html`
|
|
505
|
+
- Copy an existing component page as template (e.g., badge.html)
|
|
506
|
+
- Add `<link rel="stylesheet" href="../components/{name}/{name}.css">` to the head
|
|
507
|
+
- Add `<script type="module" src="../components/{name}/{name}.js"></script>` if interactive
|
|
508
|
+
- Replace demo content with working examples
|
|
509
|
+
|
|
510
|
+
6. **Update layout.js** → add the component to the `NAV` array and `BUILT` set
|
|
511
|
+
in `dist/documentation/js/layout.js` (this is the single source of truth for sidebar nav)
|
|
512
|
+
|
|
513
|
+
7. **Add CSS/JS imports to all HTML pages** → add the new component's `<link>` and
|
|
514
|
+
`<script>` tags to every HTML file in `dist/documentation/`
|
|
515
|
+
|
|
516
|
+
8. **Sync inline source snippets** → run `bun run sync-snippets` to replace the inline
|
|
517
|
+
`<pre><code>` blocks in every doc page with the actual contents of each component's
|
|
518
|
+
`.css` and `.ts` files. This must be done after any change to a component's CSS or
|
|
519
|
+
JS — not just for new components.
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
# Component Skill Editing
|
|
523
|
+
|
|
524
|
+
## Reference sites (REQUIRED)
|
|
525
|
+
|
|
526
|
+
Before writing or updating any component skill, fetch and review the component:
|
|
527
|
+
|
|
528
|
+
### Feature checklist (what to build)
|
|
529
|
+
1. **shadcn/ui** → `https://ui.shadcn.com/docs/components/{name}`
|
|
530
|
+
2. **Basecoat UI** → `https://basecoatui.com/components/{name}/`
|
|
531
|
+
|
|
532
|
+
Every variant, size, state, and composition pattern shown on those pages must be
|
|
533
|
+
accounted for in the component skill — adapted to our semantic HTML / CSS custom property /
|
|
534
|
+
vanilla JS model.
|
|
535
|
+
|
|
536
|
+
### Native implementation (how to build it)
|
|
537
|
+
3. **WAI-ARIA APG** → `https://www.w3.org/WAI/ARIA/apg/patterns/{name}/` — canonical keyboard navigation and ARIA patterns
|
|
538
|
+
4. **MDN Web Docs** → `https://developer.mozilla.org/` — authoritative reference for HTML elements, CSS properties, and JS APIs
|
|
539
|
+
5. **Open UI** → `https://open-ui.org` — W3C community group defining native component standards
|
|
540
|
+
6. **Base UI** → `https://base-ui.com/react/components/{name}` — headless component architecture reference
|
|
541
|
+
|
|
542
|
+
Always prefer native browser APIs over JS workarounds. Check MDN for support
|
|
543
|
+
status of newer APIs (`popover`, anchor positioning, `@starting-style`, etc.).
|
|
544
|
+
|
|
545
|
+
## Component skill template
|
|
546
|
+
|
|
547
|
+
Component skills document **how to build the HTML** for a component. CSS and JS live in
|
|
548
|
+
their own files alongside the skill — edit `.css` and `.js` directly.
|
|
549
|
+
|
|
550
|
+
Every component skill must include these sections in order:
|
|
551
|
+
|
|
552
|
+
1. **Native basis** — which HTML element/API it builds on
|
|
553
|
+
2. **Native Web APIs** — bulleted list of significant platform APIs with MDN links (see format below)
|
|
554
|
+
3. **Structure** — complete HTML markup with all attributes
|
|
555
|
+
4. **Variants** — variant table mapping `data-variant` values to visual behavior
|
|
556
|
+
5. **Sizes** — size table (if applicable)
|
|
557
|
+
6. **ARIA** — accessibility attributes table
|
|
558
|
+
7. **Notes** — edge cases, composition tips, caveats
|
|
559
|
+
|
|
560
|
+
Do NOT include CSS or JavaScript code blocks in the component skill. The `.css` and `.js` files
|
|
561
|
+
in the same folder are the source of truth for styles and behavior.
|
|
562
|
+
|
|
563
|
+
## Native Web APIs section format
|
|
564
|
+
|
|
565
|
+
Every component skill must include a `## Native Web APIs` section immediately after
|
|
566
|
+
`## Native basis`. This section lists the significant web platform APIs the component
|
|
567
|
+
relies on, with MDN links. Use this format:
|
|
568
|
+
|
|
569
|
+
```markdown
|
|
570
|
+
## Native Web APIs
|
|
571
|
+
- [`<dialog>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog) — native modal with focus trap and Escape-to-close
|
|
572
|
+
- [`@starting-style`](https://developer.mozilla.org/en-US/docs/Web/CSS/@starting-style) — entry animation starting values
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### What to include
|
|
576
|
+
- HTML elements that provide core behavior (`<dialog>`, `<details>`, `<summary>`, `<progress>`, `<meter>`, `<output>`)
|
|
577
|
+
- HTML attributes that replace JS (`popover`, `popover="hint"`, `commandfor`/`command`, `inert`, `autofocus`, `loading="lazy"`)
|
|
578
|
+
- Browser APIs (`Popover API`, `showModal()`, `View Transitions API`, `Navigation API`)
|
|
579
|
+
- Significant CSS features (`CSS Anchor Positioning`, `@starting-style`, `::backdrop`, `::details-content`, Container Queries, `:has()`, `field-sizing: content`, `interpolate-size`, `content-visibility`, `@property`, `scroll-driven animations`, `light-dark()`, `color-mix()`)
|
|
580
|
+
- Accessibility features (`prefers-reduced-motion`, `prefers-contrast`, `forced-colors`)
|
|
581
|
+
- JS APIs used (`IntersectionObserver`, `ResizeObserver`, `MutationObserver`, `Clipboard API`, `Intl.*`, `CloseWatcher`, `AbortController`, `FormData`, `structuredClone()`)
|
|
582
|
+
- WAI-ARIA patterns when the component follows a specific APG pattern
|
|
583
|
+
|
|
584
|
+
### What to exclude
|
|
585
|
+
- Basic DOM methods (`querySelector`, `classList`, `addEventListener`)
|
|
586
|
+
- Standard CSS layout (`flexbox`, `grid` unless using subgrid/container queries)
|
|
587
|
+
- Common pseudo-classes (`:hover`, `:disabled`) unless component-defining (`:focus-visible`, `:has()`)
|
|
588
|
+
|
|
589
|
+
## CSS authoring conventions
|
|
590
|
+
|
|
591
|
+
### `@layer components`
|
|
592
|
+
All component CSS must be wrapped in `@layer components { ... }`. This establishes
|
|
593
|
+
explicit cascade priority: tokens → components → utilities. Never write component CSS
|
|
594
|
+
outside a layer.
|
|
595
|
+
|
|
596
|
+
### Native CSS nesting
|
|
597
|
+
Use `&` nesting for all related selectors. Group variants, sizes, states, and child
|
|
598
|
+
element styles inside the base selector:
|
|
599
|
+
```css
|
|
600
|
+
@layer components {
|
|
601
|
+
.btn {
|
|
602
|
+
/* base styles */
|
|
603
|
+
&[data-variant="outline"] { /* ... */ }
|
|
604
|
+
&[data-size="sm"] { /* ... */ }
|
|
605
|
+
&:hover { /* ... */ }
|
|
606
|
+
&:disabled { /* ... */ }
|
|
607
|
+
& svg { /* child styles */ }
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### Modern CSS features (use where applicable)
|
|
613
|
+
- **CSS anchor positioning** — for popover/dropdown/combobox placement (`position-anchor`, `anchor()`, `position-try-fallbacks: flip-block`). No JS positioning code needed.
|
|
614
|
+
- **`:has()` selector** — for parent/sibling state reactions (e.g., label styling when input is focused)
|
|
615
|
+
- **`field-sizing: content`** — for auto-growing textareas with zero JS
|
|
616
|
+
- **Container queries** — for components that adapt to their container width (`container-type: inline-size`, `@container`)
|
|
617
|
+
- **`@starting-style`** — for enter animations on elements added to DOM or moving to top layer
|
|
618
|
+
- **`interpolate-size: allow-keywords`** — for smooth height-to-`auto` transitions (accordion, collapsible)
|
|
619
|
+
- **`content-visibility`** — for expand/collapse transitions with `allow-discrete`
|
|
620
|
+
- **`@property`** — for typed, animatable custom properties (progress rings, gradient transitions)
|
|
621
|
+
- **`color-mix(in oklch, ...)`** — for deriving hover/disabled states from token colors
|
|
622
|
+
- **`light-dark()`** — for inline dark mode values when `color-scheme` is set
|
|
623
|
+
- **`accent-color`** — for theming native form controls (checkbox, radio, range, progress)
|
|
624
|
+
- **Scroll-driven animations** — `animation-timeline: scroll()` / `view()` for scroll-linked effects
|
|
625
|
+
- **View Transitions API** — `startViewTransition()` for smooth DOM state changes
|
|
626
|
+
- **Logical properties** — `margin-inline`, `padding-block`, `inset-inline-start` for RTL support
|
|
627
|
+
- **Subgrid** — `grid-template-columns: subgrid` for child alignment to parent grid tracks
|
|
628
|
+
- **`:is()` / `:where()`** — selector grouping; `:where()` has zero specificity (ideal for resets)
|
|
629
|
+
- **`@scope`** — bounded style scoping with upper and lower boundaries (available but
|
|
630
|
+
**not used in this project** — we use `@layer` + descriptive prefixed class names instead;
|
|
631
|
+
see cascade-layers.html for rationale)
|
|
632
|
+
- **Dynamic viewport units** — `dvh`, `svh`, `lvh` for mobile browser chrome awareness
|
|
633
|
+
- **CSS math** — `clamp()`, `min()`, `max()`, `round()` for responsive sizing
|
|
634
|
+
|
|
635
|
+
### Accessibility CSS (REQUIRED for all components)
|
|
636
|
+
- **`prefers-reduced-motion: reduce`** — suppress/simplify all transitions and animations
|
|
637
|
+
- **`prefers-contrast: more`** — increase contrast when requested by the user
|
|
638
|
+
- **`forced-colors: active`** — support Windows High Contrast Mode with system colors
|
|
639
|
+
- **`prefers-color-scheme`** — automatic dark mode defaults from OS preference
|
|
640
|
+
|
|
641
|
+
### After editing component CSS or JS
|
|
642
|
+
|
|
643
|
+
Doc pages display each component's CSS and JS in inline `<pre><code>` blocks.
|
|
644
|
+
After changing any `.css` or `.js` file, run the sync scripts to keep doc pages accurate:
|
|
645
|
+
|
|
646
|
+
```
|
|
647
|
+
bun run sync-snippets
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
## Accuracy requirements
|
|
651
|
+
|
|
652
|
+
- All CSS values must match what the documentation site actually renders
|
|
653
|
+
- All class names must match the CSS selectors exactly
|
|
654
|
+
- Token references must use `var(--*)` — never raw color values (see token boundary rule in tokens.instructions.md)
|
|
655
|
+
- `<dialog>` components must include `margin: auto; position: fixed; inset: 0;` for centering (some browsers need this explicitly)
|
|
656
|
+
|
|
657
|
+
## Variant and size API (data attributes)
|
|
658
|
+
|
|
659
|
+
Components use `data-*` attributes — never CSS class modifiers — for variants and sizes.
|
|
660
|
+
|
|
661
|
+
### Rules
|
|
662
|
+
- **`data-variant`** for visual variations (e.g., `default`, `outline`, `ghost`, `destructive`)
|
|
663
|
+
- **`data-size`** for size variations (e.g., `sm`, `lg`, `icon`)
|
|
664
|
+
- **`data-side`**, **`data-position`**, etc. for structural variations where applicable
|
|
665
|
+
- **One base class** per component (`.btn`, `.badge`, `.card`) — this identifies *what* it is
|
|
666
|
+
- **Data attributes** express *which version* — never add modifier classes like `.btn-primary` or `.btn--ghost`
|
|
667
|
+
- CSS selectors combine the base class with the attribute: `.btn[data-variant="outline"]`
|
|
668
|
+
|
|
669
|
+
### Why
|
|
670
|
+
- Flat specificity — all selectors have equal weight, no conflicts
|
|
671
|
+
- Uniform API — every component follows the same pattern, easy for AI to learn
|
|
672
|
+
- Independent axes — variant and size combine freely without combinatorial class names
|
|
673
|
+
- Clean `class` attribute — no long modifier chains
|
|
674
|
+
|
|
675
|
+
### Correct
|
|
676
|
+
```html
|
|
677
|
+
<button class="btn" data-variant="destructive" data-size="lg">Delete</button>
|
|
678
|
+
<span class="badge" data-variant="outline">Status</span>
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Wrong
|
|
682
|
+
```html
|
|
683
|
+
<button class="btn btn-destructive btn-lg">Delete</button>
|
|
684
|
+
<span class="badge badge-outline">Status</span>
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
## Reference
|
|
688
|
+
|
|
689
|
+
Check shadcn/ui (ui.shadcn.com) for the expected behavior and API of each component.
|
|
690
|
+
Translate React/Radix patterns into semantic HTML + vanilla JS.
|
|
691
|
+
|
|
692
|
+
---
|
|
693
|
+
|
|
694
|
+
## Linting
|
|
695
|
+
|
|
696
|
+
`make lint` (oxlint over `src/`, `tests/`, `scripts/`) reports warnings but must stay
|
|
697
|
+
**non-blocking** — do not configure it to fail on warnings (`--deny-warnings` is banned);
|
|
698
|
+
only real errors should gate CI.
|
|
699
|
+
|
|
700
|
+
Keep the log clean: fix every warning an edit introduces. For a variable that is
|
|
701
|
+
**known to be intentionally unused**, prefix it with `_` (e.g. `var _copyBtn = …`) —
|
|
702
|
+
oxlint's `no-unused-vars` accepts that convention. For intentionally unused
|
|
703
|
+
**caught errors**, omit the parameter entirely (`catch { … }`, ES2019) — oxlint flags
|
|
704
|
+
`catch (_e)` too. Do not silence warnings with ignore comments, and do not delete
|
|
705
|
+
code that linters flag without checking why it exists (e.g. `window.THEMES` in
|
|
706
|
+
`themes.ts` is a cross-file global contract — make the contract explicit instead
|
|
707
|
+
of removing it).
|
|
708
|
+
|
|
709
|
+
## Testing
|
|
710
|
+
|
|
711
|
+
`make help` lists the shortcuts (`setup`, `dev`, `test`, `test-run`, `coverage`, `e2e`, `lint`,
|
|
712
|
+
`verify`, `screenshots`, `build`) — they wrap the equivalent `bun run <script>` commands;
|
|
713
|
+
package.json stays the single source of truth. `make build` is the full pipeline:
|
|
714
|
+
lint → compile → screenshots → docs-mirror → verify → tests → e2e (it calls `scripts/build.ts` directly,
|
|
715
|
+
since `bun run build` runs `verify` before screenshots could be refreshed).
|
|
716
|
+
|
|
717
|
+
`bun run test:run` runs the UI suite in headless Chromium (Vitest browser mode + Playwright).
|
|
718
|
+
First run needs `make setup` (or `bunx playwright install`).
|
|
719
|
+
|
|
720
|
+
Tests load the real pages from `dist/documentation/` inside a **same-origin iframe**
|
|
721
|
+
(`openDocPage()` in `tests/helpers.ts`) — Vitest browser mode has no `page.goto()`.
|
|
722
|
+
Interactions go through `userEvent.click()` on elements queried from the iframe's
|
|
723
|
+
`document` (trusted Playwright input); state is asserted by reading that same
|
|
724
|
+
same-origin `document` directly. `frame.getBy*()` locators work too, but Vitest's
|
|
725
|
+
ARIA-tree queries are slow/flaky on these very large doc pages, so prefer
|
|
726
|
+
`doc.querySelector` + `expect` for assertions.
|
|
727
|
+
|
|
728
|
+
When adding a component, add at least one interaction test in `tests/ui.test.ts`
|
|
729
|
+
covering its JS behavior (see the dialog/accordion tests as templates).
|
|
730
|
+
|
|
731
|
+
### Component E2E smoke tests (`bun run e2e`)
|
|
732
|
+
|
|
733
|
+
Per-component smoke tests live in `tests/e2e/` and run with **plain Playwright**
|
|
734
|
+
(no Vitest). Each component gets two files:
|
|
735
|
+
|
|
736
|
+
- `{name}.e2e-fixture.html` — uses the component **in every configuration** the
|
|
737
|
+
component skill documents (all variants/sizes/states/compositions), linking the
|
|
738
|
+
real files by absolute path (`/dist/theme/default-semantic-tokens.css`,
|
|
739
|
+
`/dist/components/{name}/{name}.css` + `.js`). The fixture is served by
|
|
740
|
+
`server.ts`, a static Bun server rooted at the repo root that exposes only
|
|
741
|
+
`/dist/` and `/tests/e2e/`.
|
|
742
|
+
- `{name}.e2e.ts` — a standalone script (exits non-zero on failure) that launches
|
|
743
|
+
Chromium, serves the fixture, and asserts behavior: init markers, initial state,
|
|
744
|
+
applied CSS (via computed styles), each interaction, and keyboard behavior.
|
|
745
|
+
`accordion.e2e.ts` is the reference template.
|
|
746
|
+
|
|
747
|
+
`tests/e2e/run.ts` globs and runs every `*.e2e.ts` in isolated child processes.
|
|
748
|
+
When adding a component, add both files. Interactive components follow the
|
|
749
|
+
`accordion.e2e.{ts,fixture.html}` template (drive `api.setState` + interactions);
|
|
750
|
+
CSS-only components use the shared `tests/e2e/lib/css-smoke.ts` runner — the
|
|
751
|
+
assertions are data (literal computed px values, pairwise-distinct token colors,
|
|
752
|
+
`run` escape hatch for pseudo-states), see `tests/e2e/badge.e2e.ts`.
|
|
753
|
+
|
|
754
|
+
### Legacy rollouts (complete)
|
|
755
|
+
|
|
756
|
+
Every component now ships the State API (interactive ones) and an e2e pair —
|
|
757
|
+
the `STATE_API_LEGACY` / e2e warn-ratchets in `scripts/verify.ts` are empty and
|
|
758
|
+
the checks are hard gates. New components must land compliant from day one:
|
|
759
|
+
source → skill `## States` + doc page (`<code>` per state + `data-state-demo`
|
|
760
|
+
anchor) → `bun run screenshots` → e2e fixture + test, ideally in one commit.
|
|
761
|
+
|
|
762
|
+
### Docs ↔ E2E parity (REQUIRED)
|
|
763
|
+
|
|
764
|
+
The e2e fixture and the documentation must describe the **same** component
|
|
765
|
+
surface, so a green pipeline means "documented == tested == shipped":
|
|
766
|
+
|
|
767
|
+
| Feature exists in… | Then… |
|
|
768
|
+
| --- | --- |
|
|
769
|
+
| code only | add it to the doc page **and** the e2e fixture/test |
|
|
770
|
+
| docs only | add an e2e check for it (it must work in the shipped files) |
|
|
771
|
+
| fixture only | it is undocumented — document it |
|
|
772
|
+
| all three | ✅ |
|
|
773
|
+
|
|
774
|
+
- The fixture `{name}.e2e-fixture.html` instantiates every configuration the
|
|
775
|
+
doc page demonstrates (variants, sizes, states, compositions) — same `data-*`
|
|
776
|
+
attributes, same nesting. If the doc page shows a variant, the fixture has it.
|
|
777
|
+
- Every State API state gets an assertion via `el.api.setState(name)` plus an
|
|
778
|
+
observation of the resulting UI (computed styles / DOM flags).
|
|
779
|
+
- When you add a feature to a component, update **all three artifacts in the
|
|
780
|
+
same commit**: source, doc page, fixture + e2e assertions. Reviewers should
|
|
781
|
+
reject any of the three landing alone.
|
|
782
|
+
|
|
783
|
+
## Common pitfalls
|
|
784
|
+
|
|
785
|
+
- **Dialog/Sheet centering**: Always set `margin: auto; position: fixed; inset: 0;`
|
|
786
|
+
explicitly for centered dialogs.
|
|
787
|
+
- **CSS drift**: If the component skill's variant/size tables don't match the `.css` file,
|
|
788
|
+
update the component skill to stay in sync — the `.css` file is the source of truth for styles.
|
|
789
|
+
- **CSS/JS import drift**: When adding a component, you must add its `<link>` and
|
|
790
|
+
`<script>` tags to ALL HTML pages. Missing imports cause components in cross-page
|
|
791
|
+
demos to break silently.
|
|
792
|
+
- **SPA re-initialization**: Component JS modules use `MutationObserver` to
|
|
793
|
+
auto-initialize new elements when the DOM changes — no manual re-import needed.
|
|
794
|
+
Doc-site-only scripts (site.js) use `window.onPageReady(fn)` for their own re-init.
|
|
795
|
+
- **Font stacks**: The system tokens use generic font stacks. The doc site overrides
|
|
796
|
+
them in `css/docs-theme.css`. Don't put custom fonts in `default-semantic-tokens.css`.
|
|
797
|
+
- **Inline source snippet drift**: Doc pages show the component's CSS and JS in
|
|
798
|
+
`<pre><code>` blocks. These must always match the actual files. After editing any
|
|
799
|
+
component `.css` or `.ts`, run `bun run sync-snippets` to update all doc pages
|
|
800
|
+
automatically (the syncers edit `src/`, never `dist/`).
|
|
801
|
+
|
|
802
|
+
# Documentation Pages
|
|
803
|
+
|
|
804
|
+
## Shared layout (Web Components)
|
|
805
|
+
|
|
806
|
+
The header and sidebar navigation are centralized in `dist/documentation/js/layout.js`
|
|
807
|
+
using two custom elements:
|
|
808
|
+
|
|
809
|
+
- `<site-header>` — renders the fixed header (logo, GitHub link, dark mode toggle)
|
|
810
|
+
- `<site-nav>` — renders the sidebar with navigation links, auto-detecting the active page
|
|
811
|
+
|
|
812
|
+
**To add/remove/reorder nav links or change the header, edit `layout.js` only.**
|
|
813
|
+
No need to touch individual HTML files for navigation changes.
|
|
814
|
+
|
|
815
|
+
`layout.js` is loaded **synchronously** in `<head>` (no `defer`) so the custom
|
|
816
|
+
elements render without FOUC when the parser encounters them in `<body>`.
|
|
817
|
+
|
|
818
|
+
### layout.js data structures
|
|
819
|
+
|
|
820
|
+
- `NAV` — array of `{ heading, items: [{ label, href }] }` defining the sidebar sections
|
|
821
|
+
- `BUILT` — `Set` of page filenames that have real doc pages (non-built pages render as disabled links)
|
|
822
|
+
|
|
823
|
+
## Adding a component page
|
|
824
|
+
|
|
825
|
+
1. Copy an existing component page (e.g., `badge.html`) as the template
|
|
826
|
+
2. Change the `<title>`, `<h1>`, breadcrumb, and main content
|
|
827
|
+
3. Add `<link rel="stylesheet" href="../components/{name}/{name}.css">` to the head
|
|
828
|
+
4. Add `<script type="module" src="../components/{name}/{name}.js"></script>` if interactive
|
|
829
|
+
5. In `layout.js`: add the page to the `NAV` array and the `BUILT` set
|
|
830
|
+
|
|
831
|
+
No need to update sidebar nav links in other files — `<site-nav>` handles it globally.
|
|
832
|
+
|
|
833
|
+
## Sidebar nav order
|
|
834
|
+
|
|
835
|
+
The sidebar is ordered by dependency (primitives first):
|
|
836
|
+
1. Overview (Introduction, Installation, Theming, Dark Mode, Data Attribute API, Cascade Layers, ES Modules, Native Web APIs, Animations, Accessibility, Component Skills, Changelog)
|
|
837
|
+
2. Primitives (Typography, Separator, Icon)
|
|
838
|
+
3. Layout (Scroll Area, Carousel, Sortable)
|
|
839
|
+
4. Actions (Button, Toggle, Toggle Group, Button Group, Toolbar)
|
|
840
|
+
5. Forms & Inputs (Label, Input, Textarea, Checkbox, Radio Group, Switch, Slider, Select, Number Input, File Input, Color Picker, Date Picker, Combobox, Form)
|
|
841
|
+
6. Data Display (Badge, Avatar, Card, Image, Statistic, Table, Collapsible, Timeline, Tree View, Calendar)
|
|
842
|
+
7. Feedback & Status (Spinner, Skeleton, Progress, Alert, Alert Dialog, Toast)
|
|
843
|
+
8. Overlays (Popover, Tooltip, Context Menu, Dialog, Sheet, Accordion, Command)
|
|
844
|
+
9. Navigation (Breadcrumb, Pagination, Steps, Tabs, Dropdown Menu, Navigation Menu)
|
|
845
|
+
10. Application (Sidebar)
|
|
846
|
+
|
|
847
|
+
To reorder, edit the `NAV` array in `layout.js`.
|
|
848
|
+
|
|
849
|
+
## CSS and JS imports
|
|
850
|
+
|
|
851
|
+
Every page imports ALL component CSS and JS files (not just its own). This ensures
|
|
852
|
+
components used in demos on other pages render correctly. CSS and JS files live in
|
|
853
|
+
`../components/{name}/{name}.css` and `../components/{name}/{name}.js` respectively.
|
|
854
|
+
|
|
855
|
+
## Inline source code snippets
|
|
856
|
+
|
|
857
|
+
Each component doc page displays the component's CSS and JS in `<pre><code>` blocks.
|
|
858
|
+
These inline snippets must always match the actual files in `dist/components/`.
|
|
859
|
+
After editing any component `.css` or `.js` file, run:
|
|
860
|
+
|
|
861
|
+
```
|
|
862
|
+
bun run sync-snippets
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
These scripts replace every inline snippet with the current file content.
|
|
866
|
+
Do NOT manually edit the `<pre><code>` blocks — they will be overwritten by the sync scripts.
|
|
867
|
+
|
|
868
|
+
## Doc-site utility classes
|
|
869
|
+
|
|
870
|
+
The doc site uses a small, hand-written set of utility classes for layout and
|
|
871
|
+
spacing inside doc pages (`css/docs-utilities.css`). The utilities are plain
|
|
872
|
+
class rules — they only affect elements that explicitly opt in by using the
|
|
873
|
+
class name, so they cannot leak into component styles.
|
|
874
|
+
|
|
875
|
+
If you need a new utility (e.g. `mt-4`, `gap-5`), add it directly to
|
|
876
|
+
`css/docs-utilities.css`. Keep the utility set minimal — prefer inline `style`
|
|
877
|
+
attributes for one-off layout tweaks in demo wrappers.
|