@crewlethq/ui 0.4.3 → 0.5.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 (237) hide show
  1. package/README.md +888 -24
  2. package/dist/Accordion/index.js +2 -2
  3. package/dist/AddPill/index.js +1 -1
  4. package/dist/{AddPill-DFWXYLIQ.css → AddPill-IJQYCY6C.css} +9 -0
  5. package/dist/AppShell/AppShell.d.ts +26 -5
  6. package/dist/AppShell/index.js +3 -3
  7. package/dist/{AppShell-NVE6LHNI.css → AppShell-XARELGIH.css} +178 -25
  8. package/dist/Avatar/Avatar.d.ts +85 -40
  9. package/dist/Avatar/AvatarStack.d.ts +76 -0
  10. package/dist/Avatar/index.d.ts +5 -2
  11. package/dist/Avatar/index.js +1 -1
  12. package/dist/Avatar-XID7Z74C.css +200 -0
  13. package/dist/AvatarStack-GEJBNV7E.css +72 -0
  14. package/dist/BrandLockup/index.js +1 -1
  15. package/dist/{BrandLockup-6ISDEHPJ.css → BrandLockup-JKGXFCZF.css} +25 -19
  16. package/dist/Button/Button.d.ts +7 -2
  17. package/dist/Button/index.js +1 -1
  18. package/dist/{Button-D4J6B4MA.css → Button-X4B2TJAQ.css} +50 -19
  19. package/dist/Callout/index.js +1 -1
  20. package/dist/Canvas/index.js +4 -4
  21. package/dist/Card/Card.d.ts +9 -5
  22. package/dist/Card/index.js +1 -1
  23. package/dist/{Card-RLR254LD.css → Card-GLP7SUV6.css} +25 -18
  24. package/dist/Charts/BarList.d.ts +18 -1
  25. package/dist/Charts/ChartTooltip.d.ts +68 -0
  26. package/dist/Charts/StackedBar.d.ts +25 -7
  27. package/dist/Charts/StackedColumns.d.ts +112 -0
  28. package/dist/Charts/TimeSeries.d.ts +33 -2
  29. package/dist/Charts/dataColor.d.ts +22 -14
  30. package/dist/Charts/index.d.ts +6 -0
  31. package/dist/Charts/index.js +1 -1
  32. package/dist/Charts/useChartHover.d.ts +56 -0
  33. package/dist/Charts-B3YEF7R4.css +742 -0
  34. package/dist/Checkbox/index.js +1 -1
  35. package/dist/{Checkbox-VGW26YLQ.css → Checkbox-BOXQ747I.css} +2 -2
  36. package/dist/CodeBlock/index.js +4 -4
  37. package/dist/Combobox/index.js +5 -5
  38. package/dist/CommandPalette/CommandPalette.d.ts +97 -6
  39. package/dist/CommandPalette/index.d.ts +1 -1
  40. package/dist/CommandPalette/index.js +9 -7
  41. package/dist/CommandPalette-C5AMKGN2.css +259 -0
  42. package/dist/Copyable/index.js +3 -3
  43. package/dist/DataTable/index.js +7 -7
  44. package/dist/{DataTable-ITNACQ2X.css → DataTable-OLHPF7D4.css} +44 -43
  45. package/dist/DataView/index.js +14 -14
  46. package/dist/{DataView-256YF32J.css → DataView-N6JX464S.css} +5 -4
  47. package/dist/DateTimePicker/index.js +5 -5
  48. package/dist/DiffList/index.js +1 -1
  49. package/dist/Disclosure/index.js +2 -2
  50. package/dist/EntityChip/EntityChip.d.ts +9 -12
  51. package/dist/EntityChip/index.d.ts +1 -1
  52. package/dist/EntityChip/index.js +2 -2
  53. package/dist/ErrorBoundary/index.js +2 -2
  54. package/dist/{ErrorBoundary-ME36CQTA.css → ErrorBoundary-U2PA3LY2.css} +4 -4
  55. package/dist/IconButton/index.js +1 -1
  56. package/dist/{IconButton-VQGNMJDI.css → IconButton-TVEUWK6L.css} +2 -2
  57. package/dist/ImageUpload/ImageUpload.d.ts +10 -7
  58. package/dist/ImageUpload/index.js +2 -2
  59. package/dist/{ImageUpload-HKFIZR6D.css → ImageUpload-YCHJMUGX.css} +24 -10
  60. package/dist/Input/index.js +2 -2
  61. package/dist/Kbd/Kbd.d.ts +14 -4
  62. package/dist/Kbd/index.js +1 -1
  63. package/dist/Kbd-JPLDVJIP.css +71 -0
  64. package/dist/Layer/index.js +1 -1
  65. package/dist/Link/index.js +1 -1
  66. package/dist/List/index.js +1 -1
  67. package/dist/{List-XTHESXLR.css → List-MYJIV6MP.css} +12 -2
  68. package/dist/ListInput/index.js +5 -5
  69. package/dist/Listbox/index.js +2 -2
  70. package/dist/Listbox/useListbox.d.ts +16 -0
  71. package/dist/Listbox/useOptionKeys.d.ts +12 -1
  72. package/dist/{Listbox-X2DOTSQA.css → Listbox-6WJNJQVQ.css} +60 -7
  73. package/dist/Menu/index.js +4 -4
  74. package/dist/{Menu-6DE7I66I.css → Menu-BT5PMFJI.css} +15 -0
  75. package/dist/Meter/Meter.d.ts +103 -16
  76. package/dist/Meter/index.d.ts +2 -2
  77. package/dist/Meter/index.js +1 -1
  78. package/dist/{Meter-SKOOXQBC.css → Meter-5VCSFMZW.css} +46 -7
  79. package/dist/Modal/index.js +4 -4
  80. package/dist/{Modal-XYQJ4BL6.css → Modal-JAYBS2KS.css} +13 -4
  81. package/dist/OrgLabel/OrgLabel.d.ts +60 -24
  82. package/dist/OrgLabel/index.d.ts +1 -1
  83. package/dist/OrgLabel/index.js +2 -1
  84. package/dist/{OrgLabel-D7U6QJZD.css → OrgLabel-CR233G34.css} +9 -18
  85. package/dist/OrgNode/index.js +3 -2
  86. package/dist/OrgTable/OrgTable.d.ts +2 -2
  87. package/dist/OrgTable/index.js +8 -7
  88. package/dist/Popover/index.js +2 -2
  89. package/dist/PricingCard/index.js +3 -3
  90. package/dist/{PricingCard-JFI7RYXP.css → PricingCard-7EFXRSD2.css} +4 -5
  91. package/dist/SearchTrigger/SearchTrigger.d.ts +23 -4
  92. package/dist/SearchTrigger/index.d.ts +1 -1
  93. package/dist/SearchTrigger/index.js +1 -1
  94. package/dist/SearchTrigger-Z5D4AAY7.css +112 -0
  95. package/dist/SegmentedControl/index.js +2 -2
  96. package/dist/SegmentedMeter/SegmentedMeter.d.ts +107 -0
  97. package/dist/SegmentedMeter/index.d.ts +3 -0
  98. package/dist/SegmentedMeter/index.js +2 -0
  99. package/dist/SegmentedMeter-KQNML2TW.css +109 -0
  100. package/dist/Select/index.js +3 -3
  101. package/dist/{Select-2X77FSWR.css → Select-E24U5LBC.css} +34 -0
  102. package/dist/Shortcut/index.js +2 -2
  103. package/dist/SidebarNav/SidebarNav.d.ts +85 -25
  104. package/dist/SidebarNav/index.d.ts +1 -1
  105. package/dist/SidebarNav/index.js +1 -1
  106. package/dist/SidebarNav-X5NLZNWA.css +424 -0
  107. package/dist/StatCard/StatCard.d.ts +59 -12
  108. package/dist/StatCard/index.d.ts +1 -1
  109. package/dist/StatCard/index.js +1 -1
  110. package/dist/StatCard-KPAFD4E2.css +204 -0
  111. package/dist/StatGroup/index.js +1 -1
  112. package/dist/{StatGroup-TGB6AEKM.css → StatGroup-HVG6O62W.css} +8 -9
  113. package/dist/StatusDot/StatusDot.d.ts +24 -6
  114. package/dist/StatusDot/index.js +1 -1
  115. package/dist/StatusDot-7OMCQCZF.css +186 -0
  116. package/dist/Stepper/Stepper.d.ts +78 -0
  117. package/dist/Stepper/index.d.ts +3 -0
  118. package/dist/Stepper/index.js +4 -0
  119. package/dist/Stepper-HW4JM3YH.css +176 -0
  120. package/dist/Table/index.js +1 -1
  121. package/dist/{Table-MDOLVUAW.css → Table-TGCS4C3F.css} +14 -4
  122. package/dist/Tabs/index.js +1 -1
  123. package/dist/{Tabs-VLICJFVB.css → Tabs-XCNPHA7B.css} +79 -27
  124. package/dist/Tag/Tag.d.ts +29 -22
  125. package/dist/Tag/index.js +2 -2
  126. package/dist/{Tag-VNZEYLB6.css → Tag-GBE7LQJP.css} +82 -83
  127. package/dist/TagsInput/index.js +6 -6
  128. package/dist/ThemeSwitcher/ThemeSwitcher.d.ts +53 -21
  129. package/dist/ThemeSwitcher/index.d.ts +3 -3
  130. package/dist/ThemeSwitcher/index.js +4 -3
  131. package/dist/ThemeSwitcher/preferences.d.ts +19 -5
  132. package/dist/ThemeToggle/ThemeToggle.d.ts +40 -0
  133. package/dist/ThemeToggle/index.d.ts +2 -0
  134. package/dist/ThemeToggle/index.js +5 -0
  135. package/dist/TimeWindowPicker/index.js +8 -8
  136. package/dist/Toaster/index.js +2 -2
  137. package/dist/Toolbar/index.js +2 -2
  138. package/dist/{Toolbar-IP6LXN45.css → Toolbar-HUOSMNTH.css} +3 -1
  139. package/dist/Tooltip/index.js +2 -2
  140. package/dist/Tree/index.d.ts +2 -2
  141. package/dist/Tree/index.js +1 -1
  142. package/dist/Tree/layout.d.ts +103 -28
  143. package/dist/TreeCanvas/TreeCanvas.d.ts +60 -14
  144. package/dist/TreeCanvas/index.d.ts +1 -1
  145. package/dist/TreeCanvas/index.js +6 -6
  146. package/dist/TreeCanvas/motion.d.ts +3 -2
  147. package/dist/{TreeCanvas-WBNQPHC7.css → TreeCanvas-HVOV4SQN.css} +154 -30
  148. package/dist/TreeGrid/index.js +4 -4
  149. package/dist/{chunk-F6OE5FH3.js → chunk-2FPENTCF.js} +1 -1
  150. package/dist/chunk-4AK52VHB.js +88 -0
  151. package/dist/{chunk-7EM5T4ME.js → chunk-4IQD3HUQ.js} +2 -2
  152. package/dist/{chunk-YODNNSZL.js → chunk-4PZ6FJKW.js} +43 -13
  153. package/dist/{chunk-F27EPQ7D.js → chunk-4UQ7SMPK.js} +1 -1
  154. package/dist/chunk-5QWIJSQM.js +73 -0
  155. package/dist/{chunk-GTOUGQQK.js → chunk-6MU7HNB4.js} +13 -10
  156. package/dist/{chunk-S2XHHEW4.js → chunk-74KMX7YH.js} +4 -4
  157. package/dist/{chunk-WNI2WSJF.js → chunk-7KBNFFM3.js} +1 -1
  158. package/dist/{chunk-DD5BBGBE.js → chunk-AUS5FNQE.js} +9 -5
  159. package/dist/{chunk-CMEE37QJ.js → chunk-BMYPGGPV.js} +4 -4
  160. package/dist/{chunk-H4FBTAYS.js → chunk-BNCCEER3.js} +8 -8
  161. package/dist/chunk-C5WJUZVR.js +56 -0
  162. package/dist/{chunk-5WS6L6FA.js → chunk-CAIHUYXV.js} +9 -9
  163. package/dist/{chunk-XV6WRMBC.js → chunk-CQY5NTRS.js} +4 -1
  164. package/dist/{chunk-UOGSZKLT.js → chunk-D6EVJUGU.js} +2 -2
  165. package/dist/{chunk-6ZFVFA56.js → chunk-DHPUMOTX.js} +2 -2
  166. package/dist/{chunk-HZ5XZNPS.js → chunk-DS2C73RJ.js} +3 -3
  167. package/dist/{chunk-O6232G37.js → chunk-DSUY5F4E.js} +17 -5
  168. package/dist/{chunk-Q4ZPPART.js → chunk-EFYPAJT3.js} +3 -3
  169. package/dist/{chunk-WQX73TWF.js → chunk-ERVO6OUF.js} +18 -17
  170. package/dist/{chunk-BZYDZBAN.js → chunk-ETYEBKR4.js} +3 -3
  171. package/dist/{chunk-34VGEDVV.js → chunk-FD5UEN6X.js} +30 -30
  172. package/dist/{chunk-5SDBMKUO.js → chunk-FIFNP6PL.js} +3 -3
  173. package/dist/{chunk-7HPRF5XN.js → chunk-FUF52K7E.js} +98 -16
  174. package/dist/{chunk-5KPQ6D7N.js → chunk-FZVJDJFN.js} +2 -2
  175. package/dist/chunk-IA232OTU.js +156 -0
  176. package/dist/{chunk-2EOKFKHX.js → chunk-IG27QX7Q.js} +7 -7
  177. package/dist/chunk-IKB6HFGK.js +55 -0
  178. package/dist/{chunk-FBZAKNSX.js → chunk-IPVQKAHO.js} +10 -7
  179. package/dist/{chunk-3EYF6HKB.js → chunk-IVFJD7WY.js} +28 -9
  180. package/dist/{chunk-WOYYD2YR.js → chunk-JGRNTBF2.js} +11 -11
  181. package/dist/chunk-K3OWD7BJ.js +121 -0
  182. package/dist/{chunk-BJSKPEZI.js → chunk-KD4H66L6.js} +7 -20
  183. package/dist/{chunk-SFZOKW2G.js → chunk-KJ34ZBBI.js} +8 -3
  184. package/dist/{chunk-HQNHV7D6.js → chunk-LFHCXZO5.js} +6 -6
  185. package/dist/{chunk-LWKJQTOM.js → chunk-MICH6QSJ.js} +1 -1
  186. package/dist/chunk-N3DPO6HG.js +226 -0
  187. package/dist/{chunk-S4GZWSKR.js → chunk-OM5E3TTK.js} +1 -1
  188. package/dist/{chunk-3QRYCPXQ.js → chunk-OPKIKM35.js} +6 -6
  189. package/dist/{chunk-5EKIWVOR.js → chunk-PGRPNDWM.js} +2 -2
  190. package/dist/{chunk-LFJ6UJTI.js → chunk-PQNILU27.js} +9 -9
  191. package/dist/{chunk-QNCVHRZL.js → chunk-QVAFL2LE.js} +1 -1
  192. package/dist/{chunk-QEUY3A5P.js → chunk-QY7UU5ZB.js} +3 -2
  193. package/dist/{chunk-ITHXJHBB.js → chunk-R25RGPUB.js} +1 -0
  194. package/dist/{chunk-KLJCCMF3.js → chunk-R6735B37.js} +2 -2
  195. package/dist/{chunk-3ZP55QZE.js → chunk-R6FBDTP3.js} +4 -4
  196. package/dist/{chunk-7FZ53WDJ.js → chunk-RIAZM6L3.js} +1 -1
  197. package/dist/chunk-RJM4QCGG.js +550 -0
  198. package/dist/{chunk-NTRZGNEX.js → chunk-S3BCVWTU.js} +215 -46
  199. package/dist/chunk-S7KW47IQ.js +121 -0
  200. package/dist/{chunk-OFHBK7RI.js → chunk-SJQ546ID.js} +34 -14
  201. package/dist/{chunk-D35VTV2Z.js → chunk-SV7QAONL.js} +1 -1
  202. package/dist/{chunk-IAJLHVUA.js → chunk-TIWAHZZ6.js} +1 -1
  203. package/dist/{chunk-2PRH365R.js → chunk-UA7O3KKJ.js} +1 -1
  204. package/dist/{chunk-NPZY6YYL.js → chunk-UG5ZMAXW.js} +6 -6
  205. package/dist/{chunk-FEFTGVMF.js → chunk-V2N3BMOT.js} +7 -2
  206. package/dist/{chunk-NDCATSW7.js → chunk-V34H2YCY.js} +1 -1
  207. package/dist/chunk-WIATRXEJ.js +22 -0
  208. package/dist/{chunk-5C5YMZQU.js → chunk-WOFOMTGB.js} +16 -10
  209. package/dist/{chunk-QYOFACSP.js → chunk-WSOFKOLP.js} +3 -3
  210. package/dist/{chunk-MNAXYY3R.js → chunk-WUVZDFHS.js} +31 -11
  211. package/dist/{chunk-UG46QBLT.js → chunk-YIMOT5OO.js} +10 -10
  212. package/dist/{chunk-2ZQMA2WB.js → chunk-ZPSOF6VL.js} +2 -2
  213. package/dist/generated/index.d.ts +3 -0
  214. package/dist/generated/index.js +66 -62
  215. package/dist/index.js +66 -62
  216. package/dist/styles.css +2719 -799
  217. package/dist/utils/index.d.ts +1 -1
  218. package/dist/utils/tone.d.ts +7 -12
  219. package/package.json +4 -4
  220. package/scripts/check-css-literals.mjs +159 -23
  221. package/scripts/check-css-variables.mjs +5 -3
  222. package/scripts/css-source.mjs +97 -5
  223. package/dist/Avatar-P2KRQM2B.css +0 -156
  224. package/dist/Charts-D7G2BSXH.css +0 -277
  225. package/dist/CommandPalette-CSJDUCQA.css +0 -115
  226. package/dist/Kbd-W66MXQI5.css +0 -61
  227. package/dist/SearchTrigger-QXOYAUUY.css +0 -79
  228. package/dist/SidebarNav-QGSFKZYA.css +0 -319
  229. package/dist/StatCard-KYPKZUWX.css +0 -111
  230. package/dist/StatusDot-HA2L2FSX.css +0 -84
  231. package/dist/chunk-22O7LAW2.js +0 -41
  232. package/dist/chunk-2HQR4U4D.js +0 -143
  233. package/dist/chunk-ESCO4XYW.js +0 -144
  234. package/dist/chunk-F4PJZ4ED.js +0 -245
  235. package/dist/chunk-PNFASD6F.js +0 -98
  236. package/dist/chunk-PZSWF74H.js +0 -15
  237. /package/dist/{chunk-ZCR6YGQ4.js → chunk-PKIN4IMB.js} +0 -0
@@ -1,19 +1,29 @@
1
1
  /**
2
2
  * The rail's navigation: groups of rows, one of which says where the reader is.
3
3
  *
4
- * THE ROW THE READER IS ON IS THE ONE PLACE THE ACCENT APPEARS IN THE CHROME,
5
- * and it takes the accent twice over: the accent's soft tint as its ground,
6
- * and the accent ink for its label and its glyph. Position AND hue, so the row
7
- * is found at a glance by a reader who sees the hue and by one who does not.
4
+ * THE ROW THE READER IS ON IS RAISED, WITH A HAIRLINE ROUND IT, AND NO HUE: it
5
+ * is found by its position, its lift and its line, by a reader who sees
6
+ * colour and by one who does not. The accent is the primary action's fill, so
7
+ * a violet row in the rail would read as a second primary on every screen.
8
8
  * `aria-current="page"` says the same thing to a screen reader, and the style
9
9
  * is drawn FROM that attribute, so the two cannot come apart. The stylesheet
10
- * carries why this replaced a one-pixel accent bar outside the row's edge.
10
+ * carries why the hairline is an outline rather than a shadow.
11
11
  *
12
12
  * THE LINK ELEMENT BELONGS TO THE APPLICATION (`renderLink`). A router's own
13
13
  * link is what carries a client navigation and a leave guard; a plain anchor is
14
14
  * what carries a middle click into a new tab. Neither is right everywhere, so
15
15
  * neither is built in: the engine keeps plain anchors and the console passes
16
16
  * its router's NavLink.
17
+ *
18
+ * A FIGURE AT THE END OF A ROW IS ONE OF TWO THINGS, and the two are two props
19
+ * rather than one prop with a tone. A `count` is how many of something the
20
+ * destination holds (the open tasks in a project), a quiet figure in the
21
+ * tertiary ink; a `badge` is how many things are waiting on the reader (the
22
+ * unread in the inbox), the one filled pill in the chrome. Both are READ as
23
+ * part of the row's name, with the words the caller gives them ("Inbox, 5
24
+ * unread"), because a bare "5" after a name says nothing about what it counts,
25
+ * and both carry those words as required props, so a figure without them does
26
+ * not type-check.
17
27
  */
18
28
  import { type MouseEventHandler, type ReactNode } from 'react';
19
29
  export interface SidebarNavProps {
@@ -26,6 +36,24 @@ export interface SidebarNavProps {
26
36
  className?: string | undefined;
27
37
  children?: ReactNode;
28
38
  }
39
+ /**
40
+ * The one control a group's heading can carry at its end: the add beside
41
+ * "Projects".
42
+ *
43
+ * A DESCRIPTION RATHER THAN AN ELEMENT, because the rail is what draws it: a
44
+ * square at the pointer-target floor, which is exactly the heading's height,
45
+ * named by `label`, with its ring inside its own box like every row in a
46
+ * clipping scroller. A control handed in whole would bring its own step, and
47
+ * the smallest one in the kit is two pixels taller than the heading it sits
48
+ * in.
49
+ */
50
+ export interface NavGroupAction {
51
+ /** What pressing it does, in words: "New project". It is the control's name. */
52
+ label: string;
53
+ /** The glyph. Decoration: the label is the name. */
54
+ icon: ReactNode;
55
+ onClick: MouseEventHandler<HTMLButtonElement>;
56
+ }
29
57
  export interface NavGroupProps {
30
58
  /**
31
59
  * The group's heading. Without one the rows are simply a run of rows, and an
@@ -34,6 +62,13 @@ export interface NavGroupProps {
34
62
  * rail spent on nothing.
35
63
  */
36
64
  label?: ReactNode;
65
+ /**
66
+ * A control at the end of the heading. It is a sibling of the heading's
67
+ * words rather than part of them, so the group is still named by its label
68
+ * alone, and it takes its own place in the tab order before the group's
69
+ * first row.
70
+ */
71
+ action?: NavGroupAction | undefined;
37
72
  className?: string | undefined;
38
73
  children?: ReactNode;
39
74
  }
@@ -46,33 +81,58 @@ export interface NavLinkProps {
46
81
  onClick?: MouseEventHandler<HTMLElement> | undefined;
47
82
  }
48
83
  /**
49
- * How loudly a row's badge is drawn.
84
+ * A figure at the end of a row, and what it counts.
50
85
  *
51
- * `neutral` is a quiet figure at the end of the row, in the row's own ink.
52
- * `attention` is the one badge in the chrome allowed a status hue: a count of
53
- * what is waiting on a person is the one thing that should pull the eye out of
54
- * whatever screen the reader is on. It is a tint behind a word rather than a
55
- * word in a hue, so it still reads to somebody who cannot separate the hue.
56
- *
57
- * A TONE RATHER THAN A COMPONENT THE CALLER PASSES IN, because the tint has to
58
- * clear its floor on the ground the ROW has, which is the accent tint on the
59
- * reader's own row. That is a fact about the rail, measured in the rail's own
60
- * stylesheet, and not something a call site can be asked to know.
86
+ * VALUES RATHER THAN AN ELEMENT, because the rail is what paints them: the
87
+ * pair has to clear its floor on every ground a ROW can have, the reader's
88
+ * own raised row included, and that is a fact about the rail, measured in the
89
+ * rail's own stylesheet, not something a call site can be asked to know.
61
90
  */
62
- export type NavBadgeTone = 'neutral' | 'attention';
91
+ export interface NavFigure {
92
+ /** The figure, drawn as given, so the caller decides its formatting. */
93
+ value: number | string;
94
+ /**
95
+ * What is counted, read after the figure as part of the row's name:
96
+ * `unread` makes the inbox row "Inbox, 5 unread". Required, because a
97
+ * figure read with no word after it is a number nobody can place.
98
+ */
99
+ label: string;
100
+ }
101
+ /** A quiet figure: how many of something the destination holds. */
102
+ export interface NavCount extends NavFigure {
103
+ /**
104
+ * A mark before the figure: the working dot beside a count of agents at
105
+ * work. Decoration, because the label says the same thing in words.
106
+ */
107
+ mark?: ReactNode;
108
+ }
63
109
  export interface NavItemProps {
64
110
  /** What the row is called. */
65
111
  label: ReactNode;
66
112
  /** The row's glyph. Decoration: the label beside it carries the meaning. */
67
113
  icon?: ReactNode;
68
114
  /**
69
- * A count or a state at the end of the row. The slot draws it: whatever is
70
- * passed contributes its text and the name a screen reader reads after the
71
- * row's own, so a `<Count>` here is a figure rather than a second pill.
115
+ * A short key drawn as a chip before the label, in place of a glyph: a
116
+ * project's `ENG`. It is text, and READ as the start of the row's name
117
+ * ("ENG Core platform"), because it is the prefix every item in that project
118
+ * is filed under and a reader who hears it can find them. A string rather
119
+ * than an element, because the rail paints the chip and measures it.
120
+ */
121
+ lead?: string | undefined;
122
+ /**
123
+ * How many of something the destination holds, as a quiet figure at the end
124
+ * of the row in the tertiary ink: the open tasks in a project.
125
+ */
126
+ count?: NavCount | undefined;
127
+ /**
128
+ * How many things at this destination are waiting on the reader, as the one
129
+ * filled pill in the chrome, in the accent: the unread in the inbox. A count
130
+ * of what is waiting on the reader is the one thing in the rail that asks
131
+ * them to act, which is what the accent means; it is a FILL carrying a
132
+ * figure rather than a figure in a hue, so it still reads to somebody who
133
+ * cannot separate the hue. Anything else is a `count`.
72
134
  */
73
- badge?: ReactNode;
74
- /** How loudly. Neutral unless this row is what needs a person. */
75
- badgeTone?: NavBadgeTone | undefined;
135
+ badge?: NavFigure | undefined;
76
136
  href?: string | undefined;
77
137
  /** Whether this row is the screen the reader is on. */
78
138
  current?: boolean | undefined;
@@ -112,6 +172,6 @@ export declare namespace SidebarNav {
112
172
  * `<div>` here still carries the label's own padding, which put sixteen blank
113
173
  * pixels at the top of the rail and named a group nothing could read.
114
174
  */
115
- export declare function NavGroup({ label, className, children }: NavGroupProps): import("react").JSX.Element;
175
+ export declare function NavGroup({ label, action, className, children }: NavGroupProps): import("react").JSX.Element;
116
176
  /** One row: a glyph, a label, an optional badge, and optionally rows beneath. */
117
- export declare function NavItem({ label, icon, badge, badgeTone, href, current, disabledReason, renderLink, onClick, children, expanded, defaultExpanded, onExpandedChange, expandLabel, className, }: NavItemProps): import("react").JSX.Element;
177
+ export declare function NavItem({ label, icon, lead, count, badge, href, current, disabledReason, renderLink, onClick, children, expanded, defaultExpanded, onExpandedChange, expandLabel, className, }: NavItemProps): import("react").JSX.Element;
@@ -1,3 +1,3 @@
1
1
  import './SidebarNav.css';
2
2
  export { NavGroup, NavItem, SidebarNav } from './SidebarNav.js';
3
- export type { NavBadgeTone, NavGroupProps, NavItemProps, NavLinkProps, SidebarNavProps } from './SidebarNav.js';
3
+ export type { NavCount, NavFigure, NavGroupAction, NavGroupProps, NavItemProps, NavLinkProps, SidebarNavProps, } from './SidebarNav.js';
@@ -1,3 +1,3 @@
1
- export { NavGroup, NavItem, SidebarNav } from '../chunk-3EYF6HKB.js';
1
+ export { NavGroup, NavItem, SidebarNav } from '../chunk-IVFJD7WY.js';
2
2
  import '../chunk-BZFWDIV6.js';
3
3
  import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,424 @@
1
+ /*
2
+ * The rail's navigation.
3
+ *
4
+ * ONE VERTICAL LINE. The rail pads by --size-nav-gutter and each row pads by
5
+ * --size-nav-row-pad, so the mark, the group labels and every row's text start
6
+ * on the same line: shrink the gutter and grow the pad by the same step and
7
+ * nothing moves. That is why the row's own background takes the full width the
8
+ * gutter leaves it, rather than each row carrying a horizontal margin of its
9
+ * own.
10
+ */
11
+
12
+ .crewlet-sidebar-nav {
13
+ display: flex;
14
+ flex-direction: column;
15
+ gap: var(--spacing-1);
16
+ min-width: 0;
17
+ padding: var(--spacing-2) var(--size-nav-gutter) var(--spacing-4);
18
+ }
19
+
20
+ /*
21
+ * THE ROWS INSIDE A GROUP ARE HALF A STEP APART: the approved design's 2px,
22
+ * which is what keeps a hovered row's tint from touching the raised row under
23
+ * it and reading as one band two rows tall. It is half a step rather than one
24
+ * because a rail holds fifteen destinations and more: at 4px a row the rail
25
+ * stood 823px in a 755px scroller when its rows were 36px, and the last two
26
+ * destinations were reachable only by scrolling it. At the 30px row step the
27
+ * same fifteen rows and fourteen 2px gaps are 478px against 540px flush at the
28
+ * old step, so the gap is paid for many times over by the row it sits beside.
29
+ */
30
+ .crewlet-nav-group {
31
+ display: flex;
32
+ flex-direction: column;
33
+ gap: calc(var(--spacing-1) / 2);
34
+ min-width: 0;
35
+ }
36
+
37
+ /*
38
+ * THE HEADING: the group's name and, at its end, an optional control (the add
39
+ * beside "Projects"). It stands at the pointer-target floor, because that
40
+ * control is a target and the heading is the row it is drawn in; with no
41
+ * control the heading keeps the same height, so a rail whose groups differ
42
+ * only in whether they can add something does not change its rhythm.
43
+ *
44
+ * Held off the run above by a margin rather than a padding, so its height
45
+ * does not depend on the document's box-sizing: with the rail's own gap it is
46
+ * 14px, the design's space between two runs, at density 1.
47
+ *
48
+ * Its end inset is a step SHORTER than a row's, because the control is a
49
+ * 24px square with its glyph centred in it: the row pad would put the glyph
50
+ * five pixels inside the line every count above and below it ends on.
51
+ */
52
+ .crewlet-nav-group__head {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: var(--spacing-2);
56
+ min-width: 0;
57
+ min-height: var(--size-target-min);
58
+ margin-top: calc(var(--spacing-2) + var(--spacing-1) / 2);
59
+ padding: 0 var(--spacing-2) 0 var(--size-nav-row-pad);
60
+ }
61
+
62
+ /*
63
+ * The group's name in the design's register: sentence case at the caption
64
+ * step, not the uppercase micro-label it was. It is the same case as every row
65
+ * it names, so "Projects" reads as the word it is rather than as a label
66
+ * shouted over the rows, and the quieter ink rather than the tracking is what
67
+ * sets it apart from them.
68
+ */
69
+ .crewlet-nav-group__label {
70
+ flex: 1 1 auto;
71
+ min-width: 0;
72
+ overflow: hidden;
73
+ text-overflow: ellipsis;
74
+ white-space: nowrap;
75
+ font-family: var(--font-family-sans);
76
+ font-size: var(--font-size-xs);
77
+ font-weight: var(--font-weight-regular);
78
+ line-height: var(--font-line-height-tight);
79
+ /* The 4.5:1 step: a group name is a fact a reader has to read, not
80
+ decoration. */
81
+ color: var(--color-text-tertiary);
82
+ }
83
+
84
+ /* The heading's control. Pushed to the end whether or not the heading has
85
+ words, and at the floor the heading stands at. */
86
+ .crewlet-nav-group__action {
87
+ display: inline-flex;
88
+ align-items: center;
89
+ justify-content: center;
90
+ flex: none;
91
+ width: var(--size-target-min);
92
+ height: var(--size-target-min);
93
+ margin-left: auto;
94
+ padding: 0;
95
+ border: none;
96
+ border-radius: var(--radius-sm);
97
+ background: transparent;
98
+ color: var(--color-text-tertiary);
99
+ cursor: pointer;
100
+ transition:
101
+ background var(--motion-duration-fast) var(--motion-easing-default),
102
+ color var(--motion-duration-fast) var(--motion-easing-default);
103
+ }
104
+
105
+ .crewlet-nav-group__action:hover {
106
+ background: var(--color-surface-hover);
107
+ color: var(--color-text-primary);
108
+ }
109
+
110
+ /* Inside its own box, like every control in the rail: the rail is a clipping
111
+ scroller. */
112
+ .crewlet-nav-group__action:focus-visible {
113
+ outline: 2px solid var(--color-focus);
114
+ outline-offset: var(--size-focus-ring-inset-offset);
115
+ }
116
+
117
+ .crewlet-nav-group__action-icon {
118
+ display: inline-flex;
119
+ }
120
+
121
+ .crewlet-nav-item {
122
+ min-width: 0;
123
+ }
124
+
125
+ .crewlet-nav-item__head {
126
+ display: flex;
127
+ align-items: center;
128
+ gap: var(--spacing-1);
129
+ min-width: 0;
130
+ }
131
+
132
+ .crewlet-nav-item__row {
133
+ display: flex;
134
+ align-items: center;
135
+ /* The design's 10px between a glyph and its word. */
136
+ gap: calc(var(--spacing-2) + var(--spacing-1) / 2);
137
+ flex: 1 1 auto;
138
+ min-width: 0;
139
+ width: 100%;
140
+ /* The rail's own row step, 30px: a list's 36px row spent six pixels fifteen
141
+ times over in a column the height of the window. */
142
+ min-height: var(--size-nav-row);
143
+ padding: 0 var(--size-nav-row-pad);
144
+ border: none;
145
+ /* The chrome's radius, not a card's. A 12px corner on a 30px row leaves the
146
+ tint reading as a lozenge floating in the gutter rather than as a band the
147
+ width of the rail. */
148
+ border-radius: var(--radius-md);
149
+ background: transparent;
150
+ /*
151
+ * A RESTING ROW IS THE SECONDARY STEP, and the reader's own row and a
152
+ * pointed one lift to the primary. That step is what says which row is
153
+ * which before the fill does: at full ink every row carried the current
154
+ * row's own weight, so the rail read heavier and brighter than the approved
155
+ * design and the current row was found by its lift alone. The secondary step
156
+ * is held at 4.5:1 on the rail and under the hover overlay by
157
+ * @crewlethq/tokens (RAIL_PAINTS), so quieter is not fainter.
158
+ *
159
+ * The glyph has no colour of its own: it is drawn in currentColor and so is
160
+ * this ink, on every row, which is what keeps a row from painting its word
161
+ * and its glyph two different answers to "where am I".
162
+ */
163
+ color: var(--color-text-secondary);
164
+ font-family: var(--font-family-sans);
165
+ /* THE CHROME IS NOT BODY TEXT. A rail row names a destination; it is read at
166
+ a glance and never read through, so it takes the compact step in the
167
+ medium weight, which is what keeps a one-word row legible at 13px. */
168
+ font-size: var(--font-size-compact);
169
+ font-weight: var(--font-weight-medium);
170
+ letter-spacing: var(--font-letter-spacing-snug);
171
+ line-height: var(--font-line-height-tight);
172
+ text-align: left;
173
+ text-decoration: none;
174
+ cursor: pointer;
175
+ transition:
176
+ background var(--motion-duration-fast) var(--motion-easing-default),
177
+ color var(--motion-duration-fast) var(--motion-easing-default);
178
+ }
179
+
180
+ .crewlet-nav-item__row:hover {
181
+ background: var(--color-surface-hover);
182
+ color: var(--color-text-primary);
183
+ text-decoration: none;
184
+ }
185
+
186
+ /*
187
+ * WHERE THE READER IS: the row stands on RAISED, with the plain border drawn
188
+ * round it as a hairline INSIDE the row, and lifts to the primary ink.
189
+ *
190
+ * It is found the way a card is found. In light, raised is only dE 1.84 off
191
+ * the frame the rail stands on, so the fill alone is a lift a reader may not
192
+ * see; the hairline is what carries the row, and in dark it is also what
193
+ * tells the current row from a hovered one, whose fill lands only dE 1.56
194
+ * away. @crewlethq/tokens holds both halves by name: the row lifts off the
195
+ * rail by dE 1.5 and the hairline clears dE 3 on the row it is drawn on.
196
+ *
197
+ * It used to be the accent's own soft tint with the label in the accent ink.
198
+ * The accent is the fill of the primary action now, so a violet row in the
199
+ * rail would read as a second primary on every screen, beside the one the
200
+ * screen is actually asking for. Where the reader is, is the row's position,
201
+ * its lift and its line; aria-current says it to a screen reader.
202
+ *
203
+ * THE HAIRLINE IS AN OUTLINE, not an inset box-shadow, for the reason the
204
+ * focus ring is one: forced-colors mode drops every box-shadow and every
205
+ * background and keeps outlines, so drawn as a shadow the current row would
206
+ * be indistinguishable from its neighbours for exactly the readers that mode
207
+ * exists for. The focus ring is the same property, so its rule is declared
208
+ * after this one and a focused current row draws the ring instead.
209
+ *
210
+ * Drawn from aria-current, so the picture and what a screen reader is told
211
+ * cannot come apart. It is declared after :hover deliberately: both selectors
212
+ * weigh the same, a row shows the current lift or the hover overlay and never
213
+ * both, and later is what decides which.
214
+ */
215
+ .crewlet-nav-item__row[aria-current='page'] {
216
+ background: var(--color-surface-elevated);
217
+ outline: 1px solid var(--color-border-default);
218
+ outline-offset: -1px;
219
+ color: var(--color-text-primary);
220
+ }
221
+
222
+ .crewlet-nav-item__row[aria-disabled='true'] {
223
+ cursor: not-allowed;
224
+ opacity: 0.55;
225
+ }
226
+
227
+ .crewlet-nav-item__row[aria-disabled='true']:hover {
228
+ background: transparent;
229
+ color: var(--color-text-secondary);
230
+ }
231
+
232
+ /*
233
+ * After the current row's rule, which draws its hairline on the same
234
+ * property: both weigh the same, so source order is what lets a focused
235
+ * current row draw the ring rather than the line.
236
+ */
237
+ .crewlet-nav-item__row:focus-visible {
238
+ outline: 2px solid var(--color-focus);
239
+ /* Inside the row's own box: the rail is a clipping scroller, so an outset
240
+ ring on the first or last row is cut off by it. */
241
+ outline-offset: var(--size-focus-ring-inset-offset);
242
+ }
243
+
244
+ /*
245
+ * THE GLYPH IS THE LABEL'S INK. Lucide draws in currentColor, so the glyph
246
+ * takes whatever the row is painted in, at rest, pointed and current alike,
247
+ * and there is no second ramp to fall out of step with the word beside it.
248
+ */
249
+ .crewlet-nav-item__icon {
250
+ display: inline-flex;
251
+ align-items: center;
252
+ justify-content: center;
253
+ flex: none;
254
+ }
255
+
256
+ .crewlet-nav-item__label {
257
+ flex: 1 1 auto;
258
+ min-width: 0;
259
+ overflow: hidden;
260
+ text-overflow: ellipsis;
261
+ white-space: nowrap;
262
+ }
263
+
264
+ /*
265
+ * A PROJECT'S KEY, as a chip in the glyph's place: the prefix every item in
266
+ * the project is filed under, in mono so ENG and PROD line up by letter. It
267
+ * is the raised rung inside the plain hairline, in the secondary ink, which
268
+ * the palette suite measures on every ground a row can have; on the reader's
269
+ * own row, which is raised too, the hairline is what draws it.
270
+ */
271
+ .crewlet-nav-item__lead {
272
+ display: inline-flex;
273
+ align-items: center;
274
+ flex: none;
275
+ padding: 0 calc(var(--spacing-1) + 1px);
276
+ border: 1px solid var(--color-border-default);
277
+ border-radius: var(--radius-xs);
278
+ background: var(--color-surface-elevated);
279
+ color: var(--color-text-secondary);
280
+ font-family: var(--font-family-mono);
281
+ font-size: var(--font-size-2xs);
282
+ font-weight: var(--font-weight-medium);
283
+ letter-spacing: var(--font-letter-spacing-normal);
284
+ line-height: var(--font-line-height-body);
285
+ }
286
+
287
+ /*
288
+ * THE COUNT: how many of something the destination holds, as a quiet figure
289
+ * at the end of the row. Tabular, so a count that ticks up does not move the
290
+ * words beside it. A mark before it (the working dot beside a count of agents
291
+ * at work) stands half a step off the figure.
292
+ */
293
+ .crewlet-nav-item__count {
294
+ display: inline-flex;
295
+ align-items: center;
296
+ flex: none;
297
+ margin-left: auto;
298
+ font-size: var(--font-size-2xs);
299
+ font-variant-numeric: tabular-nums;
300
+ color: var(--color-text-tertiary);
301
+ }
302
+
303
+ .crewlet-nav-item__figure {
304
+ display: inline-flex;
305
+ align-items: center;
306
+ gap: calc(var(--spacing-1) + 1px);
307
+ }
308
+
309
+ .crewlet-nav-item__mark {
310
+ display: inline-flex;
311
+ }
312
+
313
+ /* The count takes the row's ink on the current row, lifting from the tertiary
314
+ step to the primary ink with the row it sits in: the tertiary step is
315
+ measured on the rail and under the hover overlay, and the raised row is a
316
+ ground it was never held to. */
317
+ .crewlet-nav-item__row[aria-current='page'] .crewlet-nav-item__count {
318
+ color: inherit;
319
+ }
320
+
321
+ /*
322
+ * THE BADGE, THE ONE FIGURE IN THE CHROME ALLOWED A HUE, and it is the
323
+ * accent. A count of what is waiting on the reader is the one thing in the
324
+ * rail that asks them to act, which is what the accent means, and it is the
325
+ * one thing that should pull the eye out of whatever screen they are on. It
326
+ * is a FILL carrying a figure rather than a figure in a hue, so it reads to
327
+ * somebody who cannot separate the hue at all: the filled pill is the signal,
328
+ * the figure is the count.
329
+ *
330
+ * The design's 18px pill, at least as wide as it is tall so a single digit is
331
+ * a round mark and not a lozenge, and following the density like the xs Tag
332
+ * it matches. The label is the on-accent step, the primary action's own pair,
333
+ * on every row alike, because the fill is opaque.
334
+ */
335
+ .crewlet-nav-item__badge {
336
+ --crewlet-nav-item-badge-size: calc(18px * var(--density, 1));
337
+ display: inline-flex;
338
+ align-items: center;
339
+ justify-content: center;
340
+ flex: none;
341
+ box-sizing: border-box;
342
+ min-width: var(--crewlet-nav-item-badge-size);
343
+ height: var(--crewlet-nav-item-badge-size);
344
+ margin-left: auto;
345
+ padding: 0 calc(var(--spacing-1) + 1px);
346
+ border-radius: var(--radius-pill);
347
+ background: var(--color-brand-accent);
348
+ color: var(--color-text-on-accent);
349
+ font-size: var(--font-size-2xs);
350
+ font-weight: var(--font-weight-semibold);
351
+ font-variant-numeric: tabular-nums;
352
+ line-height: 1;
353
+ }
354
+
355
+ /* Beside a count the badge is the second figure, not a second push to the
356
+ end: two auto margins would split the room between them and float the
357
+ count into the middle of the row. */
358
+ .crewlet-nav-item__count + .crewlet-nav-item__badge {
359
+ margin-left: var(--spacing-2);
360
+ }
361
+
362
+ .crewlet-nav-item__toggle {
363
+ display: inline-flex;
364
+ align-items: center;
365
+ justify-content: center;
366
+ flex: none;
367
+ width: var(--size-control-sm);
368
+ height: var(--size-control-sm);
369
+ padding: 0;
370
+ border: none;
371
+ border-radius: var(--radius-sm);
372
+ background: transparent;
373
+ color: var(--color-text-tertiary);
374
+ cursor: pointer;
375
+ }
376
+
377
+ .crewlet-nav-item__toggle:hover {
378
+ background: var(--color-surface-hover);
379
+ color: var(--color-text-primary);
380
+ }
381
+
382
+ .crewlet-nav-item__toggle:focus-visible {
383
+ outline: 2px solid var(--color-focus);
384
+ outline-offset: var(--size-focus-ring-inset-offset);
385
+ }
386
+
387
+ .crewlet-nav-item__chevron {
388
+ display: inline-flex;
389
+ transition: transform var(--motion-duration-fast) var(--motion-easing-default);
390
+ }
391
+
392
+ .crewlet-nav-item__chevron--open {
393
+ transform: rotate(180deg);
394
+ }
395
+
396
+ /*
397
+ * Nested rows carry an indent guide rather than more padding, because a run of
398
+ * indents with no line is a hierarchy a reader has to measure by eye. On the
399
+ * path the reader is on the guide steps up to the strong border: the same
400
+ * neutral lift the current row itself takes, and not the accent, which the
401
+ * rail keeps for the one count that asks the reader to act.
402
+ */
403
+ .crewlet-nav-item__children {
404
+ display: flex;
405
+ flex-direction: column;
406
+ gap: var(--spacing-1);
407
+ margin-left: var(--size-nav-row-pad);
408
+ padding-left: var(--spacing-2);
409
+ border-left: 1px solid var(--color-border-default);
410
+ }
411
+
412
+ /* No type step of its own any more: every row in the rail reads at the compact
413
+ step now, and the indent guide is what says a row is nested. */
414
+ .crewlet-nav-item__children:has(.crewlet-nav-item__row[aria-current='page']) {
415
+ border-left-color: var(--color-border-strong);
416
+ }
417
+
418
+ @media (prefers-reduced-motion: reduce) {
419
+ .crewlet-nav-group__action,
420
+ .crewlet-nav-item__row,
421
+ .crewlet-nav-item__chevron {
422
+ transition: none;
423
+ }
424
+ }