@ciridae/ui 1.0.3 → 1.0.4
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/dist/chat/conversation-source.d.ts +15 -1
- package/dist/chat/describe-tool-call.d.ts +3 -3
- package/dist/chat/describe-tool-call.js +3 -3
- package/dist/chat/message-text.js +2 -2
- package/dist/ciridae.css +16 -4
- package/dist/components/activity-feed.d.ts +1 -0
- package/dist/components/activity-feed.js +1 -0
- package/dist/components/app-frame.d.ts +13 -1
- package/dist/components/app-frame.js +45 -3
- package/dist/components/app-navigation.d.ts +28 -1
- package/dist/components/app-navigation.js +105 -14
- package/dist/components/badge.d.ts +29 -4
- package/dist/components/badge.js +134 -15
- package/dist/components/bulk-action-bar.js +3 -3
- package/dist/components/button.d.ts +10 -3
- package/dist/components/button.js +77 -44
- package/dist/components/calendar.js +44 -17
- package/dist/components/centered-page.js +2 -2
- package/dist/components/chart.d.ts +1 -1
- package/dist/components/chart.js +16 -11
- package/dist/components/chat-client-source.js +47 -6
- package/dist/components/chat-sheet-controller.d.ts +1 -0
- package/dist/components/chat-sheet-controller.js +1 -0
- package/dist/components/chat-sheet.d.ts +10 -2
- package/dist/components/chat-sheet.js +76 -39
- package/dist/components/chat.d.ts +90 -14
- package/dist/components/chat.js +402 -101
- package/dist/components/checkbox-item.d.ts +5 -2
- package/dist/components/checkbox-item.js +9 -5
- package/dist/components/chip.d.ts +5 -0
- package/dist/components/chip.js +27 -1
- package/dist/components/column-settings.js +1 -1
- package/dist/components/command-menu.d.ts +5 -1
- package/dist/components/command-menu.js +98 -32
- package/dist/components/command-palette.d.ts +6 -2
- package/dist/components/command-palette.js +20 -10
- package/dist/components/data-display.d.ts +35 -4
- package/dist/components/data-display.js +138 -19
- package/dist/components/data-grid.d.ts +14 -2
- package/dist/components/data-grid.js +61 -26
- package/dist/components/date-range-picker.js +9 -20
- package/dist/components/drawer.d.ts +5 -0
- package/dist/components/drawer.js +91 -54
- package/dist/components/editable-field.d.ts +12 -3
- package/dist/components/editable-field.js +57 -27
- package/dist/components/email-input.js +6 -5
- package/dist/components/environment-frame.d.ts +1 -1
- package/dist/components/environment-frame.js +37 -6
- package/dist/components/filter-bar.js +39 -28
- package/dist/components/form-controls.d.ts +9 -0
- package/dist/components/form-controls.js +46 -22
- package/dist/components/form-layout.d.ts +7 -3
- package/dist/components/form-layout.js +68 -23
- package/dist/components/glass-menu.d.ts +3 -0
- package/dist/components/glass-menu.js +63 -0
- package/dist/components/gradient-edge.d.ts +9 -0
- package/dist/components/gradient-edge.js +31 -0
- package/dist/components/input.d.ts +4 -2
- package/dist/components/input.js +26 -15
- package/dist/components/keycap.d.ts +9 -5
- package/dist/components/keycap.js +57 -19
- package/dist/components/lightbox.js +2 -1
- package/dist/components/locale.d.ts +10 -0
- package/dist/components/locale.js +18 -2
- package/dist/components/log-entry.d.ts +40 -0
- package/dist/components/log-entry.js +146 -0
- package/dist/components/mention-input.js +4 -3
- package/dist/components/menu.d.ts +6 -2
- package/dist/components/menu.js +34 -37
- package/dist/components/meter.d.ts +9 -1
- package/dist/components/meter.js +64 -6
- package/dist/components/navigation.d.ts +21 -4
- package/dist/components/navigation.js +84 -19
- package/dist/components/notification-tray.js +5 -4
- package/dist/components/overlays.d.ts +3 -1
- package/dist/components/overlays.js +69 -40
- package/dist/components/page-frame.js +1 -1
- package/dist/components/panel.d.ts +1 -1
- package/dist/components/panel.js +18 -12
- package/dist/components/radio-card.js +10 -9
- package/dist/components/record.d.ts +25 -1
- package/dist/components/record.js +147 -18
- package/dist/components/segmented-bar.d.ts +3 -1
- package/dist/components/segmented-bar.js +16 -6
- package/dist/components/select.d.ts +5 -2
- package/dist/components/select.js +103 -127
- package/dist/components/shell-skeleton.js +1 -1
- package/dist/components/shell.d.ts +2 -2
- package/dist/components/shell.js +43 -45
- package/dist/components/sidebar.d.ts +7 -2
- package/dist/components/sidebar.js +55 -27
- package/dist/components/single-line-text.d.ts +2 -0
- package/dist/components/single-line-text.js +16 -0
- package/dist/components/site-banner.d.ts +5 -2
- package/dist/components/site-banner.js +17 -6
- package/dist/components/skeleton.d.ts +7 -6
- package/dist/components/skeleton.js +28 -16
- package/dist/components/skeletons.d.ts +12 -0
- package/dist/components/skeletons.js +71 -8
- package/dist/components/stages.d.ts +78 -6
- package/dist/components/stages.js +512 -156
- package/dist/components/stat-card.d.ts +10 -2
- package/dist/components/stat-card.js +92 -37
- package/dist/components/status-banner.js +1 -1
- package/dist/components/tabs.js +26 -13
- package/dist/components/theme-toggle.d.ts +4 -0
- package/dist/components/theme-toggle.js +67 -0
- package/dist/components/toast.d.ts +9 -2
- package/dist/components/toast.js +78 -29
- package/dist/preset.js +289 -33
- package/dist/styled-system/styles.css +3115 -1044
- package/dist/styled-system/tokens/index.mjs +598 -22
- package/dist/styled-system/tokens/tokens.d.ts +11 -11
- package/dist/styled-system/types/prop-type.d.ts +2 -2
- package/dist/styles.css +16 -4
- package/dist/theme/color.d.ts +3 -0
- package/dist/theme/color.js +5 -0
- package/dist/theme/derive.d.ts +9 -2
- package/dist/theme/derive.js +72 -12
- package/dist/theme/palettes.d.ts +49 -6
- package/dist/theme/palettes.js +84 -15
- package/dist/theme/tokens.d.ts +3 -3
- package/dist/theme/tokens.js +107 -32
- package/package.json +9 -1
|
@@ -6,8 +6,9 @@ import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
|
|
|
6
6
|
import { XIcon } from "@phosphor-icons/react";
|
|
7
7
|
import { useCallback, useRef, useState, } from "react";
|
|
8
8
|
import { css, cx } from "#primitives/css";
|
|
9
|
-
import { Button, IconButton } from "./button.js";
|
|
9
|
+
import { Button, ButtonSizeContext, IconButton } from "./button.js";
|
|
10
10
|
import { DialogHeightResetContext } from "./dialog-height-context.js";
|
|
11
|
+
import { glassMenuSurface } from "./glass-menu.js";
|
|
11
12
|
import { HotkeyLayer } from "./hotkeys.js";
|
|
12
13
|
import { icon } from "./icon.js";
|
|
13
14
|
import { heading } from "./layout.js";
|
|
@@ -15,18 +16,11 @@ import { useCiridaeLocale } from "./locale.js";
|
|
|
15
16
|
/** A positioned popup carries its own stacking order; a positioner-anchored one gets it there. */
|
|
16
17
|
const positioner = css({ zIndex: "popover" });
|
|
17
18
|
const tooltipPositioner = css({ zIndex: "tooltip" });
|
|
18
|
-
|
|
19
|
+
// A popover is the menus' glass sheet, padded for a small form. A popup takes focus when it
|
|
20
|
+
// opens or when its focused content unmounts (a wizard changing step); the sheet draws no ring.
|
|
21
|
+
const popupStyle = css.raw(glassMenuSurface, {
|
|
19
22
|
maxWidth: "overlay.dialog",
|
|
20
23
|
padding: "panel.comfortable",
|
|
21
|
-
border: "1px solid token(colors.border.control)",
|
|
22
|
-
borderRadius: "inset",
|
|
23
|
-
backgroundColor: "bg.card",
|
|
24
|
-
color: "fg.primary",
|
|
25
|
-
textStyle: "body",
|
|
26
|
-
boxShadow: "card",
|
|
27
|
-
// A popup takes focus when it opens or when its focused content unmounts (a wizard changing
|
|
28
|
-
// step); it is a container, not a control, so it draws no ring.
|
|
29
|
-
outline: "none",
|
|
30
24
|
});
|
|
31
25
|
const popup = css(popupStyle);
|
|
32
26
|
// The title and footer stay put; a long body scrolls between them.
|
|
@@ -38,17 +32,27 @@ const dialogLayout = css.raw({
|
|
|
38
32
|
// A dialog's own inset, not the page margin, so page density changes leave it alone.
|
|
39
33
|
padding: "panel.comfortable",
|
|
40
34
|
});
|
|
41
|
-
|
|
35
|
+
/*
|
|
36
|
+
* A dialog is a glass shell, 4px round its sheet, holding the sheet itself. `--dialog-sheet` is
|
|
37
|
+
* the sheet's width; the shell adds its inset and edge. Dark blurs the shell and light the sheet.
|
|
38
|
+
*/
|
|
39
|
+
const dialogShell = css.raw({
|
|
40
|
+
"--dialog-sheet": "token(sizes.overlay.dialog)",
|
|
42
41
|
zIndex: "dialog",
|
|
43
42
|
position: "fixed",
|
|
44
43
|
top: "50%",
|
|
45
44
|
left: "50%",
|
|
45
|
+
display: "grid",
|
|
46
|
+
gridTemplateRows: "minmax(0, 1fr)",
|
|
46
47
|
width: "calc(100vw - token(spacing.layout.pageGap) * 2)",
|
|
48
|
+
maxWidth: "calc(var(--dialog-sheet) + 2 * (token(spacing.layout.tightGap) + token(sizes.border.hairline)))",
|
|
47
49
|
maxHeight: "calc(100dvh - token(spacing.layout.pageGap) * 2)",
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
padding: "layout.tightGap",
|
|
51
|
+
border: "1px solid token(colors.border.control)",
|
|
52
|
+
borderRadius: "shell",
|
|
53
|
+
background: "bg.modalShell",
|
|
54
|
+
backdropFilter: "blur(token(blurs.modalShell))",
|
|
55
|
+
outline: "none",
|
|
52
56
|
transform: "translate(-50%, -50%)",
|
|
53
57
|
transitionProperty: "opacity, transform",
|
|
54
58
|
transitionDuration: "fast",
|
|
@@ -58,6 +62,17 @@ const dialogPopup = css.raw(popupStyle, dialogLayout, {
|
|
|
58
62
|
transform: "translate(-50%, calc(-50% + token(spacing.control.block)))",
|
|
59
63
|
},
|
|
60
64
|
});
|
|
65
|
+
const dialogSheetStyle = css.raw(dialogLayout, {
|
|
66
|
+
minHeight: "0",
|
|
67
|
+
border: "1px solid token(colors.border.control)",
|
|
68
|
+
borderRadius: "inset",
|
|
69
|
+
background: "bg.modalSheet",
|
|
70
|
+
backdropFilter: "blur(token(blurs.modalSheet))",
|
|
71
|
+
boxShadow: "soft",
|
|
72
|
+
color: "fg.primary",
|
|
73
|
+
textStyle: "body",
|
|
74
|
+
});
|
|
75
|
+
const dialogSheet = css(dialogSheetStyle);
|
|
61
76
|
const visuallyHidden = css({ srOnly: true });
|
|
62
77
|
const backdrop = css({
|
|
63
78
|
position: "fixed",
|
|
@@ -77,8 +92,10 @@ const dialogTitle = cx(heading(), css({ display: "flex", alignItems: "center", g
|
|
|
77
92
|
const dialogDescription = css({
|
|
78
93
|
margin: "none",
|
|
79
94
|
color: "fg.muted",
|
|
95
|
+
_light: { color: "fg.secondary" },
|
|
80
96
|
fontSize: "body",
|
|
81
|
-
|
|
97
|
+
fontWeight: "medium",
|
|
98
|
+
lineHeight: "body",
|
|
82
99
|
});
|
|
83
100
|
// Bleeds past its edges by a control's focus ring, so scrolling does not clip the ring.
|
|
84
101
|
const dialogBody = css({
|
|
@@ -98,16 +115,18 @@ const dialogLeadingActions = css({
|
|
|
98
115
|
gap: "layout.controlGap",
|
|
99
116
|
marginInlineEnd: "auto",
|
|
100
117
|
});
|
|
118
|
+
// Under a divider, its buttons at the default height and close together.
|
|
101
119
|
const dialogFooter = css({
|
|
102
120
|
display: "flex",
|
|
103
121
|
justifyContent: "flex-end",
|
|
104
|
-
gap: "layout.
|
|
105
|
-
paddingTop: "layout.
|
|
122
|
+
gap: "layout.tightGap",
|
|
123
|
+
paddingTop: "layout.clusterGap",
|
|
124
|
+
borderTop: "1px solid token(colors.border.divider)",
|
|
106
125
|
});
|
|
107
|
-
const
|
|
108
|
-
const
|
|
126
|
+
const narrowDialogShell = css.raw({ "--dialog-sheet": "token(sizes.card.centeredForm)" });
|
|
127
|
+
const wideDialogShell = css.raw({ "--dialog-sheet": "token(sizes.overlay.dialogWide)" });
|
|
109
128
|
// Beside the dialog's own column, flush to its edges; below it on a narrow screen.
|
|
110
|
-
const
|
|
129
|
+
const splitDialogSheet = css.raw({
|
|
111
130
|
padding: "none",
|
|
112
131
|
gap: "none",
|
|
113
132
|
gridTemplateRows: "auto auto",
|
|
@@ -163,13 +182,13 @@ export function Dialog({ trigger, finalFocus, title, titleVisibility = "visible"
|
|
|
163
182
|
const dismissInHeader = dismiss === "header";
|
|
164
183
|
const showCancel = !dismissInHeader;
|
|
165
184
|
const dismissalDisabled = !closable || pending;
|
|
166
|
-
const dialogContent = (_jsxs(_Fragment, { children: [_jsxs("div", { className: dismissInHeader ? dialogHeaderRow : undefined, children: [_jsxs("div", { className: dialogHeader, children: [titleVisibility === "hidden" ? (_jsx(BaseDialog.Title, { className: visuallyHidden, children: title })) : (_jsxs(BaseDialog.Title, { className: dialogTitle, children: [titleIcon, title] })), description && (_jsx(BaseDialog.Description, { className: dialogDescription, children: description }))] }), dismissInHeader && closable && (_jsx(BaseDialog.Close, { disabled: pending, render: _jsx(IconButton, { "aria-label": closeLabel, size: "compact", variant: "ghost" }), children: _jsx(XIcon, { className: icon({ size: "small" }) }) }))] }), _jsx("div", { className: dialogBody, children: _jsx(DialogHeightResetContext, { value: holdHeight ? resetHeight : null, children: children }) }), ((showCancel && closable) || actions || leadingActions) && (
|
|
185
|
+
const dialogContent = (_jsxs(_Fragment, { children: [_jsxs("div", { className: dismissInHeader ? dialogHeaderRow : undefined, children: [_jsxs("div", { className: dialogHeader, children: [titleVisibility === "hidden" ? (_jsx(BaseDialog.Title, { className: visuallyHidden, children: title })) : (_jsxs(BaseDialog.Title, { className: dialogTitle, children: [titleIcon, title] })), description && (_jsx(BaseDialog.Description, { className: dialogDescription, children: description }))] }), dismissInHeader && closable && (_jsx(BaseDialog.Close, { disabled: pending, render: _jsx(IconButton, { "aria-label": closeLabel, size: "compact", variant: "ghost" }), children: _jsx(XIcon, { className: icon({ size: "small" }) }) }))] }), _jsx("div", { className: dialogBody, children: _jsx(DialogHeightResetContext, { value: holdHeight ? resetHeight : null, children: children }) }), ((showCancel && closable) || actions || leadingActions) && (_jsx("div", { className: dialogFooter, children: _jsxs(ButtonSizeContext, { value: "medium", children: [leadingActions && _jsx("div", { className: dialogLeadingActions, children: leadingActions }), showCancel && closable && (_jsx(BaseDialog.Close, { disabled: pending, render: _jsx(Button, { variant: "secondary" }), children: dismissInHeader ? labels.common.cancel : closeLabel })), actions] }) }))] }));
|
|
167
186
|
return (_jsxs(BaseDialog.Root, { ...rootProps, onOpenChange: (open, details) => {
|
|
168
187
|
if (!open && (dismissalDisabled || (dirty && details.reason !== "close-press"))) {
|
|
169
188
|
return details.cancel();
|
|
170
189
|
}
|
|
171
190
|
onOpenChange?.(open, details);
|
|
172
|
-
}, children: [trigger && _jsx(BaseDialog.Trigger, { render: trigger }), _jsx(BaseDialog.Portal, { children: _jsxs(HotkeyLayer, { children: [_jsx(BaseDialog.Backdrop, { "data-ciridae-ui": "", className: backdrop }), _jsx(BaseDialog.Popup, { finalFocus: finalFocus, ref: holdHeight ? holdTallestHeight : undefined, className: css(
|
|
191
|
+
}, children: [trigger && _jsx(BaseDialog.Trigger, { render: trigger }), _jsx(BaseDialog.Portal, { children: _jsxs(HotkeyLayer, { children: [_jsx(BaseDialog.Backdrop, { "data-ciridae-ui": "", className: backdrop }), _jsx(BaseDialog.Popup, { finalFocus: finalFocus, ref: holdHeight ? holdTallestHeight : undefined, className: css(dialogShell, size === "narrow" && aside === undefined && narrowDialogShell, (size === "wide" || aside !== undefined) && wideDialogShell), "data-ciridae-ui": "", children: aside ? (_jsxs("div", { className: css(dialogSheetStyle, splitDialogSheet), children: [_jsx("div", { className: splitDialogMain, children: dialogContent }), _jsx("aside", { className: splitDialogAside, "aria-label": aside.label, children: aside.content })] })) : (_jsx("div", { className: dialogSheet, children: dialogContent })) })] }) })] }));
|
|
173
192
|
}
|
|
174
193
|
/**
|
|
175
194
|
* A confirmation the reader must answer. Unlike `Dialog` it carries the
|
|
@@ -207,13 +226,13 @@ export function AlertDialog({ trigger, title, children, confirmLabel, cancelLabe
|
|
|
207
226
|
if (!open && pendingRef.current)
|
|
208
227
|
return details.cancel();
|
|
209
228
|
onOpenChange?.(open, details);
|
|
210
|
-
}, children: [trigger && _jsx(BaseAlertDialog.Trigger, { render: trigger }), _jsx(BaseAlertDialog.Portal, { children: _jsxs(HotkeyLayer, { children: [_jsx(BaseAlertDialog.Backdrop, { "data-ciridae-ui": "", className: backdrop }),
|
|
229
|
+
}, children: [trigger && _jsx(BaseAlertDialog.Trigger, { render: trigger }), _jsx(BaseAlertDialog.Portal, { children: _jsxs(HotkeyLayer, { children: [_jsx(BaseAlertDialog.Backdrop, { "data-ciridae-ui": "", className: backdrop }), _jsx(BaseAlertDialog.Popup, { className: css(dialogShell), "data-ciridae-ui": "", children: _jsxs("div", { className: dialogSheet, children: [_jsx(BaseAlertDialog.Title, { className: dialogTitle, children: title }), children && _jsx("div", { className: dialogBody, children: children }), _jsxs("div", { className: dialogFooter, children: [_jsx(BaseAlertDialog.Close, { render: _jsx(Button, { variant: "secondary", size: "medium" }), disabled: pending, children: cancelLabel ?? labels.common.cancel }), _jsx(Button, { variant: variant === "danger" ? "danger" : "primary", size: "medium", loading: pending, onClick: () => void confirm(), children: confirmLabel })] })] }) })] }) })] }));
|
|
211
230
|
}
|
|
212
231
|
// Merged rather than layered, so the density's inset replaces the popup's.
|
|
213
232
|
const popoverPopups = {
|
|
214
233
|
regular: popup,
|
|
215
|
-
compact: css(popupStyle, { padding: "menu.inset"
|
|
216
|
-
flush: css(popupStyle, { padding: "none", overflow: "hidden"
|
|
234
|
+
compact: css(popupStyle, { padding: "menu.inset" }),
|
|
235
|
+
flush: css(popupStyle, { padding: "none", overflow: "hidden" }),
|
|
217
236
|
};
|
|
218
237
|
const popoverWidths = {
|
|
219
238
|
narrow: css({ width: "overlay.popoverNarrow" }),
|
|
@@ -223,18 +242,28 @@ const popoverWidths = {
|
|
|
223
242
|
const hoverOpenDelayMs = 300;
|
|
224
243
|
const hoverCloseDelayMs = 150;
|
|
225
244
|
export function Popover({ trigger, anchor, children, density = "regular", width, align, openOnHover = false, ...rootProps }) {
|
|
226
|
-
return (_jsxs(BasePopover.Root, { ...rootProps, children: [trigger && (_jsx(BasePopover.Trigger, { render: trigger, openOnHover: openOnHover, delay: hoverOpenDelayMs, closeDelay: hoverCloseDelayMs })), _jsx(BasePopover.Portal, { children: _jsx(HotkeyLayer, { enabled: !openOnHover, children: _jsx(BasePopover.Positioner, { className: positioner, sideOffset:
|
|
245
|
+
return (_jsxs(BasePopover.Root, { ...rootProps, children: [trigger && (_jsx(BasePopover.Trigger, { render: trigger, openOnHover: openOnHover, delay: hoverOpenDelayMs, closeDelay: hoverCloseDelayMs })), _jsx(BasePopover.Portal, { children: _jsx(HotkeyLayer, { enabled: !openOnHover, children: _jsx(BasePopover.Positioner, { className: positioner, sideOffset: 4, align: align, anchor: anchor, children: _jsx(BasePopover.Popup, { className: cx(popoverPopups[density], width && popoverWidths[width]), "data-ciridae-ui": "", initialFocus: openOnHover ? (openType) => openType === "keyboard" : undefined, children: children }) }) }) })] }));
|
|
227
246
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
247
|
+
/* An inverted chip: the primary face, ink in light and white in dark, with the text in the canvas's. */
|
|
248
|
+
const tooltipPopup = css({
|
|
249
|
+
zIndex: "tooltip",
|
|
250
|
+
display: "flex",
|
|
251
|
+
alignItems: "baseline",
|
|
252
|
+
gap: "layout.controlGap",
|
|
253
|
+
paddingBlock: "control.compactBlock",
|
|
254
|
+
paddingInline: "menu.itemInline",
|
|
255
|
+
borderRadius: "keycap",
|
|
256
|
+
background: "fg.primary",
|
|
257
|
+
color: "bg.canvas",
|
|
258
|
+
_light: { background: "token(gradients.primary)", color: "fg.onAccent" },
|
|
259
|
+
fontSize: "code",
|
|
260
|
+
fontWeight: "medium",
|
|
261
|
+
lineHeight: "tight",
|
|
262
|
+
letterSpacing: "compact",
|
|
263
|
+
maxWidth: "overlay.tooltip",
|
|
264
|
+
textWrap: "pretty",
|
|
265
|
+
});
|
|
266
|
+
const tooltipMeta = css({ flexShrink: "0", opacity: "0.6" });
|
|
267
|
+
export function Tooltip({ children, content, meta, ...rootProps }) {
|
|
268
|
+
return (_jsx(BaseTooltip.Provider, { children: _jsxs(BaseTooltip.Root, { ...rootProps, children: [_jsx(BaseTooltip.Trigger, { render: children }), _jsx(BaseTooltip.Portal, { children: _jsx(BaseTooltip.Positioner, { className: tooltipPositioner, sideOffset: 8, children: _jsxs(BaseTooltip.Popup, { className: tooltipPopup, "data-ciridae-ui": "", children: [content, meta !== undefined && _jsx("span", { className: tooltipMeta, children: meta })] }) }) })] }) }));
|
|
240
269
|
}
|
|
@@ -13,7 +13,7 @@ export type PanelProps = useRender.ComponentProps<"section"> & {
|
|
|
13
13
|
export declare function Panel({ padding, tone, render, className, ...props }: PanelProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
14
14
|
export type PanelHeaderProps = Omit<useRender.ComponentProps<"div">, "title"> & {
|
|
15
15
|
title: ReactNode;
|
|
16
|
-
/** Muted
|
|
16
|
+
/** Muted at the row's far edge, before the actions, such as a count or the period it covers. */
|
|
17
17
|
meta?: ReactNode;
|
|
18
18
|
/** At the row's end, such as a link to the full list. */
|
|
19
19
|
actions?: ReactNode;
|
package/dist/components/panel.js
CHANGED
|
@@ -9,13 +9,13 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
9
9
|
*/
|
|
10
10
|
import { useRender } from "@base-ui/react/use-render";
|
|
11
11
|
import { css, cva, cx } from "#primitives/css";
|
|
12
|
+
import { singleLineText } from "./single-line-text.js";
|
|
12
13
|
/** The card's surface as a style object, to merge into a `css()` call that adds layout. */
|
|
13
14
|
export const cardSurface = css.raw({
|
|
14
15
|
minWidth: "0",
|
|
15
|
-
border: "1px solid token(colors.border.
|
|
16
|
+
border: "1px solid token(colors.border.card)",
|
|
16
17
|
borderRadius: "action",
|
|
17
|
-
background: "
|
|
18
|
-
_light: { background: "bg.card" },
|
|
18
|
+
background: "token(gradients.card)",
|
|
19
19
|
});
|
|
20
20
|
const card = css(cardSurface);
|
|
21
21
|
const panel = cva({
|
|
@@ -39,7 +39,7 @@ const panel = cva({
|
|
|
39
39
|
default: { gap: "layout.contentGap", padding: "panel.default" },
|
|
40
40
|
},
|
|
41
41
|
tone: {
|
|
42
|
-
panel: { borderColor: "border.panel", background: "
|
|
42
|
+
panel: { borderColor: "border.panel", background: "token(gradients.panel)" },
|
|
43
43
|
outline: { borderColor: "border.control" },
|
|
44
44
|
},
|
|
45
45
|
},
|
|
@@ -55,19 +55,25 @@ const panelHeader = css({
|
|
|
55
55
|
paddingInline: "panel.comfortable",
|
|
56
56
|
fontSize: "body",
|
|
57
57
|
fontWeight: "medium",
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
lineHeight: "tight",
|
|
59
|
+
/*
|
|
60
|
+
* In a padded panel the header is one more row inside the padding, inset from what follows by
|
|
61
|
+
* the design's 16px: its own padding, less the panel's gap, which it takes back.
|
|
62
|
+
*/
|
|
63
|
+
"[data-panel-padding=default] > &": {
|
|
64
|
+
height: "auto",
|
|
65
|
+
gap: "layout.controlGap",
|
|
66
|
+
paddingInline: "none",
|
|
67
|
+
paddingBottom: "panel.comfortable",
|
|
68
|
+
marginBottom: "calc(token(spacing.layout.contentGap) * -1)",
|
|
69
|
+
},
|
|
60
70
|
});
|
|
61
|
-
const panelHeaderTitle = css({
|
|
71
|
+
const panelHeaderTitle = css(singleLineText, {
|
|
62
72
|
display: "flex",
|
|
63
73
|
alignItems: "center",
|
|
64
74
|
gap: "control.iconGap",
|
|
65
|
-
minWidth: "0",
|
|
66
75
|
margin: "none",
|
|
67
76
|
font: "inherit",
|
|
68
|
-
overflow: "hidden",
|
|
69
|
-
textOverflow: "ellipsis",
|
|
70
|
-
whiteSpace: "nowrap",
|
|
71
77
|
});
|
|
72
78
|
const panelHeaderMeta = css({ color: "fg.subtle", fontSize: "code" });
|
|
73
79
|
const panelHeaderActions = css({ display: "flex", alignItems: "center", gap: "layout.tightGap" });
|
|
@@ -101,7 +107,7 @@ export function PanelHeader({ title, meta, actions, level, render, className, ..
|
|
|
101
107
|
className: cx(panelHeader, className),
|
|
102
108
|
"data-ciridae-ui": "",
|
|
103
109
|
"data-panel-header": "",
|
|
104
|
-
children: (_jsxs(_Fragment, { children: [title !== undefined && title !== null && (
|
|
110
|
+
children: (_jsxs(_Fragment, { children: [title !== undefined && title !== null && (_jsx(Title, { className: panelHeaderTitle, children: title })), (meta !== undefined || actions !== undefined) && (_jsxs("span", { className: panelHeaderActions, children: [meta !== undefined && _jsx("span", { className: panelHeaderMeta, children: meta }), actions] }))] })),
|
|
105
111
|
},
|
|
106
112
|
});
|
|
107
113
|
}
|
|
@@ -2,11 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Radio as BaseRadio } from "@base-ui/react/radio";
|
|
3
3
|
import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group";
|
|
4
4
|
import { css, cx } from "#primitives/css";
|
|
5
|
-
import { checkMark, radioDot } from "./form-controls.js";
|
|
5
|
+
import { checkMark, checkMarkEdge, radioDot } from "./form-controls.js";
|
|
6
6
|
/*
|
|
7
7
|
* A choice drawn as a card: the radio, a title with its detail, and where the option comes from
|
|
8
8
|
* at the far edge. The whole card is the radio, so it takes the hover wash, the focus ring, and,
|
|
9
|
-
* once chosen, the
|
|
9
|
+
* once chosen, the selected tint under an edge in the text color.
|
|
10
10
|
*/
|
|
11
11
|
const cards = css({ display: "grid", gap: "layout.controlGap" });
|
|
12
12
|
const card = css({
|
|
@@ -28,10 +28,10 @@ const card = css({
|
|
|
28
28
|
cursor: "pointer",
|
|
29
29
|
transitionProperty: "background, border-color",
|
|
30
30
|
transitionDuration: "fast",
|
|
31
|
-
_hover: { background: "
|
|
31
|
+
_hover: { background: "token(gradients.raisedHover)" },
|
|
32
32
|
"&[data-checked]": {
|
|
33
|
-
background: "
|
|
34
|
-
borderColor: "
|
|
33
|
+
background: "token(gradients.selected)",
|
|
34
|
+
borderColor: "fg.primary",
|
|
35
35
|
},
|
|
36
36
|
_focusVisible: { focusRing: "outer" },
|
|
37
37
|
"&[data-disabled]": { opacity: "disabled", cursor: "not-allowed" },
|
|
@@ -42,10 +42,11 @@ const mark = css({
|
|
|
42
42
|
// the mark down.
|
|
43
43
|
marginTop: "calc((1em - token(sizes.control.radio)) / 2)",
|
|
44
44
|
"[data-checked] > &": {
|
|
45
|
-
background: "
|
|
46
|
-
|
|
45
|
+
background: "token(gradients.primary)",
|
|
46
|
+
_light: { background: "token(gradients.primary)" },
|
|
47
|
+
_before: { background: "token(gradients.border.primary)" },
|
|
47
48
|
},
|
|
48
|
-
"[data-checked]:hover > &": {
|
|
49
|
+
"[data-checked]:hover > &": { opacity: "checkedHover", _light: { opacity: "1" } },
|
|
49
50
|
});
|
|
50
51
|
const copy = css({ flex: "1", minWidth: "0", display: "grid", gap: "layout.tightGap" });
|
|
51
52
|
const detailText = css({ color: "fg.muted", fontSize: "code" });
|
|
@@ -62,5 +63,5 @@ export function RadioCardGroup({ name, label, defaultValue, value, onValueChange
|
|
|
62
63
|
}
|
|
63
64
|
/** One option of a `RadioCardGroup`. */
|
|
64
65
|
export function RadioCard({ title, detail, source: sourceContent, className, ...props }) {
|
|
65
|
-
return (_jsxs(BaseRadio.Root, { ...props, className: cx(card, className), "data-ciridae-ui": "", children: [_jsx("span", { className: cx(checkMark({ shape: "round", focus: "row" }), mark), children: _jsx(BaseRadio.Indicator, { className: radioDot }) }), _jsxs("span", { className: copy, children: [_jsx("span", { children: title }), detail !== undefined && _jsx("span", { className: detailText, children: detail })] }), sourceContent !== undefined && _jsx("span", { className: source, children: sourceContent })] }));
|
|
66
|
+
return (_jsxs(BaseRadio.Root, { ...props, className: cx(card, className), "data-ciridae-ui": "", children: [_jsx("span", { ...checkMarkEdge, className: cx(checkMark({ shape: "round", focus: "row" }), mark), children: _jsx(BaseRadio.Indicator, { className: radioDot }) }), _jsxs("span", { className: copy, children: [_jsx("span", { children: title }), detail !== undefined && _jsx("span", { className: detailText, children: detail })] }), sourceContent !== undefined && _jsx("span", { className: source, children: sourceContent })] }));
|
|
66
67
|
}
|
|
@@ -48,7 +48,7 @@ export type ItemCardField = {
|
|
|
48
48
|
};
|
|
49
49
|
export type ItemCardProps = Omit<useRender.ComponentProps<"button">, "children" | "onSelect"> & {
|
|
50
50
|
title: ReactNode;
|
|
51
|
-
/** One
|
|
51
|
+
/** One dot per stage, in its status. */
|
|
52
52
|
progress?: readonly StepStatus[];
|
|
53
53
|
fields: readonly ItemCardField[];
|
|
54
54
|
/** The footer's start: the stage the item is at. */
|
|
@@ -64,6 +64,30 @@ export type ItemCardProps = Omit<useRender.ComponentProps<"button">, "children"
|
|
|
64
64
|
href?: string;
|
|
65
65
|
};
|
|
66
66
|
export declare function ItemCard({ title, progress, fields, status, footer, selected, onSelect, href, render, className, style, ...props }: ItemCardProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
67
|
+
export type PartRowProps = Omit<ComponentProps<"div">, "children" | "onSelect"> & {
|
|
68
|
+
/** `wide` is one line, as in a table; `compact` stacks for a narrow column. */
|
|
69
|
+
layout?: "wide" | "compact";
|
|
70
|
+
name: ReactNode;
|
|
71
|
+
/** Under the name, such as the part's phase and amount. */
|
|
72
|
+
detail?: ReactNode;
|
|
73
|
+
/** One dot per step, in its status; the kit draws at most four. */
|
|
74
|
+
progress: readonly StepStatus[];
|
|
75
|
+
/** The stage the part is at. */
|
|
76
|
+
stage: ReactNode;
|
|
77
|
+
/** Whose move it is: `yourMove` sets the next step in the ink, the others in grey. */
|
|
78
|
+
state: "yourMove" | "waiting" | "done" | "notStarted";
|
|
79
|
+
/** Before the next step, such as a "Your move" badge. */
|
|
80
|
+
badge?: ReactNode;
|
|
81
|
+
next: ReactNode;
|
|
82
|
+
/** The part's one button, for the reader's move or a nudge while waiting. */
|
|
83
|
+
action?: {
|
|
84
|
+
label: ReactNode;
|
|
85
|
+
onClick: () => void;
|
|
86
|
+
};
|
|
87
|
+
selected?: boolean;
|
|
88
|
+
onSelect?: () => void;
|
|
89
|
+
};
|
|
90
|
+
export declare function PartRow({ layout, name, detail, progress, stage, state, badge, next, action, selected, onSelect, className, ...props }: PartRowProps): import("react").JSX.Element;
|
|
67
91
|
export type RelatedListItem = {
|
|
68
92
|
id: string;
|
|
69
93
|
title: ReactNode;
|
|
@@ -2,13 +2,15 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
/*
|
|
3
3
|
* The pieces a record's page is laid out with. `DetailLayout` splits it into the work and a side
|
|
4
4
|
* column; `PageHeading` (also exported here) is the record's title row; `RelatedTabs` is the tabbed card of what the
|
|
5
|
-
* record holds; `ItemCard` is one of a record's parts, such as a shipment or a draw
|
|
5
|
+
* record holds; `ItemCard` is one of a record's parts, such as a shipment or a draw, as a card and `PartRow` as
|
|
6
|
+
* a row; `RelatedList`
|
|
6
7
|
* lists the records and documents it points at.
|
|
7
8
|
*/
|
|
8
9
|
import { useRender } from "@base-ui/react/use-render";
|
|
9
10
|
import { CaretRightIcon } from "@phosphor-icons/react";
|
|
10
|
-
import { useLayoutEffect, useRef, useState, } from "react";
|
|
11
|
+
import { Fragment, useLayoutEffect, useRef, useState, } from "react";
|
|
11
12
|
import { css, cx } from "#primitives/css";
|
|
13
|
+
import { Button } from "./button.js";
|
|
12
14
|
import { useControllableState } from "./controllable-state.js";
|
|
13
15
|
import { directional, icon } from "./icon.js";
|
|
14
16
|
import { MutedText } from "./layout.js";
|
|
@@ -110,7 +112,10 @@ export function RelatedTabs({ tabs, value, defaultValue, onValueChange, classNam
|
|
|
110
112
|
return null;
|
|
111
113
|
return (_jsxs(TabsRoot, { value: open.value, onValueChange: (next) => setChosen(String(next)), ...props, className: cx(relatedCard, className), "data-ciridae-ui": "", children: [_jsxs("div", { className: relatedHeader, children: [_jsx(TabsList, { variant: "contained", children: tabs.map((tab) => (_jsx(TabsTab, { value: tab.value, count: tab.count, children: tab.label }, tab.value))) }), open.meta !== undefined && _jsx(MutedText, { className: relatedMeta, children: open.meta })] }), tabs.map((tab) => (_jsx(TabsPanel, { value: tab.value, children: tab.content }, tab.value)))] }));
|
|
112
114
|
}
|
|
113
|
-
/*
|
|
115
|
+
/*
|
|
116
|
+
* Item card: one of a record's parts, the kit's Part card, with its progress as a mini strip of
|
|
117
|
+
* step dots. The chosen one lifts onto the solid card inside a green edge.
|
|
118
|
+
*/
|
|
114
119
|
const itemCard = css(cardSurface, {
|
|
115
120
|
display: "grid",
|
|
116
121
|
gap: "layout.clusterGap",
|
|
@@ -121,7 +126,11 @@ const itemCard = css(cardSurface, {
|
|
|
121
126
|
letterSpacing: "compact",
|
|
122
127
|
textDecoration: "none",
|
|
123
128
|
"&:is(button, a)": { cursor: "pointer", _hover: { borderColor: "border.glass" } },
|
|
124
|
-
"&[data-selected]": {
|
|
129
|
+
"&[data-selected]": {
|
|
130
|
+
borderColor: "accent.green",
|
|
131
|
+
boxShadow: "soft",
|
|
132
|
+
_hover: { borderColor: "accent.green" },
|
|
133
|
+
},
|
|
125
134
|
_focusVisible: { focusRing: "outer" },
|
|
126
135
|
});
|
|
127
136
|
const itemHeader = css({
|
|
@@ -131,20 +140,27 @@ const itemHeader = css({
|
|
|
131
140
|
gap: "layout.controlGap",
|
|
132
141
|
fontSize: "body",
|
|
133
142
|
fontWeight: "medium",
|
|
143
|
+
lineHeight: "tight",
|
|
134
144
|
whiteSpace: "nowrap",
|
|
135
145
|
});
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
const progressStrip = css({
|
|
147
|
+
display: "inline-flex",
|
|
148
|
+
flexShrink: "0",
|
|
149
|
+
alignItems: "center",
|
|
150
|
+
gap: "layout.tightGap",
|
|
151
|
+
});
|
|
152
|
+
// 16px between dots, green out of a finished step as the stage strip's connectors are.
|
|
153
|
+
const progressConnector = css({
|
|
154
|
+
width: "token(spacing.layout.clusterGap)",
|
|
155
|
+
height: "border.hairline",
|
|
156
|
+
borderRadius: "round",
|
|
157
|
+
background: "border.divider",
|
|
158
|
+
"&[data-after=done]": { background: "accent.green" },
|
|
147
159
|
});
|
|
160
|
+
/** A part's progress: one 12px dot a step, joined by 16px connectors. */
|
|
161
|
+
function MiniStrip({ progress }) {
|
|
162
|
+
return (_jsx("span", { className: progressStrip, "aria-hidden": "true", children: progress.map((step, index) => (_jsxs(Fragment, { children: [index > 0 && (_jsx("span", { className: progressConnector, "data-after": progress[index - 1] === "done" ? "done" : undefined })), _jsx(StepDot, { status: step, size: "chip" })] }, index))) }));
|
|
163
|
+
}
|
|
148
164
|
const itemFields = css({
|
|
149
165
|
display: "grid",
|
|
150
166
|
gap: "layout.controlGap",
|
|
@@ -155,7 +171,7 @@ const itemFields = css({
|
|
|
155
171
|
const itemFieldLabel = css({
|
|
156
172
|
display: "block",
|
|
157
173
|
marginBottom: "layout.controlGap",
|
|
158
|
-
color: "fg.
|
|
174
|
+
color: "fg.subtle",
|
|
159
175
|
fontWeight: "regular",
|
|
160
176
|
letterSpacing: "normal",
|
|
161
177
|
});
|
|
@@ -188,10 +204,117 @@ export function ItemCard({ title, progress, fields, status, footer, selected = f
|
|
|
188
204
|
"data-ciridae-ui": "",
|
|
189
205
|
"data-selected": selected || undefined,
|
|
190
206
|
"aria-pressed": onSelect !== undefined && href === undefined ? selected : undefined,
|
|
191
|
-
children: (_jsxs(_Fragment, { children: [_jsxs("span", { className: itemHeader, children: [title, progress &&
|
|
207
|
+
children: (_jsxs(_Fragment, { children: [_jsxs("span", { className: itemHeader, children: [title, progress && _jsx(MiniStrip, { progress: progress })] }), _jsxs("span", { className: css({ display: "grid" }), children: [_jsx("span", { className: itemFields, style: columns, children: fields.map((field, index) => (_jsxs("span", { children: [_jsx("span", { className: itemFieldLabel, children: field.label }), field.value] }, index))) }), _jsxs("span", { className: itemFooter, children: [_jsxs("span", { className: itemStatus, children: [_jsx(StepDot, { status: status.status, size: "small" }), status.label] }), footer] })] })] })),
|
|
192
208
|
},
|
|
193
209
|
});
|
|
194
210
|
}
|
|
211
|
+
/*
|
|
212
|
+
* Part row: one of a record's parts as a table-like row, the kit's Part in its Wide and Compact
|
|
213
|
+
* layouts: name over detail, the mini strip, the stage, a badge for the reader's move, the next
|
|
214
|
+
* step and at most one action. Wide keeps it on one 56px line, wrapping the detail and next step
|
|
215
|
+
* only when the row is narrow; compact stacks the name and strip over the rest. The whole row chooses the part through its name; the action stays its own button.
|
|
216
|
+
*/
|
|
217
|
+
const partRow = css({
|
|
218
|
+
position: "relative",
|
|
219
|
+
display: "flex",
|
|
220
|
+
alignItems: "center",
|
|
221
|
+
gap: "layout.clusterGap",
|
|
222
|
+
minHeight: "calc(token(sizes.control.compact) + token(spacing.panel.default) * 2)",
|
|
223
|
+
paddingBlock: "panel.default",
|
|
224
|
+
paddingInline: "panel.comfortable",
|
|
225
|
+
borderBottom: "1px solid token(colors.border.divider)",
|
|
226
|
+
fontWeight: "medium",
|
|
227
|
+
letterSpacing: "compact",
|
|
228
|
+
lineHeight: "tight",
|
|
229
|
+
"&:has([data-part-name]:hover)": { background: "bg.rowHover" },
|
|
230
|
+
"&[data-selected]": { background: "token(gradients.selected)" },
|
|
231
|
+
// Wide is a grid, so the strips and stages of a list of parts line up. The name and the next
|
|
232
|
+
// step share what the strip, stage and action leave, two parts to three, close to the kit's
|
|
233
|
+
// 240 and 488 in its 1092 row, so a narrow row narrows both rather than starving one.
|
|
234
|
+
"&[data-layout=wide]": {
|
|
235
|
+
display: "grid",
|
|
236
|
+
gridTemplateColumns: "minmax(0, 2fr) max-content 90px minmax(0, 3fr) max-content",
|
|
237
|
+
},
|
|
238
|
+
"&[data-layout=compact]": {
|
|
239
|
+
flexDirection: "column",
|
|
240
|
+
alignItems: "stretch",
|
|
241
|
+
gap: "layout.tightGap",
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
const partLine = css({
|
|
245
|
+
display: "flex",
|
|
246
|
+
alignItems: "center",
|
|
247
|
+
gap: "layout.contentGap",
|
|
248
|
+
minWidth: "0",
|
|
249
|
+
"[data-layout=wide] > &": { display: "contents" },
|
|
250
|
+
});
|
|
251
|
+
const partName = css({
|
|
252
|
+
display: "grid",
|
|
253
|
+
gap: "control.trackInset",
|
|
254
|
+
flex: "1 1 0",
|
|
255
|
+
minWidth: "0",
|
|
256
|
+
textAlign: "start",
|
|
257
|
+
"& > *": { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
|
|
258
|
+
});
|
|
259
|
+
// The name is the row's button: its box stretches over the whole row.
|
|
260
|
+
const partNameButton = css({
|
|
261
|
+
padding: "none",
|
|
262
|
+
border: "none",
|
|
263
|
+
background: "transparent",
|
|
264
|
+
color: "fg.primary",
|
|
265
|
+
font: "inherit",
|
|
266
|
+
fontSize: "body",
|
|
267
|
+
textAlign: "start",
|
|
268
|
+
cursor: "pointer",
|
|
269
|
+
_after: { content: '""', position: "absolute", inset: "0" },
|
|
270
|
+
_focusVisible: { outline: "none", _after: { focusRing: "inset" } },
|
|
271
|
+
});
|
|
272
|
+
// A narrow wide row wraps the detail rather than cut off its amount.
|
|
273
|
+
const partDetail = css({
|
|
274
|
+
color: "fg.subtle",
|
|
275
|
+
fontSize: "code",
|
|
276
|
+
"[data-layout=wide] &": { whiteSpace: "normal", lineHeight: "compact" },
|
|
277
|
+
});
|
|
278
|
+
const partStage = css({
|
|
279
|
+
flexShrink: "0",
|
|
280
|
+
color: "fg.subtle",
|
|
281
|
+
fontSize: "code",
|
|
282
|
+
whiteSpace: "nowrap",
|
|
283
|
+
"[data-layout=wide] &": { overflow: "hidden", textOverflow: "ellipsis" },
|
|
284
|
+
});
|
|
285
|
+
const partStatus = css({
|
|
286
|
+
display: "flex",
|
|
287
|
+
alignItems: "center",
|
|
288
|
+
gap: "layout.controlGap",
|
|
289
|
+
flexShrink: "0",
|
|
290
|
+
"[data-layout=wide] > * > &": { display: "contents" },
|
|
291
|
+
});
|
|
292
|
+
// Wide sets the badge after the stage, in the next step's cell; compact leads the status with it.
|
|
293
|
+
const partNextCell = css({
|
|
294
|
+
display: "flex",
|
|
295
|
+
alignItems: "center",
|
|
296
|
+
gap: "layout.clusterGap",
|
|
297
|
+
minWidth: "0",
|
|
298
|
+
"[data-layout=compact] &": { display: "contents" },
|
|
299
|
+
});
|
|
300
|
+
const partBadge = css({
|
|
301
|
+
display: "inline-flex",
|
|
302
|
+
flexShrink: "0",
|
|
303
|
+
"[data-layout=compact] &": { order: "-1" },
|
|
304
|
+
});
|
|
305
|
+
// The step the reader acts on wraps in a narrow row, never cut short.
|
|
306
|
+
const partNext = css({
|
|
307
|
+
minWidth: "0",
|
|
308
|
+
color: "fg.secondary",
|
|
309
|
+
fontSize: "caption",
|
|
310
|
+
lineHeight: "compact",
|
|
311
|
+
"[data-state=yourMove] &": { color: "fg.primary" },
|
|
312
|
+
});
|
|
313
|
+
// The action sits over the stretched name, so it stays its own button.
|
|
314
|
+
const partAction = css({ position: "relative", flexShrink: "0" });
|
|
315
|
+
export function PartRow({ layout = "wide", name, detail, progress, stage, state, badge, next, action, selected = false, onSelect, className, ...props }) {
|
|
316
|
+
return (_jsxs("div", { ...props, className: cx(partRow, className), "data-ciridae-ui": "", "data-layout": layout, "data-state": state, "data-selected": selected || undefined, children: [_jsxs("span", { className: partLine, children: [_jsxs("span", { className: partName, children: [onSelect ? (_jsx("button", { type: "button", className: partNameButton, "data-part-name": "", "aria-pressed": selected, onClick: onSelect, children: name })) : (_jsx("span", { className: css({ fontSize: "body" }), children: name })), layout === "wide" && detail !== undefined && (_jsx("span", { className: partDetail, children: detail }))] }), _jsx(MiniStrip, { progress: progress })] }), _jsxs("span", { className: partLine, children: [layout === "compact" && _jsx("span", { className: cx(partName, partDetail), children: detail }), _jsxs("span", { className: partStatus, children: [_jsx("span", { className: partStage, children: stage }), _jsxs("span", { className: partNextCell, children: [badge !== undefined && _jsx("span", { className: partBadge, children: badge }), _jsx("span", { className: partNext, children: next })] }), action && (_jsx(Button, { variant: "secondary", className: partAction, onClick: action.onClick, children: action.label }))] })] })] }));
|
|
317
|
+
}
|
|
195
318
|
/* Related list: the records and documents a record points at, grouped by relation. */
|
|
196
319
|
const groupHeader = css({
|
|
197
320
|
display: "flex",
|
|
@@ -221,7 +344,11 @@ const relatedRow = css({
|
|
|
221
344
|
font: "inherit",
|
|
222
345
|
textAlign: "start",
|
|
223
346
|
textDecoration: "none",
|
|
224
|
-
|
|
347
|
+
// The kit's Linked record hovers to the selected glass in dark and the row wash in light.
|
|
348
|
+
"&:is(button, a)": {
|
|
349
|
+
cursor: "pointer",
|
|
350
|
+
_hover: { background: "token(gradients.selected)", _light: { background: "bg.rowHover" } },
|
|
351
|
+
},
|
|
225
352
|
_focusVisible: { focusRing: "outer" },
|
|
226
353
|
});
|
|
227
354
|
const tile = css({
|
|
@@ -234,6 +361,7 @@ const tile = css({
|
|
|
234
361
|
borderRadius: "action",
|
|
235
362
|
background: "bg.panel",
|
|
236
363
|
color: "fg.secondary",
|
|
364
|
+
_light: { background: "bg.field" },
|
|
237
365
|
"& svg": { fontSize: "icon.small" },
|
|
238
366
|
});
|
|
239
367
|
const rowTitle = css({
|
|
@@ -251,6 +379,7 @@ const rowMeta = css({
|
|
|
251
379
|
color: "fg.secondary",
|
|
252
380
|
fontSize: "code",
|
|
253
381
|
fontWeight: "medium",
|
|
382
|
+
lineHeight: "tight",
|
|
254
383
|
"& [data-separator]": { color: "fg.muted" },
|
|
255
384
|
"& [data-tone=info]": { color: "accent.blue" },
|
|
256
385
|
"& [data-tone=success]": { color: "accent.green" },
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { type ComponentProps, type ReactNode } from "react";
|
|
2
2
|
import type { Tone } from "./badge.js";
|
|
3
|
+
/** A segment's hue: a tone by meaning, or `indigo`, the chart's category no status hue covers. */
|
|
4
|
+
export type SegmentedBarHue = Tone | "indigo";
|
|
3
5
|
export type SegmentedBarSegment = {
|
|
4
6
|
id: string;
|
|
5
7
|
label: string;
|
|
6
8
|
value: number;
|
|
7
9
|
/** The segment's color by meaning; `neutral` by default. */
|
|
8
|
-
tone?:
|
|
10
|
+
tone?: SegmentedBarHue;
|
|
9
11
|
/** A color of its own, such as a CSS variable the app themes, over `tone`. */
|
|
10
12
|
color?: string;
|
|
11
13
|
};
|