@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.
- package/README.md +888 -24
- package/dist/Accordion/index.js +2 -2
- package/dist/AddPill/index.js +1 -1
- package/dist/{AddPill-DFWXYLIQ.css → AddPill-IJQYCY6C.css} +9 -0
- package/dist/AppShell/AppShell.d.ts +26 -5
- package/dist/AppShell/index.js +3 -3
- package/dist/{AppShell-NVE6LHNI.css → AppShell-XARELGIH.css} +178 -25
- package/dist/Avatar/Avatar.d.ts +85 -40
- package/dist/Avatar/AvatarStack.d.ts +76 -0
- package/dist/Avatar/index.d.ts +5 -2
- package/dist/Avatar/index.js +1 -1
- package/dist/Avatar-XID7Z74C.css +200 -0
- package/dist/AvatarStack-GEJBNV7E.css +72 -0
- package/dist/BrandLockup/index.js +1 -1
- package/dist/{BrandLockup-6ISDEHPJ.css → BrandLockup-JKGXFCZF.css} +25 -19
- package/dist/Button/Button.d.ts +7 -2
- package/dist/Button/index.js +1 -1
- package/dist/{Button-D4J6B4MA.css → Button-X4B2TJAQ.css} +50 -19
- package/dist/Callout/index.js +1 -1
- package/dist/Canvas/index.js +4 -4
- package/dist/Card/Card.d.ts +9 -5
- package/dist/Card/index.js +1 -1
- package/dist/{Card-RLR254LD.css → Card-GLP7SUV6.css} +25 -18
- package/dist/Charts/BarList.d.ts +18 -1
- package/dist/Charts/ChartTooltip.d.ts +68 -0
- package/dist/Charts/StackedBar.d.ts +25 -7
- package/dist/Charts/StackedColumns.d.ts +112 -0
- package/dist/Charts/TimeSeries.d.ts +33 -2
- package/dist/Charts/dataColor.d.ts +22 -14
- package/dist/Charts/index.d.ts +6 -0
- package/dist/Charts/index.js +1 -1
- package/dist/Charts/useChartHover.d.ts +56 -0
- package/dist/Charts-B3YEF7R4.css +742 -0
- package/dist/Checkbox/index.js +1 -1
- package/dist/{Checkbox-VGW26YLQ.css → Checkbox-BOXQ747I.css} +2 -2
- package/dist/CodeBlock/index.js +4 -4
- package/dist/Combobox/index.js +5 -5
- package/dist/CommandPalette/CommandPalette.d.ts +97 -6
- package/dist/CommandPalette/index.d.ts +1 -1
- package/dist/CommandPalette/index.js +9 -7
- package/dist/CommandPalette-C5AMKGN2.css +259 -0
- package/dist/Copyable/index.js +3 -3
- package/dist/DataTable/index.js +7 -7
- package/dist/{DataTable-37UWTRN6.css → DataTable-OLHPF7D4.css} +35 -38
- package/dist/DataView/index.js +16 -16
- package/dist/{DataView-256YF32J.css → DataView-N6JX464S.css} +5 -4
- package/dist/DateTimePicker/index.js +5 -5
- package/dist/DiffList/index.js +1 -1
- package/dist/Disclosure/index.js +2 -2
- package/dist/EntityChip/EntityChip.d.ts +9 -12
- package/dist/EntityChip/index.d.ts +1 -1
- package/dist/EntityChip/index.js +2 -2
- package/dist/ErrorBoundary/index.js +2 -2
- package/dist/{ErrorBoundary-ME36CQTA.css → ErrorBoundary-U2PA3LY2.css} +4 -4
- package/dist/IconButton/index.js +1 -1
- package/dist/{IconButton-VQGNMJDI.css → IconButton-TVEUWK6L.css} +2 -2
- package/dist/ImageUpload/ImageUpload.d.ts +10 -7
- package/dist/ImageUpload/index.js +2 -2
- package/dist/{ImageUpload-HKFIZR6D.css → ImageUpload-YCHJMUGX.css} +24 -10
- package/dist/Input/index.js +2 -2
- package/dist/Kbd/Kbd.d.ts +14 -4
- package/dist/Kbd/index.js +1 -1
- package/dist/Kbd-JPLDVJIP.css +71 -0
- package/dist/Layer/index.js +1 -1
- package/dist/Link/index.js +1 -1
- package/dist/List/index.js +1 -1
- package/dist/{List-XTHESXLR.css → List-MYJIV6MP.css} +12 -2
- package/dist/ListInput/index.js +6 -6
- package/dist/Listbox/index.js +2 -2
- package/dist/Listbox/useListbox.d.ts +2 -0
- package/dist/{Listbox-ZXYYNN6U.css → Listbox-6WJNJQVQ.css} +32 -7
- package/dist/Menu/index.js +4 -4
- package/dist/Meter/Meter.d.ts +103 -16
- package/dist/Meter/index.d.ts +2 -2
- package/dist/Meter/index.js +1 -1
- package/dist/{Meter-SKOOXQBC.css → Meter-5VCSFMZW.css} +46 -7
- package/dist/Modal/index.js +4 -4
- package/dist/{Modal-XYQJ4BL6.css → Modal-JAYBS2KS.css} +13 -4
- package/dist/OrgLabel/OrgLabel.d.ts +60 -24
- package/dist/OrgLabel/index.d.ts +1 -1
- package/dist/OrgLabel/index.js +2 -1
- package/dist/{OrgLabel-D7U6QJZD.css → OrgLabel-CR233G34.css} +9 -18
- package/dist/OrgNode/index.js +3 -2
- package/dist/OrgTable/OrgTable.d.ts +2 -2
- package/dist/OrgTable/index.js +8 -7
- package/dist/Popover/index.js +2 -2
- package/dist/PricingCard/index.js +3 -3
- package/dist/{PricingCard-JFI7RYXP.css → PricingCard-7EFXRSD2.css} +4 -5
- package/dist/SearchTrigger/SearchTrigger.d.ts +23 -4
- package/dist/SearchTrigger/index.d.ts +1 -1
- package/dist/SearchTrigger/index.js +1 -1
- package/dist/SearchTrigger-Z5D4AAY7.css +112 -0
- package/dist/SegmentedControl/index.js +2 -2
- package/dist/SegmentedMeter/SegmentedMeter.d.ts +107 -0
- package/dist/SegmentedMeter/index.d.ts +3 -0
- package/dist/SegmentedMeter/index.js +2 -0
- package/dist/SegmentedMeter-KQNML2TW.css +109 -0
- package/dist/Select/index.js +3 -3
- package/dist/Shortcut/index.js +2 -2
- package/dist/SidebarNav/SidebarNav.d.ts +85 -25
- package/dist/SidebarNav/index.d.ts +1 -1
- package/dist/SidebarNav/index.js +1 -1
- package/dist/SidebarNav-X5NLZNWA.css +424 -0
- package/dist/StatCard/StatCard.d.ts +59 -12
- package/dist/StatCard/index.d.ts +1 -1
- package/dist/StatCard/index.js +1 -1
- package/dist/StatCard-KPAFD4E2.css +204 -0
- package/dist/StatGroup/index.js +1 -1
- package/dist/{StatGroup-TGB6AEKM.css → StatGroup-HVG6O62W.css} +8 -9
- package/dist/StatusDot/StatusDot.d.ts +24 -6
- package/dist/StatusDot/index.js +1 -1
- package/dist/StatusDot-7OMCQCZF.css +186 -0
- package/dist/Stepper/Stepper.d.ts +78 -0
- package/dist/Stepper/index.d.ts +3 -0
- package/dist/Stepper/index.js +4 -0
- package/dist/Stepper-HW4JM3YH.css +176 -0
- package/dist/Tabs/index.js +1 -1
- package/dist/{Tabs-MJ2E3VPK.css → Tabs-XCNPHA7B.css} +46 -26
- package/dist/Tag/Tag.d.ts +29 -22
- package/dist/Tag/index.js +2 -2
- package/dist/{Tag-VNZEYLB6.css → Tag-GBE7LQJP.css} +82 -83
- package/dist/TagsInput/index.js +7 -7
- package/dist/ThemeSwitcher/ThemeSwitcher.d.ts +53 -21
- package/dist/ThemeSwitcher/index.d.ts +3 -3
- package/dist/ThemeSwitcher/index.js +4 -3
- package/dist/ThemeSwitcher/preferences.d.ts +19 -5
- package/dist/ThemeToggle/ThemeToggle.d.ts +40 -0
- package/dist/ThemeToggle/index.d.ts +2 -0
- package/dist/ThemeToggle/index.js +5 -0
- package/dist/TimeWindowPicker/index.js +8 -8
- package/dist/Toaster/index.js +2 -2
- package/dist/Toolbar/index.js +2 -2
- package/dist/{Toolbar-IP6LXN45.css → Toolbar-HUOSMNTH.css} +3 -1
- package/dist/Tooltip/index.js +2 -2
- package/dist/Tree/index.d.ts +2 -2
- package/dist/Tree/index.js +1 -1
- package/dist/Tree/layout.d.ts +103 -28
- package/dist/TreeCanvas/TreeCanvas.d.ts +60 -14
- package/dist/TreeCanvas/index.d.ts +1 -1
- package/dist/TreeCanvas/index.js +6 -6
- package/dist/TreeCanvas/motion.d.ts +3 -2
- package/dist/{TreeCanvas-WBNQPHC7.css → TreeCanvas-HVOV4SQN.css} +154 -30
- package/dist/TreeGrid/index.js +4 -4
- package/dist/{chunk-F6OE5FH3.js → chunk-2FPENTCF.js} +1 -1
- package/dist/chunk-4AK52VHB.js +88 -0
- package/dist/{chunk-7EM5T4ME.js → chunk-4IQD3HUQ.js} +2 -2
- package/dist/{chunk-YODNNSZL.js → chunk-4PZ6FJKW.js} +43 -13
- package/dist/{chunk-F27EPQ7D.js → chunk-4UQ7SMPK.js} +1 -1
- package/dist/chunk-5QWIJSQM.js +73 -0
- package/dist/{chunk-KIC7BZYJ.js → chunk-6MU7HNB4.js} +6 -5
- package/dist/{chunk-S2XHHEW4.js → chunk-74KMX7YH.js} +4 -4
- package/dist/{chunk-WNI2WSJF.js → chunk-7KBNFFM3.js} +1 -1
- package/dist/{chunk-EFSG7HNU.js → chunk-AUS5FNQE.js} +1 -1
- package/dist/{chunk-CMEE37QJ.js → chunk-BMYPGGPV.js} +4 -4
- package/dist/{chunk-H4FBTAYS.js → chunk-BNCCEER3.js} +8 -8
- package/dist/chunk-C5WJUZVR.js +56 -0
- package/dist/{chunk-5WS6L6FA.js → chunk-CAIHUYXV.js} +9 -9
- package/dist/{chunk-5KSRXHOW.js → chunk-CQY5NTRS.js} +1 -1
- package/dist/{chunk-MW356IVK.js → chunk-D6EVJUGU.js} +2 -2
- package/dist/{chunk-7PEFUMQJ.js → chunk-DHPUMOTX.js} +2 -2
- package/dist/{chunk-HZ5XZNPS.js → chunk-DS2C73RJ.js} +3 -3
- package/dist/{chunk-GKHAKGOF.js → chunk-DSUY5F4E.js} +3 -3
- package/dist/{chunk-Q4ZPPART.js → chunk-EFYPAJT3.js} +3 -3
- package/dist/{chunk-PATXSJGR.js → chunk-ERVO6OUF.js} +17 -17
- package/dist/{chunk-BZYDZBAN.js → chunk-ETYEBKR4.js} +3 -3
- package/dist/{chunk-CC67MUUO.js → chunk-FD5UEN6X.js} +30 -30
- package/dist/{chunk-5SDBMKUO.js → chunk-FIFNP6PL.js} +3 -3
- package/dist/{chunk-7HPRF5XN.js → chunk-FUF52K7E.js} +98 -16
- package/dist/{chunk-5KPQ6D7N.js → chunk-FZVJDJFN.js} +2 -2
- package/dist/chunk-IA232OTU.js +156 -0
- package/dist/{chunk-2EOKFKHX.js → chunk-IG27QX7Q.js} +7 -7
- package/dist/chunk-IKB6HFGK.js +55 -0
- package/dist/{chunk-T43A26SD.js → chunk-IPVQKAHO.js} +6 -6
- package/dist/{chunk-3EYF6HKB.js → chunk-IVFJD7WY.js} +28 -9
- package/dist/{chunk-XJWXPRSK.js → chunk-JGRNTBF2.js} +11 -11
- package/dist/chunk-K3OWD7BJ.js +121 -0
- package/dist/{chunk-6KCO2D5C.js → chunk-KD4H66L6.js} +7 -20
- package/dist/{chunk-SFZOKW2G.js → chunk-KJ34ZBBI.js} +8 -3
- package/dist/{chunk-AQTBF4EB.js → chunk-LFHCXZO5.js} +5 -5
- package/dist/{chunk-LWKJQTOM.js → chunk-MICH6QSJ.js} +1 -1
- package/dist/chunk-N3DPO6HG.js +226 -0
- package/dist/{chunk-S4GZWSKR.js → chunk-OM5E3TTK.js} +1 -1
- package/dist/{chunk-3QRYCPXQ.js → chunk-OPKIKM35.js} +6 -6
- package/dist/{chunk-5EKIWVOR.js → chunk-PGRPNDWM.js} +2 -2
- package/dist/{chunk-FSOW3ARP.js → chunk-PQNILU27.js} +9 -9
- package/dist/{chunk-QNCVHRZL.js → chunk-QVAFL2LE.js} +1 -1
- package/dist/{chunk-Q3B66TJM.js → chunk-QY7UU5ZB.js} +1 -1
- package/dist/{chunk-ITHXJHBB.js → chunk-R25RGPUB.js} +1 -0
- package/dist/{chunk-KLJCCMF3.js → chunk-R6735B37.js} +2 -2
- package/dist/{chunk-3ZP55QZE.js → chunk-R6FBDTP3.js} +4 -4
- package/dist/{chunk-7FZ53WDJ.js → chunk-RIAZM6L3.js} +1 -1
- package/dist/chunk-RJM4QCGG.js +550 -0
- package/dist/{chunk-NTRZGNEX.js → chunk-S3BCVWTU.js} +215 -46
- package/dist/chunk-S7KW47IQ.js +121 -0
- package/dist/{chunk-KNYYCWMK.js → chunk-SJQ546ID.js} +4 -4
- package/dist/{chunk-D35VTV2Z.js → chunk-SV7QAONL.js} +1 -1
- package/dist/{chunk-IAJLHVUA.js → chunk-TIWAHZZ6.js} +1 -1
- package/dist/{chunk-2PRH365R.js → chunk-UA7O3KKJ.js} +1 -1
- package/dist/{chunk-NPZY6YYL.js → chunk-UG5ZMAXW.js} +6 -6
- package/dist/{chunk-NDCATSW7.js → chunk-V34H2YCY.js} +1 -1
- package/dist/chunk-WIATRXEJ.js +22 -0
- package/dist/{chunk-5C5YMZQU.js → chunk-WOFOMTGB.js} +16 -10
- package/dist/{chunk-QYOFACSP.js → chunk-WSOFKOLP.js} +3 -3
- package/dist/{chunk-MNAXYY3R.js → chunk-WUVZDFHS.js} +31 -11
- package/dist/{chunk-DB2VDLVR.js → chunk-YIMOT5OO.js} +10 -10
- package/dist/{chunk-2ZQMA2WB.js → chunk-ZPSOF6VL.js} +2 -2
- package/dist/generated/index.d.ts +3 -0
- package/dist/generated/index.js +70 -66
- package/dist/index.js +70 -66
- package/dist/styles.css +2538 -741
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/tone.d.ts +7 -12
- package/package.json +4 -4
- package/scripts/check-css-literals.mjs +159 -23
- package/scripts/check-css-variables.mjs +5 -3
- package/scripts/css-source.mjs +97 -5
- package/dist/Avatar-P2KRQM2B.css +0 -156
- package/dist/Charts-D7G2BSXH.css +0 -277
- package/dist/CommandPalette-CSJDUCQA.css +0 -115
- package/dist/Kbd-W66MXQI5.css +0 -61
- package/dist/SearchTrigger-QXOYAUUY.css +0 -79
- package/dist/SidebarNav-QGSFKZYA.css +0 -319
- package/dist/StatCard-KYPKZUWX.css +0 -111
- package/dist/StatusDot-HA2L2FSX.css +0 -84
- package/dist/chunk-22O7LAW2.js +0 -41
- package/dist/chunk-AJNCATWZ.js +0 -144
- package/dist/chunk-F4PJZ4ED.js +0 -245
- package/dist/chunk-PNFASD6F.js +0 -98
- package/dist/chunk-PZSWF74H.js +0 -15
- package/dist/chunk-R66KLW7S.js +0 -143
- /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,
|
|
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", "/
|
|
39
|
+
/** A unit after the value, at a quieter weight: "ms", "/ 7", "per turn". */
|
|
22
40
|
unit?: ReactNode;
|
|
23
|
-
/**
|
|
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
|
|
43
|
-
*
|
|
44
|
-
* a reader scans to find the tile they want, and the
|
|
45
|
-
* underneath it. It is also the order a screen reader
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* is
|
|
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;
|
package/dist/StatCard/index.d.ts
CHANGED
package/dist/StatCard/index.js
CHANGED