@crewlethq/ui 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1714 -14
- package/dist/Accordion/Accordion.d.ts +54 -0
- package/dist/Accordion/index.d.ts +4 -0
- package/dist/Accordion/index.js +6 -0
- package/dist/Accordion-ZI2WLD5C.css +87 -0
- package/dist/AddPill/AddPill.d.ts +114 -0
- package/dist/AddPill/index.d.ts +3 -0
- package/dist/AddPill/index.js +3 -0
- package/dist/AddPill-DFWXYLIQ.css +434 -0
- package/dist/Announcer/Announcer.d.ts +15 -0
- package/dist/Announcer/index.d.ts +2 -0
- package/dist/Announcer/index.js +3 -0
- package/dist/AppShell/AppShell.d.ts +193 -0
- package/dist/AppShell/index.d.ts +3 -0
- package/dist/AppShell/index.js +6 -0
- package/dist/AppShell-NVE6LHNI.css +395 -0
- package/dist/Avatar/Avatar.d.ts +104 -0
- package/dist/Avatar/index.d.ts +3 -0
- package/dist/Avatar/index.js +2 -0
- package/dist/Avatar-P2KRQM2B.css +156 -0
- package/dist/BrandLockup/BrandLockup.d.ts +41 -0
- package/dist/BrandLockup/index.d.ts +3 -0
- package/dist/BrandLockup/index.js +2 -0
- package/dist/BrandLockup-6ISDEHPJ.css +108 -0
- package/dist/Button/Button.d.ts +88 -0
- package/dist/Button/index.d.ts +3 -0
- package/dist/Button/index.js +3 -0
- package/dist/Button-D4J6B4MA.css +302 -0
- package/dist/CalendarGrid/CalendarGrid.d.ts +87 -0
- package/dist/CalendarGrid/index.d.ts +3 -0
- package/dist/CalendarGrid/index.js +2 -0
- package/dist/CalendarGrid-V6TQ5QKS.css +128 -0
- package/dist/Callout/Callout.d.ts +47 -0
- package/dist/Callout/index.d.ts +3 -0
- package/dist/Callout/index.js +2 -0
- package/dist/Callout-S7QDWHDL.css +111 -0
- package/dist/Canvas/Canvas.d.ts +234 -0
- package/dist/Canvas/geometry.d.ts +249 -0
- package/dist/Canvas/index.d.ts +5 -0
- package/dist/Canvas/index.js +8 -0
- package/dist/Canvas/layerNode.d.ts +20 -0
- package/dist/Canvas-Q6JETCWR.css +315 -0
- package/dist/Card/Card.d.ts +142 -0
- package/dist/Card/headerSlot.d.ts +65 -0
- package/dist/Card/index.d.ts +5 -0
- package/dist/Card/index.js +6 -0
- package/dist/Card-AHX3Q2JD.css +428 -0
- package/dist/Charts/ActivityStrip.d.ts +45 -0
- package/dist/Charts/BarList.d.ts +51 -0
- package/dist/Charts/Legend.d.ts +32 -0
- package/dist/Charts/StackedBar.d.ts +38 -0
- package/dist/Charts/TimeSeries.d.ts +92 -0
- package/dist/Charts/dataColor.d.ts +20 -0
- package/dist/Charts/index.d.ts +12 -0
- package/dist/Charts/index.js +3 -0
- package/dist/Charts-D7G2BSXH.css +277 -0
- package/dist/Checkbox/Checkbox.d.ts +45 -0
- package/dist/Checkbox/index.d.ts +3 -0
- package/dist/Checkbox/index.js +2 -0
- package/dist/Checkbox-VGW26YLQ.css +111 -0
- package/dist/CodeBlock/CodeBlock.d.ts +60 -0
- package/dist/CodeBlock/index.d.ts +3 -0
- package/dist/CodeBlock/index.js +7 -0
- package/dist/CodeBlock-U2W6NNVC.css +153 -0
- package/dist/Combobox/Combobox.d.ts +89 -0
- package/dist/Combobox/index.d.ts +3 -0
- package/dist/Combobox/index.js +8 -0
- package/dist/Combobox-4FUVYIE7.css +80 -0
- package/dist/CommandPalette/CommandPalette.d.ts +77 -0
- package/dist/CommandPalette/index.d.ts +3 -0
- package/dist/CommandPalette/index.js +11 -0
- package/dist/CommandPalette-CSJDUCQA.css +115 -0
- package/dist/Container/Container.d.ts +17 -0
- package/dist/Container/index.d.ts +3 -0
- package/dist/Container/index.js +2 -0
- package/dist/Container-3TSKMGNI.css +52 -0
- package/dist/Copyable/CopyButton.d.ts +54 -0
- package/dist/Copyable/Copyable.d.ts +34 -0
- package/dist/Copyable/index.d.ts +5 -0
- package/dist/Copyable/index.js +6 -0
- package/dist/Copyable-5PNRFOLS.css +125 -0
- package/dist/Count/Count.d.ts +24 -0
- package/dist/Count/index.d.ts +3 -0
- package/dist/Count/index.js +3 -0
- package/dist/Count-ZVCJ6VPD.css +20 -0
- package/dist/DataTable/CopyableCell.d.ts +12 -0
- package/dist/DataTable/DataTable.d.ts +615 -0
- package/dist/DataTable/RowActionsMenu.d.ts +7 -0
- package/dist/DataTable/index.d.ts +7 -0
- package/dist/DataTable/index.js +14 -0
- package/dist/DataTable-ITNACQ2X.css +2020 -0
- package/dist/DataView/DataView.d.ts +109 -0
- package/dist/DataView/DataViewToolbar.d.ts +87 -0
- package/dist/DataView/FilterAxisBar.d.ts +103 -0
- package/dist/DataView/columns.d.ts +35 -0
- package/dist/DataView/filters.d.ts +184 -0
- package/dist/DataView/index.d.ts +11 -0
- package/dist/DataView/index.js +25 -0
- package/dist/DataView-256YF32J.css +441 -0
- package/dist/DateTimePicker/DateTimePicker.d.ts +91 -0
- package/dist/DateTimePicker/index.d.ts +3 -0
- package/dist/DateTimePicker/index.js +9 -0
- package/dist/DateTimePicker-22VNXRWC.css +199 -0
- package/dist/DescriptionList/DescriptionList.d.ts +36 -0
- package/dist/DescriptionList/index.d.ts +3 -0
- package/dist/DescriptionList/index.js +2 -0
- package/dist/DescriptionList-YYY3V3O6.css +59 -0
- package/dist/DiffList/DiffList.d.ts +47 -0
- package/dist/DiffList/index.d.ts +3 -0
- package/dist/DiffList/index.js +3 -0
- package/dist/DiffList-3EX64AAE.css +94 -0
- package/dist/Disclosure/Disclosure.d.ts +56 -0
- package/dist/Disclosure/anatomy.d.ts +43 -0
- package/dist/Disclosure/index.d.ts +5 -0
- package/dist/Disclosure/index.js +6 -0
- package/dist/Disclosure-VKBJJIZ7.css +176 -0
- package/dist/EmptyState/EmptyState.d.ts +39 -0
- package/dist/EmptyState/index.d.ts +3 -0
- package/dist/EmptyState/index.js +3 -0
- package/dist/EmptyState-C6HRBGT7.css +73 -0
- package/dist/EmptyValue/EmptyValue.d.ts +31 -0
- package/dist/EmptyValue/index.d.ts +3 -0
- package/dist/EmptyValue/index.js +3 -0
- package/dist/EmptyValue-4B6ODXHT.css +12 -0
- package/dist/EntityChip/EntityChip.d.ts +40 -0
- package/dist/EntityChip/index.d.ts +3 -0
- package/dist/EntityChip/index.js +3 -0
- package/dist/EntityChip-LUCPZBBG.css +64 -0
- package/dist/ErrorBoundary/ErrorBoundary.d.ts +58 -0
- package/dist/ErrorBoundary/index.d.ts +3 -0
- package/dist/ErrorBoundary/index.js +4 -0
- package/dist/ErrorBoundary-ME36CQTA.css +59 -0
- package/dist/Eyebrow/Eyebrow.d.ts +18 -0
- package/dist/Eyebrow/index.d.ts +3 -0
- package/dist/Eyebrow/index.js +2 -0
- package/dist/Eyebrow-5NREGHQH.css +46 -0
- package/dist/FilterChip/FilterChip.d.ts +68 -0
- package/dist/FilterChip/index.d.ts +3 -0
- package/dist/FilterChip/index.js +3 -0
- package/dist/FilterChip-GTGLLOXE.css +107 -0
- package/dist/Fullscreen/index.d.ts +2 -0
- package/dist/Fullscreen/index.js +1 -0
- package/dist/Fullscreen/useFullscreen.d.ts +32 -0
- package/dist/IconButton/IconButton.d.ts +45 -0
- package/dist/IconButton/index.d.ts +3 -0
- package/dist/IconButton/index.js +3 -0
- package/dist/IconButton-VQGNMJDI.css +158 -0
- package/dist/ImageUpload/ImageUpload.d.ts +37 -0
- package/dist/ImageUpload/index.d.ts +3 -0
- package/dist/ImageUpload/index.js +3 -0
- package/dist/ImageUpload-HKFIZR6D.css +193 -0
- package/dist/InlineCode/InlineCode.d.ts +37 -0
- package/dist/InlineCode/index.d.ts +3 -0
- package/dist/InlineCode/index.js +2 -0
- package/dist/InlineCode-6WSR5COL.css +65 -0
- package/dist/Input/FormField.d.ts +61 -0
- package/dist/Input/FormRow.d.ts +6 -0
- package/dist/Input/FormSection.d.ts +28 -0
- package/dist/Input/Input.d.ts +98 -0
- package/dist/Input/Label.d.ts +31 -0
- package/dist/Input/ReadOnlyField.d.ts +30 -0
- package/dist/Input/Textarea.d.ts +16 -0
- package/dist/Input/index.d.ts +15 -0
- package/dist/Input/index.js +5 -0
- package/dist/Input-2PU5CPKK.css +616 -0
- package/dist/Kbd/Kbd.d.ts +40 -0
- package/dist/Kbd/index.d.ts +3 -0
- package/dist/Kbd/index.js +3 -0
- package/dist/Kbd-W66MXQI5.css +61 -0
- package/dist/Layer/LayerHost.d.ts +23 -0
- package/dist/Layer/index.d.ts +7 -0
- package/dist/Layer/index.js +3 -0
- package/dist/Layer/place.d.ts +63 -0
- package/dist/Layer/stack.d.ts +159 -0
- package/dist/Layer-NAFSGCFA.css +23 -0
- package/dist/Layout/Layout.d.ts +104 -0
- package/dist/Layout/index.d.ts +3 -0
- package/dist/Layout/index.js +2 -0
- package/dist/Layout-2ZCV3IGF.css +171 -0
- package/dist/Link/Link.d.ts +45 -0
- package/dist/Link/index.d.ts +3 -0
- package/dist/Link/index.js +3 -0
- package/dist/Link-6BEFNMN2.css +80 -0
- package/dist/List/List.d.ts +73 -0
- package/dist/List/index.d.ts +3 -0
- package/dist/List/index.js +3 -0
- package/dist/List-XTHESXLR.css +161 -0
- package/dist/ListInput/ListInput.d.ts +68 -0
- package/dist/ListInput/index.d.ts +3 -0
- package/dist/ListInput/index.js +10 -0
- package/dist/ListInput-O7LJKOIG.css +147 -0
- package/dist/Listbox/index.d.ts +5 -0
- package/dist/Listbox/index.js +2 -0
- package/dist/Listbox/useListbox.d.ts +97 -0
- package/dist/Listbox/useOptionKeys.d.ts +64 -0
- package/dist/Listbox-X2DOTSQA.css +110 -0
- package/dist/Menu/Menu.d.ts +118 -0
- package/dist/Menu/index.d.ts +3 -0
- package/dist/Menu/index.js +7 -0
- package/dist/Menu-6DE7I66I.css +222 -0
- package/dist/Meter/Meter.d.ts +49 -0
- package/dist/Meter/index.d.ts +3 -0
- package/dist/Meter/index.js +3 -0
- package/dist/Meter-SKOOXQBC.css +87 -0
- package/dist/Modal/ConfirmModal.d.ts +74 -0
- package/dist/Modal/Modal.d.ts +154 -0
- package/dist/Modal/index.d.ts +5 -0
- package/dist/Modal/index.js +8 -0
- package/dist/Modal-XYQJ4BL6.css +484 -0
- package/dist/NewItemsNotice/NewItemsNotice.d.ts +28 -0
- package/dist/NewItemsNotice/index.d.ts +3 -0
- package/dist/NewItemsNotice/index.js +4 -0
- package/dist/NewItemsNotice-T4DSSPVV.css +60 -0
- package/dist/OrgLabel/OrgLabel.d.ts +117 -0
- package/dist/OrgLabel/index.d.ts +3 -0
- package/dist/OrgLabel/index.js +2 -0
- package/dist/OrgLabel-D7U6QJZD.css +293 -0
- package/dist/OrgNode/OrgNode.d.ts +103 -0
- package/dist/OrgNode/index.d.ts +3 -0
- package/dist/OrgNode/index.js +3 -0
- package/dist/OrgNode-BT7T2Q2X.css +214 -0
- package/dist/OrgTable/OrgTable.d.ts +113 -0
- package/dist/OrgTable/index.d.ts +3 -0
- package/dist/OrgTable/index.js +11 -0
- package/dist/OrgTable-VWMFC3TB.css +360 -0
- package/dist/PageHeader/PageHeader.d.ts +35 -0
- package/dist/PageHeader/index.d.ts +3 -0
- package/dist/PageHeader/index.js +3 -0
- package/dist/PageHeader-6EYWQXRE.css +88 -0
- package/dist/Popover/Popover.d.ts +91 -0
- package/dist/Popover/index.d.ts +3 -0
- package/dist/Popover/index.js +4 -0
- package/dist/Popover-WJGCF3ZQ.css +185 -0
- package/dist/PricingCard/PricingCard.d.ts +56 -0
- package/dist/PricingCard/index.d.ts +3 -0
- package/dist/PricingCard/index.js +4 -0
- package/dist/PricingCard-JFI7RYXP.css +278 -0
- package/dist/Prose/Prose.d.ts +33 -0
- package/dist/Prose/index.d.ts +3 -0
- package/dist/Prose/index.js +2 -0
- package/dist/Prose-BTXNFT2Q.css +99 -0
- package/dist/RelativeTime/RelativeTime.d.ts +31 -0
- package/dist/RelativeTime/clock.d.ts +9 -0
- package/dist/RelativeTime/format.d.ts +38 -0
- package/dist/RelativeTime/index.d.ts +6 -0
- package/dist/RelativeTime/index.js +4 -0
- package/dist/RelativeTime-EBAQPGO2.css +10 -0
- package/dist/SearchTrigger/SearchTrigger.d.ts +29 -0
- package/dist/SearchTrigger/index.d.ts +3 -0
- package/dist/SearchTrigger/index.js +2 -0
- package/dist/SearchTrigger-QXOYAUUY.css +79 -0
- package/dist/Section/Section.d.ts +41 -0
- package/dist/Section/index.d.ts +3 -0
- package/dist/Section/index.js +3 -0
- package/dist/Section-QRUPRIQ2.css +127 -0
- package/dist/SegmentedControl/SegmentedControl.d.ts +68 -0
- package/dist/SegmentedControl/index.d.ts +4 -0
- package/dist/SegmentedControl/index.js +5 -0
- package/dist/SegmentedControl-X3BI3XU4.css +68 -0
- package/dist/Select/Select.d.ts +138 -0
- package/dist/Select/index.d.ts +3 -0
- package/dist/Select/index.js +5 -0
- package/dist/Select-2X77FSWR.css +350 -0
- package/dist/Shortcut/index.d.ts +2 -0
- package/dist/Shortcut/index.js +4 -0
- package/dist/Shortcut/useShortcut.d.ts +68 -0
- package/dist/SidebarNav/SidebarNav.d.ts +117 -0
- package/dist/SidebarNav/index.d.ts +3 -0
- package/dist/SidebarNav/index.js +3 -0
- package/dist/SidebarNav-QGSFKZYA.css +319 -0
- package/dist/Skeleton/Skeleton.d.ts +50 -0
- package/dist/Skeleton/index.d.ts +3 -0
- package/dist/Skeleton/index.js +3 -0
- package/dist/Skeleton-V735HRGM.css +421 -0
- package/dist/StatCard/StatCard.d.ts +56 -0
- package/dist/StatCard/index.d.ts +3 -0
- package/dist/StatCard/index.js +3 -0
- package/dist/StatCard-KYPKZUWX.css +111 -0
- package/dist/StatGroup/StatGroup.d.ts +20 -0
- package/dist/StatGroup/index.d.ts +3 -0
- package/dist/StatGroup/index.js +2 -0
- package/dist/StatGroup-TGB6AEKM.css +80 -0
- package/dist/StatusDot/StatusDot.d.ts +25 -0
- package/dist/StatusDot/index.d.ts +3 -0
- package/dist/StatusDot/index.js +2 -0
- package/dist/StatusDot-HA2L2FSX.css +84 -0
- package/dist/Switch/Switch.d.ts +38 -0
- package/dist/Switch/index.d.ts +3 -0
- package/dist/Switch/index.js +2 -0
- package/dist/Switch-U4OWK4CL.css +169 -0
- package/dist/Table/Table.d.ts +51 -0
- package/dist/Table/index.d.ts +3 -0
- package/dist/Table/index.js +3 -0
- package/dist/Table-MDOLVUAW.css +159 -0
- package/dist/Tabs/Tabs.d.ts +97 -0
- package/dist/Tabs/index.d.ts +3 -0
- package/dist/Tabs/index.js +4 -0
- package/dist/Tabs/roving.d.ts +36 -0
- package/dist/Tabs-VLICJFVB.css +275 -0
- package/dist/Tag/Tag.d.ts +107 -0
- package/dist/Tag/index.d.ts +3 -0
- package/dist/Tag/index.js +3 -0
- package/dist/Tag-VNZEYLB6.css +406 -0
- package/dist/TagGroup/TagGroup.d.ts +41 -0
- package/dist/TagGroup/index.d.ts +3 -0
- package/dist/TagGroup/index.js +4 -0
- package/dist/TagGroup-APC2EFH4.css +75 -0
- package/dist/TagsInput/TagsInput.d.ts +112 -0
- package/dist/TagsInput/index.d.ts +3 -0
- package/dist/TagsInput/index.js +10 -0
- package/dist/TagsInput-W4P36PRJ.css +168 -0
- package/dist/Text/Text.d.ts +67 -0
- package/dist/Text/index.d.ts +3 -0
- package/dist/Text/index.js +2 -0
- package/dist/Text-XIPYYZX2.css +154 -0
- package/dist/ThemeSwitcher/ThemeSwitcher.d.ts +47 -0
- package/dist/ThemeSwitcher/index.d.ts +4 -0
- package/dist/ThemeSwitcher/index.js +6 -0
- package/dist/ThemeSwitcher/preferences.d.ts +51 -0
- package/dist/TimeWindowPicker/TimeWindowPicker.d.ts +231 -0
- package/dist/TimeWindowPicker/index.d.ts +3 -0
- package/dist/TimeWindowPicker/index.js +13 -0
- package/dist/TimeWindowPicker/mask.d.ts +82 -0
- package/dist/TimeWindowPicker-7I7KWCMU.css +403 -0
- package/dist/Timeline/Timeline.d.ts +51 -0
- package/dist/Timeline/index.d.ts +3 -0
- package/dist/Timeline/index.js +3 -0
- package/dist/Timeline-27SYKOFX.css +144 -0
- package/dist/Toaster/Toaster.d.ts +108 -0
- package/dist/Toaster/index.d.ts +3 -0
- package/dist/Toaster/index.js +5 -0
- package/dist/Toaster-NVDCEIP5.css +306 -0
- package/dist/Toolbar/Toolbar.d.ts +62 -0
- package/dist/Toolbar/index.d.ts +3 -0
- package/dist/Toolbar/index.js +4 -0
- package/dist/Toolbar-IP6LXN45.css +48 -0
- package/dist/Tooltip/Tooltip.d.ts +51 -0
- package/dist/Tooltip/index.d.ts +3 -0
- package/dist/Tooltip/index.js +4 -0
- package/dist/Tooltip-LKQF7CE4.css +71 -0
- package/dist/Tree/index.d.ts +8 -0
- package/dist/Tree/index.js +1 -0
- package/dist/Tree/layout.d.ts +160 -0
- package/dist/Tree/model.d.ts +110 -0
- package/dist/Tree/useMeasuredSizes.d.ts +61 -0
- package/dist/Tree/useTreeState.d.ts +89 -0
- package/dist/TreeCanvas/TreeCanvas.d.ts +384 -0
- package/dist/TreeCanvas/index.d.ts +3 -0
- package/dist/TreeCanvas/index.js +10 -0
- package/dist/TreeCanvas/motion.d.ts +59 -0
- package/dist/TreeCanvas-WBNQPHC7.css +1098 -0
- package/dist/TreeGrid/TreeGrid.d.ts +142 -0
- package/dist/TreeGrid/index.d.ts +3 -0
- package/dist/TreeGrid/index.js +8 -0
- package/dist/TreeGrid-NSW7VMOX.css +132 -0
- package/dist/VisuallyHidden/VisuallyHidden.d.ts +23 -0
- package/dist/VisuallyHidden/index.d.ts +3 -0
- package/dist/VisuallyHidden/index.js +2 -0
- package/dist/VisuallyHidden-L552H7OA.css +21 -0
- package/dist/chunk-22O7LAW2.js +41 -0
- package/dist/chunk-23DHIMJA.js +38 -0
- package/dist/chunk-2EOKFKHX.js +263 -0
- package/dist/chunk-2PRH365R.js +74 -0
- package/dist/chunk-2ZQMA2WB.js +57 -0
- package/dist/chunk-3CZ7XAVY.js +139 -0
- package/dist/chunk-3EYF6HKB.js +135 -0
- package/dist/chunk-3ZP55QZE.js +40 -0
- package/dist/chunk-53DVJCVW.js +14 -0
- package/dist/chunk-5C5YMZQU.js +51 -0
- package/dist/chunk-5EKIWVOR.js +132 -0
- package/dist/chunk-5IMACPJS.js +495 -0
- package/dist/chunk-5KPQ6D7N.js +54 -0
- package/dist/chunk-5SDBMKUO.js +297 -0
- package/dist/chunk-5WS6L6FA.js +114 -0
- package/dist/chunk-7EM5T4ME.js +39 -0
- package/dist/chunk-7FZ53WDJ.js +163 -0
- package/dist/chunk-7HPRF5XN.js +525 -0
- package/dist/chunk-7RPGY3JE.js +43 -0
- package/dist/chunk-A2UXBCLO.js +48 -0
- package/dist/chunk-ARMRX2YV.js +96 -0
- package/dist/chunk-AV2DXAEL.js +27 -0
- package/dist/chunk-BHHIIK3M.js +17 -0
- package/dist/chunk-BZFWDIV6.js +9 -0
- package/dist/chunk-BZYDZBAN.js +123 -0
- package/dist/chunk-CMEE37QJ.js +628 -0
- package/dist/chunk-D3OADIM6.js +112 -0
- package/dist/chunk-DD5BBGBE.js +162 -0
- package/dist/chunk-EHMQQHYR.js +1652 -0
- package/dist/chunk-EN6K2IFA.js +256 -0
- package/dist/chunk-EPOOQZYA.js +118 -0
- package/dist/chunk-ESCO4XYW.js +144 -0
- package/dist/chunk-EUCC37WY.js +14 -0
- package/dist/chunk-EV6IMYJ6.js +62 -0
- package/dist/chunk-F27EPQ7D.js +68 -0
- package/dist/chunk-F4PJZ4ED.js +245 -0
- package/dist/chunk-F6OE5FH3.js +49 -0
- package/dist/chunk-FBZAKNSX.js +263 -0
- package/dist/chunk-FEFTGVMF.js +46 -0
- package/dist/chunk-G2QFRTJ2.js +823 -0
- package/dist/chunk-GHYY2WPF.js +907 -0
- package/dist/chunk-GTOUGQQK.js +147 -0
- package/dist/chunk-GUIF6Q6N.js +143 -0
- package/dist/chunk-GXQ3B46I.js +216 -0
- package/dist/chunk-H4FBTAYS.js +130 -0
- package/dist/chunk-HOXGBLEY.js +37 -0
- package/dist/chunk-HQNHV7D6.js +54 -0
- package/dist/chunk-HTDFCRJZ.js +92 -0
- package/dist/chunk-HZ5XZNPS.js +98 -0
- package/dist/chunk-IAJLHVUA.js +28 -0
- package/dist/chunk-IJ7QXNIJ.js +1 -0
- package/dist/chunk-ITHXJHBB.js +280 -0
- package/dist/chunk-JCSA3XVH.js +32 -0
- package/dist/chunk-KLJCCMF3.js +97 -0
- package/dist/chunk-LGCPQIOZ.js +49 -0
- package/dist/chunk-LWKJQTOM.js +77 -0
- package/dist/chunk-MNAXYY3R.js +215 -0
- package/dist/chunk-NN62JQLR.js +29 -0
- package/dist/chunk-NPZY6YYL.js +251 -0
- package/dist/chunk-NTRZGNEX.js +529 -0
- package/dist/chunk-O6232G37.js +273 -0
- package/dist/chunk-O67VF5MS.js +58 -0
- package/dist/chunk-ODEQTPFM.js +6 -0
- package/dist/chunk-PNFASD6F.js +98 -0
- package/dist/chunk-PQADV6P6.js +19 -0
- package/dist/chunk-PZSWF74H.js +15 -0
- package/dist/chunk-Q4ZPPART.js +26 -0
- package/dist/chunk-QNCVHRZL.js +17 -0
- package/dist/chunk-QVE4GJAT.js +15 -0
- package/dist/chunk-QYOFACSP.js +36 -0
- package/dist/chunk-RA2ULG6H.js +29 -0
- package/dist/chunk-RDGD7Z7I.js +350 -0
- package/dist/chunk-RK4XPHVG.js +16 -0
- package/dist/chunk-RSAQOKH3.js +38 -0
- package/dist/chunk-S2XHHEW4.js +84 -0
- package/dist/chunk-S4GZWSKR.js +137 -0
- package/dist/chunk-SFZOKW2G.js +52 -0
- package/dist/chunk-T7FKOJKW.js +221 -0
- package/dist/chunk-UG46QBLT.js +325 -0
- package/dist/chunk-UOGSZKLT.js +134 -0
- package/dist/chunk-V2XMNLMS.js +52 -0
- package/dist/chunk-V663QU4R.js +51 -0
- package/dist/chunk-W4ENKCXJ.js +40 -0
- package/dist/chunk-W5J7R5EB.js +107 -0
- package/dist/chunk-WNI2WSJF.js +27 -0
- package/dist/chunk-XDTYBF2F.js +36 -0
- package/dist/chunk-XN4JBAN3.js +32 -0
- package/dist/chunk-XV6WRMBC.js +211 -0
- package/dist/chunk-YLYOWZ4V.js +33 -0
- package/dist/chunk-YMWONFSI.js +170 -0
- package/dist/chunk-ZCR6YGQ4.js +1 -0
- package/dist/generated/index.d.ts +83 -0
- package/dist/generated/index.js +91 -0
- package/dist/index.d.ts +1 -1217
- package/dist/index.js +91 -4518
- package/dist/styles.css +14841 -4274
- package/dist/utils/cx.d.ts +10 -0
- package/dist/utils/headingLevel.d.ts +16 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/tone.d.ts +25 -0
- package/dist/utils/useClipboard.d.ts +30 -0
- package/package.json +18 -10
- package/scripts/bundle-css.mjs +25 -0
- package/scripts/check-css-literals.mjs +166 -0
- package/scripts/check-css-variables.mjs +184 -0
- package/scripts/check-css.mjs +27 -0
- package/scripts/css-source.mjs +67 -0
- package/scripts/write-barrel.mjs +60 -0
- package/dist/Accordion-NIMJQIOI.css +0 -88
- package/dist/AppShell-ZW3NSFBP.css +0 -51
- package/dist/Avatar-V6NG6Q45.css +0 -67
- package/dist/Button-XGCTXXYP.css +0 -174
- package/dist/Callout-LEGDIMAM.css +0 -52
- package/dist/Card-BOZGBML7.css +0 -86
- package/dist/Checkbox-OCUICIIZ.css +0 -58
- package/dist/CodeBlock-IEMBNIQC.css +0 -90
- package/dist/Container-LTKBA2FW.css +0 -21
- package/dist/Copyable-IB57OTHZ.css +0 -123
- package/dist/DataTable-3GALZUW2.css +0 -1593
- package/dist/DateTimePicker-NMSSGVPK.css +0 -312
- package/dist/Eyebrow-AVBORAS2.css +0 -30
- package/dist/IconButton-GB4PJDG2.css +0 -82
- package/dist/ImageUpload-3HQDF2KC.css +0 -158
- package/dist/Input-ZHUTN7CU.css +0 -210
- package/dist/Kbd-Q77CDZY7.css +0 -23
- package/dist/Modal-FJVG66S4.css +0 -138
- package/dist/Popover-FUFULUE2.css +0 -123
- package/dist/PricingCard-NKYV3JHA.css +0 -238
- package/dist/Section-665ZIPG6.css +0 -20
- package/dist/Select-GPRF7PRB.css +0 -294
- package/dist/Skeleton-3WEFLRDN.css +0 -378
- package/dist/StatCard-RTJIVTRB.css +0 -50
- package/dist/Table-AR3TRY2E.css +0 -89
- package/dist/Tabs-XZ4JIH3E.css +0 -153
- package/dist/Tag-R5QDJLYJ.css +0 -163
- package/dist/TimeWindowPicker-L3G5Q7UT.css +0 -629
- package/dist/Toaster-2O65VOR4.css +0 -264
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Joining a class list, once for the whole package.
|
|
3
|
+
*
|
|
4
|
+
* Every component had its own copy of `[a, b].filter(Boolean).join(' ')`, and
|
|
5
|
+
* Skeleton declared a named one beside it. A helper spelled nine times is a
|
|
6
|
+
* helper whose copies come to disagree about what a `0` means; this one drops
|
|
7
|
+
* every falsy part, so a `count && 'has-count'` guard cannot render the number
|
|
8
|
+
* into the class attribute.
|
|
9
|
+
*/
|
|
10
|
+
export declare function cx(...parts: (string | false | null | undefined)[]): string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/** The heading elements a component may render. */
|
|
3
|
+
export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
4
|
+
export interface HeadingLevelProviderProps {
|
|
5
|
+
/** The level the children's own headings start at. */
|
|
6
|
+
level: HeadingLevel;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/** Declares the level a surface's contents start at. */
|
|
10
|
+
export declare function HeadingLevelProvider({ level, children }: HeadingLevelProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
/** The level a heading rendered here should be. Defaults to 2, under a page title. */
|
|
12
|
+
export declare function useHeadingLevel(): HeadingLevel;
|
|
13
|
+
/** One level deeper, clamped at 6. */
|
|
14
|
+
export declare function nextHeadingLevel(level: HeadingLevel): HeadingLevel;
|
|
15
|
+
/** The tag name for a level, for a component that renders one. */
|
|
16
|
+
export declare function headingTag(level: HeadingLevel): `h${HeadingLevel}`;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { cx } from './cx.js';
|
|
2
|
+
export { useClipboard } from './useClipboard.js';
|
|
3
|
+
export type { Clipboard, ClipboardOptions, ClipboardState } from './useClipboard.js';
|
|
4
|
+
export type { PhaseTone, Tone } from './tone.js';
|
|
5
|
+
export { HeadingLevelProvider, headingTag, nextHeadingLevel, useHeadingLevel } from './headingLevel.js';
|
|
6
|
+
export type { HeadingLevel, HeadingLevelProviderProps } from './headingLevel.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two colour vocabularies a component is allowed to take as a prop.
|
|
3
|
+
*
|
|
4
|
+
* ONE SPELLING. The package shipped `warn` in Tag and Toaster and `warning` in
|
|
5
|
+
* StatCard and Callout, and `danger` beside `error`, so the same state had two
|
|
6
|
+
* names depending on which component drew it. A union declared once is what
|
|
7
|
+
* stops the next component inventing a third.
|
|
8
|
+
*
|
|
9
|
+
* A tone says what a thing IS, never who it is: success, warning, danger and
|
|
10
|
+
* info are states, `brand` is where the reader is, and everything else is
|
|
11
|
+
* neutral. Identity (a seat, a node, a vendor, a tool) takes neutral colour and
|
|
12
|
+
* is carried by its name, its glyph and its position.
|
|
13
|
+
*/
|
|
14
|
+
export type Tone = 'neutral' | 'info' | 'success' | 'warning' | 'danger' | 'brand';
|
|
15
|
+
/**
|
|
16
|
+
* The phase vocabulary, and nothing else.
|
|
17
|
+
*
|
|
18
|
+
* Three phases, because that is the whole of the engine's phase model. A
|
|
19
|
+
* per-model or per-worker breakdown is a CHART SERIES SET and takes the data
|
|
20
|
+
* ramp (`--color-data-1` and the rest) inside a legend, not this family: a
|
|
21
|
+
* reader compares phase marks against each other, so the three are separated
|
|
22
|
+
* from one another and from every status hue, which a growing set of series
|
|
23
|
+
* could not be.
|
|
24
|
+
*/
|
|
25
|
+
export type PhaseTone = 'phase-onboarding' | 'phase-execute' | 'phase-review';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type ClipboardState = 'idle' | 'copied' | 'failed';
|
|
2
|
+
export interface ClipboardOptions {
|
|
3
|
+
/** How long the copied or failed answer stands before the control settles back. */
|
|
4
|
+
resetMs?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Clipboard {
|
|
7
|
+
state: ClipboardState;
|
|
8
|
+
copy: (text: string | (() => string)) => Promise<boolean>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Putting text on the clipboard, and saying whether it arrived.
|
|
12
|
+
*
|
|
13
|
+
* TWO THINGS ARE LOAD BEARING, and both were wrong before this existed.
|
|
14
|
+
*
|
|
15
|
+
* 1. THE CLIPBOARD API IS NOT ALWAYS THERE. It is gated on a secure context,
|
|
16
|
+
* so `navigator.clipboard` is simply undefined on the plain http origin
|
|
17
|
+
* anybody reads a dashboard at that is not their own laptop. An optional
|
|
18
|
+
* call made that failure silent: the button clicked, nothing was copied,
|
|
19
|
+
* and nothing said so. The `execCommand` fallback is deprecated and is
|
|
20
|
+
* also the only thing that works there, so it stays, and its boolean
|
|
21
|
+
* result is honoured rather than assumed.
|
|
22
|
+
* 2. A COPY WITH NO FEEDBACK IS A DEAD BUTTON. The clipboard is invisible;
|
|
23
|
+
* the only way a reader learns it worked is if the control says so, which
|
|
24
|
+
* is what `state` is for.
|
|
25
|
+
*
|
|
26
|
+
* The text may be a THUNK, resolved on the press. On a live screen the thing
|
|
27
|
+
* worth copying is assembled from everything on it, so a string prop means
|
|
28
|
+
* building it again on every push for a control nobody has touched.
|
|
29
|
+
*/
|
|
30
|
+
export declare function useClipboard({ resetMs }?: ClipboardOptions): Clipboard;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewlethq/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Crewlet shared React components built on @crewlethq/tokens and @crewlethq/icons.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -24,21 +24,26 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"import": "./dist/index.js"
|
|
26
26
|
},
|
|
27
|
-
"./styles.css": "./dist/styles.css"
|
|
27
|
+
"./styles.css": "./dist/styles.css",
|
|
28
|
+
"./*": {
|
|
29
|
+
"types": "./dist/*/index.d.ts",
|
|
30
|
+
"import": "./dist/*/index.js"
|
|
31
|
+
}
|
|
28
32
|
},
|
|
29
33
|
"files": [
|
|
30
|
-
"dist"
|
|
34
|
+
"dist",
|
|
35
|
+
"scripts"
|
|
31
36
|
],
|
|
32
37
|
"scripts": {
|
|
33
|
-
"build": "tsup && node scripts/bundle-css.mjs",
|
|
34
|
-
"dev": "tsup --watch --onSuccess \"node scripts/bundle-css.mjs\"",
|
|
35
|
-
"lint": "eslint src scripts && node scripts/check-css-variables.mjs",
|
|
36
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
37
|
-
"clean": "rm -rf dist"
|
|
38
|
+
"build": "node scripts/write-barrel.mjs && tsup && tsc -p tsconfig.build.json && node scripts/bundle-css.mjs",
|
|
39
|
+
"dev": "node scripts/write-barrel.mjs && tsup --watch --onSuccess \"node scripts/bundle-css.mjs\"",
|
|
40
|
+
"lint": "node scripts/write-barrel.mjs && eslint src scripts && node scripts/check-css-variables.mjs && node scripts/check-css-literals.mjs src/Avatar src/Layer src/Listbox src/Announcer src/Modal src/Tooltip src/CommandPalette src/VisuallyHidden src/utils src/Count src/StatusDot src/EmptyValue src/Button src/IconButton src/Popover src/Menu src/DataView src/DataTable src/Input src/Tag src/TagGroup src/FilterChip src/EntityChip src/Callout src/Toaster src/Skeleton src/EmptyState src/Meter src/StatCard src/StatGroup src/NewItemsNotice src/PricingCard src/ImageUpload src/Tabs src/SegmentedControl src/PageHeader src/Card src/Section src/Charts src/Layout src/Canvas src/Tree src/TreeCanvas src/TreeGrid src/OrgNode src/OrgLabel src/AddPill src/OrgTable",
|
|
41
|
+
"typecheck": "node scripts/write-barrel.mjs && tsc -p tsconfig.json --noEmit",
|
|
42
|
+
"clean": "rm -rf dist src/generated"
|
|
38
43
|
},
|
|
39
44
|
"dependencies": {
|
|
40
|
-
"@crewlethq/icons": "0.
|
|
41
|
-
"@crewlethq/tokens": "0.
|
|
45
|
+
"@crewlethq/icons": "0.3.0",
|
|
46
|
+
"@crewlethq/tokens": "0.3.0"
|
|
42
47
|
},
|
|
43
48
|
"peerDependencies": {
|
|
44
49
|
"react": ">=18",
|
|
@@ -54,5 +59,8 @@
|
|
|
54
59
|
"publishConfig": {
|
|
55
60
|
"access": "public",
|
|
56
61
|
"registry": "https://registry.npmjs.org"
|
|
62
|
+
},
|
|
63
|
+
"bin": {
|
|
64
|
+
"crewlet-css-check": "./scripts/check-css.mjs"
|
|
57
65
|
}
|
|
58
66
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
// tsup emits hashed CSS chunks that the compiled JS imports via side-effect.
|
|
6
|
+
// We additionally publish a single dist/styles.css containing the same rules,
|
|
7
|
+
// so consumers can do either:
|
|
8
|
+
// (1) import { Button } from '@crewlethq/ui' // CSS auto-loads via side-effect
|
|
9
|
+
// (2) import '@crewlethq/ui/styles.css' // single bundle (SSR / non-tree-shaking consumers)
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const dist = resolve(__dirname, '..', 'dist');
|
|
12
|
+
|
|
13
|
+
const all = await readdir(dist);
|
|
14
|
+
const chunks = all.filter((f) => f.endsWith('.css') && f !== 'styles.css').sort();
|
|
15
|
+
|
|
16
|
+
const parts = await Promise.all(
|
|
17
|
+
chunks.map(async (f) => `/* ${f} */\n${await readFile(resolve(dist, f), 'utf8')}`),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
await writeFile(
|
|
21
|
+
resolve(dist, 'styles.css'),
|
|
22
|
+
parts.length === 0 ? '/* empty */\n' : parts.join('\n\n'),
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
console.warn(`[ui] bundled ${chunks.length} css chunk(s) into styles.css`);
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Refuses a value a component should have taken from a token, over the folders
|
|
3
|
+
// it is given.
|
|
4
|
+
//
|
|
5
|
+
// WHY IT TAKES FOLDERS. Its sibling, check-css-variables.mjs, runs over the
|
|
6
|
+
// whole package and holds rules no component may break at any point. This one
|
|
7
|
+
// holds the rules a folder OPTS INTO as it is rewritten onto the token layer,
|
|
8
|
+
// so a component that has not been rewritten yet does not have to be
|
|
9
|
+
// allow-listed to keep the build green. The list of folders in the package's
|
|
10
|
+
// lint script is the record of which are done; when the last one lands, the
|
|
11
|
+
// list becomes `src` and this paragraph goes with it.
|
|
12
|
+
//
|
|
13
|
+
// It is also the published bin, `crewlet-css-check`, so a consumer can hold
|
|
14
|
+
// its own stylesheets to the same rules.
|
|
15
|
+
//
|
|
16
|
+
// THE RULES.
|
|
17
|
+
//
|
|
18
|
+
// 1. No colour literal. A hex, an rgb(), an hsl() or a named colour is a
|
|
19
|
+
// colour that does not follow the theme, and a fallback literal inside
|
|
20
|
+
// var() is the same thing with a comforting shape: it is what renders
|
|
21
|
+
// whenever the token name is misspelt, so it hides the very failure it
|
|
22
|
+
// looks like insurance against.
|
|
23
|
+
// 2. No px font size, no literal radius, no literal duration, no literal
|
|
24
|
+
// z-index. Each of those is a scale, and a component that spends a number
|
|
25
|
+
// off the scale is a component that drifts from the one beside it.
|
|
26
|
+
// 3. No color-mix(). Mixing two tokens produces a third colour nobody
|
|
27
|
+
// measured, which is how a "warning text" step ended up at 4.41:1.
|
|
28
|
+
// 4. An animation or a transition is paired with a reduced-motion rule IN THE
|
|
29
|
+
// SAME FILE. The document baseline collapses motion too, but a component
|
|
30
|
+
// is also used in an application that does not import the baseline.
|
|
31
|
+
// 5. A media query's length is one of the breakpoint tokens. A media query
|
|
32
|
+
// cannot read a custom property, so the number has to be written out; this
|
|
33
|
+
// is what says it is still the same number.
|
|
34
|
+
// 6. No hover overlay on a pseudo element. A row shows the selected tint or
|
|
35
|
+
// the hover overlay, never both, because both are a background on the same
|
|
36
|
+
// element and the selected state wins. Drawing the hover on a ::before is
|
|
37
|
+
// the one way to stack them, and it produces a composite nothing measured.
|
|
38
|
+
|
|
39
|
+
import { dirname, resolve } from 'node:path';
|
|
40
|
+
import { fileURLToPath } from 'node:url';
|
|
41
|
+
import { lineOf, readSources, report, rules } from './css-source.mjs';
|
|
42
|
+
|
|
43
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
44
|
+
|
|
45
|
+
const NAMED_COLOURS =
|
|
46
|
+
/\b(aqua|black|blue|fuchsia|gray|grey|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow|orange|pink|brown|violet|indigo|gold|beige|coral|crimson|cyan|magenta|salmon|tan|turquoise)\b/;
|
|
47
|
+
const HEX = /#[0-9a-fA-F]{3,8}\b/;
|
|
48
|
+
const COLOUR_FUNCTION = /\b(rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\s*\(/;
|
|
49
|
+
const DURATION = /(?<![\w-])\d*\.?\d+m?s\b/;
|
|
50
|
+
const LENGTH_IN_QUERY = /(\d*\.?\d+)px/g;
|
|
51
|
+
|
|
52
|
+
/** Properties whose value is a colour, so a literal in one is a colour literal. */
|
|
53
|
+
const COLOUR_PROPERTY =
|
|
54
|
+
/^(color|background|background-color|border(-(top|right|bottom|left))?-color|border|border-(top|right|bottom|left)|outline|outline-color|fill|stroke|box-shadow|text-shadow|caret-color|column-rule-color|text-decoration-color|accent-color|scrollbar-color|--crewlet-[\w-]*)$/;
|
|
55
|
+
|
|
56
|
+
function declarations(body) {
|
|
57
|
+
const found = [];
|
|
58
|
+
for (const part of body.split(';')) {
|
|
59
|
+
const at = part.indexOf(':');
|
|
60
|
+
if (at < 0) continue;
|
|
61
|
+
found.push({ property: part.slice(0, at).trim().toLowerCase(), value: part.slice(at + 1).trim() });
|
|
62
|
+
}
|
|
63
|
+
return found;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** A value with every var() reference removed, so only its own literals remain. */
|
|
67
|
+
function withoutTokens(value) {
|
|
68
|
+
let text = value;
|
|
69
|
+
let previous;
|
|
70
|
+
do {
|
|
71
|
+
previous = text;
|
|
72
|
+
// Innermost var() first, so a nested fallback is stripped with its parent.
|
|
73
|
+
text = text.replace(/var\(\s*--[\w-]+\s*(?:,[^()]*)?\)/g, ' ');
|
|
74
|
+
} while (text !== previous);
|
|
75
|
+
return text;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The breakpoint steps, from the tokens package's own typed export.
|
|
80
|
+
*
|
|
81
|
+
* `import.meta.resolve` rather than `createRequire().resolve`: the tokens
|
|
82
|
+
* package declares only an `import` condition, so CJS resolution refuses its
|
|
83
|
+
* main entry outright.
|
|
84
|
+
*/
|
|
85
|
+
async function breakpoints() {
|
|
86
|
+
const { breakpoint } = await import(import.meta.resolve('@crewlethq/tokens'));
|
|
87
|
+
return new Set(Object.values(breakpoint).map((value) => Number.parseFloat(String(value))));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function findings(roots, base = packageRoot) {
|
|
91
|
+
const files = readSources(roots, base, /\.css$/);
|
|
92
|
+
const problems = [];
|
|
93
|
+
const allowed = await breakpoints();
|
|
94
|
+
|
|
95
|
+
for (const file of files) {
|
|
96
|
+
const at = (index) => `${file.where}:${lineOf(file.text, index)}`;
|
|
97
|
+
const hasReducedMotion = file.text.includes('prefers-reduced-motion');
|
|
98
|
+
|
|
99
|
+
for (const { selector, body, index } of rules(file.text)) {
|
|
100
|
+
const where = at(index);
|
|
101
|
+
const inQuery = /@media/.test(selector);
|
|
102
|
+
|
|
103
|
+
if (inQuery) {
|
|
104
|
+
for (const match of selector.matchAll(LENGTH_IN_QUERY)) {
|
|
105
|
+
if (!allowed.has(Number(match[1]))) {
|
|
106
|
+
problems.push(
|
|
107
|
+
`${where}: the media query switches at ${match[0]}, which is not a breakpoint token. Use one of ${[...allowed].sort((a, b) => a - b).join('px, ')}px, or add the step to packages/tokens/tokens/breakpoint.json`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (/:hover\s*::?(before|after)\b/.test(selector) && /(^|;|\s)background/.test(body)) {
|
|
114
|
+
problems.push(
|
|
115
|
+
`${where}: draws a hover overlay on a pseudo element. A row shows the selected tint or the hover overlay, never both, and a pseudo element is the one way to stack them into a composite nothing has measured`,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (const { property, value } of declarations(body)) {
|
|
120
|
+
const bare = withoutTokens(value);
|
|
121
|
+
const colourish = COLOUR_PROPERTY.test(property);
|
|
122
|
+
if (colourish && (HEX.test(bare) || COLOUR_FUNCTION.test(bare) || NAMED_COLOURS.test(bare))) {
|
|
123
|
+
problems.push(`${where}: ${property} carries a colour literal (${value.trim()}). Every colour comes from a token`);
|
|
124
|
+
}
|
|
125
|
+
if (value.includes('color-mix(')) {
|
|
126
|
+
problems.push(
|
|
127
|
+
`${where}: ${property} uses color-mix(), which makes a colour nobody measured. Add the step to packages/tokens/tokens/ instead`,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
if (property === 'font-size' && /(?<![\w-])\d*\.?\d+(px|rem|em)\b/.test(bare)) {
|
|
131
|
+
problems.push(`${where}: font-size is a literal (${value.trim()}). Use a --font-size-* token`);
|
|
132
|
+
}
|
|
133
|
+
if (/^border(-[a-z]+)?-radius$/.test(property) && /(?<![\w-])\d*\.?\d+(px|rem|em)\b/.test(bare)) {
|
|
134
|
+
problems.push(`${where}: ${property} is a literal (${value.trim()}). Use a --radius-* token`);
|
|
135
|
+
}
|
|
136
|
+
if (/^(transition|animation)(-duration|-delay)?$/.test(property) && DURATION.test(bare)) {
|
|
137
|
+
problems.push(`${where}: ${property} carries a literal duration (${value.trim()}). Use a --motion-duration-* token`);
|
|
138
|
+
}
|
|
139
|
+
if (property === 'z-index' && /^-?\d+$/.test(bare.trim()) && Math.abs(Number(bare.trim())) > 1) {
|
|
140
|
+
problems.push(`${where}: z-index is a literal (${value.trim()}). Use a --z-index-* token, or the Layer module's own depth`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!hasReducedMotion && /(^|[;{\s])(animation|transition)\s*:/.test(file.text)) {
|
|
146
|
+
problems.push(
|
|
147
|
+
`${file.where}: animates or transitions with no prefers-reduced-motion rule in the file. The document baseline is opt-in, so a component states its own`,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return { problems, checked: `${files.length} stylesheets in ${roots.length} folder(s)` };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function main() {
|
|
156
|
+
const roots = process.argv.slice(2).map((path) => resolve(process.cwd(), path));
|
|
157
|
+
if (roots.length === 0) {
|
|
158
|
+
console.error('usage: check-css-literals.mjs <folder> [folder...]');
|
|
159
|
+
process.exitCode = 2;
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const { problems, checked } = await findings(roots);
|
|
163
|
+
report('CSS literal check', problems, checked);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (process.argv[1] && import.meta.url === `file://${process.argv[1]}`) await main();
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The rules EVERY component in the package keeps, checked over all of src/.
|
|
3
|
+
//
|
|
4
|
+
// Its sibling, check-css-literals.mjs, holds the rules a folder opts into as
|
|
5
|
+
// it is rewritten onto the token layer. These are the ones nothing may break
|
|
6
|
+
// at any point, because each of them fails silently in production:
|
|
7
|
+
//
|
|
8
|
+
// 1. A name in a token namespace (--color-*, --font-*, --spacing-* and the
|
|
9
|
+
// rest of TOKEN_PREFIXES) must be one the @crewlethq/tokens build emits,
|
|
10
|
+
// whether or not the reference carries a fallback. A `var(--name)` that
|
|
11
|
+
// resolves to nothing is not an error the browser reports: the property
|
|
12
|
+
// falls back to its initial value, and a `var(--name, x)` with a misspelt
|
|
13
|
+
// name quietly renders `x` forever.
|
|
14
|
+
// 2. Every other name belongs to a component and is namespaced --crewlet-*,
|
|
15
|
+
// both where it is read and where it is declared, so a component never
|
|
16
|
+
// claims a name an application stylesheet may already use.
|
|
17
|
+
// 3. A --crewlet-* name read without a fallback must be declared somewhere
|
|
18
|
+
// in the scanned source.
|
|
19
|
+
// 4. No glyph is drawn as a Material Symbols ligature. A component that
|
|
20
|
+
// spells `material-symbols-outlined` renders the WORD until a stylesheet
|
|
21
|
+
// it does not own has fetched a font from a third-party host, and renders
|
|
22
|
+
// that word for good on a closed network.
|
|
23
|
+
// 5. Nothing loads from a host: no `url()` with a scheme or a protocol
|
|
24
|
+
// relative path, and no `@import` of a remote stylesheet. A design system
|
|
25
|
+
// that phones home is one an air-gapped deployment cannot use and a
|
|
26
|
+
// strict Content-Security-Policy refuses.
|
|
27
|
+
// 6. No `body.theme-*` selector. The theme is a contract on the ROOT element
|
|
28
|
+
// now, and a body class silently paints nothing.
|
|
29
|
+
// 7. `--color-text-muted` is the DECORATION step, measured into the 2.8 to
|
|
30
|
+
// 4.5 band on purpose, so it is never the `color` of anything but an svg.
|
|
31
|
+
// Anything a reader has to make out takes --color-text-tertiary.
|
|
32
|
+
// 8. A `:focus-visible` rule does not turn the outline off without putting
|
|
33
|
+
// one back. Forced-colors mode drops every box-shadow and keeps outlines,
|
|
34
|
+
// so a ring drawn as a shadow alone disappears for exactly the readers
|
|
35
|
+
// who most need one. A component that also wants a shadow pairs it with a
|
|
36
|
+
// transparent outline, which forced colors then substitutes into.
|
|
37
|
+
//
|
|
38
|
+
// It reads the built token stylesheets, so it runs after the tokens build; the
|
|
39
|
+
// turbo lint task depends on it.
|
|
40
|
+
|
|
41
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
42
|
+
import { createRequire } from 'node:module';
|
|
43
|
+
import { dirname, join, resolve } from 'node:path';
|
|
44
|
+
import { fileURLToPath } from 'node:url';
|
|
45
|
+
import { lineOf, readSources, report, rules, withoutComments } from './css-source.mjs';
|
|
46
|
+
|
|
47
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
48
|
+
|
|
49
|
+
const TOKEN_PREFIXES = [
|
|
50
|
+
'--blur-',
|
|
51
|
+
'--breakpoint-',
|
|
52
|
+
'--color-',
|
|
53
|
+
'--density',
|
|
54
|
+
'--font-',
|
|
55
|
+
'--motion-',
|
|
56
|
+
'--radius-',
|
|
57
|
+
'--shadow-',
|
|
58
|
+
'--size-',
|
|
59
|
+
'--spacing-',
|
|
60
|
+
'--z-index-',
|
|
61
|
+
];
|
|
62
|
+
const COMPONENT_PREFIX = '--crewlet-';
|
|
63
|
+
|
|
64
|
+
const NAME = '--[A-Za-z0-9_-]+';
|
|
65
|
+
const REFERENCE = new RegExp(`var\\(\\s*(${NAME})\\s*(,)?`, 'g');
|
|
66
|
+
// A declaration in a stylesheet: the name at the start of a declaration.
|
|
67
|
+
const CSS_DECLARATION = new RegExp(`(?:^|[{;\\s])(${NAME})\\s*:`, 'g');
|
|
68
|
+
// A declaration from a script: a quoted name used as a style key or passed to
|
|
69
|
+
// style.setProperty().
|
|
70
|
+
const SCRIPT_DECLARATION = new RegExp(`['"\`](${NAME})['"\`]`, 'g');
|
|
71
|
+
|
|
72
|
+
const REMOTE_URL = /url\(\s*['"]?(?:[a-z][a-z0-9+.-]*:)?\/\//i;
|
|
73
|
+
const REMOTE_IMPORT = /@import\s+(?:url\()?\s*['"]?(?:[a-z][a-z0-9+.-]*:)?\/\//i;
|
|
74
|
+
|
|
75
|
+
function tokenNames() {
|
|
76
|
+
const require = createRequire(import.meta.url);
|
|
77
|
+
let tokensCss;
|
|
78
|
+
try {
|
|
79
|
+
tokensCss = require.resolve('@crewlethq/tokens/css');
|
|
80
|
+
} catch (error) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`cannot resolve @crewlethq/tokens/css (${error.message}). Build the tokens package first: npm run build --workspace @crewlethq/tokens`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const directory = dirname(tokensCss);
|
|
86
|
+
const names = new Set();
|
|
87
|
+
for (const file of readdirSync(directory).filter((name) => name.endsWith('.css'))) {
|
|
88
|
+
const text = withoutComments(readFileSync(join(directory, file), 'utf8'), true);
|
|
89
|
+
for (const match of text.matchAll(CSS_DECLARATION)) names.add(match[1]);
|
|
90
|
+
}
|
|
91
|
+
if (names.size === 0) {
|
|
92
|
+
throw new Error(`found no custom properties in ${directory}; the tokens build output is empty`);
|
|
93
|
+
}
|
|
94
|
+
return names;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function findings(roots, base = packageRoot) {
|
|
98
|
+
const tokens = tokenNames();
|
|
99
|
+
const files = readSources(roots, base);
|
|
100
|
+
const declared = new Set();
|
|
101
|
+
const references = [];
|
|
102
|
+
const problems = [];
|
|
103
|
+
|
|
104
|
+
for (const file of files) {
|
|
105
|
+
const { text, isStylesheet } = file;
|
|
106
|
+
const where = (index) => `${file.where}:${lineOf(text, index)}`;
|
|
107
|
+
|
|
108
|
+
for (const match of text.matchAll(isStylesheet ? CSS_DECLARATION : SCRIPT_DECLARATION)) {
|
|
109
|
+
const name = match[1];
|
|
110
|
+
declared.add(name);
|
|
111
|
+
if (!name.startsWith(COMPONENT_PREFIX)) {
|
|
112
|
+
problems.push(
|
|
113
|
+
`${where(match.index)}: declares ${name}; a component declares only ${COMPONENT_PREFIX}* names (token values belong in @crewlethq/tokens)`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
for (const match of text.matchAll(REFERENCE)) {
|
|
118
|
+
references.push({ name: match[1], hasFallback: match[2] === ',', where: where(match.index) });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const ligature = text.indexOf('material-symbols-outlined');
|
|
122
|
+
if (ligature >= 0) {
|
|
123
|
+
problems.push(
|
|
124
|
+
`${where(ligature)}: draws a glyph as a Material Symbols ligature. Use a component from @crewlethq/icons/glyphs, which ships the drawing`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
for (const [pattern, said] of [
|
|
128
|
+
[REMOTE_URL, 'loads from a host with url(). Inline the asset or ship it in the package'],
|
|
129
|
+
[REMOTE_IMPORT, 'imports a remote stylesheet. A design system must not phone home'],
|
|
130
|
+
[/body\.theme-[a-z]+/, 'selects a body theme class. The theme is a contract on the root element'],
|
|
131
|
+
]) {
|
|
132
|
+
const found = text.search(pattern);
|
|
133
|
+
if (found >= 0) problems.push(`${where(found)}: ${said}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!isStylesheet) continue;
|
|
137
|
+
|
|
138
|
+
for (const { selector, body, index } of rules(text)) {
|
|
139
|
+
if (/(^|[;{\s])color\s*:[^;]*--color-text-muted/.test(body) && !/\bsvg\b/.test(selector)) {
|
|
140
|
+
problems.push(
|
|
141
|
+
`${where(index)}: paints text with --color-text-muted, which is the decoration step (2.8 to 4.5:1 by design). Use --color-text-tertiary for anything a reader has to make out`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
if (!selector.includes(':focus')) continue;
|
|
145
|
+
const turnsOff = /(^|[;{\s])outline\s*:\s*(none|0)\s*(;|$)/.test(body);
|
|
146
|
+
const putsBack = /outline\s*:[^;]*(solid|auto|dashed|dotted)/.test(body) || /forced-colors/.test(selector);
|
|
147
|
+
if (turnsOff && !putsBack) {
|
|
148
|
+
problems.push(
|
|
149
|
+
`${where(index)}: turns the outline off on ${selector.trim()} without putting one back. Forced-colors mode drops every box-shadow and keeps outlines, so a shadow-only ring is no ring at all there. Draw the ring as an outline, or pair --shadow-focus with "outline: 2px solid transparent"`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for (const { name, hasFallback, where } of references) {
|
|
156
|
+
if (TOKEN_PREFIXES.some((prefix) => name.startsWith(prefix))) {
|
|
157
|
+
if (!tokens.has(name)) {
|
|
158
|
+
problems.push(
|
|
159
|
+
`${where}: reads ${name}, which @crewlethq/tokens does not emit. Use an existing token or add it to packages/tokens/tokens/`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
} else if (!name.startsWith(COMPONENT_PREFIX)) {
|
|
163
|
+
problems.push(
|
|
164
|
+
`${where}: reads ${name}, which is neither a @crewlethq/tokens variable nor a ${COMPONENT_PREFIX}* component variable`,
|
|
165
|
+
);
|
|
166
|
+
} else if (!hasFallback && !declared.has(name)) {
|
|
167
|
+
problems.push(`${where}: reads ${name} without a fallback, and nothing in the scanned source declares it`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
problems,
|
|
173
|
+
checked: `${references.length} custom property references over ${files.length} files, against ${tokens.size} token variables and ${declared.size} component declarations`,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function main() {
|
|
178
|
+
const given = process.argv.slice(2).map((path) => resolve(process.cwd(), path));
|
|
179
|
+
const roots = given.length > 0 ? given : [join(packageRoot, 'src')];
|
|
180
|
+
const { problems, checked } = await findings(roots, given.length > 0 ? process.cwd() : packageRoot);
|
|
181
|
+
report('CSS custom property check', problems, checked);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (process.argv[1] && import.meta.url === `file://${process.argv[1]}`) await main();
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `crewlet-css-check`: both CSS checks, over the folders you give it.
|
|
3
|
+
//
|
|
4
|
+
// The bin a consumer runs over its own stylesheets, so an application holds
|
|
5
|
+
// itself to the same rules the design system holds itself to:
|
|
6
|
+
//
|
|
7
|
+
// npx crewlet-css-check src/styles src/features
|
|
8
|
+
//
|
|
9
|
+
// With no folder it checks the package's own src/. The two checks are separate
|
|
10
|
+
// files because they answer different questions (see each one's header), and
|
|
11
|
+
// this runs them together because a caller almost never wants one of them.
|
|
12
|
+
|
|
13
|
+
import { dirname, join, resolve } from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { findings as literalFindings } from './check-css-literals.mjs';
|
|
16
|
+
import { findings as variableFindings } from './check-css-variables.mjs';
|
|
17
|
+
import { report } from './css-source.mjs';
|
|
18
|
+
|
|
19
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
20
|
+
const roots = process.argv.slice(2).map((path) => resolve(process.cwd(), path));
|
|
21
|
+
const scanned = roots.length > 0 ? roots : [join(packageRoot, 'src')];
|
|
22
|
+
const base = roots.length > 0 ? process.cwd() : packageRoot;
|
|
23
|
+
|
|
24
|
+
const variables = await variableFindings(scanned, base);
|
|
25
|
+
report('CSS custom property check', variables.problems, variables.checked);
|
|
26
|
+
const literals = await literalFindings(scanned, base);
|
|
27
|
+
report('CSS literal check', literals.problems, literals.checked);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// What both CSS checks read, so the two cannot come to disagree about which
|
|
2
|
+
// files they cover or where a finding is.
|
|
3
|
+
//
|
|
4
|
+
// Comments are BLANKED rather than removed, so a line number in a finding is
|
|
5
|
+
// the line a person will open, and so prose about a rule is never mistaken for
|
|
6
|
+
// the rule being broken: `check-css-variables` had already caught a stylesheet
|
|
7
|
+
// whose own header explained why a style element is forbidden.
|
|
8
|
+
|
|
9
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
10
|
+
import { join, relative } from 'node:path';
|
|
11
|
+
|
|
12
|
+
export function sourceFiles(directory, extensions = /\.(css|tsx?)$/) {
|
|
13
|
+
const found = [];
|
|
14
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
15
|
+
const path = join(directory, entry.name);
|
|
16
|
+
if (entry.isDirectory()) found.push(...sourceFiles(path, extensions));
|
|
17
|
+
else if (extensions.test(entry.name)) found.push(path);
|
|
18
|
+
}
|
|
19
|
+
return found;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function withoutComments(text, isStylesheet) {
|
|
23
|
+
const pattern = isStylesheet ? /\/\*[\s\S]*?\*\//g : /\/\*[\s\S]*?\*\/|\/\/[^\n]*/g;
|
|
24
|
+
return text.replace(pattern, (comment) => comment.replace(/[^\n]/g, ' '));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function lineOf(text, index) {
|
|
28
|
+
return text.slice(0, index).split('\n').length;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Every file under the given roots, with its comments blanked. */
|
|
32
|
+
export function readSources(roots, base, extensions) {
|
|
33
|
+
const files = [];
|
|
34
|
+
for (const root of roots) {
|
|
35
|
+
if (!statSync(root).isDirectory()) throw new Error(`${root} is not a directory`);
|
|
36
|
+
for (const path of sourceFiles(root, extensions)) {
|
|
37
|
+
const raw = readFileSync(path, 'utf8');
|
|
38
|
+
files.push({
|
|
39
|
+
path,
|
|
40
|
+
where: relative(base, path),
|
|
41
|
+
isStylesheet: path.endsWith('.css'),
|
|
42
|
+
text: withoutComments(raw, path.endsWith('.css')),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return files;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Every rule body in a stylesheet, with its selector and its start offset. */
|
|
50
|
+
export function rules(text) {
|
|
51
|
+
const found = [];
|
|
52
|
+
const pattern = /([^{}]+)\{([^{}]*)\}/g;
|
|
53
|
+
for (const match of text.matchAll(pattern)) {
|
|
54
|
+
found.push({ selector: match[1].trim(), body: match[2], index: match.index });
|
|
55
|
+
}
|
|
56
|
+
return found;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function report(name, problems, checked) {
|
|
60
|
+
if (problems.length > 0) {
|
|
61
|
+
console.error(`${name} failed:\n${problems.map((problem) => ` ${problem}`).join('\n')}`);
|
|
62
|
+
process.exitCode = 1;
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
console.warn(`[ui] ${name}: ${checked}`);
|
|
66
|
+
return true;
|
|
67
|
+
}
|