@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.
Files changed (497) hide show
  1. package/README.md +1714 -14
  2. package/dist/Accordion/Accordion.d.ts +54 -0
  3. package/dist/Accordion/index.d.ts +4 -0
  4. package/dist/Accordion/index.js +6 -0
  5. package/dist/Accordion-ZI2WLD5C.css +87 -0
  6. package/dist/AddPill/AddPill.d.ts +114 -0
  7. package/dist/AddPill/index.d.ts +3 -0
  8. package/dist/AddPill/index.js +3 -0
  9. package/dist/AddPill-DFWXYLIQ.css +434 -0
  10. package/dist/Announcer/Announcer.d.ts +15 -0
  11. package/dist/Announcer/index.d.ts +2 -0
  12. package/dist/Announcer/index.js +3 -0
  13. package/dist/AppShell/AppShell.d.ts +193 -0
  14. package/dist/AppShell/index.d.ts +3 -0
  15. package/dist/AppShell/index.js +6 -0
  16. package/dist/AppShell-NVE6LHNI.css +395 -0
  17. package/dist/Avatar/Avatar.d.ts +104 -0
  18. package/dist/Avatar/index.d.ts +3 -0
  19. package/dist/Avatar/index.js +2 -0
  20. package/dist/Avatar-P2KRQM2B.css +156 -0
  21. package/dist/BrandLockup/BrandLockup.d.ts +41 -0
  22. package/dist/BrandLockup/index.d.ts +3 -0
  23. package/dist/BrandLockup/index.js +2 -0
  24. package/dist/BrandLockup-6ISDEHPJ.css +108 -0
  25. package/dist/Button/Button.d.ts +88 -0
  26. package/dist/Button/index.d.ts +3 -0
  27. package/dist/Button/index.js +3 -0
  28. package/dist/Button-D4J6B4MA.css +302 -0
  29. package/dist/CalendarGrid/CalendarGrid.d.ts +87 -0
  30. package/dist/CalendarGrid/index.d.ts +3 -0
  31. package/dist/CalendarGrid/index.js +2 -0
  32. package/dist/CalendarGrid-V6TQ5QKS.css +128 -0
  33. package/dist/Callout/Callout.d.ts +47 -0
  34. package/dist/Callout/index.d.ts +3 -0
  35. package/dist/Callout/index.js +2 -0
  36. package/dist/Callout-S7QDWHDL.css +111 -0
  37. package/dist/Canvas/Canvas.d.ts +234 -0
  38. package/dist/Canvas/geometry.d.ts +249 -0
  39. package/dist/Canvas/index.d.ts +5 -0
  40. package/dist/Canvas/index.js +8 -0
  41. package/dist/Canvas/layerNode.d.ts +20 -0
  42. package/dist/Canvas-Q6JETCWR.css +315 -0
  43. package/dist/Card/Card.d.ts +142 -0
  44. package/dist/Card/headerSlot.d.ts +65 -0
  45. package/dist/Card/index.d.ts +5 -0
  46. package/dist/Card/index.js +6 -0
  47. package/dist/Card-AHX3Q2JD.css +428 -0
  48. package/dist/Charts/ActivityStrip.d.ts +45 -0
  49. package/dist/Charts/BarList.d.ts +51 -0
  50. package/dist/Charts/Legend.d.ts +32 -0
  51. package/dist/Charts/StackedBar.d.ts +38 -0
  52. package/dist/Charts/TimeSeries.d.ts +92 -0
  53. package/dist/Charts/dataColor.d.ts +20 -0
  54. package/dist/Charts/index.d.ts +12 -0
  55. package/dist/Charts/index.js +3 -0
  56. package/dist/Charts-D7G2BSXH.css +277 -0
  57. package/dist/Checkbox/Checkbox.d.ts +45 -0
  58. package/dist/Checkbox/index.d.ts +3 -0
  59. package/dist/Checkbox/index.js +2 -0
  60. package/dist/Checkbox-VGW26YLQ.css +111 -0
  61. package/dist/CodeBlock/CodeBlock.d.ts +60 -0
  62. package/dist/CodeBlock/index.d.ts +3 -0
  63. package/dist/CodeBlock/index.js +7 -0
  64. package/dist/CodeBlock-U2W6NNVC.css +153 -0
  65. package/dist/Combobox/Combobox.d.ts +89 -0
  66. package/dist/Combobox/index.d.ts +3 -0
  67. package/dist/Combobox/index.js +8 -0
  68. package/dist/Combobox-4FUVYIE7.css +80 -0
  69. package/dist/CommandPalette/CommandPalette.d.ts +77 -0
  70. package/dist/CommandPalette/index.d.ts +3 -0
  71. package/dist/CommandPalette/index.js +11 -0
  72. package/dist/CommandPalette-CSJDUCQA.css +115 -0
  73. package/dist/Container/Container.d.ts +17 -0
  74. package/dist/Container/index.d.ts +3 -0
  75. package/dist/Container/index.js +2 -0
  76. package/dist/Container-3TSKMGNI.css +52 -0
  77. package/dist/Copyable/CopyButton.d.ts +54 -0
  78. package/dist/Copyable/Copyable.d.ts +34 -0
  79. package/dist/Copyable/index.d.ts +5 -0
  80. package/dist/Copyable/index.js +6 -0
  81. package/dist/Copyable-5PNRFOLS.css +125 -0
  82. package/dist/Count/Count.d.ts +24 -0
  83. package/dist/Count/index.d.ts +3 -0
  84. package/dist/Count/index.js +3 -0
  85. package/dist/Count-ZVCJ6VPD.css +20 -0
  86. package/dist/DataTable/CopyableCell.d.ts +12 -0
  87. package/dist/DataTable/DataTable.d.ts +615 -0
  88. package/dist/DataTable/RowActionsMenu.d.ts +7 -0
  89. package/dist/DataTable/index.d.ts +7 -0
  90. package/dist/DataTable/index.js +14 -0
  91. package/dist/DataTable-ITNACQ2X.css +2020 -0
  92. package/dist/DataView/DataView.d.ts +109 -0
  93. package/dist/DataView/DataViewToolbar.d.ts +87 -0
  94. package/dist/DataView/FilterAxisBar.d.ts +103 -0
  95. package/dist/DataView/columns.d.ts +35 -0
  96. package/dist/DataView/filters.d.ts +184 -0
  97. package/dist/DataView/index.d.ts +11 -0
  98. package/dist/DataView/index.js +25 -0
  99. package/dist/DataView-256YF32J.css +441 -0
  100. package/dist/DateTimePicker/DateTimePicker.d.ts +91 -0
  101. package/dist/DateTimePicker/index.d.ts +3 -0
  102. package/dist/DateTimePicker/index.js +9 -0
  103. package/dist/DateTimePicker-22VNXRWC.css +199 -0
  104. package/dist/DescriptionList/DescriptionList.d.ts +36 -0
  105. package/dist/DescriptionList/index.d.ts +3 -0
  106. package/dist/DescriptionList/index.js +2 -0
  107. package/dist/DescriptionList-YYY3V3O6.css +59 -0
  108. package/dist/DiffList/DiffList.d.ts +47 -0
  109. package/dist/DiffList/index.d.ts +3 -0
  110. package/dist/DiffList/index.js +3 -0
  111. package/dist/DiffList-3EX64AAE.css +94 -0
  112. package/dist/Disclosure/Disclosure.d.ts +56 -0
  113. package/dist/Disclosure/anatomy.d.ts +43 -0
  114. package/dist/Disclosure/index.d.ts +5 -0
  115. package/dist/Disclosure/index.js +6 -0
  116. package/dist/Disclosure-VKBJJIZ7.css +176 -0
  117. package/dist/EmptyState/EmptyState.d.ts +39 -0
  118. package/dist/EmptyState/index.d.ts +3 -0
  119. package/dist/EmptyState/index.js +3 -0
  120. package/dist/EmptyState-C6HRBGT7.css +73 -0
  121. package/dist/EmptyValue/EmptyValue.d.ts +31 -0
  122. package/dist/EmptyValue/index.d.ts +3 -0
  123. package/dist/EmptyValue/index.js +3 -0
  124. package/dist/EmptyValue-4B6ODXHT.css +12 -0
  125. package/dist/EntityChip/EntityChip.d.ts +40 -0
  126. package/dist/EntityChip/index.d.ts +3 -0
  127. package/dist/EntityChip/index.js +3 -0
  128. package/dist/EntityChip-LUCPZBBG.css +64 -0
  129. package/dist/ErrorBoundary/ErrorBoundary.d.ts +58 -0
  130. package/dist/ErrorBoundary/index.d.ts +3 -0
  131. package/dist/ErrorBoundary/index.js +4 -0
  132. package/dist/ErrorBoundary-ME36CQTA.css +59 -0
  133. package/dist/Eyebrow/Eyebrow.d.ts +18 -0
  134. package/dist/Eyebrow/index.d.ts +3 -0
  135. package/dist/Eyebrow/index.js +2 -0
  136. package/dist/Eyebrow-5NREGHQH.css +46 -0
  137. package/dist/FilterChip/FilterChip.d.ts +68 -0
  138. package/dist/FilterChip/index.d.ts +3 -0
  139. package/dist/FilterChip/index.js +3 -0
  140. package/dist/FilterChip-GTGLLOXE.css +107 -0
  141. package/dist/Fullscreen/index.d.ts +2 -0
  142. package/dist/Fullscreen/index.js +1 -0
  143. package/dist/Fullscreen/useFullscreen.d.ts +32 -0
  144. package/dist/IconButton/IconButton.d.ts +45 -0
  145. package/dist/IconButton/index.d.ts +3 -0
  146. package/dist/IconButton/index.js +3 -0
  147. package/dist/IconButton-VQGNMJDI.css +158 -0
  148. package/dist/ImageUpload/ImageUpload.d.ts +37 -0
  149. package/dist/ImageUpload/index.d.ts +3 -0
  150. package/dist/ImageUpload/index.js +3 -0
  151. package/dist/ImageUpload-HKFIZR6D.css +193 -0
  152. package/dist/InlineCode/InlineCode.d.ts +37 -0
  153. package/dist/InlineCode/index.d.ts +3 -0
  154. package/dist/InlineCode/index.js +2 -0
  155. package/dist/InlineCode-6WSR5COL.css +65 -0
  156. package/dist/Input/FormField.d.ts +61 -0
  157. package/dist/Input/FormRow.d.ts +6 -0
  158. package/dist/Input/FormSection.d.ts +28 -0
  159. package/dist/Input/Input.d.ts +98 -0
  160. package/dist/Input/Label.d.ts +31 -0
  161. package/dist/Input/ReadOnlyField.d.ts +30 -0
  162. package/dist/Input/Textarea.d.ts +16 -0
  163. package/dist/Input/index.d.ts +15 -0
  164. package/dist/Input/index.js +5 -0
  165. package/dist/Input-2PU5CPKK.css +616 -0
  166. package/dist/Kbd/Kbd.d.ts +40 -0
  167. package/dist/Kbd/index.d.ts +3 -0
  168. package/dist/Kbd/index.js +3 -0
  169. package/dist/Kbd-W66MXQI5.css +61 -0
  170. package/dist/Layer/LayerHost.d.ts +23 -0
  171. package/dist/Layer/index.d.ts +7 -0
  172. package/dist/Layer/index.js +3 -0
  173. package/dist/Layer/place.d.ts +63 -0
  174. package/dist/Layer/stack.d.ts +159 -0
  175. package/dist/Layer-NAFSGCFA.css +23 -0
  176. package/dist/Layout/Layout.d.ts +104 -0
  177. package/dist/Layout/index.d.ts +3 -0
  178. package/dist/Layout/index.js +2 -0
  179. package/dist/Layout-2ZCV3IGF.css +171 -0
  180. package/dist/Link/Link.d.ts +45 -0
  181. package/dist/Link/index.d.ts +3 -0
  182. package/dist/Link/index.js +3 -0
  183. package/dist/Link-6BEFNMN2.css +80 -0
  184. package/dist/List/List.d.ts +73 -0
  185. package/dist/List/index.d.ts +3 -0
  186. package/dist/List/index.js +3 -0
  187. package/dist/List-XTHESXLR.css +161 -0
  188. package/dist/ListInput/ListInput.d.ts +68 -0
  189. package/dist/ListInput/index.d.ts +3 -0
  190. package/dist/ListInput/index.js +10 -0
  191. package/dist/ListInput-O7LJKOIG.css +147 -0
  192. package/dist/Listbox/index.d.ts +5 -0
  193. package/dist/Listbox/index.js +2 -0
  194. package/dist/Listbox/useListbox.d.ts +97 -0
  195. package/dist/Listbox/useOptionKeys.d.ts +64 -0
  196. package/dist/Listbox-X2DOTSQA.css +110 -0
  197. package/dist/Menu/Menu.d.ts +118 -0
  198. package/dist/Menu/index.d.ts +3 -0
  199. package/dist/Menu/index.js +7 -0
  200. package/dist/Menu-6DE7I66I.css +222 -0
  201. package/dist/Meter/Meter.d.ts +49 -0
  202. package/dist/Meter/index.d.ts +3 -0
  203. package/dist/Meter/index.js +3 -0
  204. package/dist/Meter-SKOOXQBC.css +87 -0
  205. package/dist/Modal/ConfirmModal.d.ts +74 -0
  206. package/dist/Modal/Modal.d.ts +154 -0
  207. package/dist/Modal/index.d.ts +5 -0
  208. package/dist/Modal/index.js +8 -0
  209. package/dist/Modal-XYQJ4BL6.css +484 -0
  210. package/dist/NewItemsNotice/NewItemsNotice.d.ts +28 -0
  211. package/dist/NewItemsNotice/index.d.ts +3 -0
  212. package/dist/NewItemsNotice/index.js +4 -0
  213. package/dist/NewItemsNotice-T4DSSPVV.css +60 -0
  214. package/dist/OrgLabel/OrgLabel.d.ts +117 -0
  215. package/dist/OrgLabel/index.d.ts +3 -0
  216. package/dist/OrgLabel/index.js +2 -0
  217. package/dist/OrgLabel-D7U6QJZD.css +293 -0
  218. package/dist/OrgNode/OrgNode.d.ts +103 -0
  219. package/dist/OrgNode/index.d.ts +3 -0
  220. package/dist/OrgNode/index.js +3 -0
  221. package/dist/OrgNode-BT7T2Q2X.css +214 -0
  222. package/dist/OrgTable/OrgTable.d.ts +113 -0
  223. package/dist/OrgTable/index.d.ts +3 -0
  224. package/dist/OrgTable/index.js +11 -0
  225. package/dist/OrgTable-VWMFC3TB.css +360 -0
  226. package/dist/PageHeader/PageHeader.d.ts +35 -0
  227. package/dist/PageHeader/index.d.ts +3 -0
  228. package/dist/PageHeader/index.js +3 -0
  229. package/dist/PageHeader-6EYWQXRE.css +88 -0
  230. package/dist/Popover/Popover.d.ts +91 -0
  231. package/dist/Popover/index.d.ts +3 -0
  232. package/dist/Popover/index.js +4 -0
  233. package/dist/Popover-WJGCF3ZQ.css +185 -0
  234. package/dist/PricingCard/PricingCard.d.ts +56 -0
  235. package/dist/PricingCard/index.d.ts +3 -0
  236. package/dist/PricingCard/index.js +4 -0
  237. package/dist/PricingCard-JFI7RYXP.css +278 -0
  238. package/dist/Prose/Prose.d.ts +33 -0
  239. package/dist/Prose/index.d.ts +3 -0
  240. package/dist/Prose/index.js +2 -0
  241. package/dist/Prose-BTXNFT2Q.css +99 -0
  242. package/dist/RelativeTime/RelativeTime.d.ts +31 -0
  243. package/dist/RelativeTime/clock.d.ts +9 -0
  244. package/dist/RelativeTime/format.d.ts +38 -0
  245. package/dist/RelativeTime/index.d.ts +6 -0
  246. package/dist/RelativeTime/index.js +4 -0
  247. package/dist/RelativeTime-EBAQPGO2.css +10 -0
  248. package/dist/SearchTrigger/SearchTrigger.d.ts +29 -0
  249. package/dist/SearchTrigger/index.d.ts +3 -0
  250. package/dist/SearchTrigger/index.js +2 -0
  251. package/dist/SearchTrigger-QXOYAUUY.css +79 -0
  252. package/dist/Section/Section.d.ts +41 -0
  253. package/dist/Section/index.d.ts +3 -0
  254. package/dist/Section/index.js +3 -0
  255. package/dist/Section-QRUPRIQ2.css +127 -0
  256. package/dist/SegmentedControl/SegmentedControl.d.ts +68 -0
  257. package/dist/SegmentedControl/index.d.ts +4 -0
  258. package/dist/SegmentedControl/index.js +5 -0
  259. package/dist/SegmentedControl-X3BI3XU4.css +68 -0
  260. package/dist/Select/Select.d.ts +138 -0
  261. package/dist/Select/index.d.ts +3 -0
  262. package/dist/Select/index.js +5 -0
  263. package/dist/Select-2X77FSWR.css +350 -0
  264. package/dist/Shortcut/index.d.ts +2 -0
  265. package/dist/Shortcut/index.js +4 -0
  266. package/dist/Shortcut/useShortcut.d.ts +68 -0
  267. package/dist/SidebarNav/SidebarNav.d.ts +117 -0
  268. package/dist/SidebarNav/index.d.ts +3 -0
  269. package/dist/SidebarNav/index.js +3 -0
  270. package/dist/SidebarNav-QGSFKZYA.css +319 -0
  271. package/dist/Skeleton/Skeleton.d.ts +50 -0
  272. package/dist/Skeleton/index.d.ts +3 -0
  273. package/dist/Skeleton/index.js +3 -0
  274. package/dist/Skeleton-V735HRGM.css +421 -0
  275. package/dist/StatCard/StatCard.d.ts +56 -0
  276. package/dist/StatCard/index.d.ts +3 -0
  277. package/dist/StatCard/index.js +3 -0
  278. package/dist/StatCard-KYPKZUWX.css +111 -0
  279. package/dist/StatGroup/StatGroup.d.ts +20 -0
  280. package/dist/StatGroup/index.d.ts +3 -0
  281. package/dist/StatGroup/index.js +2 -0
  282. package/dist/StatGroup-TGB6AEKM.css +80 -0
  283. package/dist/StatusDot/StatusDot.d.ts +25 -0
  284. package/dist/StatusDot/index.d.ts +3 -0
  285. package/dist/StatusDot/index.js +2 -0
  286. package/dist/StatusDot-HA2L2FSX.css +84 -0
  287. package/dist/Switch/Switch.d.ts +38 -0
  288. package/dist/Switch/index.d.ts +3 -0
  289. package/dist/Switch/index.js +2 -0
  290. package/dist/Switch-U4OWK4CL.css +169 -0
  291. package/dist/Table/Table.d.ts +51 -0
  292. package/dist/Table/index.d.ts +3 -0
  293. package/dist/Table/index.js +3 -0
  294. package/dist/Table-MDOLVUAW.css +159 -0
  295. package/dist/Tabs/Tabs.d.ts +97 -0
  296. package/dist/Tabs/index.d.ts +3 -0
  297. package/dist/Tabs/index.js +4 -0
  298. package/dist/Tabs/roving.d.ts +36 -0
  299. package/dist/Tabs-VLICJFVB.css +275 -0
  300. package/dist/Tag/Tag.d.ts +107 -0
  301. package/dist/Tag/index.d.ts +3 -0
  302. package/dist/Tag/index.js +3 -0
  303. package/dist/Tag-VNZEYLB6.css +406 -0
  304. package/dist/TagGroup/TagGroup.d.ts +41 -0
  305. package/dist/TagGroup/index.d.ts +3 -0
  306. package/dist/TagGroup/index.js +4 -0
  307. package/dist/TagGroup-APC2EFH4.css +75 -0
  308. package/dist/TagsInput/TagsInput.d.ts +112 -0
  309. package/dist/TagsInput/index.d.ts +3 -0
  310. package/dist/TagsInput/index.js +10 -0
  311. package/dist/TagsInput-W4P36PRJ.css +168 -0
  312. package/dist/Text/Text.d.ts +67 -0
  313. package/dist/Text/index.d.ts +3 -0
  314. package/dist/Text/index.js +2 -0
  315. package/dist/Text-XIPYYZX2.css +154 -0
  316. package/dist/ThemeSwitcher/ThemeSwitcher.d.ts +47 -0
  317. package/dist/ThemeSwitcher/index.d.ts +4 -0
  318. package/dist/ThemeSwitcher/index.js +6 -0
  319. package/dist/ThemeSwitcher/preferences.d.ts +51 -0
  320. package/dist/TimeWindowPicker/TimeWindowPicker.d.ts +231 -0
  321. package/dist/TimeWindowPicker/index.d.ts +3 -0
  322. package/dist/TimeWindowPicker/index.js +13 -0
  323. package/dist/TimeWindowPicker/mask.d.ts +82 -0
  324. package/dist/TimeWindowPicker-7I7KWCMU.css +403 -0
  325. package/dist/Timeline/Timeline.d.ts +51 -0
  326. package/dist/Timeline/index.d.ts +3 -0
  327. package/dist/Timeline/index.js +3 -0
  328. package/dist/Timeline-27SYKOFX.css +144 -0
  329. package/dist/Toaster/Toaster.d.ts +108 -0
  330. package/dist/Toaster/index.d.ts +3 -0
  331. package/dist/Toaster/index.js +5 -0
  332. package/dist/Toaster-NVDCEIP5.css +306 -0
  333. package/dist/Toolbar/Toolbar.d.ts +62 -0
  334. package/dist/Toolbar/index.d.ts +3 -0
  335. package/dist/Toolbar/index.js +4 -0
  336. package/dist/Toolbar-IP6LXN45.css +48 -0
  337. package/dist/Tooltip/Tooltip.d.ts +51 -0
  338. package/dist/Tooltip/index.d.ts +3 -0
  339. package/dist/Tooltip/index.js +4 -0
  340. package/dist/Tooltip-LKQF7CE4.css +71 -0
  341. package/dist/Tree/index.d.ts +8 -0
  342. package/dist/Tree/index.js +1 -0
  343. package/dist/Tree/layout.d.ts +160 -0
  344. package/dist/Tree/model.d.ts +110 -0
  345. package/dist/Tree/useMeasuredSizes.d.ts +61 -0
  346. package/dist/Tree/useTreeState.d.ts +89 -0
  347. package/dist/TreeCanvas/TreeCanvas.d.ts +384 -0
  348. package/dist/TreeCanvas/index.d.ts +3 -0
  349. package/dist/TreeCanvas/index.js +10 -0
  350. package/dist/TreeCanvas/motion.d.ts +59 -0
  351. package/dist/TreeCanvas-WBNQPHC7.css +1098 -0
  352. package/dist/TreeGrid/TreeGrid.d.ts +142 -0
  353. package/dist/TreeGrid/index.d.ts +3 -0
  354. package/dist/TreeGrid/index.js +8 -0
  355. package/dist/TreeGrid-NSW7VMOX.css +132 -0
  356. package/dist/VisuallyHidden/VisuallyHidden.d.ts +23 -0
  357. package/dist/VisuallyHidden/index.d.ts +3 -0
  358. package/dist/VisuallyHidden/index.js +2 -0
  359. package/dist/VisuallyHidden-L552H7OA.css +21 -0
  360. package/dist/chunk-22O7LAW2.js +41 -0
  361. package/dist/chunk-23DHIMJA.js +38 -0
  362. package/dist/chunk-2EOKFKHX.js +263 -0
  363. package/dist/chunk-2PRH365R.js +74 -0
  364. package/dist/chunk-2ZQMA2WB.js +57 -0
  365. package/dist/chunk-3CZ7XAVY.js +139 -0
  366. package/dist/chunk-3EYF6HKB.js +135 -0
  367. package/dist/chunk-3ZP55QZE.js +40 -0
  368. package/dist/chunk-53DVJCVW.js +14 -0
  369. package/dist/chunk-5C5YMZQU.js +51 -0
  370. package/dist/chunk-5EKIWVOR.js +132 -0
  371. package/dist/chunk-5IMACPJS.js +495 -0
  372. package/dist/chunk-5KPQ6D7N.js +54 -0
  373. package/dist/chunk-5SDBMKUO.js +297 -0
  374. package/dist/chunk-5WS6L6FA.js +114 -0
  375. package/dist/chunk-7EM5T4ME.js +39 -0
  376. package/dist/chunk-7FZ53WDJ.js +163 -0
  377. package/dist/chunk-7HPRF5XN.js +525 -0
  378. package/dist/chunk-7RPGY3JE.js +43 -0
  379. package/dist/chunk-A2UXBCLO.js +48 -0
  380. package/dist/chunk-ARMRX2YV.js +96 -0
  381. package/dist/chunk-AV2DXAEL.js +27 -0
  382. package/dist/chunk-BHHIIK3M.js +17 -0
  383. package/dist/chunk-BZFWDIV6.js +9 -0
  384. package/dist/chunk-BZYDZBAN.js +123 -0
  385. package/dist/chunk-CMEE37QJ.js +628 -0
  386. package/dist/chunk-D3OADIM6.js +112 -0
  387. package/dist/chunk-DD5BBGBE.js +162 -0
  388. package/dist/chunk-EHMQQHYR.js +1652 -0
  389. package/dist/chunk-EN6K2IFA.js +256 -0
  390. package/dist/chunk-EPOOQZYA.js +118 -0
  391. package/dist/chunk-ESCO4XYW.js +144 -0
  392. package/dist/chunk-EUCC37WY.js +14 -0
  393. package/dist/chunk-EV6IMYJ6.js +62 -0
  394. package/dist/chunk-F27EPQ7D.js +68 -0
  395. package/dist/chunk-F4PJZ4ED.js +245 -0
  396. package/dist/chunk-F6OE5FH3.js +49 -0
  397. package/dist/chunk-FBZAKNSX.js +263 -0
  398. package/dist/chunk-FEFTGVMF.js +46 -0
  399. package/dist/chunk-G2QFRTJ2.js +823 -0
  400. package/dist/chunk-GHYY2WPF.js +907 -0
  401. package/dist/chunk-GTOUGQQK.js +147 -0
  402. package/dist/chunk-GUIF6Q6N.js +143 -0
  403. package/dist/chunk-GXQ3B46I.js +216 -0
  404. package/dist/chunk-H4FBTAYS.js +130 -0
  405. package/dist/chunk-HOXGBLEY.js +37 -0
  406. package/dist/chunk-HQNHV7D6.js +54 -0
  407. package/dist/chunk-HTDFCRJZ.js +92 -0
  408. package/dist/chunk-HZ5XZNPS.js +98 -0
  409. package/dist/chunk-IAJLHVUA.js +28 -0
  410. package/dist/chunk-IJ7QXNIJ.js +1 -0
  411. package/dist/chunk-ITHXJHBB.js +280 -0
  412. package/dist/chunk-JCSA3XVH.js +32 -0
  413. package/dist/chunk-KLJCCMF3.js +97 -0
  414. package/dist/chunk-LGCPQIOZ.js +49 -0
  415. package/dist/chunk-LWKJQTOM.js +77 -0
  416. package/dist/chunk-MNAXYY3R.js +215 -0
  417. package/dist/chunk-NN62JQLR.js +29 -0
  418. package/dist/chunk-NPZY6YYL.js +251 -0
  419. package/dist/chunk-NTRZGNEX.js +529 -0
  420. package/dist/chunk-O6232G37.js +273 -0
  421. package/dist/chunk-O67VF5MS.js +58 -0
  422. package/dist/chunk-ODEQTPFM.js +6 -0
  423. package/dist/chunk-PNFASD6F.js +98 -0
  424. package/dist/chunk-PQADV6P6.js +19 -0
  425. package/dist/chunk-PZSWF74H.js +15 -0
  426. package/dist/chunk-Q4ZPPART.js +26 -0
  427. package/dist/chunk-QNCVHRZL.js +17 -0
  428. package/dist/chunk-QVE4GJAT.js +15 -0
  429. package/dist/chunk-QYOFACSP.js +36 -0
  430. package/dist/chunk-RA2ULG6H.js +29 -0
  431. package/dist/chunk-RDGD7Z7I.js +350 -0
  432. package/dist/chunk-RK4XPHVG.js +16 -0
  433. package/dist/chunk-RSAQOKH3.js +38 -0
  434. package/dist/chunk-S2XHHEW4.js +84 -0
  435. package/dist/chunk-S4GZWSKR.js +137 -0
  436. package/dist/chunk-SFZOKW2G.js +52 -0
  437. package/dist/chunk-T7FKOJKW.js +221 -0
  438. package/dist/chunk-UG46QBLT.js +325 -0
  439. package/dist/chunk-UOGSZKLT.js +134 -0
  440. package/dist/chunk-V2XMNLMS.js +52 -0
  441. package/dist/chunk-V663QU4R.js +51 -0
  442. package/dist/chunk-W4ENKCXJ.js +40 -0
  443. package/dist/chunk-W5J7R5EB.js +107 -0
  444. package/dist/chunk-WNI2WSJF.js +27 -0
  445. package/dist/chunk-XDTYBF2F.js +36 -0
  446. package/dist/chunk-XN4JBAN3.js +32 -0
  447. package/dist/chunk-XV6WRMBC.js +211 -0
  448. package/dist/chunk-YLYOWZ4V.js +33 -0
  449. package/dist/chunk-YMWONFSI.js +170 -0
  450. package/dist/chunk-ZCR6YGQ4.js +1 -0
  451. package/dist/generated/index.d.ts +83 -0
  452. package/dist/generated/index.js +91 -0
  453. package/dist/index.d.ts +1 -1217
  454. package/dist/index.js +91 -4518
  455. package/dist/styles.css +14841 -4274
  456. package/dist/utils/cx.d.ts +10 -0
  457. package/dist/utils/headingLevel.d.ts +16 -0
  458. package/dist/utils/index.d.ts +6 -0
  459. package/dist/utils/index.js +4 -0
  460. package/dist/utils/tone.d.ts +25 -0
  461. package/dist/utils/useClipboard.d.ts +30 -0
  462. package/package.json +18 -10
  463. package/scripts/bundle-css.mjs +25 -0
  464. package/scripts/check-css-literals.mjs +166 -0
  465. package/scripts/check-css-variables.mjs +184 -0
  466. package/scripts/check-css.mjs +27 -0
  467. package/scripts/css-source.mjs +67 -0
  468. package/scripts/write-barrel.mjs +60 -0
  469. package/dist/Accordion-NIMJQIOI.css +0 -88
  470. package/dist/AppShell-ZW3NSFBP.css +0 -51
  471. package/dist/Avatar-V6NG6Q45.css +0 -67
  472. package/dist/Button-XGCTXXYP.css +0 -174
  473. package/dist/Callout-LEGDIMAM.css +0 -52
  474. package/dist/Card-BOZGBML7.css +0 -86
  475. package/dist/Checkbox-OCUICIIZ.css +0 -58
  476. package/dist/CodeBlock-IEMBNIQC.css +0 -90
  477. package/dist/Container-LTKBA2FW.css +0 -21
  478. package/dist/Copyable-IB57OTHZ.css +0 -123
  479. package/dist/DataTable-3GALZUW2.css +0 -1593
  480. package/dist/DateTimePicker-NMSSGVPK.css +0 -312
  481. package/dist/Eyebrow-AVBORAS2.css +0 -30
  482. package/dist/IconButton-GB4PJDG2.css +0 -82
  483. package/dist/ImageUpload-3HQDF2KC.css +0 -158
  484. package/dist/Input-ZHUTN7CU.css +0 -210
  485. package/dist/Kbd-Q77CDZY7.css +0 -23
  486. package/dist/Modal-FJVG66S4.css +0 -138
  487. package/dist/Popover-FUFULUE2.css +0 -123
  488. package/dist/PricingCard-NKYV3JHA.css +0 -238
  489. package/dist/Section-665ZIPG6.css +0 -20
  490. package/dist/Select-GPRF7PRB.css +0 -294
  491. package/dist/Skeleton-3WEFLRDN.css +0 -378
  492. package/dist/StatCard-RTJIVTRB.css +0 -50
  493. package/dist/Table-AR3TRY2E.css +0 -89
  494. package/dist/Tabs-XZ4JIH3E.css +0 -153
  495. package/dist/Tag-R5QDJLYJ.css +0 -163
  496. package/dist/TimeWindowPicker-L3G5Q7UT.css +0 -629
  497. 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,4 @@
1
+ import '../chunk-IJ7QXNIJ.js';
2
+ export { useClipboard } from '../chunk-V663QU4R.js';
3
+ export { HeadingLevelProvider, headingTag, nextHeadingLevel, useHeadingLevel } from '../chunk-PQADV6P6.js';
4
+ export { cx } from '../chunk-ODEQTPFM.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.2.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.2.0",
41
- "@crewlethq/tokens": "0.2.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
+ }