@ciridae/ui 1.0.2 → 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/app/auth.d.ts +10 -0
- package/dist/app/auth.js +60 -0
- package/dist/app/error-boundary.d.ts +18 -0
- package/dist/app/error-boundary.js +45 -0
- package/dist/app/feedback.d.ts +12 -0
- package/dist/app/feedback.js +128 -0
- package/dist/app/index.d.ts +8 -0
- package/dist/app/index.js +8 -0
- package/dist/app/request-errors.d.ts +63 -0
- package/dist/app/request-errors.js +172 -0
- package/dist/app/sentry.d.ts +18 -0
- package/dist/app/sentry.js +52 -0
- package/dist/app/telemetry.d.ts +7 -0
- package/dist/app/telemetry.js +28 -0
- package/dist/app/trail.d.ts +9 -0
- package/dist/app/trail.js +18 -0
- package/dist/chat/chat-query-keys.d.ts +3 -3
- package/dist/chat/contract.d.ts +15 -15
- package/dist/chat/conversation-items-query-options.d.ts +114 -114
- package/dist/chat/conversation-source.d.ts +89 -0
- package/dist/chat/conversation-source.js +1 -0
- package/dist/chat/describe-tool-call.d.ts +3 -3
- package/dist/chat/describe-tool-call.js +3 -3
- package/dist/chat/message-text.d.ts +1 -1
- package/dist/chat/message-text.js +116 -48
- package/dist/chat/use-conversation-list.d.ts +6 -6
- package/dist/ciridae.css +16 -4
- package/dist/components/activity-feed.d.ts +3 -2
- package/dist/components/activity-feed.js +1 -0
- package/dist/components/agent-work.d.ts +3 -3
- package/dist/components/app-frame.d.ts +91 -0
- package/dist/components/app-frame.js +134 -0
- package/dist/components/app-navigation.d.ts +30 -3
- package/dist/components/app-navigation.js +105 -14
- package/dist/components/badge.d.ts +30 -5
- package/dist/components/badge.js +134 -15
- package/dist/components/brand-icons.d.ts +3 -3
- package/dist/components/bulk-action-bar.d.ts +1 -1
- package/dist/components/bulk-action-bar.js +3 -3
- package/dist/components/button.d.ts +12 -5
- package/dist/components/button.js +77 -44
- package/dist/components/calendar.d.ts +1 -1
- package/dist/components/calendar.js +44 -17
- package/dist/components/centered-page.d.ts +1 -1
- package/dist/components/centered-page.js +2 -2
- package/dist/components/chart.d.ts +22 -2
- package/dist/components/chart.js +251 -51
- package/dist/components/chat-client-source.d.ts +16 -0
- package/dist/components/chat-client-source.js +297 -0
- package/dist/components/chat-page.d.ts +9 -8
- package/dist/components/chat-page.js +7 -11
- package/dist/components/chat-sheet-controller.d.ts +11 -14
- package/dist/components/chat-sheet-controller.js +3 -3
- package/dist/components/chat-sheet.d.ts +18 -11
- package/dist/components/chat-sheet.js +188 -289
- package/dist/components/chat.d.ts +109 -19
- package/dist/components/chat.js +520 -124
- package/dist/components/checkbox-item.d.ts +6 -3
- package/dist/components/checkbox-item.js +9 -5
- package/dist/components/checkbox-list.d.ts +1 -1
- package/dist/components/chip.d.ts +6 -1
- package/dist/components/chip.js +27 -1
- package/dist/components/collapsible.d.ts +1 -1
- package/dist/components/color-theme.d.ts +1 -1
- package/dist/components/column-settings.d.ts +1 -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 +7 -3
- package/dist/components/command-palette.js +20 -11
- package/dist/components/copyable-id.d.ts +22 -5
- package/dist/components/copyable-id.js +46 -6
- package/dist/components/data-display.d.ts +39 -8
- package/dist/components/data-display.js +138 -19
- package/dist/components/data-grid.d.ts +23 -11
- package/dist/components/data-grid.js +61 -26
- package/dist/components/date-range-picker.d.ts +1 -1
- package/dist/components/date-range-picker.js +9 -20
- package/dist/components/date-time.d.ts +1 -1
- package/dist/components/dialog-height-context.d.ts +1 -1
- package/dist/components/document-viewer.d.ts +2 -2
- package/dist/components/drawer.d.ts +11 -6
- package/dist/components/drawer.js +91 -54
- package/dist/components/dropzone.d.ts +4 -4
- package/dist/components/editable-field.d.ts +12 -3
- package/dist/components/editable-field.js +57 -27
- package/dist/components/email-input.d.ts +1 -1
- package/dist/components/email-input.js +6 -5
- package/dist/components/environment-frame.d.ts +2 -2
- package/dist/components/environment-frame.js +37 -6
- package/dist/components/expandable-text.d.ts +1 -1
- package/dist/components/feedback-screenshot.d.ts +1 -1
- package/dist/components/feedback-sheet.d.ts +18 -3
- package/dist/components/feedback-sheet.js +216 -55
- package/dist/components/field-context.d.ts +1 -1
- package/dist/components/filter-bar.d.ts +3 -3
- package/dist/components/filter-bar.js +43 -29
- package/dist/components/form-controls.d.ts +12 -3
- package/dist/components/form-controls.js +46 -22
- package/dist/components/form-layout.d.ts +14 -10
- 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/hotkeys.d.ts +2 -2
- package/dist/components/icon.d.ts +1 -1
- package/dist/components/input.d.ts +7 -5
- package/dist/components/input.js +29 -17
- package/dist/components/keyboard-shortcuts.d.ts +2 -2
- package/dist/components/keycap.d.ts +10 -6
- package/dist/components/keycap.js +57 -19
- package/dist/components/layout.d.ts +13 -13
- package/dist/components/lightbox.d.ts +9 -3
- package/dist/components/lightbox.js +13 -9
- package/dist/components/link.d.ts +1 -1
- package/dist/components/locale.d.ts +42 -2
- package/dist/components/locale.js +43 -3
- package/dist/components/log-entry.d.ts +40 -0
- package/dist/components/log-entry.js +146 -0
- package/dist/components/log-list.d.ts +3 -3
- package/dist/components/mention-input.d.ts +2 -2
- package/dist/components/mention-input.js +4 -3
- package/dist/components/menu.d.ts +7 -3
- package/dist/components/menu.js +34 -37
- package/dist/components/meter.d.ts +10 -2
- 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.d.ts +1 -1
- package/dist/components/notification-tray.js +5 -4
- package/dist/components/overlays.d.ts +6 -4
- package/dist/components/overlays.js +69 -40
- package/dist/components/page-frame.d.ts +4 -4
- package/dist/components/page-frame.js +1 -1
- package/dist/components/panel.d.ts +4 -4
- package/dist/components/panel.js +18 -12
- package/dist/components/profile-header.d.ts +1 -1
- package/dist/components/progress.d.ts +1 -1
- package/dist/components/project-avatar.d.ts +1 -1
- package/dist/components/radio-card.d.ts +2 -2
- package/dist/components/radio-card.js +10 -9
- package/dist/components/record.d.ts +29 -5
- package/dist/components/record.js +147 -18
- package/dist/components/resolved-file-url.d.ts +19 -0
- package/dist/components/resolved-file-url.js +49 -0
- package/dist/components/scroll-area.d.ts +1 -1
- package/dist/components/secret-dialog.d.ts +1 -1
- package/dist/components/segmented-bar.d.ts +4 -2
- package/dist/components/segmented-bar.js +16 -6
- package/dist/components/select.d.ts +9 -6
- package/dist/components/select.js +103 -127
- package/dist/components/settings.d.ts +4 -4
- package/dist/components/shell-skeleton.d.ts +1 -1
- package/dist/components/shell-skeleton.js +1 -1
- package/dist/components/shell.d.ts +21 -21
- package/dist/components/shell.js +43 -43
- package/dist/components/side-panel.d.ts +3 -3
- package/dist/components/sidebar.d.ts +13 -8
- 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 +8 -7
- package/dist/components/skeleton.js +28 -16
- package/dist/components/skeletons.d.ts +17 -5
- package/dist/components/skeletons.js +71 -8
- package/dist/components/stages.d.ts +83 -11
- package/dist/components/stages.js +512 -156
- package/dist/components/stat-card.d.ts +12 -4
- package/dist/components/stat-card.js +92 -37
- package/dist/components/status-banner.d.ts +1 -1
- package/dist/components/status-banner.js +1 -1
- package/dist/components/status.d.ts +2 -2
- package/dist/components/steps.d.ts +1 -1
- package/dist/components/switch.d.ts +1 -1
- package/dist/components/tabs.d.ts +8 -8
- package/dist/components/tabs.js +26 -13
- package/dist/components/theme-customizer.d.ts +2 -2
- package/dist/components/theme-toggle.d.ts +4 -0
- package/dist/components/theme-toggle.js +67 -0
- package/dist/components/toast.d.ts +10 -3
- package/dist/components/toast.js +78 -29
- package/dist/components/use-new-version-available.d.ts +6 -0
- package/dist/components/use-new-version-available.js +29 -0
- package/dist/components/user-chip.d.ts +3 -3
- package/dist/components/wizard.d.ts +2 -2
- package/dist/feedback/contract.d.ts +136 -136
- package/dist/feedback/feedback-controller.d.ts +6 -6
- package/dist/feedback/generated/zod.gen.d.ts +28 -28
- package/dist/feedback/operator-contract.d.ts +11 -11
- package/dist/feedback/operator-controller.d.ts +32 -13
- package/dist/feedback/operator-controller.js +44 -11
- package/dist/preset.js +289 -33
- package/dist/styled-system/styles.css +3294 -1079
- 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 +40 -3
|
@@ -1,159 +1,215 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/*
|
|
3
3
|
* A record's path through its stages, and the work at the stage it is at. `StepDot` marks a
|
|
4
|
-
* step's status wherever one is listed; `StageStrip` is the path as one row of
|
|
5
|
-
* each a button that chooses its stage
|
|
6
|
-
*
|
|
4
|
+
* step's status wherever one is listed; `StageStrip` is the path as one row of stages joined by
|
|
5
|
+
* connectors, each a button that chooses its stage, and `PartsRollup` stands in for it on a record
|
|
6
|
+
* split into parts; `CurrentStep` is the attention row for the step the reader acts on, and
|
|
7
|
+
* `StepChain` the steps that follow from it, as `StepChip`s, and `HelpMenu` its ways forward when
|
|
8
|
+
* stuck; `Requirement` is one thing a stage needs and `StageChecklist` lists them per stage;
|
|
9
|
+
* `ParallelChip` is someone else's work under way; `ConfirmationRow` says a move landed.
|
|
7
10
|
*/
|
|
8
|
-
import {
|
|
11
|
+
import { Menu as BaseMenu } from "@base-ui/react/menu";
|
|
12
|
+
import { CaretDownIcon, CaretUpIcon, CheckIcon, SparkleIcon } from "@phosphor-icons/react";
|
|
9
13
|
import { css, cva, cx } from "#primitives/css";
|
|
10
14
|
import { Button } from "./button.js";
|
|
11
15
|
import { useControllableState } from "./controllable-state.js";
|
|
12
16
|
import { DateTime } from "./date-time.js";
|
|
17
|
+
import { HotkeyLayer } from "./hotkeys.js";
|
|
13
18
|
import { icon, Spinner } from "./icon.js";
|
|
14
19
|
import { Cluster, MutedText } from "./layout.js";
|
|
15
20
|
import { useCiridaeLocale } from "./locale.js";
|
|
16
21
|
import { Menu } from "./menu.js";
|
|
17
22
|
import { Popover } from "./overlays.js";
|
|
18
|
-
/*
|
|
23
|
+
/*
|
|
24
|
+
* Step dot: 16 on the strip, 14 on rows, 12 inside chips. A ring in its status's hue, solid or
|
|
25
|
+
* dashed, with a mark inside: a check on the green glass once done, a dot for the reader's step
|
|
26
|
+
* and the agent's, a bar for a blocked one. Waiting, ahead and locked are the ring alone.
|
|
27
|
+
*/
|
|
19
28
|
const stepDot = cva({
|
|
20
29
|
base: {
|
|
21
30
|
display: "inline-grid",
|
|
22
31
|
placeItems: "center",
|
|
23
32
|
flexShrink: "0",
|
|
24
33
|
borderRadius: "round",
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
borderStyle: "solid",
|
|
35
|
+
borderColor: "currentColor",
|
|
36
|
+
color: "fg.secondary",
|
|
27
37
|
lineHeight: "tight",
|
|
38
|
+
"&[data-status=waiting], &[data-status=agent]": { borderStyle: "dashed" },
|
|
28
39
|
},
|
|
29
40
|
variants: {
|
|
30
41
|
status: {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
// The green glass, its hairline drawn by the `[data-edge]` ring in place of the border.
|
|
43
|
+
done: {
|
|
44
|
+
borderWidth: "0!",
|
|
45
|
+
background: "token(gradients.stepDoneGlass)",
|
|
46
|
+
color: "fg.primary",
|
|
47
|
+
"--edge": "token(gradients.border.stepDoneGlass)",
|
|
48
|
+
_light: { color: "accent.green" },
|
|
49
|
+
},
|
|
50
|
+
current: { color: "accent.yellowIcon" },
|
|
51
|
+
waiting: { color: "fg.label" },
|
|
34
52
|
agent: { color: "accent.blue" },
|
|
35
53
|
blocked: { color: "accent.red" },
|
|
36
|
-
|
|
37
|
-
|
|
54
|
+
// The kit's Gray 50 ring in dark and Light Gray 66 in light; a locked one fades to half.
|
|
55
|
+
locked: { color: "border.control", opacity: "locked.step" },
|
|
56
|
+
todo: { color: "border.control" },
|
|
38
57
|
},
|
|
39
58
|
size: {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
// The kit's strokes per size: a 12px ring is 1.25 and an empty one 1.5; a 14px ring is 1,
|
|
60
|
+
// and 1.3125 for the dashed and blocked ones; a 16px ring is 1.5 throughout.
|
|
61
|
+
chip: {
|
|
62
|
+
"--step-dot-size": "token(sizes.avatar.micro)",
|
|
63
|
+
width: "avatar.micro",
|
|
64
|
+
height: "avatar.micro",
|
|
65
|
+
borderWidth: "1.25px",
|
|
66
|
+
fontSize: "icon.tiny",
|
|
67
|
+
"&:is([data-status=todo], [data-status=locked])": { borderWidth: "1.5px" },
|
|
68
|
+
},
|
|
69
|
+
small: {
|
|
70
|
+
"--step-dot-size": "token(sizes.control.knob)",
|
|
71
|
+
width: "control.knob",
|
|
72
|
+
height: "control.knob",
|
|
73
|
+
borderWidth: "1px",
|
|
74
|
+
fontSize: "icon.tiny",
|
|
75
|
+
"&:is([data-status=waiting], [data-status=agent], [data-status=blocked])": {
|
|
76
|
+
borderWidth: "1.3125px",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
medium: {
|
|
80
|
+
"--step-dot-size": "token(sizes.control.checkbox)",
|
|
81
|
+
width: "control.checkbox",
|
|
82
|
+
height: "control.checkbox",
|
|
83
|
+
borderWidth: "1.5px",
|
|
84
|
+
fontSize: "icon.check",
|
|
85
|
+
},
|
|
43
86
|
},
|
|
44
87
|
},
|
|
45
88
|
defaultVariants: { status: "todo", size: "medium" },
|
|
46
89
|
});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
90
|
+
// The marks inside, as shares of the dot so every size draws them alike: the kit's 7px centre in
|
|
91
|
+
// a 16px dot, measured across the whole dot rather than inside its ring.
|
|
92
|
+
const stepDotCenter = css({
|
|
93
|
+
width: "calc(var(--step-dot-size) * 0.4375)",
|
|
94
|
+
height: "calc(var(--step-dot-size) * 0.4375)",
|
|
95
|
+
borderRadius: "round",
|
|
96
|
+
background: "currentColor",
|
|
97
|
+
"[data-status=agent] > &": { width: "25%", height: "25%" },
|
|
98
|
+
});
|
|
99
|
+
const stepDotBar = css({
|
|
100
|
+
width: "44%",
|
|
101
|
+
height: "10%",
|
|
102
|
+
minHeight: "1px",
|
|
50
103
|
borderRadius: "round",
|
|
51
104
|
background: "currentColor",
|
|
52
105
|
});
|
|
53
106
|
/** A step's status as a dot; decorative, so the text beside it says the status. */
|
|
54
107
|
export function StepDot({ status, size = "medium", className, children, ...props }) {
|
|
55
|
-
return (_jsx("span", { "aria-hidden": "true", ...props, className: cx(stepDot({ status, size }), className), "data-ciridae-ui": "",
|
|
108
|
+
return (_jsx("span", { "aria-hidden": "true", ...props, className: cx(stepDot({ status, size }), className), "data-ciridae-ui": "", "data-edge": status === "done" ? "gradient" : undefined, "data-status": status, children: children ?? (_jsxs(_Fragment, { children: [status === "done" && _jsx(CheckIcon, { weight: "bold" }), (status === "current" || status === "agent") && _jsx("span", { className: stepDotCenter }), status === "blocked" && _jsx("span", { className: stepDotBar })] })) }));
|
|
56
109
|
}
|
|
57
110
|
/*
|
|
58
|
-
* Stage strip:
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
111
|
+
* Stage strip: the stages in one row, each its dot, name and meta, joined by connectors that
|
|
112
|
+
* stretch to fill the width, green out of a finished stage and grey ahead. The reader's stage is
|
|
113
|
+
* a warm pill, a blocked one a grey pill with its meta in red. Every stage is a button that
|
|
114
|
+
* chooses it. As the box narrows, metas go first, then every stage but the current and the chosen
|
|
115
|
+
* one folds to its dot. Past `maxVisible` the finished stages fold into one "N done" stage and the
|
|
116
|
+
* tail into a "+N" count, each listing its stages when pressed; the fold follows the current
|
|
117
|
+
* stage, never the choice, so a stage stays where it was clicked.
|
|
64
118
|
*/
|
|
65
119
|
const strip = css({
|
|
66
|
-
"--stage-arrow": "10px",
|
|
67
120
|
display: "flex",
|
|
68
|
-
alignItems: "
|
|
69
|
-
gap: "
|
|
121
|
+
alignItems: "center",
|
|
122
|
+
gap: "stage.connectorGap",
|
|
70
123
|
minWidth: "0",
|
|
71
|
-
height: "control.compact",
|
|
72
124
|
margin: "none",
|
|
73
125
|
padding: "none",
|
|
74
126
|
listStyle: "none",
|
|
75
127
|
containerType: "inline-size",
|
|
76
128
|
"@container (max-width: 720px)": { "& [data-stage-meta]": { display: "none" } },
|
|
77
129
|
"@container (max-width: 520px)": {
|
|
78
|
-
"& > li > :not([data-current], [aria-pressed=true])": {
|
|
79
|
-
|
|
80
|
-
"& [data-stage-label]": { display: "none" },
|
|
81
|
-
},
|
|
82
|
-
"& > li > [data-folded]": {
|
|
83
|
-
paddingInline: "calc(var(--stage-arrow) + token(spacing.layout.tightGap))",
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
"&[data-many]": {
|
|
87
|
-
// A folded run is a summary, so it takes only what its count needs.
|
|
88
|
-
"& > li > [data-run]": { flex: "0 0 auto" },
|
|
89
|
-
"@container (max-width: 1100px)": { "& [data-stage-meta]": { display: "none" } },
|
|
90
|
-
"@container (max-width: 480px)": {
|
|
91
|
-
"& > li > :not([data-current], [aria-pressed=true])": {
|
|
92
|
-
flex: "0 0 auto",
|
|
93
|
-
"& [data-stage-label]": { display: "none" },
|
|
94
|
-
},
|
|
130
|
+
"& > li > :not([data-current], [aria-pressed=true], [data-selected]) [data-stage-label]": {
|
|
131
|
+
display: "none",
|
|
95
132
|
},
|
|
96
133
|
},
|
|
97
134
|
});
|
|
98
135
|
const stripItem = css({ display: "contents" });
|
|
136
|
+
const connector = css({
|
|
137
|
+
flex: "1 1 0",
|
|
138
|
+
minWidth: "token(spacing.layout.controlGap)",
|
|
139
|
+
height: "border.hairline",
|
|
140
|
+
borderRadius: "round",
|
|
141
|
+
background: "border.divider",
|
|
142
|
+
"&[data-after=done]": { background: "accent.green" },
|
|
143
|
+
});
|
|
99
144
|
const stage = css({
|
|
100
145
|
display: "flex",
|
|
101
146
|
alignItems: "center",
|
|
102
|
-
justifyContent: "center",
|
|
103
147
|
gap: "control.iconGap",
|
|
104
|
-
flex: "
|
|
148
|
+
flex: "0 1 auto",
|
|
105
149
|
minWidth: "0",
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
150
|
+
paddingBlock: "panel.hairline",
|
|
151
|
+
paddingInline: "0",
|
|
152
|
+
border: "none",
|
|
153
|
+
borderRadius: "round",
|
|
154
|
+
background: "transparent",
|
|
155
|
+
color: "fg.primary",
|
|
156
|
+
font: "inherit",
|
|
113
157
|
fontSize: "caption",
|
|
114
158
|
fontWeight: "medium",
|
|
115
159
|
letterSpacing: "compact",
|
|
160
|
+
lineHeight: "tight",
|
|
116
161
|
whiteSpace: "nowrap",
|
|
117
|
-
|
|
118
|
-
"
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
162
|
+
cursor: "pointer",
|
|
163
|
+
"&[data-state=todo], &[data-state=locked]": { color: "fg.secondary" },
|
|
164
|
+
// The reader's stage and a blocked one are pills: the current stage's warm glass, and the
|
|
165
|
+
// selected glass in light, the red glass in dark. Their edge takes a pixel a side, as the kit's.
|
|
166
|
+
"&:is([data-state=current], [data-state=blocked])": {
|
|
167
|
+
paddingInlineStart: "control.block",
|
|
168
|
+
paddingInlineEnd: "control.iconInline",
|
|
169
|
+
border: "1px solid transparent",
|
|
124
170
|
},
|
|
125
|
-
"
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
clipPath: "polygon(0 0, 100% 0, 100% 100%, 0 100%, var(--stage-arrow) 50%)",
|
|
171
|
+
"&[data-state=current]": {
|
|
172
|
+
background: "token(gradients.currentStageGlass)",
|
|
173
|
+
color: "accent.yellow",
|
|
174
|
+
"--edge": "token(gradients.border.currentStageGlass)",
|
|
130
175
|
},
|
|
131
|
-
"&[data-state=
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
color: "fg.muted",
|
|
137
|
-
// The dot's own hairline grey vanishes on the segment's fill.
|
|
138
|
-
"& > :first-child": { color: "fg.muted" },
|
|
176
|
+
"&[data-state=blocked]": {
|
|
177
|
+
background: "token(gradients.dangerGlass)",
|
|
178
|
+
_light: { background: "token(gradients.selected)" },
|
|
179
|
+
"--edge": "token(gradients.border.raised)",
|
|
180
|
+
"& [data-stage-meta]": { color: "accent.red" },
|
|
139
181
|
},
|
|
140
|
-
//
|
|
182
|
+
// A stage under the pointer, focused or chosen takes a faint pill, reaching past a plain one.
|
|
183
|
+
"&:is(:hover, :focus-visible, [aria-pressed=true], [data-selected]):not([data-current])": {
|
|
184
|
+
background: "bg.rowHover",
|
|
185
|
+
boxShadow: "0 0 0 token(spacing.panel.hairline) token(colors.bg.rowHover)",
|
|
186
|
+
},
|
|
187
|
+
_focusVisible: { focusRing: "outer" },
|
|
188
|
+
});
|
|
189
|
+
const stageLabel = css({ overflow: "hidden", textOverflow: "ellipsis" });
|
|
190
|
+
const stageMeta = css({
|
|
191
|
+
flexShrink: "0",
|
|
192
|
+
color: "fg.label",
|
|
193
|
+
fontSize: "code",
|
|
194
|
+
"[data-state=current] > &": { color: "inherit" },
|
|
195
|
+
});
|
|
196
|
+
// The tail past the fold: a quiet count that lists the stages it stands for.
|
|
197
|
+
const moreStages = css({
|
|
198
|
+
flexShrink: "0",
|
|
199
|
+
padding: "none",
|
|
141
200
|
border: "none",
|
|
201
|
+
borderRadius: "control",
|
|
202
|
+
background: "transparent",
|
|
203
|
+
color: "fg.subtle",
|
|
142
204
|
font: "inherit",
|
|
205
|
+
fontSize: "code",
|
|
206
|
+
fontWeight: "medium",
|
|
207
|
+
lineHeight: "tight",
|
|
208
|
+
whiteSpace: "nowrap",
|
|
143
209
|
cursor: "pointer",
|
|
144
|
-
_hover: {
|
|
145
|
-
_focusVisible: {
|
|
146
|
-
"&[aria-pressed=true]": { boxShadow: "inset 0 0 0 999px token(colors.bg.rowHover)" },
|
|
147
|
-
// A chosen stage ahead has no fill of its own, so its text lifts to show the choice.
|
|
148
|
-
"&[aria-pressed=true]:is([data-state=todo], [data-state=locked])": {
|
|
149
|
-
color: "fg.primary",
|
|
150
|
-
"& > :first-child": { color: "fg.primary" },
|
|
151
|
-
},
|
|
210
|
+
_hover: { color: "fg.primary" },
|
|
211
|
+
_focusVisible: { focusRing: "outer" },
|
|
152
212
|
});
|
|
153
|
-
const stageLabel = css({ overflow: "hidden", textOverflow: "ellipsis" });
|
|
154
|
-
const stageMeta = css({ flexShrink: "0", opacity: "0.7", fontSize: "code" });
|
|
155
|
-
/* A folded run's dot carries its count instead of an icon. */
|
|
156
|
-
const countDot = css({ fontSize: "icon.tiny", fontWeight: "medium", lineHeight: "1" });
|
|
157
213
|
/** The stage a record is at: the first neither done nor ahead, else the last done, else the first. */
|
|
158
214
|
export function currentStageIndex(stages) {
|
|
159
215
|
const active = stages.findIndex((item) => item.status !== "done" && item.status !== "todo" && item.status !== "locked");
|
|
@@ -162,33 +218,21 @@ export function currentStageIndex(stages) {
|
|
|
162
218
|
const lastDone = stages.map((item) => item.status).lastIndexOf("done");
|
|
163
219
|
return lastDone >= 0 ? lastDone : 0;
|
|
164
220
|
}
|
|
165
|
-
/**
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
run = [];
|
|
181
|
-
};
|
|
182
|
-
stages.forEach((stage, index) => {
|
|
183
|
-
if (kept.has(index)) {
|
|
184
|
-
closeRun();
|
|
185
|
-
items.push({ kind: "stage", stage, index });
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
run.push(index);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
closeRun();
|
|
221
|
+
/**
|
|
222
|
+
* The strip's items: every stage, or past `maxVisible` the stages before the current one folded
|
|
223
|
+
* into one, then as many as fit, then the rest as a count.
|
|
224
|
+
*/
|
|
225
|
+
function stripItems(stages, maxVisible, currentIndex) {
|
|
226
|
+
const all = stages.map((stage, index) => ({ kind: "stage", stage, index }));
|
|
227
|
+
if (stages.length <= maxVisible)
|
|
228
|
+
return all;
|
|
229
|
+
const before = stages.slice(0, currentIndex).map((_, index) => index);
|
|
230
|
+
const items = before.length > 1 ? [{ kind: "done", indices: before }] : all.slice(0, currentIndex);
|
|
231
|
+
const room = Math.max(maxVisible - items.length - 1, 1);
|
|
232
|
+
items.push(...all.slice(currentIndex, currentIndex + room));
|
|
233
|
+
const rest = stages.slice(currentIndex + room).map((_, offset) => currentIndex + room + offset);
|
|
234
|
+
if (rest.length > 0)
|
|
235
|
+
items.push({ kind: "more", indices: rest });
|
|
192
236
|
return items;
|
|
193
237
|
}
|
|
194
238
|
export function StageStrip({ stages, value, defaultValue, onValueChange, maxVisible = 7, className, ...props }) {
|
|
@@ -197,16 +241,32 @@ export function StageStrip({ stages, value, defaultValue, onValueChange, maxVisi
|
|
|
197
241
|
const [chosen, setChosen] = useControllableState(value, defaultValue ?? stages[currentIndex]?.id ?? "", onValueChange);
|
|
198
242
|
const chosenIndex = stages.findIndex((item) => item.id === chosen);
|
|
199
243
|
const selectedIndex = chosenIndex >= 0 ? chosenIndex : currentIndex;
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
244
|
+
const menuItems = (indices) => indices.map((index) => ({
|
|
245
|
+
label: stages[index].label,
|
|
246
|
+
icon: _jsx(StepDot, { status: stages[index].status, size: "small" }),
|
|
247
|
+
checked: index === selectedIndex,
|
|
248
|
+
onSelect: () => setChosen(stages[index].id),
|
|
249
|
+
}));
|
|
250
|
+
const items = stripItems(stages, maxVisible, currentIndex);
|
|
251
|
+
return (_jsx("ol", { "aria-label": labels.record.stages, ...props, className: cx(strip, className), "data-ciridae-ui": "", children: items.map((item, position) => {
|
|
252
|
+
const next = items[position + 1];
|
|
253
|
+
const join = next !== undefined && next.kind !== "more" && (_jsx("span", { className: connector, "aria-hidden": "true", "data-after": item.kind === "done" || (item.kind === "stage" && item.stage.status === "done")
|
|
254
|
+
? "done"
|
|
255
|
+
: undefined }));
|
|
256
|
+
if (item.kind === "stage")
|
|
257
|
+
return (_jsxs("li", { className: stripItem, children: [_jsxs("button", { type: "button", className: stage, "data-ciridae-ui": "", "data-edge": item.stage.status === "current" || item.stage.status === "blocked"
|
|
258
|
+
? "gradient"
|
|
259
|
+
: undefined, "data-state": item.stage.status, "data-current": item.index === currentIndex || undefined, title: item.stage.label, "aria-current": item.index === currentIndex ? "step" : undefined, "aria-pressed": item.index === selectedIndex, onClick: () => setChosen(item.stage.id), children: [_jsx(StepDot, { status: item.stage.status }), _jsx("span", { className: stageLabel, "data-stage-label": "", children: item.stage.label }), item.stage.meta && (_jsx("span", { className: stageMeta, "data-stage-meta": "", children: item.stage.meta }))] }), join] }, item.stage.id));
|
|
260
|
+
if (item.kind === "done")
|
|
261
|
+
return (_jsxs("li", { className: stripItem, children: [_jsx(Menu, { trigger: _jsxs("button", { type: "button", className: stage, "data-state": "done", "aria-label": labels.record.runDoneLabel(item.indices.length), "data-selected": item.indices.includes(selectedIndex) || undefined, children: [_jsx(StepDot, { status: "done" }), _jsx("span", { className: stageLabel, "data-stage-label": "", children: labels.record.runDoneShort(item.indices.length) })] }), items: menuItems(item.indices) }), join] }, "done"));
|
|
262
|
+
return (_jsx("li", { className: stripItem, children: _jsx(Menu, { trigger: _jsx("button", { type: "button", className: moreStages, "aria-label": labels.record.runToGoLabel(item.indices.length), "data-selected": item.indices.includes(selectedIndex) || undefined, children: labels.common.moreCount(item.indices.length) }), items: menuItems(item.indices) }) }, "more"));
|
|
263
|
+
}) }));
|
|
208
264
|
}
|
|
209
|
-
/*
|
|
265
|
+
/*
|
|
266
|
+
* Current step: the attention row, with the inner card when expanded. Light paints the reader's
|
|
267
|
+
* move, a ready step and a stuck one in their solid tint, dark in their hue's glass. The row sets
|
|
268
|
+
* `--step-edge`, the hairline it and its card draw, in the tint's edge; the grey glass's otherwise.
|
|
269
|
+
*/
|
|
210
270
|
const attentionRow = cva({
|
|
211
271
|
base: {
|
|
212
272
|
// The step card stacks by its own width, so a narrow record column stacks it as a phone does.
|
|
@@ -214,17 +274,73 @@ const attentionRow = cva({
|
|
|
214
274
|
display: "grid",
|
|
215
275
|
gap: "layout.tightGap",
|
|
216
276
|
padding: "layout.tightGap",
|
|
217
|
-
border: "1px solid
|
|
277
|
+
border: "1px solid transparent",
|
|
218
278
|
borderRadius: "action",
|
|
219
|
-
|
|
279
|
+
"--step-edge": "token(gradients.border.raised)",
|
|
280
|
+
"--edge": "var(--step-edge)",
|
|
220
281
|
},
|
|
221
282
|
variants: {
|
|
222
283
|
tone: {
|
|
223
|
-
warning: {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
284
|
+
warning: {
|
|
285
|
+
background: "token(gradients.tinted)",
|
|
286
|
+
"--step-edge": "token(gradients.border.warningTint)",
|
|
287
|
+
_light: { background: "bg.warningTint" },
|
|
288
|
+
},
|
|
289
|
+
success: {
|
|
290
|
+
background: "token(gradients.successGlass)",
|
|
291
|
+
"--step-edge": "token(gradients.border.successTint)",
|
|
292
|
+
_light: { background: "bg.successTint" },
|
|
293
|
+
},
|
|
294
|
+
info: {
|
|
295
|
+
background: "token(gradients.infoGlass)",
|
|
296
|
+
"--step-edge": "token(gradients.border.infoGlass)",
|
|
297
|
+
},
|
|
298
|
+
// Waiting: the raised glass in dark; in light the grey well inside a flat divider hairline.
|
|
299
|
+
neutral: {
|
|
300
|
+
background: "token(gradients.raised)",
|
|
301
|
+
_light: {
|
|
302
|
+
background: "bg.field",
|
|
303
|
+
"--step-edge": "linear-gradient(token(colors.border.divider), token(colors.border.divider))",
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
danger: {
|
|
307
|
+
background: "token(gradients.dangerGlass)",
|
|
308
|
+
"--step-edge": "token(gradients.border.errorTint)",
|
|
309
|
+
_light: { background: "bg.errorTint" },
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
/*
|
|
315
|
+
* The fold toggle at the header's end: a 24px round button in its hue's glass. In dark it takes
|
|
316
|
+
* the row's edge; in light the yellow and red ones keep their glass's own, softer than the tint's.
|
|
317
|
+
*/
|
|
318
|
+
const collapseToggle = cva({
|
|
319
|
+
base: {
|
|
320
|
+
display: "inline-grid",
|
|
321
|
+
placeItems: "center",
|
|
322
|
+
flexShrink: "0",
|
|
323
|
+
width: "control.shortcut",
|
|
324
|
+
height: "control.shortcut",
|
|
325
|
+
borderRadius: "round",
|
|
326
|
+
background: "token(gradients.raised)",
|
|
327
|
+
color: "fg.primary",
|
|
328
|
+
"--edge": "var(--step-edge)",
|
|
329
|
+
},
|
|
330
|
+
variants: {
|
|
331
|
+
tone: {
|
|
332
|
+
warning: {
|
|
333
|
+
background: "token(gradients.tinted)",
|
|
334
|
+
_light: { "--edge": "token(gradients.border.tinted)" },
|
|
335
|
+
},
|
|
336
|
+
success: { background: "token(gradients.successGlass)" },
|
|
337
|
+
info: { background: "token(gradients.infoGlass)" },
|
|
338
|
+
// The grey toggle keeps the raised glass's edge where its row draws a flat hairline.
|
|
339
|
+
neutral: { _light: { "--edge": "token(gradients.border.raised)" } },
|
|
340
|
+
danger: {
|
|
341
|
+
background: "token(gradients.dangerGlass)",
|
|
342
|
+
_light: { "--edge": "token(gradients.border.dangerGlass)" },
|
|
343
|
+
},
|
|
228
344
|
},
|
|
229
345
|
},
|
|
230
346
|
});
|
|
@@ -245,21 +361,26 @@ const attentionHeader = css({
|
|
|
245
361
|
fontSize: "code",
|
|
246
362
|
fontWeight: "medium",
|
|
247
363
|
letterSpacing: "compact",
|
|
364
|
+
lineHeight: "tight",
|
|
248
365
|
"&[data-tone=warning]": { color: "accent.yellow" },
|
|
249
366
|
"&[data-tone=success]": { color: "accent.green" },
|
|
250
367
|
"&[data-tone=info]": { color: "accent.blue" },
|
|
251
|
-
"&[data-tone=neutral]": { color: "fg.
|
|
252
|
-
|
|
368
|
+
"&[data-tone=neutral]": { color: "fg.secondary" },
|
|
369
|
+
// A stuck step's header is the muted red the kit gives red text on its tint.
|
|
370
|
+
"&[data-tone=danger]": { color: "accent.redDark" },
|
|
253
371
|
});
|
|
372
|
+
// The card holds the step on the page's own face: the solid card in light, the panel in dark.
|
|
254
373
|
const attentionCard = css({
|
|
255
374
|
display: "flex",
|
|
256
375
|
alignItems: "center",
|
|
257
376
|
justifyContent: "space-between",
|
|
258
377
|
gap: "layout.clusterGap",
|
|
259
378
|
padding: "panel.default",
|
|
260
|
-
border: "1px solid
|
|
379
|
+
border: "1px solid transparent",
|
|
261
380
|
borderRadius: "control",
|
|
262
381
|
background: "bg.panel",
|
|
382
|
+
_light: { background: "bg.card" },
|
|
383
|
+
"--edge": "var(--step-edge)",
|
|
263
384
|
"@container (max-width: 560px)": { flexDirection: "column", alignItems: "stretch" },
|
|
264
385
|
_phone: { padding: "panel.compact" },
|
|
265
386
|
});
|
|
@@ -278,6 +399,7 @@ const attentionDescription = css({
|
|
|
278
399
|
color: "fg.secondary",
|
|
279
400
|
fontSize: "code",
|
|
280
401
|
fontWeight: "medium",
|
|
402
|
+
lineHeight: "body",
|
|
281
403
|
marginTop: "layout.tightGap",
|
|
282
404
|
});
|
|
283
405
|
const toneStatus = {
|
|
@@ -293,31 +415,116 @@ function StepActionButton({ action, variant, }) {
|
|
|
293
415
|
return button;
|
|
294
416
|
return (_jsx(Popover, { trigger: button, open: action.popover.open, onOpenChange: action.popover.onOpenChange, children: action.popover.content }));
|
|
295
417
|
}
|
|
418
|
+
/*
|
|
419
|
+
* Help menu: the ways forward a stuck step offers behind "Not sure?", on the popover's glass. A
|
|
420
|
+
* header says what the menu is for; each option is an icon on the raised tile, a title and a line
|
|
421
|
+
* on what it does.
|
|
422
|
+
*/
|
|
423
|
+
const helpPopup = css({
|
|
424
|
+
display: "grid",
|
|
425
|
+
width: "overlay.helpMenu",
|
|
426
|
+
maxWidth: "calc(100vw - token(spacing.panel.roomy))",
|
|
427
|
+
padding: "menu.inset",
|
|
428
|
+
border: "1px solid token(colors.border.divider)",
|
|
429
|
+
borderRadius: "action",
|
|
430
|
+
background: "bg.popover",
|
|
431
|
+
backdropFilter: "blur(token(blurs.popover))",
|
|
432
|
+
boxShadow: "soft",
|
|
433
|
+
color: "fg.primary",
|
|
434
|
+
fontWeight: "medium",
|
|
435
|
+
letterSpacing: "compact",
|
|
436
|
+
outline: "none",
|
|
437
|
+
});
|
|
438
|
+
const helpHeader = css({
|
|
439
|
+
display: "grid",
|
|
440
|
+
gap: "control.trackInset",
|
|
441
|
+
paddingBlock: "control.block",
|
|
442
|
+
paddingInline: "control.compactInline",
|
|
443
|
+
fontSize: "caption",
|
|
444
|
+
lineHeight: "tight",
|
|
445
|
+
});
|
|
446
|
+
const helpDetail = css({ color: "fg.subtle", fontSize: "code", lineHeight: "body" });
|
|
447
|
+
const helpOption = css({
|
|
448
|
+
display: "flex",
|
|
449
|
+
alignItems: "center",
|
|
450
|
+
gap: "layout.controlGap",
|
|
451
|
+
paddingBlock: "control.block",
|
|
452
|
+
paddingInline: "control.compactInline",
|
|
453
|
+
borderRadius: "control",
|
|
454
|
+
cursor: "pointer",
|
|
455
|
+
outline: "none",
|
|
456
|
+
"&[data-highlighted]": { background: "token(gradients.selected)" },
|
|
457
|
+
});
|
|
458
|
+
const helpTile = css({
|
|
459
|
+
display: "grid",
|
|
460
|
+
placeItems: "center",
|
|
461
|
+
flexShrink: "0",
|
|
462
|
+
width: "control.roundSmall",
|
|
463
|
+
height: "control.roundSmall",
|
|
464
|
+
borderRadius: "action",
|
|
465
|
+
background: "token(gradients.raised)",
|
|
466
|
+
fontSize: "icon.small",
|
|
467
|
+
"--edge": "token(gradients.border.raised)",
|
|
468
|
+
});
|
|
469
|
+
const helpCopy = css({ display: "grid", gap: "control.trackInset", minWidth: "0" });
|
|
470
|
+
const helpTitle = css({ fontSize: "caption", lineHeight: "tight" });
|
|
471
|
+
export function HelpMenu({ trigger, title, detail, options }) {
|
|
472
|
+
return (_jsxs(BaseMenu.Root, { children: [_jsx(BaseMenu.Trigger, { render: trigger }), _jsx(BaseMenu.Portal, { children: _jsx(HotkeyLayer, { children: _jsx(BaseMenu.Positioner, { className: css({ zIndex: "popover" }), sideOffset: 6, align: "end", children: _jsxs(BaseMenu.Popup, { className: helpPopup, "data-ciridae-ui": "", children: [_jsxs("div", { className: helpHeader, role: "presentation", children: [title, detail !== undefined && _jsx("span", { className: helpDetail, children: detail })] }), options.map((option) => (_jsxs(BaseMenu.Item, { className: helpOption, onClick: option.onSelect, children: [option.icon && (_jsx("span", { className: helpTile, "data-ciridae-ui": "", "data-edge": "gradient", children: option.icon })), _jsxs("span", { className: helpCopy, children: [_jsx("span", { className: helpTitle, children: option.label }), option.detail && _jsx("span", { className: helpDetail, children: option.detail })] })] }, option.label)))] }) }) }) })] }));
|
|
473
|
+
}
|
|
296
474
|
/** The step the reader acts on: a tinted header that folds the card with its title and actions. */
|
|
297
475
|
export function CurrentStep({ tone, meta, title, description, primary, secondary, help, busy = false, expanded: ownExpanded, defaultExpanded = true, onExpandedChange, className, ...props }) {
|
|
298
476
|
const { labels } = useCiridaeLocale();
|
|
299
477
|
const [expanded, setExpanded] = useControllableState(ownExpanded, defaultExpanded, onExpandedChange);
|
|
300
|
-
return (_jsxs("div", { ...props, className: cx(attentionRow({ tone }), className), "data-ciridae-ui": "", children: [_jsxs("button", { type: "button", className: attentionHeader, "data-tone": tone, "aria-expanded": expanded, onClick: () => setExpanded(!expanded), children: [busy ? (_jsx(Spinner, { size: "compact", "aria-hidden": "true" })) : (_jsx(StepDot, { status: toneStatus[tone], size: "small" })), _jsx("span", { className: css({ flex: "1" }), children: meta }), expanded ? (_jsx(CaretUpIcon, { className: icon({ size: "compact" }) })) : (_jsx(CaretDownIcon, { className: icon({ size: "compact" }) }))] }), expanded && (_jsxs("div", { className: attentionCard, children: [_jsxs("div", { className: css({ minWidth: "0" }), children: [_jsx("div", { className: attentionTitle, children: title }), description !== undefined && _jsx("div", { className: attentionDescription, children: description })] }), (help || secondary || primary) && (_jsxs(Cluster, { gap: "4", className: stepActions, children: [help && (_jsx(
|
|
478
|
+
return (_jsxs("div", { ...props, className: cx(attentionRow({ tone }), className), "data-ciridae-ui": "", "data-edge": "gradient", children: [_jsxs("button", { type: "button", className: attentionHeader, "data-tone": tone, "aria-expanded": expanded, onClick: () => setExpanded(!expanded), children: [busy ? (_jsx(Spinner, { size: "compact", "aria-hidden": "true" })) : (_jsx(StepDot, { status: toneStatus[tone], size: "small" })), _jsx("span", { className: css({ flex: "1" }), children: meta }), _jsx("span", { className: collapseToggle({ tone }), "data-ciridae-ui": "", "data-edge": "gradient", children: expanded ? (_jsx(CaretUpIcon, { className: icon({ size: "compact" }) })) : (_jsx(CaretDownIcon, { className: icon({ size: "compact" }) })) })] }), expanded && (_jsxs("div", { className: attentionCard, "data-ciridae-ui": "", "data-edge": "gradient", children: [_jsxs("div", { className: css({ minWidth: "0" }), children: [_jsx("div", { className: attentionTitle, children: title }), description !== undefined && _jsx("div", { className: attentionDescription, children: description })] }), (help || secondary || primary) && (_jsxs(Cluster, { gap: "4", className: stepActions, children: [help && (_jsx(HelpMenu, { ...help, trigger: _jsx(Button, { variant: "ghost", children: labels.record.notSure }) })), secondary && (_jsx(StepActionButton, { action: secondary, variant: tone === "warning" ? "tinted" : "secondary" })), primary && _jsx(StepActionButton, { action: primary, variant: "primary" })] }))] }))] }));
|
|
301
479
|
}
|
|
302
|
-
/* Confirmation row. */
|
|
480
|
+
/* Confirmation row: the ready step's green, one 32px line inside a 4px inset. */
|
|
303
481
|
const confirmation = css({
|
|
304
482
|
display: "flex",
|
|
305
483
|
alignItems: "center",
|
|
306
484
|
gap: "control.iconGap",
|
|
307
|
-
minHeight: "control.
|
|
485
|
+
minHeight: "calc(token(sizes.control.compact) + token(spacing.panel.hairline) * 2)",
|
|
486
|
+
padding: "panel.hairline",
|
|
308
487
|
paddingInlineStart: "control.compactInline",
|
|
309
|
-
|
|
310
|
-
border: "1px solid token(colors.border.glass)",
|
|
488
|
+
border: "1px solid transparent",
|
|
311
489
|
borderRadius: "action",
|
|
312
|
-
background: "
|
|
490
|
+
background: "token(gradients.successGlass)",
|
|
313
491
|
color: "accent.green",
|
|
314
492
|
fontSize: "code",
|
|
315
493
|
fontWeight: "medium",
|
|
494
|
+
lineHeight: "tight",
|
|
495
|
+
"--edge": "token(gradients.border.successTint)",
|
|
496
|
+
_light: { background: "bg.successTint" },
|
|
316
497
|
});
|
|
317
498
|
/** A move that just landed, with when and an undo. */
|
|
318
499
|
export function ConfirmationRow({ message, at, onUndo, labels: ownLabels, className, ...props }) {
|
|
319
500
|
const labels = { ...useCiridaeLocale().labels.record, ...ownLabels };
|
|
320
|
-
return (_jsxs("div", { role: "status", ...props, className: cx(confirmation, className), "data-ciridae-ui": "", children: [_jsx(StepDot, { status: "done", size: "small" }), _jsx("span", { className: css({ flex: "1" }), children: message }), _jsx(MutedText, { children: _jsx(DateTime, { value: at }) }), onUndo && (_jsx(Button, { variant: "secondary", onClick: onUndo, children: labels.undo }))] }));
|
|
501
|
+
return (_jsxs("div", { role: "status", ...props, className: cx(confirmation, className), "data-ciridae-ui": "", "data-edge": "gradient", children: [_jsx(StepDot, { status: "done", size: "small" }), _jsx("span", { className: css({ flex: "1" }), children: message }), _jsx(MutedText, { children: _jsx(DateTime, { value: at }) }), onUndo && (_jsx(Button, { variant: "secondary", size: "small", onClick: onUndo, children: labels.undo }))] }));
|
|
502
|
+
}
|
|
503
|
+
/*
|
|
504
|
+
* Requirement: one thing a stage needs, as its 12px dot, its 13px name and a muted meta. A done
|
|
505
|
+
* one steps back to the muted grey; a locked one fades, so what is coming stays in view; a
|
|
506
|
+
* dependent one indents under the step it waits on.
|
|
507
|
+
*/
|
|
508
|
+
const requirement = css({
|
|
509
|
+
display: "inline-flex",
|
|
510
|
+
alignItems: "center",
|
|
511
|
+
gap: "control.iconGap",
|
|
512
|
+
minWidth: "0",
|
|
513
|
+
color: "fg.primary",
|
|
514
|
+
fontSize: "caption",
|
|
515
|
+
fontWeight: "medium",
|
|
516
|
+
letterSpacing: "compact",
|
|
517
|
+
lineHeight: "tight",
|
|
518
|
+
"&[data-status=done]": { color: "fg.subtle" },
|
|
519
|
+
// The row fades as a whole, so its dot does not fade a second time.
|
|
520
|
+
"&[data-status=locked]": { opacity: "locked.requirement", "& > [data-status]": { opacity: "1" } },
|
|
521
|
+
"&[data-nested]": {
|
|
522
|
+
paddingInlineStart: "calc(token(sizes.avatar.micro) + token(spacing.control.iconGap))",
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
const requirementMeta = css({ flexShrink: "0", color: "fg.subtle", fontSize: "code" });
|
|
526
|
+
export function Requirement({ status, meta, nested = false, children, className, ...props }) {
|
|
527
|
+
return (_jsxs("span", { ...props, className: cx(requirement, className), "data-ciridae-ui": "", "data-status": status, "data-nested": nested || undefined, children: [_jsx(StepDot, { status: status, size: "chip" }), _jsx("span", { className: css({ minWidth: "0" }), children: children }), meta !== undefined && _jsx("span", { className: requirementMeta, children: meta })] }));
|
|
321
528
|
}
|
|
322
529
|
/* Stage checklists: what each stage needs, needed or will need, as plain rows under its label. */
|
|
323
530
|
const checklist = css({
|
|
@@ -340,26 +547,175 @@ const checklistHeading = css({
|
|
|
340
547
|
fontWeight: "medium",
|
|
341
548
|
});
|
|
342
549
|
const checklistList = css({ display: "grid", margin: "none", padding: "none", listStyle: "none" });
|
|
343
|
-
const checklistRow = css({
|
|
550
|
+
const checklistRow = css({ display: "flex", alignItems: "center", minHeight: "control.shortcut" });
|
|
551
|
+
/** Checklists side by side, each under its label with its meta or how many of its steps are done. */
|
|
552
|
+
export function StageChecklist({ groups, className, ...props }) {
|
|
553
|
+
const { labels } = useCiridaeLocale();
|
|
554
|
+
return (_jsx("div", { ...props, className: cx(checklist, className), "data-ciridae-ui": "", children: groups.map(({ id, label, meta, steps }) => {
|
|
555
|
+
const done = steps.filter((step) => step.status === "done").length;
|
|
556
|
+
return (_jsxs("section", { className: checklistGroup, children: [_jsxs("h3", { className: checklistHeading, children: [label, _jsx("span", { children: meta ?? (steps.length > 0 && labels.record.checklistProgress(done, steps.length)) })] }), _jsx("ul", { className: checklistList, children: steps.map((step, index) => (_jsx("li", { className: checklistRow, children: _jsx(Requirement, { status: step.status, meta: step.meta, nested: step.nested, children: step.label }) }, step.id ?? index))) })] }, id));
|
|
557
|
+
}) }));
|
|
558
|
+
}
|
|
559
|
+
const stepChip = css({
|
|
560
|
+
display: "inline-flex",
|
|
561
|
+
alignItems: "center",
|
|
562
|
+
gap: "control.iconGap",
|
|
563
|
+
flexShrink: "0",
|
|
564
|
+
height: "control.chip",
|
|
565
|
+
paddingInlineStart: "control.iconGap",
|
|
566
|
+
paddingInlineEnd: "control.block",
|
|
567
|
+
border: "1px solid transparent",
|
|
568
|
+
borderRadius: "pill",
|
|
569
|
+
background: "token(gradients.raised)",
|
|
570
|
+
boxShadow: "soft",
|
|
571
|
+
color: "fg.label",
|
|
572
|
+
fontSize: "code",
|
|
573
|
+
fontWeight: "medium",
|
|
574
|
+
letterSpacing: "compact",
|
|
575
|
+
lineHeight: "tight",
|
|
576
|
+
whiteSpace: "nowrap",
|
|
577
|
+
"--edge": "token(gradients.border.raised)",
|
|
578
|
+
"&[data-status=done]": { color: "accent.green" },
|
|
579
|
+
"&[data-status=current]": { color: "accent.yellow" },
|
|
580
|
+
"&[data-status=agent]": {
|
|
581
|
+
height: "control.shortcut",
|
|
582
|
+
color: "accent.blue",
|
|
583
|
+
"& > [data-label]": {
|
|
584
|
+
background: "token(gradients.chart.progress)",
|
|
585
|
+
backgroundClip: "text",
|
|
586
|
+
color: "transparent",
|
|
587
|
+
},
|
|
588
|
+
"& > svg": { fontSize: "icon.small" },
|
|
589
|
+
},
|
|
590
|
+
});
|
|
591
|
+
export function StepChip({ status, children, className, ...props }) {
|
|
592
|
+
return (_jsxs("span", { ...props, className: cx(stepChip, className), "data-ciridae-ui": "", "data-edge": "gradient", "data-status": status, children: [status === "agent" ? (_jsx(SparkleIcon, { weight: "fill", "aria-hidden": "true" })) : (_jsx(StepDot, { status: status, size: "chip" })), _jsx("span", { "data-label": "", children: children })] }));
|
|
593
|
+
}
|
|
594
|
+
/*
|
|
595
|
+
* Step chain: the steps that follow from the expanded step, one row a lead: a tree line from the
|
|
596
|
+
* step above, the lead's dot and words, then its steps as chips, each joined to the one before by
|
|
597
|
+
* a short link in that one's hue: green after a done step, yellow after the current, grey ahead.
|
|
598
|
+
*/
|
|
599
|
+
const stepChain = css({
|
|
600
|
+
display: "flex",
|
|
601
|
+
alignItems: "flex-end",
|
|
602
|
+
gap: "layout.tightGap",
|
|
603
|
+
height: "control.compact",
|
|
604
|
+
paddingInline: "control.iconGap",
|
|
605
|
+
minWidth: "0",
|
|
606
|
+
});
|
|
607
|
+
// An L from the step above down to the lead, its corner rounded.
|
|
608
|
+
const chainTree = css({
|
|
609
|
+
flexShrink: "0",
|
|
610
|
+
alignSelf: "flex-start",
|
|
611
|
+
width: "9px",
|
|
612
|
+
height: "calc(100% - token(spacing.panel.default) + 1px)",
|
|
613
|
+
borderInlineStart: "1px solid token(colors.border.divider)",
|
|
614
|
+
borderBottom: "1px solid token(colors.border.divider)",
|
|
615
|
+
borderEndStartRadius: "keycap",
|
|
616
|
+
});
|
|
617
|
+
const chainItems = css({
|
|
344
618
|
display: "flex",
|
|
345
619
|
alignItems: "center",
|
|
346
620
|
gap: "control.iconGap",
|
|
347
|
-
|
|
348
|
-
|
|
621
|
+
height: "control.chip",
|
|
622
|
+
minWidth: "0",
|
|
623
|
+
overflow: "hidden",
|
|
624
|
+
});
|
|
625
|
+
const chainLead = css({
|
|
626
|
+
flexShrink: "0",
|
|
349
627
|
fontSize: "code",
|
|
350
628
|
fontWeight: "medium",
|
|
351
629
|
letterSpacing: "compact",
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
"&[data-status=
|
|
356
|
-
"&[data-status=
|
|
630
|
+
lineHeight: "tight",
|
|
631
|
+
whiteSpace: "nowrap",
|
|
632
|
+
color: "fg.label",
|
|
633
|
+
"&[data-status=done]": { color: "accent.green" },
|
|
634
|
+
"&[data-status=current]": { color: "accent.yellow" },
|
|
357
635
|
});
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
636
|
+
const chainLink = css({
|
|
637
|
+
flexShrink: "0",
|
|
638
|
+
width: "token(spacing.control.compactInline)",
|
|
639
|
+
height: "border.hairline",
|
|
640
|
+
background: "border.divider",
|
|
641
|
+
"&[data-after=done]": { background: "accent.green" },
|
|
642
|
+
"&[data-after=current]": { background: "accent.yellowIcon" },
|
|
643
|
+
});
|
|
644
|
+
export function StepChain({ lead, steps, className, ...props }) {
|
|
645
|
+
return (_jsxs("div", { ...props, className: cx(stepChain, className), "data-ciridae-ui": "", children: [_jsx("span", { className: chainTree, "aria-hidden": "true" }), _jsxs("span", { className: chainItems, children: [_jsx(StepDot, { status: lead.status, size: "small" }), _jsx("span", { className: chainLead, "data-status": lead.status, children: lead.label }), steps.map((step, index) => (_jsxs("span", { className: css({ display: "contents" }), children: [_jsx("span", { className: chainLink, "aria-hidden": "true", "data-after": index === 0 ? lead.status : steps[index - 1].status }), _jsx(StepChip, { status: step.status, children: step.label })] }, step.id)))] })] }));
|
|
646
|
+
}
|
|
647
|
+
/*
|
|
648
|
+
* Parallel chip: someone else's work under way beside the reader's, on the selected glass. A
|
|
649
|
+
* person shows their avatar, the agent its dashed blue dot, the system a dashed grey one; then
|
|
650
|
+
* who, what they are doing, and at most one action.
|
|
651
|
+
*/
|
|
652
|
+
const parallelChip = css({
|
|
653
|
+
display: "inline-flex",
|
|
654
|
+
alignItems: "center",
|
|
655
|
+
gap: "layout.controlGap",
|
|
656
|
+
minWidth: "0",
|
|
657
|
+
paddingBlock: "control.compactBlock",
|
|
658
|
+
paddingInlineStart: "control.block",
|
|
659
|
+
paddingInlineEnd: "control.compactInline",
|
|
660
|
+
border: "1px solid transparent",
|
|
661
|
+
borderRadius: "shell",
|
|
662
|
+
background: "token(gradients.selected)",
|
|
663
|
+
fontWeight: "medium",
|
|
664
|
+
letterSpacing: "compact",
|
|
665
|
+
lineHeight: "tight",
|
|
666
|
+
whiteSpace: "nowrap",
|
|
667
|
+
"--edge": "token(gradients.border.selected)",
|
|
668
|
+
});
|
|
669
|
+
const parallelWho = css({ color: "fg.primary", fontSize: "caption" });
|
|
670
|
+
const parallelDoing = css({
|
|
671
|
+
minWidth: "0",
|
|
672
|
+
overflow: "hidden",
|
|
673
|
+
textOverflow: "ellipsis",
|
|
674
|
+
color: "fg.subtle",
|
|
675
|
+
fontSize: "code",
|
|
676
|
+
});
|
|
677
|
+
const parallelAction = css({
|
|
678
|
+
padding: "none",
|
|
679
|
+
border: "none",
|
|
680
|
+
borderRadius: "control",
|
|
681
|
+
background: "transparent",
|
|
682
|
+
color: "accent.blue",
|
|
683
|
+
font: "inherit",
|
|
684
|
+
fontSize: "caption",
|
|
685
|
+
cursor: "pointer",
|
|
686
|
+
_hover: { textDecoration: "underline" },
|
|
687
|
+
_focusVisible: { focusRing: "outer" },
|
|
688
|
+
});
|
|
689
|
+
export function ParallelChip({ actor, who, doing, action, className, ...props }) {
|
|
690
|
+
return (_jsxs("span", { ...props, className: cx(parallelChip, className), "data-ciridae-ui": "", "data-edge": "gradient", children: [actor.kind === "person" ? (actor.avatar) : (_jsx(StepDot, { status: actor.kind === "agent" ? "agent" : "waiting" })), _jsx("span", { className: parallelWho, children: who }), _jsx("span", { className: parallelDoing, children: doing }), action && (_jsx("button", { type: "button", className: parallelAction, onClick: action.onClick, children: action.label }))] }));
|
|
691
|
+
}
|
|
692
|
+
const partsRollup = css({
|
|
693
|
+
display: "flex",
|
|
694
|
+
alignItems: "center",
|
|
695
|
+
flexWrap: "wrap",
|
|
696
|
+
gap: "layout.contentGap",
|
|
697
|
+
minHeight: "partsRollup.height",
|
|
698
|
+
paddingBlock: "panel.hairline",
|
|
699
|
+
fontWeight: "medium",
|
|
700
|
+
letterSpacing: "compact",
|
|
701
|
+
lineHeight: "tight",
|
|
702
|
+
});
|
|
703
|
+
const partsLabel = css({ color: "fg.primary", fontSize: "caption" });
|
|
704
|
+
const partsBar = css({
|
|
705
|
+
display: "flex",
|
|
706
|
+
gap: "layout.tightGap",
|
|
707
|
+
width: "320px",
|
|
708
|
+
maxWidth: "100%",
|
|
709
|
+
height: "progress.track",
|
|
710
|
+
});
|
|
711
|
+
const partsSegment = css({
|
|
712
|
+
flex: "1 1 0",
|
|
713
|
+
borderRadius: "round",
|
|
714
|
+
background: "chart.notStarted",
|
|
715
|
+
"&[data-state=done]": { background: "accent.green" },
|
|
716
|
+
"&[data-state=needsYou]": { background: "token(gradients.chart.atRisk)" },
|
|
717
|
+
});
|
|
718
|
+
const partsLegend = css({ color: "fg.muted", fontSize: "code", _light: { color: "fg.subtle" } });
|
|
719
|
+
export function PartsRollup({ label, parts, legend, className, ...props }) {
|
|
720
|
+
return (_jsxs("div", { ...props, className: cx(partsRollup, className), "data-ciridae-ui": "", children: [_jsx("span", { className: partsLabel, children: label }), _jsx("span", { className: partsBar, "aria-hidden": "true", children: parts.map((state, index) => (_jsx("span", { className: partsSegment, "data-state": state }, index))) }), _jsx("span", { className: partsLegend, children: legend })] }));
|
|
365
721
|
}
|