@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
|
@@ -65,16 +65,23 @@ export type EditableFieldProps = Omit<ComponentProps<"div">, "children"> & {
|
|
|
65
65
|
badge?: ReactNode;
|
|
66
66
|
/** Under the value while the row is idle. */
|
|
67
67
|
note?: ReactNode;
|
|
68
|
-
/** The field needs the reader: the row lifts and this button sits at its end. */
|
|
68
|
+
/** The field needs the reader: the row lifts on the selected glass and this button sits at its end. */
|
|
69
69
|
action?: {
|
|
70
70
|
label: ReactNode;
|
|
71
71
|
onClick: () => void;
|
|
72
72
|
disabled?: boolean;
|
|
73
73
|
};
|
|
74
|
+
/** `bottom` by default; `none` for the last row of a list whose container draws its own edge. */
|
|
75
|
+
divider?: "bottom" | "none";
|
|
76
|
+
/**
|
|
77
|
+
* `selected` washes the row with the selected glass, such as the field a side panel is
|
|
78
|
+
* showing; `inset` sets it into the list between hairlines, such as a field set apart.
|
|
79
|
+
*/
|
|
80
|
+
emphasis?: "selected" | "inset" | "highlighted";
|
|
74
81
|
edit?: FieldEdit;
|
|
75
82
|
labels?: Partial<CiridaeLabels["editableField"]>;
|
|
76
83
|
};
|
|
77
|
-
export declare function EditableField({ label, value, provenance, badge, note, action, edit, labels: ownLabels, className, ...props }: EditableFieldProps): import("
|
|
84
|
+
export declare function EditableField({ label, value, provenance, badge, note, action, divider, emphasis, edit, labels: ownLabels, className, ...props }: EditableFieldProps): import("react").JSX.Element;
|
|
78
85
|
export type ConflictingSource = {
|
|
79
86
|
id: string;
|
|
80
87
|
label: ReactNode;
|
|
@@ -92,8 +99,10 @@ export type SourceConflictProps = Omit<ComponentProps<"div">, "children"> & {
|
|
|
92
99
|
};
|
|
93
100
|
/** At the effective row's end, such as a Resolve button. */
|
|
94
101
|
action?: ReactNode;
|
|
102
|
+
/** `highlighted` while the agent points at the field; `neutral` by default. */
|
|
103
|
+
tone?: "highlighted" | "neutral";
|
|
95
104
|
labels?: Partial<{
|
|
96
105
|
effectiveValue: string;
|
|
97
106
|
}>;
|
|
98
107
|
};
|
|
99
|
-
export declare function SourceConflict({ sources, effective, action, labels: ownLabels, className, ...props }: SourceConflictProps): import("
|
|
108
|
+
export declare function SourceConflict({ sources, effective, action, tone, labels: ownLabels, className, ...props }: SourceConflictProps): import("react").JSX.Element;
|
|
@@ -10,6 +10,7 @@ import { useEffect, useId, useRef, useState, } from "react";
|
|
|
10
10
|
import { css, cx } from "#primitives/css";
|
|
11
11
|
import { Button } from "./button.js";
|
|
12
12
|
import { Calendar } from "./calendar.js";
|
|
13
|
+
import { glassMenuSurface } from "./glass-menu.js";
|
|
13
14
|
import { useHotkey } from "./hotkeys.js";
|
|
14
15
|
import { icon, Spinner } from "./icon.js";
|
|
15
16
|
import { Input } from "./input.js";
|
|
@@ -18,24 +19,48 @@ import { Tooltip } from "./overlays.js";
|
|
|
18
19
|
import { Combobox } from "./select.js";
|
|
19
20
|
/* The row stacks its label over the value in a narrow box, so each field is its own container. */
|
|
20
21
|
const fieldBox = css({ containerType: "inline-size" });
|
|
22
|
+
/*
|
|
23
|
+
* The kit's Detail field: 12 · 16 padding, a hairline under it. A field that needs the reader
|
|
24
|
+
* (the inline edit's Needs confirm) and an inset row wear the selected glass between the selected
|
|
25
|
+
* edge's hairlines; a selected row wears the glass alone; a highlighted row, while the agent points
|
|
26
|
+
* at it, is the flat yellow band between hairlines.
|
|
27
|
+
*/
|
|
21
28
|
const fieldRow = css({
|
|
22
29
|
position: "relative",
|
|
23
30
|
display: "grid",
|
|
24
31
|
gridTemplateColumns: "150px minmax(0, 1fr) auto",
|
|
25
|
-
|
|
32
|
+
// The label sits on the value's first line, as the kit's does; the trailing control centres.
|
|
33
|
+
alignItems: "baseline",
|
|
26
34
|
gap: "layout.contentGap",
|
|
27
35
|
paddingBlock: "panel.default",
|
|
28
36
|
paddingInline: "panel.comfortable",
|
|
29
|
-
borderBottom: "1px solid token(colors.border.
|
|
37
|
+
borderBottom: "1px solid token(colors.border.divider)",
|
|
30
38
|
fontSize: "caption",
|
|
31
39
|
letterSpacing: "compact",
|
|
40
|
+
"& > :last-child": { alignSelf: "center" },
|
|
32
41
|
"&[data-needs]": {
|
|
33
|
-
background: "
|
|
34
|
-
borderBlock: "1px solid
|
|
42
|
+
background: "token(gradients.selected)",
|
|
43
|
+
borderBlock: "1px solid",
|
|
44
|
+
borderImage: "token(gradients.border.selected) 1",
|
|
45
|
+
},
|
|
46
|
+
// After the band's hairlines, so a last highlighted row keeps only its top one, as the kit's.
|
|
47
|
+
"&[data-divider=none]": { borderBottom: "0" },
|
|
48
|
+
"&[data-emphasis=selected]": { background: "token(gradients.selected)" },
|
|
49
|
+
"&[data-emphasis=inset]": {
|
|
50
|
+
background: "token(gradients.selected)",
|
|
51
|
+
borderBlock: "1px solid",
|
|
52
|
+
borderImage: "token(gradients.border.selected) 1",
|
|
53
|
+
},
|
|
54
|
+
// The kit's Highlighted detail field: the yellow band while the agent points at the field.
|
|
55
|
+
"&[data-emphasis=highlighted]": {
|
|
56
|
+
background: "bg.warningTint",
|
|
57
|
+
borderBlock: "1px solid token(colors.border.divider)",
|
|
58
|
+
},
|
|
59
|
+
"&[data-editable]": {
|
|
60
|
+
cursor: "pointer",
|
|
61
|
+
_hover: { background: "token(gradients.card)", _light: { background: "bg.rowHover" } },
|
|
35
62
|
},
|
|
36
|
-
"&[data-editable]": { cursor: "pointer", _hover: { background: "bg.rowHover" } },
|
|
37
63
|
"&[data-editable]:is(:hover, :focus-within) [data-affordance], &[data-editing] [data-affordance]": { opacity: "1" },
|
|
38
|
-
"&[data-editable]:hover > [data-label]": { color: "fg.secondary" },
|
|
39
64
|
"@container (max-width: 520px)": {
|
|
40
65
|
gridTemplateColumns: "minmax(0, 1fr) auto",
|
|
41
66
|
rowGap: "layout.tightGap",
|
|
@@ -43,10 +68,10 @@ const fieldRow = css({
|
|
|
43
68
|
},
|
|
44
69
|
});
|
|
45
70
|
const fieldLabel = css({
|
|
46
|
-
color: "fg.
|
|
71
|
+
color: "fg.secondary",
|
|
47
72
|
fontSize: "code",
|
|
48
73
|
fontWeight: "medium",
|
|
49
|
-
|
|
74
|
+
lineHeight: "tight",
|
|
50
75
|
});
|
|
51
76
|
const fieldValue = css({
|
|
52
77
|
display: "flex",
|
|
@@ -101,9 +126,10 @@ const provenanceLine = css({
|
|
|
101
126
|
gap: "layout.contentGap",
|
|
102
127
|
marginTop: "control.iconGap",
|
|
103
128
|
minHeight: "control.knob",
|
|
104
|
-
color: "fg.
|
|
129
|
+
color: "fg.label",
|
|
105
130
|
fontSize: "code",
|
|
106
131
|
fontWeight: "medium",
|
|
132
|
+
lineHeight: "tight",
|
|
107
133
|
"& > span, & > button, & > a": {
|
|
108
134
|
display: "inline-flex",
|
|
109
135
|
alignItems: "center",
|
|
@@ -133,31 +159,29 @@ const fieldNote = css({
|
|
|
133
159
|
color: "fg.secondary",
|
|
134
160
|
fontSize: "code",
|
|
135
161
|
fontWeight: "medium",
|
|
162
|
+
lineHeight: "tight",
|
|
136
163
|
});
|
|
137
|
-
const editor = css({ width: "200px", maxWidth: "100%"
|
|
164
|
+
const editor = css({ width: "200px", maxWidth: "100%" });
|
|
138
165
|
const editorValue = css({ position: "relative", display: "flex", alignItems: "center" });
|
|
139
166
|
const tooltipTitle = css({ display: "block", fontWeight: "medium" });
|
|
140
167
|
const tooltipDetail = css({ display: "block", fontSize: "code", opacity: "0.8" });
|
|
141
168
|
const trailingActions = css({ display: "inline-flex", gap: "layout.tightGap" });
|
|
142
|
-
/* The calendar opens above the date editor. */
|
|
143
|
-
const calendarPicker = css({
|
|
169
|
+
/* The calendar opens above the date editor, on the menus' glass sheet. */
|
|
170
|
+
const calendarPicker = css(glassMenuSurface, {
|
|
144
171
|
position: "absolute",
|
|
145
172
|
bottom: "calc(100% + token(spacing.control.iconGap))",
|
|
146
173
|
insetInlineStart: "0",
|
|
147
174
|
zIndex: "popover",
|
|
148
175
|
cursor: "default",
|
|
149
|
-
border: "1px solid token(colors.border.control)",
|
|
150
|
-
borderRadius: "inset",
|
|
151
|
-
background: "bg.card",
|
|
152
|
-
boxShadow: "card",
|
|
153
|
-
"& > section": { border: "0", background: "transparent" },
|
|
154
176
|
});
|
|
177
|
+
// Under the days, inset as the calendar is, such as the value it had before.
|
|
155
178
|
const calendarFooter = css({
|
|
156
|
-
paddingInline: "panel.
|
|
179
|
+
paddingInline: "panel.compact",
|
|
157
180
|
paddingBottom: "panel.compact",
|
|
158
181
|
color: "fg.muted",
|
|
159
182
|
fontSize: "code",
|
|
160
183
|
fontWeight: "medium",
|
|
184
|
+
lineHeight: "body",
|
|
161
185
|
});
|
|
162
186
|
/** An editor opens with its text selected, so typing replaces the value. */
|
|
163
187
|
function selectTyped(event) {
|
|
@@ -167,7 +191,7 @@ function selectTyped(event) {
|
|
|
167
191
|
function localMidnight(date) {
|
|
168
192
|
return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
|
|
169
193
|
}
|
|
170
|
-
export function EditableField({ label, value, provenance, badge, note, action, edit, labels: ownLabels, className, ...props }) {
|
|
194
|
+
export function EditableField({ label, value, provenance, badge, note, action, divider = "bottom", emphasis, edit, labels: ownLabels, className, ...props }) {
|
|
171
195
|
const locale = useCiridaeLocale();
|
|
172
196
|
const labels = { ...locale.labels.editableField, ...ownLabels };
|
|
173
197
|
const formatDate = (timestamp) => locale.formatDate(timestamp);
|
|
@@ -307,7 +331,7 @@ export function EditableField({ label, value, provenance, badge, note, action, e
|
|
|
307
331
|
cancel();
|
|
308
332
|
} }) }) }));
|
|
309
333
|
}
|
|
310
|
-
return (_jsxs("span", { className: editorValue, onFocus: selectTyped, children: [_jsx(Input, { ref: inputRef, className: editor, "aria-labelledby": labelId, "aria-invalid": status.mode === "error" || undefined, value: draft, onChange: (event) => {
|
|
334
|
+
return (_jsxs("span", { className: editorValue, onFocus: selectTyped, children: [_jsx(Input, { ref: inputRef, size: "inline", className: editor, "aria-labelledby": labelId, "aria-invalid": status.mode === "error" || undefined, value: draft, onChange: (event) => {
|
|
311
335
|
setDraft(event.target.value);
|
|
312
336
|
if (status.mode === "error")
|
|
313
337
|
setStatus({ mode: "editing" });
|
|
@@ -364,18 +388,24 @@ export function EditableField({ label, value, provenance, badge, note, action, e
|
|
|
364
388
|
}
|
|
365
389
|
return _jsx("span", {});
|
|
366
390
|
};
|
|
367
|
-
return (_jsx("div", { ...props, className: cx(fieldBox, className), "data-ciridae-ui": "", children: _jsxs("div", { ref: rowRef, className: fieldRow, "data-needs": action && !editing ? "" : undefined, "data-editable": editable && !editing ? "" : undefined, "data-editing": editing ? "" : undefined, onClick: begin, children: [_jsx("span", { className: fieldLabel, id: labelId, "data-label": "", children: label }), _jsxs("span", { className: css({ minWidth: "0" }), children: [valueLine(), _jsx("span", { role: "status", children: statusLine() }), note !== undefined && status.mode === "idle" && (_jsx("span", { className: fieldNote, children: note }))] }), trailing()] }) }));
|
|
391
|
+
return (_jsx("div", { ...props, className: cx(fieldBox, className), "data-ciridae-ui": "", children: _jsxs("div", { ref: rowRef, className: fieldRow, "data-needs": action && !editing ? "" : undefined, "data-divider": divider, "data-emphasis": emphasis, "data-editable": editable && !editing ? "" : undefined, "data-editing": editing ? "" : undefined, onClick: begin, children: [_jsx("span", { className: fieldLabel, id: labelId, "data-label": "", children: label }), _jsxs("span", { className: css({ minWidth: "0" }), children: [valueLine(), _jsx("span", { role: "status", children: statusLine() }), note !== undefined && status.mode === "idle" && (_jsx("span", { className: fieldNote, children: note }))] }), trailing()] }) }));
|
|
368
392
|
}
|
|
369
|
-
/*
|
|
393
|
+
/*
|
|
394
|
+
* Source conflict: each source's value under a disputed field, then the value in effect. The
|
|
395
|
+
* kit's Contested sources: flat and square between hairlines, the yellow band while the agent
|
|
396
|
+
* points at the field, the panel's face otherwise (the grey well in light).
|
|
397
|
+
*/
|
|
370
398
|
const conflictBlock = css({
|
|
371
399
|
display: "grid",
|
|
372
400
|
gap: "layout.controlGap",
|
|
373
401
|
paddingBlock: "panel.default",
|
|
374
402
|
paddingInline: "panel.comfortable",
|
|
375
|
-
|
|
376
|
-
background: "bg.panel",
|
|
403
|
+
borderBlock: "1px solid token(colors.border.divider)",
|
|
377
404
|
letterSpacing: "compact",
|
|
405
|
+
lineHeight: "tight",
|
|
378
406
|
containerType: "inline-size",
|
|
407
|
+
"&[data-tone=neutral]": { background: "bg.panel", _light: { background: "bg.field" } },
|
|
408
|
+
"&[data-tone=highlighted]": { background: "bg.warningTint" },
|
|
379
409
|
});
|
|
380
410
|
const conflictRow = css({
|
|
381
411
|
display: "grid",
|
|
@@ -406,7 +436,7 @@ const sourceMeta = css({
|
|
|
406
436
|
});
|
|
407
437
|
const effectiveRow = css({
|
|
408
438
|
paddingTop: "panel.default",
|
|
409
|
-
borderTop: "1px solid token(colors.border.
|
|
439
|
+
borderTop: "1px solid token(colors.border.divider)",
|
|
410
440
|
});
|
|
411
441
|
const effectiveLabel = css({ fontSize: "code", fontWeight: "medium" });
|
|
412
442
|
const effectiveNote = css({
|
|
@@ -416,7 +446,7 @@ const effectiveNote = css({
|
|
|
416
446
|
fontSize: "code",
|
|
417
447
|
fontWeight: "medium",
|
|
418
448
|
});
|
|
419
|
-
export function SourceConflict({ sources, effective, action, labels: ownLabels, className, ...props }) {
|
|
449
|
+
export function SourceConflict({ sources, effective, action, tone = "neutral", labels: ownLabels, className, ...props }) {
|
|
420
450
|
const labels = { ...useCiridaeLocale().labels.editableField, ...ownLabels };
|
|
421
|
-
return (_jsxs("div", { ...props, className: cx(conflictBlock, className), "data-ciridae-ui": "", children: [sources.map((source) => (_jsxs("div", { className: conflictRow, children: [_jsxs("span", { className: sourceName, children: [source.icon, source.label] }), _jsx("span", { className: sourceValue, children: source.value }), _jsx("span", { className: sourceMeta, children: source.meta })] }, source.id))), _jsxs("div", { className: cx(conflictRow, effectiveRow), children: [_jsx("span", { className: effectiveLabel, children: labels.effectiveValue }), _jsxs("span", { children: [_jsx("span", { className: sourceValue, children: effective.value }), effective.note !== undefined && _jsx("span", { className: effectiveNote, children: effective.note })] }), action ?? _jsx("span", {})] })] }));
|
|
451
|
+
return (_jsxs("div", { ...props, className: cx(conflictBlock, className), "data-ciridae-ui": "", "data-tone": tone, children: [sources.map((source) => (_jsxs("div", { className: conflictRow, children: [_jsxs("span", { className: sourceName, children: [source.icon, source.label] }), _jsx("span", { className: sourceValue, children: source.value }), _jsx("span", { className: sourceMeta, children: source.meta })] }, source.id))), _jsxs("div", { className: cx(conflictRow, effectiveRow), children: [_jsx("span", { className: effectiveLabel, children: labels.effectiveValue }), _jsxs("span", { children: [_jsx("span", { className: sourceValue, children: effective.value }), effective.note !== undefined && _jsx("span", { className: effectiveNote, children: effective.note })] }), action ?? _jsx("span", {})] })] }));
|
|
422
452
|
}
|
|
@@ -9,4 +9,4 @@ export type EmailInputProps = Omit<InputProps, "value" | "defaultValue" | "onCha
|
|
|
9
9
|
invalidEmails?: readonly string[];
|
|
10
10
|
};
|
|
11
11
|
/** Comma, semicolon, whitespace, Enter, Tab, or blur commits addresses; duplicates are ignored. */
|
|
12
|
-
export declare function EmailInput({ value, onValueChange, inputValue, onInputValueChange, invalidEmails, disabled, className, onKeyDown, onBlur, onPaste, ...props }: EmailInputProps): import("
|
|
12
|
+
export declare function EmailInput({ value, onValueChange, inputValue, onInputValueChange, invalidEmails, disabled, className, onKeyDown, onBlur, onPaste, ...props }: EmailInputProps): import("react").JSX.Element;
|
|
@@ -2,18 +2,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { css, cx } from "#primitives/css";
|
|
3
3
|
import { Chip } from "./chip.js";
|
|
4
4
|
import { useFieldControl } from "./field-context.js";
|
|
5
|
+
// The field face `Input` wears, holding chips that wrap onto more lines as they fill it.
|
|
5
6
|
const emailField = css({
|
|
6
7
|
display: "flex",
|
|
7
8
|
flexWrap: "wrap",
|
|
8
9
|
alignItems: "center",
|
|
9
10
|
gap: "layout.tightGap",
|
|
10
11
|
padding: "control.compactBlock",
|
|
11
|
-
minHeight: "control.
|
|
12
|
+
minHeight: "control.default",
|
|
12
13
|
border: "1px solid token(colors.border.control)",
|
|
13
|
-
borderRadius: "
|
|
14
|
-
background: "bg.
|
|
14
|
+
borderRadius: "control",
|
|
15
|
+
background: "bg.formField",
|
|
15
16
|
_focusWithin: { focusRing: "outer" },
|
|
16
|
-
"&[data-invalid]": { borderColor: "
|
|
17
|
+
"&[data-invalid]": { borderColor: "border.error" },
|
|
17
18
|
"&[data-disabled]": { opacity: "disabled" },
|
|
18
19
|
});
|
|
19
20
|
const draftInput = css({
|
|
@@ -28,7 +29,7 @@ const draftInput = css({
|
|
|
28
29
|
height: "control.shortcut",
|
|
29
30
|
paddingInline: "control.compactInline",
|
|
30
31
|
outline: "none",
|
|
31
|
-
_placeholder: { color: "fg.
|
|
32
|
+
_placeholder: { color: "fg.subtle" },
|
|
32
33
|
_focusVisible: { outline: "none", boxShadow: "none" },
|
|
33
34
|
});
|
|
34
35
|
/** Comma, semicolon, whitespace, Enter, Tab, or blur commits addresses; duplicates are ignored. */
|
|
@@ -9,5 +9,5 @@ export type EnvironmentFrameProps = ComponentProps<"div"> & {
|
|
|
9
9
|
/** The strip's tint: `warning` for a staging build, `info` for dev. */
|
|
10
10
|
tone?: SiteBannerProps["tone"];
|
|
11
11
|
};
|
|
12
|
-
/**
|
|
13
|
-
export declare function EnvironmentFrame({ label, tone, children, className, ...props }: EnvironmentFrameProps): import("
|
|
12
|
+
/** An environment strip, which the reader can dismiss for the session, and an inset AppShell viewport. */
|
|
13
|
+
export declare function EnvironmentFrame({ label, tone, children, className, ...props }: EnvironmentFrameProps): import("react").JSX.Element;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
2
3
|
import { css, cx } from "#primitives/css";
|
|
3
4
|
import { useCiridaeLocale } from "./locale.js";
|
|
4
5
|
import { SiteBanner } from "./site-banner.js";
|
|
@@ -17,26 +18,56 @@ const viewport = css({
|
|
|
17
18
|
flex: "1",
|
|
18
19
|
minHeight: "0",
|
|
19
20
|
overflow: "hidden",
|
|
20
|
-
background: "
|
|
21
|
+
background: "token(gradients.canvas)",
|
|
21
22
|
// Only under the environment strip does the app read as inset below it.
|
|
22
23
|
"&[data-under-banner]": {
|
|
23
24
|
borderTopRadius: "field",
|
|
24
25
|
boxShadow: "inset 0 2px 4px rgba(0, 0, 0, 0.18)",
|
|
25
26
|
},
|
|
26
|
-
// Keep the shell and its phone layout within the space below the site banner.
|
|
27
|
+
// Keep the shell and its phone layout within the space below the site banner. On a desktop the
|
|
28
|
+
// shell's row sizes the main panel inside its block margins, so a full height would push it past
|
|
29
|
+
// them; a phone's main panel is a full window tall, so there it takes the space under the strip.
|
|
27
30
|
"& > [data-ciridae-ui]": { height: "100%", background: "transparent" },
|
|
28
31
|
"& > [data-ciridae-ui] > main": {
|
|
29
|
-
height: "100%",
|
|
30
32
|
borderRadius: "inset",
|
|
31
|
-
_phone: { borderRadius: "0" },
|
|
33
|
+
_phone: { borderRadius: "0", height: "100%" },
|
|
32
34
|
},
|
|
33
35
|
"& > [data-ciridae-ui] > main > header": {
|
|
34
36
|
paddingInlineStart: "page.inline",
|
|
35
37
|
_phone: { paddingInlineStart: "panel.default" },
|
|
36
38
|
},
|
|
37
39
|
});
|
|
38
|
-
|
|
40
|
+
/*
|
|
41
|
+
* Dismissing the strip hides it for the rest of the browser tab's session. Where the browser blocks
|
|
42
|
+
* storage, such as a sandboxed frame or site data turned off, even reading `sessionStorage` throws;
|
|
43
|
+
* the strip then shows on each load and a dismissal lasts until the page reloads.
|
|
44
|
+
*/
|
|
45
|
+
const dismissedStorageKey = "ciridae-ui-environment-banner-dismissed";
|
|
46
|
+
function readDismissedForSession() {
|
|
47
|
+
try {
|
|
48
|
+
return sessionStorage.getItem(dismissedStorageKey) === "1";
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.warn(`Showing the environment strip: could not read ${dismissedStorageKey}`, error);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function rememberDismissedForSession() {
|
|
56
|
+
try {
|
|
57
|
+
sessionStorage.setItem(dismissedStorageKey, "1");
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.warn(`Could not save ${dismissedStorageKey}; the strip stays hidden until the page reloads`, error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** An environment strip, which the reader can dismiss for the session, and an inset AppShell viewport. */
|
|
39
64
|
export function EnvironmentFrame({ label, tone = "info", children, className, ...props }) {
|
|
40
65
|
const { labels } = useCiridaeLocale();
|
|
41
|
-
|
|
66
|
+
const [dismissed, setDismissed] = useState(readDismissedForSession);
|
|
67
|
+
const shown = label !== undefined && !dismissed;
|
|
68
|
+
const dismiss = () => {
|
|
69
|
+
rememberDismissedForSession();
|
|
70
|
+
setDismissed(true);
|
|
71
|
+
};
|
|
72
|
+
return (_jsxs("div", { ...props, className: cx(frame, className), children: [shown && (_jsx(SiteBanner, { className: environmentBanner, tone: tone, onDismiss: dismiss, children: typeof label === "string" ? labels.shell.environment(label) : label })), _jsx("div", { className: viewport, "data-under-banner": shown || undefined, children: children })] }));
|
|
42
73
|
}
|
|
@@ -16,4 +16,4 @@ export declare function FeedbackScreenshot({ src, pointers, onPointersChange, di
|
|
|
16
16
|
pointers: readonly PlacedScreenshotPointer[];
|
|
17
17
|
onPointersChange: (pointers: readonly PlacedScreenshotPointer[]) => void;
|
|
18
18
|
disabled?: boolean;
|
|
19
|
-
}): import("
|
|
19
|
+
}): import("react").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import { type FeedbackItem, type FeedbackSummary } from "../feedback/contract.js";
|
|
3
|
+
import { type FeedbackTriageStatus, type OperatorFeedbackItem, type OperatorFeedbackSummary } from "../feedback/operator-contract.js";
|
|
3
4
|
import { type FeedbackScreenshotPointer } from "./feedback-screenshot.js";
|
|
4
5
|
import { type CiridaeLabels } from "./locale.js";
|
|
5
6
|
export type FeedbackKind = "wrong" | "idea" | "question";
|
|
@@ -42,7 +43,7 @@ export type FeedbackFormProps = {
|
|
|
42
43
|
onClose: () => void;
|
|
43
44
|
};
|
|
44
45
|
/** The sheet's form, body and footer, for a `Drawer` that holds more than the form. */
|
|
45
|
-
export declare function FeedbackForm({ where: about, screenshot, onSubmit, errorDetail, onClose, }: FeedbackFormProps): import("
|
|
46
|
+
export declare function FeedbackForm({ where: about, screenshot, onSubmit, errorDetail, onClose, }: FeedbackFormProps): import("react").JSX.Element;
|
|
46
47
|
/** Something the caller loads for the sheet: in flight, failed with a way to try again, or here. */
|
|
47
48
|
export type FeedbackLoadState<Data> = {
|
|
48
49
|
status: "loading";
|
|
@@ -66,15 +67,29 @@ export type FeedbackSentProps = {
|
|
|
66
67
|
/** Resolves once `item` is withdrawn. */
|
|
67
68
|
onWithdraw: (feedbackId: string) => Promise<void>;
|
|
68
69
|
};
|
|
70
|
+
/** The All tab, for the people who answer feedback: everyone's items, triaged and replied to. */
|
|
71
|
+
export type FeedbackOperatorProps = {
|
|
72
|
+
/** Every reporter's feedback, in any order; the tab lists the latest change first. */
|
|
73
|
+
items: FeedbackLoadState<readonly OperatorFeedbackSummary[]>;
|
|
74
|
+
/** Loads the item into `item`; the sheet shows it once the ids match. */
|
|
75
|
+
onOpenItem: (feedbackId: string) => void;
|
|
76
|
+
item?: FeedbackLoadState<OperatorFeedbackItem>;
|
|
77
|
+
/** Resolves once `item` carries the reply; rejecting keeps the reply in the composer. */
|
|
78
|
+
onReply: (feedbackId: string, body: string) => Promise<void>;
|
|
79
|
+
/** Resolves once `item` carries the status; withdrawing stays the reporter's. */
|
|
80
|
+
onStatusChange: (feedbackId: string, status: FeedbackTriageStatus) => Promise<void>;
|
|
81
|
+
};
|
|
69
82
|
export type FeedbackSheetProps = Omit<FeedbackFormProps, "onClose"> & {
|
|
70
83
|
open: boolean;
|
|
71
84
|
onOpenChange: (open: boolean) => void;
|
|
72
85
|
/** Controls in the sheet's header, before the close button. */
|
|
73
86
|
actions?: ReactNode;
|
|
74
|
-
/** The
|
|
87
|
+
/** The person's own tickets; without it or `operator` the sheet is the form alone. */
|
|
75
88
|
sent?: FeedbackSentProps;
|
|
89
|
+
/** For an operator, the Tickets tab lists everyone's, with a filter for their own (`sent`). */
|
|
90
|
+
operator?: FeedbackOperatorProps;
|
|
76
91
|
/** Rewords the sheet's labels over the locale's. */
|
|
77
92
|
labels?: Partial<FeedbackLabels>;
|
|
78
93
|
};
|
|
79
94
|
/** The floating feedback sheet. Closing it drops the draft and the open item. */
|
|
80
|
-
export declare function FeedbackSheet({ labels, ...props }: FeedbackSheetProps): import("
|
|
95
|
+
export declare function FeedbackSheet({ labels, ...props }: FeedbackSheetProps): import("react").JSX.Element;
|