@crewlethq/ui 0.4.4 → 0.5.1

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 (231) 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-37UWTRN6.css → DataTable-OLHPF7D4.css} +35 -38
  45. package/dist/DataView/index.js +16 -16
  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 +6 -6
  69. package/dist/Listbox/index.js +2 -2
  70. package/dist/Listbox/useListbox.d.ts +2 -0
  71. package/dist/{Listbox-ZXYYNN6U.css → Listbox-6WJNJQVQ.css} +32 -7
  72. package/dist/Menu/index.js +4 -4
  73. package/dist/Meter/Meter.d.ts +103 -16
  74. package/dist/Meter/index.d.ts +2 -2
  75. package/dist/Meter/index.js +1 -1
  76. package/dist/{Meter-SKOOXQBC.css → Meter-5VCSFMZW.css} +46 -7
  77. package/dist/Modal/index.js +4 -4
  78. package/dist/{Modal-XYQJ4BL6.css → Modal-JAYBS2KS.css} +13 -4
  79. package/dist/OrgLabel/OrgLabel.d.ts +60 -24
  80. package/dist/OrgLabel/index.d.ts +1 -1
  81. package/dist/OrgLabel/index.js +2 -1
  82. package/dist/{OrgLabel-D7U6QJZD.css → OrgLabel-CR233G34.css} +9 -18
  83. package/dist/OrgNode/index.js +3 -2
  84. package/dist/OrgTable/OrgTable.d.ts +2 -2
  85. package/dist/OrgTable/index.js +8 -7
  86. package/dist/Popover/index.js +2 -2
  87. package/dist/PricingCard/index.js +3 -3
  88. package/dist/{PricingCard-JFI7RYXP.css → PricingCard-7EFXRSD2.css} +4 -5
  89. package/dist/SearchTrigger/SearchTrigger.d.ts +23 -4
  90. package/dist/SearchTrigger/index.d.ts +1 -1
  91. package/dist/SearchTrigger/index.js +1 -1
  92. package/dist/SearchTrigger-Z5D4AAY7.css +112 -0
  93. package/dist/SegmentedControl/index.js +2 -2
  94. package/dist/SegmentedMeter/SegmentedMeter.d.ts +107 -0
  95. package/dist/SegmentedMeter/index.d.ts +3 -0
  96. package/dist/SegmentedMeter/index.js +2 -0
  97. package/dist/SegmentedMeter-KQNML2TW.css +109 -0
  98. package/dist/Select/index.js +3 -3
  99. package/dist/Shortcut/index.js +2 -2
  100. package/dist/SidebarNav/SidebarNav.d.ts +85 -25
  101. package/dist/SidebarNav/index.d.ts +1 -1
  102. package/dist/SidebarNav/index.js +1 -1
  103. package/dist/SidebarNav-X5NLZNWA.css +424 -0
  104. package/dist/StatCard/StatCard.d.ts +59 -12
  105. package/dist/StatCard/index.d.ts +1 -1
  106. package/dist/StatCard/index.js +1 -1
  107. package/dist/StatCard-KPAFD4E2.css +204 -0
  108. package/dist/StatGroup/index.js +1 -1
  109. package/dist/{StatGroup-TGB6AEKM.css → StatGroup-HVG6O62W.css} +8 -9
  110. package/dist/StatusDot/StatusDot.d.ts +24 -6
  111. package/dist/StatusDot/index.js +1 -1
  112. package/dist/StatusDot-7OMCQCZF.css +186 -0
  113. package/dist/Stepper/Stepper.d.ts +78 -0
  114. package/dist/Stepper/index.d.ts +3 -0
  115. package/dist/Stepper/index.js +4 -0
  116. package/dist/Stepper-HW4JM3YH.css +176 -0
  117. package/dist/Tabs/index.js +1 -1
  118. package/dist/{Tabs-MJ2E3VPK.css → Tabs-XCNPHA7B.css} +46 -26
  119. package/dist/Tag/Tag.d.ts +29 -22
  120. package/dist/Tag/index.js +2 -2
  121. package/dist/{Tag-VNZEYLB6.css → Tag-GBE7LQJP.css} +82 -83
  122. package/dist/TagsInput/index.js +7 -7
  123. package/dist/ThemeSwitcher/ThemeSwitcher.d.ts +53 -21
  124. package/dist/ThemeSwitcher/index.d.ts +3 -3
  125. package/dist/ThemeSwitcher/index.js +4 -3
  126. package/dist/ThemeSwitcher/preferences.d.ts +19 -5
  127. package/dist/ThemeToggle/ThemeToggle.d.ts +40 -0
  128. package/dist/ThemeToggle/index.d.ts +2 -0
  129. package/dist/ThemeToggle/index.js +5 -0
  130. package/dist/TimeWindowPicker/index.js +8 -8
  131. package/dist/Toaster/index.js +2 -2
  132. package/dist/Toolbar/index.js +2 -2
  133. package/dist/{Toolbar-IP6LXN45.css → Toolbar-HUOSMNTH.css} +3 -1
  134. package/dist/Tooltip/index.js +2 -2
  135. package/dist/Tree/index.d.ts +2 -2
  136. package/dist/Tree/index.js +1 -1
  137. package/dist/Tree/layout.d.ts +103 -28
  138. package/dist/TreeCanvas/TreeCanvas.d.ts +60 -14
  139. package/dist/TreeCanvas/index.d.ts +1 -1
  140. package/dist/TreeCanvas/index.js +6 -6
  141. package/dist/TreeCanvas/motion.d.ts +3 -2
  142. package/dist/{TreeCanvas-WBNQPHC7.css → TreeCanvas-HVOV4SQN.css} +154 -30
  143. package/dist/TreeGrid/index.js +4 -4
  144. package/dist/{chunk-F6OE5FH3.js → chunk-2FPENTCF.js} +1 -1
  145. package/dist/chunk-4AK52VHB.js +88 -0
  146. package/dist/{chunk-7EM5T4ME.js → chunk-4IQD3HUQ.js} +2 -2
  147. package/dist/{chunk-YODNNSZL.js → chunk-4PZ6FJKW.js} +43 -13
  148. package/dist/{chunk-F27EPQ7D.js → chunk-4UQ7SMPK.js} +1 -1
  149. package/dist/chunk-5QWIJSQM.js +73 -0
  150. package/dist/{chunk-KIC7BZYJ.js → chunk-6MU7HNB4.js} +6 -5
  151. package/dist/{chunk-S2XHHEW4.js → chunk-74KMX7YH.js} +4 -4
  152. package/dist/{chunk-WNI2WSJF.js → chunk-7KBNFFM3.js} +1 -1
  153. package/dist/{chunk-EFSG7HNU.js → chunk-AUS5FNQE.js} +1 -1
  154. package/dist/{chunk-CMEE37QJ.js → chunk-BMYPGGPV.js} +4 -4
  155. package/dist/{chunk-H4FBTAYS.js → chunk-BNCCEER3.js} +8 -8
  156. package/dist/chunk-C5WJUZVR.js +56 -0
  157. package/dist/{chunk-5WS6L6FA.js → chunk-CAIHUYXV.js} +9 -9
  158. package/dist/{chunk-5KSRXHOW.js → chunk-CQY5NTRS.js} +1 -1
  159. package/dist/{chunk-MW356IVK.js → chunk-D6EVJUGU.js} +2 -2
  160. package/dist/{chunk-7PEFUMQJ.js → chunk-DHPUMOTX.js} +2 -2
  161. package/dist/{chunk-HZ5XZNPS.js → chunk-DS2C73RJ.js} +3 -3
  162. package/dist/{chunk-GKHAKGOF.js → chunk-DSUY5F4E.js} +3 -3
  163. package/dist/{chunk-Q4ZPPART.js → chunk-EFYPAJT3.js} +3 -3
  164. package/dist/{chunk-PATXSJGR.js → chunk-ERVO6OUF.js} +17 -17
  165. package/dist/{chunk-BZYDZBAN.js → chunk-ETYEBKR4.js} +3 -3
  166. package/dist/{chunk-CC67MUUO.js → chunk-FD5UEN6X.js} +30 -30
  167. package/dist/{chunk-5SDBMKUO.js → chunk-FIFNP6PL.js} +3 -3
  168. package/dist/{chunk-7HPRF5XN.js → chunk-FUF52K7E.js} +98 -16
  169. package/dist/{chunk-5KPQ6D7N.js → chunk-FZVJDJFN.js} +2 -2
  170. package/dist/chunk-IA232OTU.js +156 -0
  171. package/dist/{chunk-2EOKFKHX.js → chunk-IG27QX7Q.js} +7 -7
  172. package/dist/chunk-IKB6HFGK.js +55 -0
  173. package/dist/{chunk-T43A26SD.js → chunk-IPVQKAHO.js} +6 -6
  174. package/dist/{chunk-3EYF6HKB.js → chunk-IVFJD7WY.js} +28 -9
  175. package/dist/{chunk-XJWXPRSK.js → chunk-JGRNTBF2.js} +11 -11
  176. package/dist/chunk-K3OWD7BJ.js +121 -0
  177. package/dist/{chunk-6KCO2D5C.js → chunk-KD4H66L6.js} +7 -20
  178. package/dist/{chunk-SFZOKW2G.js → chunk-KJ34ZBBI.js} +8 -3
  179. package/dist/{chunk-AQTBF4EB.js → chunk-LFHCXZO5.js} +5 -5
  180. package/dist/{chunk-LWKJQTOM.js → chunk-MICH6QSJ.js} +1 -1
  181. package/dist/chunk-N3DPO6HG.js +226 -0
  182. package/dist/{chunk-S4GZWSKR.js → chunk-OM5E3TTK.js} +1 -1
  183. package/dist/{chunk-3QRYCPXQ.js → chunk-OPKIKM35.js} +6 -6
  184. package/dist/{chunk-5EKIWVOR.js → chunk-PGRPNDWM.js} +2 -2
  185. package/dist/{chunk-FSOW3ARP.js → chunk-PQNILU27.js} +9 -9
  186. package/dist/{chunk-QNCVHRZL.js → chunk-QVAFL2LE.js} +1 -1
  187. package/dist/{chunk-Q3B66TJM.js → chunk-QY7UU5ZB.js} +1 -1
  188. package/dist/{chunk-ITHXJHBB.js → chunk-R25RGPUB.js} +1 -0
  189. package/dist/{chunk-KLJCCMF3.js → chunk-R6735B37.js} +2 -2
  190. package/dist/{chunk-3ZP55QZE.js → chunk-R6FBDTP3.js} +4 -4
  191. package/dist/{chunk-7FZ53WDJ.js → chunk-RIAZM6L3.js} +1 -1
  192. package/dist/chunk-RJM4QCGG.js +550 -0
  193. package/dist/{chunk-NTRZGNEX.js → chunk-S3BCVWTU.js} +215 -46
  194. package/dist/chunk-S7KW47IQ.js +121 -0
  195. package/dist/{chunk-KNYYCWMK.js → chunk-SJQ546ID.js} +4 -4
  196. package/dist/{chunk-D35VTV2Z.js → chunk-SV7QAONL.js} +1 -1
  197. package/dist/{chunk-IAJLHVUA.js → chunk-TIWAHZZ6.js} +1 -1
  198. package/dist/{chunk-2PRH365R.js → chunk-UA7O3KKJ.js} +1 -1
  199. package/dist/{chunk-NPZY6YYL.js → chunk-UG5ZMAXW.js} +6 -6
  200. package/dist/{chunk-NDCATSW7.js → chunk-V34H2YCY.js} +1 -1
  201. package/dist/chunk-WIATRXEJ.js +22 -0
  202. package/dist/{chunk-5C5YMZQU.js → chunk-WOFOMTGB.js} +16 -10
  203. package/dist/{chunk-QYOFACSP.js → chunk-WSOFKOLP.js} +3 -3
  204. package/dist/{chunk-MNAXYY3R.js → chunk-WUVZDFHS.js} +31 -11
  205. package/dist/{chunk-DB2VDLVR.js → chunk-YIMOT5OO.js} +10 -10
  206. package/dist/{chunk-2ZQMA2WB.js → chunk-ZPSOF6VL.js} +2 -2
  207. package/dist/generated/index.d.ts +3 -0
  208. package/dist/generated/index.js +70 -66
  209. package/dist/index.js +70 -66
  210. package/dist/styles.css +2538 -741
  211. package/dist/utils/index.d.ts +1 -1
  212. package/dist/utils/tone.d.ts +7 -12
  213. package/package.json +4 -4
  214. package/scripts/check-css-literals.mjs +159 -23
  215. package/scripts/check-css-variables.mjs +5 -3
  216. package/scripts/css-source.mjs +97 -5
  217. package/dist/Avatar-P2KRQM2B.css +0 -156
  218. package/dist/Charts-D7G2BSXH.css +0 -277
  219. package/dist/CommandPalette-CSJDUCQA.css +0 -115
  220. package/dist/Kbd-W66MXQI5.css +0 -61
  221. package/dist/SearchTrigger-QXOYAUUY.css +0 -79
  222. package/dist/SidebarNav-QGSFKZYA.css +0 -319
  223. package/dist/StatCard-KYPKZUWX.css +0 -111
  224. package/dist/StatusDot-HA2L2FSX.css +0 -84
  225. package/dist/chunk-22O7LAW2.js +0 -41
  226. package/dist/chunk-AJNCATWZ.js +0 -144
  227. package/dist/chunk-F4PJZ4ED.js +0 -245
  228. package/dist/chunk-PNFASD6F.js +0 -98
  229. package/dist/chunk-PZSWF74H.js +0 -15
  230. package/dist/chunk-R66KLW7S.js +0 -143
  231. /package/dist/{chunk-ZCR6YGQ4.js → chunk-PKIN4IMB.js} +0 -0
@@ -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
+ }
@@ -13,15 +13,54 @@ import type { HTMLAttributes, ReactNode } from 'react';
13
13
  * number is never that.
14
14
  */
15
15
  export type StatCardTone = 'neutral' | 'success' | 'warning' | 'danger' | 'info';
16
+ /**
17
+ * Whether a change is the one the reader wanted.
18
+ *
19
+ * NOT the direction. The sign in the value already says which way the number
20
+ * moved, and whether up is good is a property of what is counted rather than
21
+ * of the arithmetic: twelve percent more work completed is good news and
22
+ * twelve percent more tokens spent may not be. So the caller, who knows what
23
+ * the tile counts, says which it is, and `neutral` is a change that is neither
24
+ * (four more tasks in progress is not a verdict, it is a fact).
25
+ */
26
+ export type StatCardDeltaPolarity = 'good' | 'bad' | 'neutral';
27
+ /** A change against an earlier reading, drawn at the head of the second line. */
28
+ export interface StatCardDelta {
29
+ /** The change, already formatted by the caller and carrying its own sign: "+12%", "−3", "+4". */
30
+ value: ReactNode;
31
+ /** Whether it is the change the reader wanted. See the type. */
32
+ polarity: StatCardDeltaPolarity;
33
+ }
16
34
  export interface StatCardProps extends HTMLAttributes<HTMLDivElement> {
17
- /** What is being counted, for example "Total tokens". */
35
+ /** What is being counted, in sentence case: "Tasks in progress". */
18
36
  label: ReactNode;
19
37
  /** The headline value, already formatted by the caller. */
20
38
  value: ReactNode;
21
- /** A unit after the value, at a quieter weight: "ms", "/ 20K", "per turn". */
39
+ /** A unit after the value, at a quieter weight: "ms", "/ 7", "per turn". */
22
40
  unit?: ReactNode;
23
- /** A second line under the label: "3 working, 4 idle". Its line is reserved either way. */
41
+ /** The second line: "vs last week · 2 blocked". Its line is reserved either way. */
24
42
  sub?: ReactNode;
43
+ /**
44
+ * The STATE the second line reports, when it reports one: "Oldest waiting
45
+ * 2h 10m" is a person being kept waiting, so it is `warning`. Paints the
46
+ * line in that tone's ink, the step measured as text on every rung. The
47
+ * same rule as `tone`: most second lines are a fact, not a state, and stay
48
+ * in the quiet ink. A `delta` keeps the ink of its own polarity.
49
+ */
50
+ subTone?: StatCardTone;
51
+ /**
52
+ * A change against an earlier reading, drawn first on the second line in
53
+ * the ink of its polarity, with `sub` after it: "+12% vs previous 7 days".
54
+ */
55
+ delta?: StatCardDelta | undefined;
56
+ /**
57
+ * A small figure at the end of the value's line, such as a `Sparkline`, a
58
+ * `Meter` or a `SegmentedMeter`, or a small control that acts on the
59
+ * number. A figure fills the slot's width and a control keeps its own. The
60
+ * slot is `--crewlet-statcard-trend-width` wide, 96px unless a stylesheet
61
+ * says otherwise.
62
+ */
63
+ trend?: ReactNode;
25
64
  /** A glyph before the label. A component, not a name. */
26
65
  icon?: ReactNode;
27
66
  /** Colours the VALUE's ink. See the type for when that is right. */
@@ -39,18 +78,26 @@ export interface StatCardProps extends HTMLAttributes<HTMLDivElement> {
39
78
  /**
40
79
  * One number, with what it counts.
41
80
  *
42
- * THE LABEL SITS ABOVE THE VALUE, in the micro-caps register, which is the
43
- * engine's order and the one a board is actually read in: the labels are what
44
- * a reader scans to find the tile they want, and the number is the answer
45
- * underneath it. It is also the order a screen reader reads correctly, "live
46
- * nodes, four, holding an unexpired lease" rather than "four, live nodes".
47
- * The numbers still sit on one line across the row, because the label register
48
- * is one line at every tile and the value box is a fixed step.
81
+ * THE LABEL SITS ABOVE THE VALUE, in sentence case at the caption step, which
82
+ * is the approved design's tile and the order a board is actually read in:
83
+ * the labels are what a reader scans to find the tile they want, and the
84
+ * number is the answer underneath it. It is also the order a screen reader
85
+ * reads correctly, "tasks in progress, 18, +4 vs last week" rather than "18,
86
+ * tasks in progress". The label is set as it is written: the uppercased,
87
+ * tracked-open register is a table's column head, and five of them over five
88
+ * numbers shouted a heading at every tile.
89
+ *
90
+ * THE VALUE IS THE SCREEN'S ONE DISPLAY NUMBER, at `--font-size-display` with
91
+ * tabular figures, so a number that ticks up moves nothing beside it. A
92
+ * figure showing where it has been going sits at the END of the same line
93
+ * (`trend`), and a change against an earlier reading heads the line under it
94
+ * (`delta`), in the ink of whether it was the change the reader wanted.
49
95
  *
50
96
  * WHILE IT IS LOADING IT SAYS SO. It used to draw a literal `--`, which a
51
97
  * screen reader reads aloud as "dash dash" and which looks exactly like a
52
98
  * measured value of nothing. A placeholder line plus `aria-busy` on the tile
53
99
  * says the number has not arrived, which is a different fact from the number
54
- * being zero.
100
+ * being zero. The trend and the delta wait with it: both are readings of the
101
+ * number that has not arrived.
55
102
  */
56
- export declare const StatCard: ({ label, value, unit, sub, icon, tone, loading, loadingLabel, flush, className, ...rest }: StatCardProps) => import("react").JSX.Element;
103
+ export declare const StatCard: ({ label, value, unit, sub, subTone, delta, trend, icon, tone, loading, loadingLabel, flush, className, ...rest }: StatCardProps) => import("react").JSX.Element;
@@ -1,3 +1,3 @@
1
1
  import './StatCard.css';
2
2
  export { StatCard } from './StatCard.js';
3
- export type { StatCardProps, StatCardTone } from './StatCard.js';
3
+ export type { StatCardDelta, StatCardDeltaPolarity, StatCardProps, StatCardTone } from './StatCard.js';
@@ -1,3 +1,3 @@
1
- export { StatCard } from '../chunk-22O7LAW2.js';
1
+ export { StatCard } from '../chunk-IKB6HFGK.js';
2
2
  import '../chunk-BZFWDIV6.js';
3
3
  import '../chunk-ODEQTPFM.js';