@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
package/dist/components/input.js
CHANGED
|
@@ -16,7 +16,7 @@ import { useCiridaeLocale } from "./locale.js";
|
|
|
16
16
|
const fieldFace = {
|
|
17
17
|
border: "1px solid token(colors.border.control)",
|
|
18
18
|
borderRadius: "control",
|
|
19
|
-
background: "bg.
|
|
19
|
+
background: "bg.formField",
|
|
20
20
|
color: "fg.primary",
|
|
21
21
|
fontFamily: "sans",
|
|
22
22
|
fontWeight: "medium",
|
|
@@ -34,13 +34,19 @@ const field = cva({
|
|
|
34
34
|
base: { ...fieldFace, width: "100%", lineHeight: "tight" },
|
|
35
35
|
variants: {
|
|
36
36
|
size: {
|
|
37
|
-
/**
|
|
37
|
+
/** The editor an inline-edit row opens in place of its value. */
|
|
38
|
+
inline: {
|
|
39
|
+
height: "field.inline",
|
|
40
|
+
paddingInline: "menu.itemInline",
|
|
41
|
+
fontSize: "body",
|
|
42
|
+
},
|
|
43
|
+
/** For a row of filters, beside compact selects and small buttons. */
|
|
38
44
|
small: {
|
|
39
45
|
height: "control.compact",
|
|
40
46
|
paddingInline: "control.compactInline",
|
|
41
47
|
fontSize: "caption",
|
|
42
48
|
},
|
|
43
|
-
/** The
|
|
49
|
+
/** The field: the height of the default button. */
|
|
44
50
|
medium: {
|
|
45
51
|
height: "control.default",
|
|
46
52
|
paddingInline: "control.compactInline",
|
|
@@ -55,9 +61,9 @@ const field = cva({
|
|
|
55
61
|
},
|
|
56
62
|
},
|
|
57
63
|
},
|
|
58
|
-
defaultVariants: { size: "
|
|
64
|
+
defaultVariants: { size: "medium" },
|
|
59
65
|
});
|
|
60
|
-
export function Input({ className, size = "
|
|
66
|
+
export function Input({ className, size = "medium", ...props }) {
|
|
61
67
|
const fieldIds = useFieldControl(props);
|
|
62
68
|
return (_jsx(BaseInput, { ...props, ...fieldIds, className: cx(field({ size }), className), "data-ciridae-ui": "" }));
|
|
63
69
|
}
|
|
@@ -179,12 +185,13 @@ export function SearchInput({ variant = "regular", size: ownSize, width = "fill"
|
|
|
179
185
|
onValueCommit(event.currentTarget.value);
|
|
180
186
|
}
|
|
181
187
|
onKeyDown?.(event);
|
|
182
|
-
}, className: cx(searchText({ variant, size }), className) }), shortcut && _jsx(ShortcutHint, { hotkey: shortcut })] }));
|
|
188
|
+
}, className: cx(searchText({ variant, size }), className) }), shortcut && _jsx(ShortcutHint, { boxed: true, hotkey: shortcut })] }));
|
|
183
189
|
}
|
|
184
190
|
/*
|
|
185
191
|
* The Round 2 search field is an underline, not a box: an icon, the text, and a clear button on
|
|
186
|
-
* one hairline.
|
|
187
|
-
*
|
|
192
|
+
* one hairline. Hovered it takes the hover wash, and focused the ring, both on its own nearly
|
|
193
|
+
* square corners. Quiet, in a menu or popover, the hairline is the sheet's divider and nothing
|
|
194
|
+
* else changes: the popup opens with the field focused, and its caret shows that.
|
|
188
195
|
*/
|
|
189
196
|
const underline = cva({
|
|
190
197
|
base: {
|
|
@@ -195,10 +202,6 @@ const underline = cva({
|
|
|
195
202
|
paddingInline: "search.inline",
|
|
196
203
|
borderBottom: "1px solid token(colors.border.control)",
|
|
197
204
|
color: "fg.muted",
|
|
198
|
-
"&:has(:focus-visible)": {
|
|
199
|
-
borderBottomColor: "border.focus",
|
|
200
|
-
boxShadow: "inset 0 -1px 0 0 token(colors.border.focus)",
|
|
201
|
-
},
|
|
202
205
|
"&:has(:disabled)": { opacity: "disabled" },
|
|
203
206
|
},
|
|
204
207
|
variants: {
|
|
@@ -206,8 +209,16 @@ const underline = cva({
|
|
|
206
209
|
regular: { height: "control.default" },
|
|
207
210
|
compact: { height: "control.compact" },
|
|
208
211
|
},
|
|
212
|
+
quiet: {
|
|
213
|
+
false: {
|
|
214
|
+
borderRadius: "control",
|
|
215
|
+
_hover: { background: "bg.controlHover" },
|
|
216
|
+
"&:has(:focus-visible)": { focusRing: "outer" },
|
|
217
|
+
},
|
|
218
|
+
true: { paddingInline: "none", borderBottomColor: "border.divider" },
|
|
219
|
+
},
|
|
209
220
|
},
|
|
210
|
-
defaultVariants: { size: "regular" },
|
|
221
|
+
defaultVariants: { size: "regular", quiet: false },
|
|
211
222
|
});
|
|
212
223
|
const underlineText = css({
|
|
213
224
|
flex: "1",
|
|
@@ -242,9 +253,9 @@ const clear = css({
|
|
|
242
253
|
_hover: { color: "fg.primary", background: "bg.hover" },
|
|
243
254
|
_focusVisible: { focusRing: "inset" },
|
|
244
255
|
});
|
|
245
|
-
export function SearchField({ size: ownSize, onClear, shortcut, wrapperClassName, className, disabled, ...props }) {
|
|
256
|
+
export function SearchField({ size: ownSize, onClear, quiet = false, shortcut, wrapperClassName, className, disabled, ...props }) {
|
|
246
257
|
const inToolbar = useInToolbar();
|
|
247
258
|
const { labels } = useCiridaeLocale();
|
|
248
259
|
const size = ownSize ?? (inToolbar ? "compact" : "regular");
|
|
249
|
-
return (_jsxs("label", { className: cx(underline({ size }), wrapperClassName), "data-ciridae-ui": "", children: [_jsx(MagnifyingGlassIcon, { className: icon({ size: "small" }) }), _jsx(BaseInput, { ...props, type: "search", disabled: disabled, className: cx(underlineText, className) }), onClear && (_jsx("button", { type: "button", className: clear, "aria-label": labels.common.clear, disabled: disabled, onClick: onClear, children: _jsx(XIcon, { className: icon({ size: "small" }) }) })), shortcut && !onClear && _jsx(ShortcutHint, { hotkey: shortcut })] }));
|
|
260
|
+
return (_jsxs("label", { className: cx(underline({ size, quiet }), wrapperClassName), "data-ciridae-ui": "", children: [_jsx(MagnifyingGlassIcon, { className: icon({ size: "small" }) }), _jsx(BaseInput, { ...props, type: "search", disabled: disabled, className: cx(underlineText, className) }), onClear && (_jsx("button", { type: "button", className: clear, "aria-label": labels.common.clear, disabled: disabled, onClick: onClear, children: _jsx(XIcon, { className: icon({ size: "small" }) }) })), shortcut && !onClear && _jsx(ShortcutHint, { boxed: true, hotkey: shortcut })] }));
|
|
250
261
|
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { type Hotkey } from "./hotkeys.js";
|
|
2
2
|
import type { ComponentProps } from "react";
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* One key as a 22px square cap, such as the `K` after a search field. A label of more than one
|
|
5
|
+
* character, such as `Esc`, takes the wider word cap on its own.
|
|
6
|
+
*/
|
|
7
|
+
export declare function Keycap({ className, children, ...props }: ComponentProps<"kbd">): import("react").JSX.Element;
|
|
5
8
|
/**
|
|
6
9
|
* A hotkey as one quiet line, as the hotkeys layer writes it: `Mod` is "⌘" on a Mac and "Ctrl"
|
|
7
|
-
* elsewhere, and a sequence's steps are spaced ("G I"). `
|
|
8
|
-
*
|
|
10
|
+
* elsewhere, and a sequence's steps are spaced ("G I"). `boxed` sets each key in its own
|
|
11
|
+
* `Keycap`, 2px apart, as a menu row or a search field shows it.
|
|
9
12
|
*/
|
|
10
|
-
export declare function ShortcutHint({ hotkey, className, ...props }: ComponentProps<"kbd"> & {
|
|
13
|
+
export declare function ShortcutHint({ hotkey, boxed, className, ...props }: ComponentProps<"kbd"> & {
|
|
11
14
|
hotkey: Hotkey;
|
|
15
|
+
boxed?: boolean;
|
|
12
16
|
}): import("react").JSX.Element;
|
|
@@ -1,18 +1,44 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { css, cx } from "#primitives/css";
|
|
2
|
+
import { css, cva, cx } from "#primitives/css";
|
|
3
3
|
import { detectPlatform, formatForDisplay } from "./hotkeys.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
4
|
+
/*
|
|
5
|
+
* A key on the raised face: a glyph such as ⌘ or ↵ sits in a 22px square, and a word such as Esc
|
|
6
|
+
* in a wider cap. The edge is the canvas hairline.
|
|
7
|
+
*/
|
|
8
|
+
const keycap = cva({
|
|
9
|
+
base: {
|
|
10
|
+
display: "inline-grid",
|
|
11
|
+
placeItems: "center",
|
|
12
|
+
flexShrink: "0",
|
|
13
|
+
width: "control.chip",
|
|
14
|
+
height: "control.chip",
|
|
15
|
+
paddingInline: "none",
|
|
16
|
+
border: "1px solid token(colors.border.canvas)",
|
|
17
|
+
borderRadius: "keycap",
|
|
18
|
+
background: "token(gradients.raised)",
|
|
19
|
+
color: "fg.primary",
|
|
20
|
+
fontFamily: "sans",
|
|
21
|
+
fontSize: "code",
|
|
22
|
+
fontWeight: "medium",
|
|
23
|
+
letterSpacing: "compact",
|
|
24
|
+
lineHeight: "tight",
|
|
25
|
+
whiteSpace: "nowrap",
|
|
26
|
+
"& > svg": { fontSize: "icon.small" },
|
|
27
|
+
},
|
|
28
|
+
variants: {
|
|
29
|
+
// A longer word than Esc, such as Shift, still widens the cap rather than spilling out of it.
|
|
30
|
+
label: {
|
|
31
|
+
glyph: {},
|
|
32
|
+
word: { width: "auto", minWidth: "control.wordKeycap", paddingInline: "control.iconGap" },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const keycaps = css({
|
|
37
|
+
display: "inline-flex",
|
|
38
|
+
alignItems: "center",
|
|
39
|
+
gap: "control.trackInset",
|
|
40
|
+
flexShrink: "0",
|
|
41
|
+
_phone: { display: "none" },
|
|
16
42
|
});
|
|
17
43
|
// A quiet inline hint, as a menu writes its shortcuts: no box, no extra height, and none on a
|
|
18
44
|
// phone, which has no keyboard to press it on.
|
|
@@ -31,15 +57,27 @@ const shortcut = css({
|
|
|
31
57
|
});
|
|
32
58
|
// "⌘K" on a Mac, as a menu writes it; "Ctrl+K" elsewhere.
|
|
33
59
|
const separatorToken = detectPlatform() === "mac" ? "" : undefined;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
60
|
+
// Between the keys of a boxed hint, split apart again so each takes its own cap.
|
|
61
|
+
const keySeparator = "\n";
|
|
62
|
+
/**
|
|
63
|
+
* One key as a 22px square cap, such as the `K` after a search field. A label of more than one
|
|
64
|
+
* character, such as `Esc`, takes the wider word cap on its own.
|
|
65
|
+
*/
|
|
66
|
+
export function Keycap({ className, children, ...props }) {
|
|
67
|
+
const holdsWord = typeof children === "string" && Array.from(children).length > 1;
|
|
68
|
+
return (_jsx("kbd", { ...props, className: cx(keycap({ label: holdsWord ? "word" : "glyph" }), className), "data-ciridae-ui": "", children: children }));
|
|
37
69
|
}
|
|
38
70
|
/**
|
|
39
71
|
* A hotkey as one quiet line, as the hotkeys layer writes it: `Mod` is "⌘" on a Mac and "Ctrl"
|
|
40
|
-
* elsewhere, and a sequence's steps are spaced ("G I"). `
|
|
41
|
-
*
|
|
72
|
+
* elsewhere, and a sequence's steps are spaced ("G I"). `boxed` sets each key in its own
|
|
73
|
+
* `Keycap`, 2px apart, as a menu row or a search field shows it.
|
|
42
74
|
*/
|
|
43
|
-
export function ShortcutHint({ hotkey, className, ...props }) {
|
|
75
|
+
export function ShortcutHint({ hotkey, boxed = false, className, ...props }) {
|
|
76
|
+
if (boxed) {
|
|
77
|
+
const keys = formatForDisplay(hotkey, { separatorToken: keySeparator })
|
|
78
|
+
.split(/[\n ]/)
|
|
79
|
+
.filter((key) => key !== "");
|
|
80
|
+
return (_jsx("kbd", { ...props, dir: "ltr", "aria-label": formatForDisplay(hotkey, { useSymbols: false }), className: cx(keycaps, className), "data-ciridae-ui": "", children: keys.map((key, index) => (_jsx(Keycap, { "aria-hidden": "true", children: key }, index))) }));
|
|
81
|
+
}
|
|
44
82
|
return (_jsx("kbd", { ...props, dir: "ltr", "aria-label": formatForDisplay(hotkey, { useSymbols: false }), className: cx(shortcut, className), "data-ciridae-ui": "", children: formatForDisplay(hotkey, { separatorToken }) }));
|
|
45
83
|
}
|
|
@@ -58,7 +58,8 @@ const stage = css({
|
|
|
58
58
|
height: "100%",
|
|
59
59
|
border: "0",
|
|
60
60
|
borderRadius: "action",
|
|
61
|
-
background
|
|
61
|
+
// Solid, so a document with no background of its own does not show the scrim through it.
|
|
62
|
+
background: "bg.surface",
|
|
62
63
|
},
|
|
63
64
|
});
|
|
64
65
|
const step = css({
|
|
@@ -63,6 +63,9 @@ export declare const englishLabels: {
|
|
|
63
63
|
label: string;
|
|
64
64
|
previous: string;
|
|
65
65
|
next: string;
|
|
66
|
+
/** The rows a page shows and the page size, from numbers already formatted. */
|
|
67
|
+
summary: (first: string, last: string, total: string) => string;
|
|
68
|
+
perPage: (count: string) => string;
|
|
66
69
|
};
|
|
67
70
|
calendar: {
|
|
68
71
|
previousMonth: string;
|
|
@@ -76,6 +79,9 @@ export declare const englishLabels: {
|
|
|
76
79
|
};
|
|
77
80
|
commandMenu: {
|
|
78
81
|
title: string;
|
|
82
|
+
/** The footer's key hints beside the close key. */
|
|
83
|
+
move: string;
|
|
84
|
+
open: string;
|
|
79
85
|
};
|
|
80
86
|
keyboard: {
|
|
81
87
|
shortcuts: string;
|
|
@@ -230,6 +236,8 @@ export declare const englishLabels: {
|
|
|
230
236
|
sendMessage: string;
|
|
231
237
|
stopped: string;
|
|
232
238
|
failed: string;
|
|
239
|
+
/** The title of a failed reply's notice. */
|
|
240
|
+
couldNotAnswer: string;
|
|
233
241
|
notSent: string;
|
|
234
242
|
typing: string;
|
|
235
243
|
resize: string;
|
|
@@ -372,6 +380,8 @@ export declare const englishLabels: {
|
|
|
372
380
|
runToGo: string;
|
|
373
381
|
runDoneLabel: (count: number) => string;
|
|
374
382
|
runToGoLabel: (count: number) => string;
|
|
383
|
+
/** The folded finished stages, with their count. */
|
|
384
|
+
runDoneShort: (count: number) => string;
|
|
375
385
|
checklistProgress: (done: number, total: number) => string;
|
|
376
386
|
};
|
|
377
387
|
settings: {
|
|
@@ -50,7 +50,14 @@ export const englishLabels = {
|
|
|
50
50
|
parentPages: "Parent pages",
|
|
51
51
|
environment: (label) => `${label} environment`,
|
|
52
52
|
},
|
|
53
|
-
pagination: {
|
|
53
|
+
pagination: {
|
|
54
|
+
label: "Pagination",
|
|
55
|
+
previous: "Previous",
|
|
56
|
+
next: "Next",
|
|
57
|
+
/** The rows a page shows and the page size, from numbers already formatted. */
|
|
58
|
+
summary: (first, last, total) => `Showing ${first} to ${last} of ${total}`,
|
|
59
|
+
perPage: (count) => `${count} per page`,
|
|
60
|
+
},
|
|
54
61
|
calendar: { previousMonth: "Previous month", nextMonth: "Next month" },
|
|
55
62
|
select: {
|
|
56
63
|
placeholder: "Select…",
|
|
@@ -58,7 +65,12 @@ export const englishLabels = {
|
|
|
58
65
|
searchLabel: "Search options",
|
|
59
66
|
filters: "Filters",
|
|
60
67
|
},
|
|
61
|
-
commandMenu: {
|
|
68
|
+
commandMenu: {
|
|
69
|
+
title: "Command menu",
|
|
70
|
+
/** The footer's key hints beside the close key. */
|
|
71
|
+
move: "Move",
|
|
72
|
+
open: "Open",
|
|
73
|
+
},
|
|
62
74
|
keyboard: {
|
|
63
75
|
shortcuts: "Keyboard shortcuts",
|
|
64
76
|
/** The group of a shortcut registered without one. */
|
|
@@ -206,6 +218,8 @@ export const englishLabels = {
|
|
|
206
218
|
sendMessage: "Send message",
|
|
207
219
|
stopped: "Stopped",
|
|
208
220
|
failed: "Failed",
|
|
221
|
+
/** The title of a failed reply's notice. */
|
|
222
|
+
couldNotAnswer: "Couldn't finish that answer",
|
|
209
223
|
notSent: "Not sent",
|
|
210
224
|
typing: "Typing",
|
|
211
225
|
resize: "Resize",
|
|
@@ -342,6 +356,8 @@ export const englishLabels = {
|
|
|
342
356
|
runToGo: "To go",
|
|
343
357
|
runDoneLabel: (count) => `${count} stages done`,
|
|
344
358
|
runToGoLabel: (count) => `${count} stages to go`,
|
|
359
|
+
/** The folded finished stages, with their count. */
|
|
360
|
+
runDoneShort: (count) => `${count} done`,
|
|
345
361
|
checklistProgress: (done, total) => `${done} of ${total}`,
|
|
346
362
|
},
|
|
347
363
|
settings: { navigation: "Settings" },
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ComponentProps, ReactNode } from "react";
|
|
2
|
+
export type LogEntryProps = Omit<ComponentProps<"div">, "children"> & {
|
|
3
|
+
/** When it happened, epoch milliseconds, written as the time of day. */
|
|
4
|
+
at: number;
|
|
5
|
+
/** Who did it: a person's avatar, or a system's or an agent's icon. */
|
|
6
|
+
actor: ReactNode;
|
|
7
|
+
/** What happened, such as "The agent drafted remittance advice for INV-4799". */
|
|
8
|
+
headline: ReactNode;
|
|
9
|
+
/** A line more about it, such as what it waits on. */
|
|
10
|
+
detail?: ReactNode;
|
|
11
|
+
/** At the end of the row, such as a badge naming whether a person, a model or an agent did it. */
|
|
12
|
+
badge?: ReactNode;
|
|
13
|
+
/** `comfortable` for a page's log, `compact` for one line per entry, `panel` in a drawer. */
|
|
14
|
+
density?: "comfortable" | "compact" | "panel";
|
|
15
|
+
selected?: boolean;
|
|
16
|
+
/** A hairline under the row, between it and the next. */
|
|
17
|
+
divider?: boolean;
|
|
18
|
+
/** Makes the row a button, such as one that opens the entry beside the log. */
|
|
19
|
+
onSelect?: () => void;
|
|
20
|
+
};
|
|
21
|
+
/** One thing that happened, as a row of a log. */
|
|
22
|
+
export declare function LogEntry({ at, actor, headline, detail, badge, density, selected, divider, onSelect, className, ...props }: LogEntryProps): import("react").JSX.Element;
|
|
23
|
+
export type LogGroupHeaderProps = Omit<ComponentProps<"div">, "children"> & {
|
|
24
|
+
/** What the group is, such as "Today". */
|
|
25
|
+
label: ReactNode;
|
|
26
|
+
/** Beside it, quieter, such as the date. */
|
|
27
|
+
meta?: ReactNode;
|
|
28
|
+
};
|
|
29
|
+
/** A log's heading over a group of its rows, such as a day's: "Today", then "Oct 6". */
|
|
30
|
+
export declare function LogGroupHeader({ label, meta, className, ...props }: LogGroupHeaderProps): import("react").JSX.Element;
|
|
31
|
+
export type LogActorProps = {
|
|
32
|
+
/** Who or what acted, read out in place of the mark. */
|
|
33
|
+
name: string;
|
|
34
|
+
/** A person's photo; their initials stand in without one. */
|
|
35
|
+
src?: string | null;
|
|
36
|
+
/** For an agent, a sync or a rule: its icon in place of a person's photo or initials. */
|
|
37
|
+
icon?: ReactNode;
|
|
38
|
+
};
|
|
39
|
+
/** Who did a log entry's thing, as the mark for its `actor`. */
|
|
40
|
+
export declare function LogActor({ name, src, icon }: LogActorProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* A record's activity as a log: a row per thing that happened, under a heading per day. A row is
|
|
4
|
+
* the time, who did it, what happened and a line more about it, and a trailing badge such as
|
|
5
|
+
* whether a person, a model or an agent did it. `comfortable` is a page's log, `compact` puts the
|
|
6
|
+
* line more beside what happened, and `panel` is the log in a drawer or side panel.
|
|
7
|
+
*/
|
|
8
|
+
import { css, cx } from "#primitives/css";
|
|
9
|
+
import { Avatar } from "./data-display.js";
|
|
10
|
+
import { useCiridaeLocale } from "./locale.js";
|
|
11
|
+
const entry = css({
|
|
12
|
+
display: "flex",
|
|
13
|
+
alignItems: "flex-start",
|
|
14
|
+
gap: "layout.clusterGap",
|
|
15
|
+
width: "100%",
|
|
16
|
+
minWidth: "0",
|
|
17
|
+
paddingBlock: "log.entryBlock",
|
|
18
|
+
paddingInline: "log.entryInline",
|
|
19
|
+
color: "fg.primary",
|
|
20
|
+
_hover: { background: "token(gradients.rowHover)" },
|
|
21
|
+
"&[data-selected], &[data-selected]:hover": { background: "token(gradients.selected)" },
|
|
22
|
+
"&[role=button]": { cursor: "pointer" },
|
|
23
|
+
_focusVisible: { focusRing: "inset" },
|
|
24
|
+
"&[data-divider]": { borderBottom: "1px solid token(colors.border.divider)" },
|
|
25
|
+
"&[data-density=compact]": { alignItems: "center", paddingBlock: "log.entryCompactBlock" },
|
|
26
|
+
// A compact row's rule sits inside its padding, so it stays the kit's 40px with or without one.
|
|
27
|
+
"&[data-density=compact][data-divider]": {
|
|
28
|
+
paddingBottom: "calc(token(spacing.log.entryCompactBlock) - token(sizes.border.hairline))",
|
|
29
|
+
},
|
|
30
|
+
"&[data-density=panel]": {
|
|
31
|
+
paddingBlock: "log.entryPanelBlock",
|
|
32
|
+
paddingInline: "log.entryPanelInline",
|
|
33
|
+
},
|
|
34
|
+
// The time, the actor and the badge each sit in a line as tall as the actor, level with the
|
|
35
|
+
// headline beside them.
|
|
36
|
+
"& > [data-time], & > [data-actor], & > [data-badge]": {
|
|
37
|
+
display: "flex",
|
|
38
|
+
flexShrink: "0",
|
|
39
|
+
alignItems: "center",
|
|
40
|
+
height: "avatar.menu",
|
|
41
|
+
},
|
|
42
|
+
"& > [data-time]": {
|
|
43
|
+
width: "log.timeColumn",
|
|
44
|
+
color: "fg.subtle",
|
|
45
|
+
fontSize: "code",
|
|
46
|
+
fontWeight: "medium",
|
|
47
|
+
lineHeight: "tight",
|
|
48
|
+
fontVariantNumeric: "tabular-nums",
|
|
49
|
+
whiteSpace: "nowrap",
|
|
50
|
+
},
|
|
51
|
+
"& > [data-actor]": { justifyContent: "center", width: "avatar.menu" },
|
|
52
|
+
"& > [data-body]": {
|
|
53
|
+
display: "grid",
|
|
54
|
+
gridTemplateColumns: "minmax(0, 1fr)",
|
|
55
|
+
flex: "1",
|
|
56
|
+
minWidth: "0",
|
|
57
|
+
},
|
|
58
|
+
// One line as tall as the actor, ending in an ellipsis where the row is too narrow for it.
|
|
59
|
+
"& [data-headline]": {
|
|
60
|
+
display: "flex",
|
|
61
|
+
alignItems: "center",
|
|
62
|
+
minHeight: "avatar.menu",
|
|
63
|
+
fontSize: "body",
|
|
64
|
+
fontWeight: "medium",
|
|
65
|
+
lineHeight: "tight",
|
|
66
|
+
"& > span": {
|
|
67
|
+
minWidth: "0",
|
|
68
|
+
overflow: "hidden",
|
|
69
|
+
textOverflow: "ellipsis",
|
|
70
|
+
whiteSpace: "nowrap",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
"& [data-detail]": {
|
|
74
|
+
color: "fg.label",
|
|
75
|
+
fontSize: "code",
|
|
76
|
+
fontWeight: "medium",
|
|
77
|
+
lineHeight: "log",
|
|
78
|
+
},
|
|
79
|
+
"&[data-density=compact] > [data-body]": {
|
|
80
|
+
display: "flex",
|
|
81
|
+
alignItems: "center",
|
|
82
|
+
gap: "layout.controlGap",
|
|
83
|
+
"& > *": { minWidth: "0", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
|
|
84
|
+
// Block, so a long headline ends in an ellipsis; its own line height, so it centres with
|
|
85
|
+
// the detail.
|
|
86
|
+
"& > [data-headline]": { display: "block", minHeight: "auto" },
|
|
87
|
+
"& > [data-detail]": { flex: "1", lineHeight: "tight" },
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
// The log's actor mark: a person's photo or initials, or an icon for an agent, a sync or a rule,
|
|
91
|
+
// on the raised glass circle. The icon is the small icon's size at every density.
|
|
92
|
+
const actorIcon = css({
|
|
93
|
+
display: "inline-grid",
|
|
94
|
+
placeItems: "center",
|
|
95
|
+
flexShrink: "0",
|
|
96
|
+
width: "avatar.menu",
|
|
97
|
+
height: "avatar.menu",
|
|
98
|
+
borderRadius: "round",
|
|
99
|
+
background: "token(gradients.raised)",
|
|
100
|
+
color: "fg.label",
|
|
101
|
+
"--edge": "token(gradients.border.raised)",
|
|
102
|
+
"& > svg": { fontSize: "icon.small" },
|
|
103
|
+
});
|
|
104
|
+
// Initials sit in the label grey here, where the avatar's own are the primary text colour; the
|
|
105
|
+
// extra attribute outranks the avatar's kind rule.
|
|
106
|
+
const actorPerson = css({ "&[data-ciridae-ui][data-kind=user]": { color: "fg.label" } });
|
|
107
|
+
const groupHeader = css({
|
|
108
|
+
display: "flex",
|
|
109
|
+
alignItems: "center",
|
|
110
|
+
gap: "layout.controlGap",
|
|
111
|
+
paddingTop: "panel.comfortable",
|
|
112
|
+
paddingInline: "panel.default",
|
|
113
|
+
paddingBottom: "layout.tightGap",
|
|
114
|
+
fontSize: "code",
|
|
115
|
+
fontWeight: "medium",
|
|
116
|
+
lineHeight: "tight",
|
|
117
|
+
"& > [data-label]": { color: "fg.primary" },
|
|
118
|
+
"& > [data-meta]": { color: "fg.subtle" },
|
|
119
|
+
});
|
|
120
|
+
/** One thing that happened, as a row of a log. */
|
|
121
|
+
export function LogEntry({ at, actor, headline, detail, badge, density = "comfortable", selected = false, divider = true, onSelect, className, ...props }) {
|
|
122
|
+
const { formatTime } = useCiridaeLocale();
|
|
123
|
+
const selectOnKey = (event) => {
|
|
124
|
+
if (event.target !== event.currentTarget || (event.key !== "Enter" && event.key !== " "))
|
|
125
|
+
return;
|
|
126
|
+
event.preventDefault();
|
|
127
|
+
onSelect?.();
|
|
128
|
+
};
|
|
129
|
+
return (_jsxs("div", { ...props, ...(onSelect && {
|
|
130
|
+
role: "button",
|
|
131
|
+
tabIndex: 0,
|
|
132
|
+
"aria-pressed": selected,
|
|
133
|
+
onClick: onSelect,
|
|
134
|
+
onKeyDown: selectOnKey,
|
|
135
|
+
}), className: cx(entry, className), "data-ciridae-ui": "", "data-density": density, "data-selected": selected || undefined, "data-divider": divider || undefined, children: [_jsx("time", { "data-time": "", dateTime: new Date(at).toISOString(), children: formatTime(at) }), _jsx("span", { "data-actor": "", children: actor }), _jsxs("div", { "data-body": "", children: [_jsx("span", { "data-headline": "", children: _jsx("span", { children: headline }) }), detail && _jsx("span", { "data-detail": "", children: detail })] }), badge && _jsx("span", { "data-badge": "", children: badge })] }));
|
|
136
|
+
}
|
|
137
|
+
/** A log's heading over a group of its rows, such as a day's: "Today", then "Oct 6". */
|
|
138
|
+
export function LogGroupHeader({ label, meta, className, ...props }) {
|
|
139
|
+
return (_jsxs("div", { ...props, className: cx(groupHeader, className), "data-ciridae-ui": "", children: [_jsx("span", { "data-label": "", children: label }), meta && _jsx("span", { "data-meta": "", children: meta })] }));
|
|
140
|
+
}
|
|
141
|
+
/** Who did a log entry's thing, as the mark for its `actor`. */
|
|
142
|
+
export function LogActor({ name, src, icon }) {
|
|
143
|
+
if (icon)
|
|
144
|
+
return (_jsx("span", { role: "img", "aria-label": name, className: actorIcon, "data-ciridae-ui": "", "data-edge": "gradient", children: icon }));
|
|
145
|
+
return _jsx(Avatar, { label: name, src: src, size: "menu", className: actorPerson });
|
|
146
|
+
}
|
|
@@ -244,7 +244,7 @@ const field = css({
|
|
|
244
244
|
},
|
|
245
245
|
"&[aria-disabled=true]": { cursor: "default", opacity: "0.5" },
|
|
246
246
|
});
|
|
247
|
-
/* The picker: a flush menu over the caret, its rows edge to edge. */
|
|
247
|
+
/* The picker: a flush menu over the caret on the popovers' glass, its rows edge to edge. */
|
|
248
248
|
const picker = css({
|
|
249
249
|
zIndex: "popover",
|
|
250
250
|
display: "grid",
|
|
@@ -254,9 +254,10 @@ const picker = css({
|
|
|
254
254
|
overflowY: "auto",
|
|
255
255
|
border: "1px solid token(colors.border.control)",
|
|
256
256
|
borderRadius: "action",
|
|
257
|
-
background: "bg.
|
|
257
|
+
background: "bg.popover",
|
|
258
|
+
backdropFilter: "blur(token(blurs.popover))",
|
|
258
259
|
color: "fg.primary",
|
|
259
|
-
boxShadow: "
|
|
260
|
+
boxShadow: "soft",
|
|
260
261
|
outline: "none",
|
|
261
262
|
});
|
|
262
263
|
const pickerRow = css({
|
|
@@ -12,7 +12,7 @@ export type MenuItem = {
|
|
|
12
12
|
variant?: "default" | "danger";
|
|
13
13
|
/** Shows a check mark, for the active choice in a set. */
|
|
14
14
|
checked?: boolean;
|
|
15
|
-
/** Muted
|
|
15
|
+
/** Muted at the row's end, such as what a choice covers. */
|
|
16
16
|
meta?: string;
|
|
17
17
|
/** The hotkey that does what the item does, at the row's end; the host binds it. */
|
|
18
18
|
shortcut?: Hotkey;
|
|
@@ -59,8 +59,12 @@ export type MenuProps = Omit<ComponentProps<typeof BaseMenu.Root>, "children"> &
|
|
|
59
59
|
items: readonly MenuItem[];
|
|
60
60
|
/** Which edge of the trigger the menu lines up with; `end` keeps a right-hand menu inside its container. */
|
|
61
61
|
align?: "start" | "end";
|
|
62
|
+
/** How far the menu floats from its trigger, in px. Defaults to the kit's 4. */
|
|
63
|
+
sideOffset?: number;
|
|
64
|
+
/** Makes the menu exactly as wide as its trigger rather than at least `overlay.menu`. */
|
|
65
|
+
matchTriggerWidth?: boolean;
|
|
62
66
|
};
|
|
63
|
-
export declare function Menu({ trigger, items, align, ...rootProps }: MenuProps): import("react").JSX.Element;
|
|
67
|
+
export declare function Menu({ trigger, items, align, sideOffset, matchTriggerWidth, ...rootProps }: MenuProps): import("react").JSX.Element;
|
|
64
68
|
export type OverflowMenuProps = Omit<MenuProps, "trigger" | "align"> & {
|
|
65
69
|
/** The button's accessible name, such as "Record actions" or "More for INV-4821". */
|
|
66
70
|
label: string;
|