@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.
Files changed (209) hide show
  1. package/dist/app/auth.d.ts +10 -0
  2. package/dist/app/auth.js +60 -0
  3. package/dist/app/error-boundary.d.ts +18 -0
  4. package/dist/app/error-boundary.js +45 -0
  5. package/dist/app/feedback.d.ts +12 -0
  6. package/dist/app/feedback.js +128 -0
  7. package/dist/app/index.d.ts +8 -0
  8. package/dist/app/index.js +8 -0
  9. package/dist/app/request-errors.d.ts +63 -0
  10. package/dist/app/request-errors.js +172 -0
  11. package/dist/app/sentry.d.ts +18 -0
  12. package/dist/app/sentry.js +52 -0
  13. package/dist/app/telemetry.d.ts +7 -0
  14. package/dist/app/telemetry.js +28 -0
  15. package/dist/app/trail.d.ts +9 -0
  16. package/dist/app/trail.js +18 -0
  17. package/dist/chat/chat-query-keys.d.ts +3 -3
  18. package/dist/chat/contract.d.ts +15 -15
  19. package/dist/chat/conversation-items-query-options.d.ts +114 -114
  20. package/dist/chat/conversation-source.d.ts +89 -0
  21. package/dist/chat/conversation-source.js +1 -0
  22. package/dist/chat/describe-tool-call.d.ts +3 -3
  23. package/dist/chat/describe-tool-call.js +3 -3
  24. package/dist/chat/message-text.d.ts +1 -1
  25. package/dist/chat/message-text.js +116 -48
  26. package/dist/chat/use-conversation-list.d.ts +6 -6
  27. package/dist/ciridae.css +16 -4
  28. package/dist/components/activity-feed.d.ts +3 -2
  29. package/dist/components/activity-feed.js +1 -0
  30. package/dist/components/agent-work.d.ts +3 -3
  31. package/dist/components/app-frame.d.ts +91 -0
  32. package/dist/components/app-frame.js +134 -0
  33. package/dist/components/app-navigation.d.ts +30 -3
  34. package/dist/components/app-navigation.js +105 -14
  35. package/dist/components/badge.d.ts +30 -5
  36. package/dist/components/badge.js +134 -15
  37. package/dist/components/brand-icons.d.ts +3 -3
  38. package/dist/components/bulk-action-bar.d.ts +1 -1
  39. package/dist/components/bulk-action-bar.js +3 -3
  40. package/dist/components/button.d.ts +12 -5
  41. package/dist/components/button.js +77 -44
  42. package/dist/components/calendar.d.ts +1 -1
  43. package/dist/components/calendar.js +44 -17
  44. package/dist/components/centered-page.d.ts +1 -1
  45. package/dist/components/centered-page.js +2 -2
  46. package/dist/components/chart.d.ts +22 -2
  47. package/dist/components/chart.js +251 -51
  48. package/dist/components/chat-client-source.d.ts +16 -0
  49. package/dist/components/chat-client-source.js +297 -0
  50. package/dist/components/chat-page.d.ts +9 -8
  51. package/dist/components/chat-page.js +7 -11
  52. package/dist/components/chat-sheet-controller.d.ts +11 -14
  53. package/dist/components/chat-sheet-controller.js +3 -3
  54. package/dist/components/chat-sheet.d.ts +18 -11
  55. package/dist/components/chat-sheet.js +188 -289
  56. package/dist/components/chat.d.ts +109 -19
  57. package/dist/components/chat.js +520 -124
  58. package/dist/components/checkbox-item.d.ts +6 -3
  59. package/dist/components/checkbox-item.js +9 -5
  60. package/dist/components/checkbox-list.d.ts +1 -1
  61. package/dist/components/chip.d.ts +6 -1
  62. package/dist/components/chip.js +27 -1
  63. package/dist/components/collapsible.d.ts +1 -1
  64. package/dist/components/color-theme.d.ts +1 -1
  65. package/dist/components/column-settings.d.ts +1 -1
  66. package/dist/components/column-settings.js +1 -1
  67. package/dist/components/command-menu.d.ts +5 -1
  68. package/dist/components/command-menu.js +98 -32
  69. package/dist/components/command-palette.d.ts +7 -3
  70. package/dist/components/command-palette.js +20 -11
  71. package/dist/components/copyable-id.d.ts +22 -5
  72. package/dist/components/copyable-id.js +46 -6
  73. package/dist/components/data-display.d.ts +39 -8
  74. package/dist/components/data-display.js +138 -19
  75. package/dist/components/data-grid.d.ts +23 -11
  76. package/dist/components/data-grid.js +61 -26
  77. package/dist/components/date-range-picker.d.ts +1 -1
  78. package/dist/components/date-range-picker.js +9 -20
  79. package/dist/components/date-time.d.ts +1 -1
  80. package/dist/components/dialog-height-context.d.ts +1 -1
  81. package/dist/components/document-viewer.d.ts +2 -2
  82. package/dist/components/drawer.d.ts +11 -6
  83. package/dist/components/drawer.js +91 -54
  84. package/dist/components/dropzone.d.ts +4 -4
  85. package/dist/components/editable-field.d.ts +12 -3
  86. package/dist/components/editable-field.js +57 -27
  87. package/dist/components/email-input.d.ts +1 -1
  88. package/dist/components/email-input.js +6 -5
  89. package/dist/components/environment-frame.d.ts +2 -2
  90. package/dist/components/environment-frame.js +37 -6
  91. package/dist/components/expandable-text.d.ts +1 -1
  92. package/dist/components/feedback-screenshot.d.ts +1 -1
  93. package/dist/components/feedback-sheet.d.ts +18 -3
  94. package/dist/components/feedback-sheet.js +216 -55
  95. package/dist/components/field-context.d.ts +1 -1
  96. package/dist/components/filter-bar.d.ts +3 -3
  97. package/dist/components/filter-bar.js +43 -29
  98. package/dist/components/form-controls.d.ts +12 -3
  99. package/dist/components/form-controls.js +46 -22
  100. package/dist/components/form-layout.d.ts +14 -10
  101. package/dist/components/form-layout.js +68 -23
  102. package/dist/components/glass-menu.d.ts +3 -0
  103. package/dist/components/glass-menu.js +63 -0
  104. package/dist/components/gradient-edge.d.ts +9 -0
  105. package/dist/components/gradient-edge.js +31 -0
  106. package/dist/components/hotkeys.d.ts +2 -2
  107. package/dist/components/icon.d.ts +1 -1
  108. package/dist/components/input.d.ts +7 -5
  109. package/dist/components/input.js +29 -17
  110. package/dist/components/keyboard-shortcuts.d.ts +2 -2
  111. package/dist/components/keycap.d.ts +10 -6
  112. package/dist/components/keycap.js +57 -19
  113. package/dist/components/layout.d.ts +13 -13
  114. package/dist/components/lightbox.d.ts +9 -3
  115. package/dist/components/lightbox.js +13 -9
  116. package/dist/components/link.d.ts +1 -1
  117. package/dist/components/locale.d.ts +42 -2
  118. package/dist/components/locale.js +43 -3
  119. package/dist/components/log-entry.d.ts +40 -0
  120. package/dist/components/log-entry.js +146 -0
  121. package/dist/components/log-list.d.ts +3 -3
  122. package/dist/components/mention-input.d.ts +2 -2
  123. package/dist/components/mention-input.js +4 -3
  124. package/dist/components/menu.d.ts +7 -3
  125. package/dist/components/menu.js +34 -37
  126. package/dist/components/meter.d.ts +10 -2
  127. package/dist/components/meter.js +64 -6
  128. package/dist/components/navigation.d.ts +21 -4
  129. package/dist/components/navigation.js +84 -19
  130. package/dist/components/notification-tray.d.ts +1 -1
  131. package/dist/components/notification-tray.js +5 -4
  132. package/dist/components/overlays.d.ts +6 -4
  133. package/dist/components/overlays.js +69 -40
  134. package/dist/components/page-frame.d.ts +4 -4
  135. package/dist/components/page-frame.js +1 -1
  136. package/dist/components/panel.d.ts +4 -4
  137. package/dist/components/panel.js +18 -12
  138. package/dist/components/profile-header.d.ts +1 -1
  139. package/dist/components/progress.d.ts +1 -1
  140. package/dist/components/project-avatar.d.ts +1 -1
  141. package/dist/components/radio-card.d.ts +2 -2
  142. package/dist/components/radio-card.js +10 -9
  143. package/dist/components/record.d.ts +29 -5
  144. package/dist/components/record.js +147 -18
  145. package/dist/components/resolved-file-url.d.ts +19 -0
  146. package/dist/components/resolved-file-url.js +49 -0
  147. package/dist/components/scroll-area.d.ts +1 -1
  148. package/dist/components/secret-dialog.d.ts +1 -1
  149. package/dist/components/segmented-bar.d.ts +4 -2
  150. package/dist/components/segmented-bar.js +16 -6
  151. package/dist/components/select.d.ts +9 -6
  152. package/dist/components/select.js +103 -127
  153. package/dist/components/settings.d.ts +4 -4
  154. package/dist/components/shell-skeleton.d.ts +1 -1
  155. package/dist/components/shell-skeleton.js +1 -1
  156. package/dist/components/shell.d.ts +21 -21
  157. package/dist/components/shell.js +43 -43
  158. package/dist/components/side-panel.d.ts +3 -3
  159. package/dist/components/sidebar.d.ts +13 -8
  160. package/dist/components/sidebar.js +55 -27
  161. package/dist/components/single-line-text.d.ts +2 -0
  162. package/dist/components/single-line-text.js +16 -0
  163. package/dist/components/site-banner.d.ts +5 -2
  164. package/dist/components/site-banner.js +17 -6
  165. package/dist/components/skeleton.d.ts +8 -7
  166. package/dist/components/skeleton.js +28 -16
  167. package/dist/components/skeletons.d.ts +17 -5
  168. package/dist/components/skeletons.js +71 -8
  169. package/dist/components/stages.d.ts +83 -11
  170. package/dist/components/stages.js +512 -156
  171. package/dist/components/stat-card.d.ts +12 -4
  172. package/dist/components/stat-card.js +92 -37
  173. package/dist/components/status-banner.d.ts +1 -1
  174. package/dist/components/status-banner.js +1 -1
  175. package/dist/components/status.d.ts +2 -2
  176. package/dist/components/steps.d.ts +1 -1
  177. package/dist/components/switch.d.ts +1 -1
  178. package/dist/components/tabs.d.ts +8 -8
  179. package/dist/components/tabs.js +26 -13
  180. package/dist/components/theme-customizer.d.ts +2 -2
  181. package/dist/components/theme-toggle.d.ts +4 -0
  182. package/dist/components/theme-toggle.js +67 -0
  183. package/dist/components/toast.d.ts +10 -3
  184. package/dist/components/toast.js +78 -29
  185. package/dist/components/use-new-version-available.d.ts +6 -0
  186. package/dist/components/use-new-version-available.js +29 -0
  187. package/dist/components/user-chip.d.ts +3 -3
  188. package/dist/components/wizard.d.ts +2 -2
  189. package/dist/feedback/contract.d.ts +136 -136
  190. package/dist/feedback/feedback-controller.d.ts +6 -6
  191. package/dist/feedback/generated/zod.gen.d.ts +28 -28
  192. package/dist/feedback/operator-contract.d.ts +11 -11
  193. package/dist/feedback/operator-controller.d.ts +32 -13
  194. package/dist/feedback/operator-controller.js +44 -11
  195. package/dist/preset.js +289 -33
  196. package/dist/styled-system/styles.css +3294 -1079
  197. package/dist/styled-system/tokens/index.mjs +598 -22
  198. package/dist/styled-system/tokens/tokens.d.ts +11 -11
  199. package/dist/styled-system/types/prop-type.d.ts +2 -2
  200. package/dist/styles.css +16 -4
  201. package/dist/theme/color.d.ts +3 -0
  202. package/dist/theme/color.js +5 -0
  203. package/dist/theme/derive.d.ts +9 -2
  204. package/dist/theme/derive.js +72 -12
  205. package/dist/theme/palettes.d.ts +49 -6
  206. package/dist/theme/palettes.js +84 -15
  207. package/dist/theme/tokens.d.ts +3 -3
  208. package/dist/theme/tokens.js +107 -32
  209. package/package.json +40 -3
@@ -2,11 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Radio as BaseRadio } from "@base-ui/react/radio";
3
3
  import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group";
4
4
  import { css, cx } from "#primitives/css";
5
- import { checkMark, radioDot } from "./form-controls.js";
5
+ import { checkMark, checkMarkEdge, radioDot } from "./form-controls.js";
6
6
  /*
7
7
  * A choice drawn as a card: the radio, a title with its detail, and where the option comes from
8
8
  * at the far edge. The whole card is the radio, so it takes the hover wash, the focus ring, and,
9
- * once chosen, the accent wash under the accent's edge.
9
+ * once chosen, the selected tint under an edge in the text color.
10
10
  */
11
11
  const cards = css({ display: "grid", gap: "layout.controlGap" });
12
12
  const card = css({
@@ -28,10 +28,10 @@ const card = css({
28
28
  cursor: "pointer",
29
29
  transitionProperty: "background, border-color",
30
30
  transitionDuration: "fast",
31
- _hover: { background: "bg.glassHover" },
31
+ _hover: { background: "token(gradients.raisedHover)" },
32
32
  "&[data-checked]": {
33
- background: "bg.selected",
34
- borderColor: "border.selected",
33
+ background: "token(gradients.selected)",
34
+ borderColor: "fg.primary",
35
35
  },
36
36
  _focusVisible: { focusRing: "outer" },
37
37
  "&[data-disabled]": { opacity: "disabled", cursor: "not-allowed" },
@@ -42,10 +42,11 @@ const mark = css({
42
42
  // the mark down.
43
43
  marginTop: "calc((1em - token(sizes.control.radio)) / 2)",
44
44
  "[data-checked] > &": {
45
- background: "bg.primary",
46
- borderColor: "transparent",
45
+ background: "token(gradients.primary)",
46
+ _light: { background: "token(gradients.primary)" },
47
+ _before: { background: "token(gradients.border.primary)" },
47
48
  },
48
- "[data-checked]:hover > &": { background: "bg.primaryHover" },
49
+ "[data-checked]:hover > &": { opacity: "checkedHover", _light: { opacity: "1" } },
49
50
  });
50
51
  const copy = css({ flex: "1", minWidth: "0", display: "grid", gap: "layout.tightGap" });
51
52
  const detailText = css({ color: "fg.muted", fontSize: "code" });
@@ -62,5 +63,5 @@ export function RadioCardGroup({ name, label, defaultValue, value, onValueChange
62
63
  }
63
64
  /** One option of a `RadioCardGroup`. */
64
65
  export function RadioCard({ title, detail, source: sourceContent, className, ...props }) {
65
- return (_jsxs(BaseRadio.Root, { ...props, className: cx(card, className), "data-ciridae-ui": "", children: [_jsx("span", { className: cx(checkMark({ shape: "round", focus: "row" }), mark), children: _jsx(BaseRadio.Indicator, { className: radioDot }) }), _jsxs("span", { className: copy, children: [_jsx("span", { children: title }), detail !== undefined && _jsx("span", { className: detailText, children: detail })] }), sourceContent !== undefined && _jsx("span", { className: source, children: sourceContent })] }));
66
+ return (_jsxs(BaseRadio.Root, { ...props, className: cx(card, className), "data-ciridae-ui": "", children: [_jsx("span", { ...checkMarkEdge, className: cx(checkMark({ shape: "round", focus: "row" }), mark), children: _jsx(BaseRadio.Indicator, { className: radioDot }) }), _jsxs("span", { className: copy, children: [_jsx("span", { children: title }), detail !== undefined && _jsx("span", { className: detailText, children: detail })] }), sourceContent !== undefined && _jsx("span", { className: source, children: sourceContent })] }));
66
67
  }
@@ -20,7 +20,7 @@ export type DetailLayoutProps = Omit<ComponentProps<"div">, "children"> & {
20
20
  aside: ReactNode;
21
21
  };
22
22
  };
23
- export declare function DetailLayout({ header, main, aside, stackBelow, stickyAside, stacking, tabLabels, className, ...props }: DetailLayoutProps): import("@types/react").JSX.Element;
23
+ export declare function DetailLayout({ header, main, aside, stackBelow, stickyAside, stacking, tabLabels, className, ...props }: DetailLayoutProps): import("react").JSX.Element;
24
24
  /** The record's title row is the page's: `PageHeading`, with `leading`, `badge` and menu `actions`. */
25
25
  export { PageHeading, type PageHeadingProps } from "./page-frame.js";
26
26
  export type RelatedTab = {
@@ -39,7 +39,7 @@ export type RelatedTabsProps = Omit<ComponentProps<typeof TabsRoot>, "children"
39
39
  defaultValue?: string;
40
40
  onValueChange?: (value: string) => void;
41
41
  };
42
- export declare function RelatedTabs({ tabs, value, defaultValue, onValueChange, className, ...props }: RelatedTabsProps): import("@types/react").JSX.Element | null;
42
+ export declare function RelatedTabs({ tabs, value, defaultValue, onValueChange, className, ...props }: RelatedTabsProps): import("react").JSX.Element | null;
43
43
  export type ItemCardField = {
44
44
  label: ReactNode;
45
45
  value: ReactNode;
@@ -48,7 +48,7 @@ export type ItemCardField = {
48
48
  };
49
49
  export type ItemCardProps = Omit<useRender.ComponentProps<"button">, "children" | "onSelect"> & {
50
50
  title: ReactNode;
51
- /** One segment per stage, in its status's color. */
51
+ /** One dot per stage, in its status. */
52
52
  progress?: readonly StepStatus[];
53
53
  fields: readonly ItemCardField[];
54
54
  /** The footer's start: the stage the item is at. */
@@ -63,7 +63,31 @@ export type ItemCardProps = Omit<useRender.ComponentProps<"button">, "children"
63
63
  onSelect?: () => void;
64
64
  href?: string;
65
65
  };
66
- export declare function ItemCard({ title, progress, fields, status, footer, selected, onSelect, href, render, className, style, ...props }: ItemCardProps): import("@types/react").ReactElement<unknown, string | import("@types/react").JSXElementConstructor<any>>;
66
+ export declare function ItemCard({ title, progress, fields, status, footer, selected, onSelect, href, render, className, style, ...props }: ItemCardProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
67
+ export type PartRowProps = Omit<ComponentProps<"div">, "children" | "onSelect"> & {
68
+ /** `wide` is one line, as in a table; `compact` stacks for a narrow column. */
69
+ layout?: "wide" | "compact";
70
+ name: ReactNode;
71
+ /** Under the name, such as the part's phase and amount. */
72
+ detail?: ReactNode;
73
+ /** One dot per step, in its status; the kit draws at most four. */
74
+ progress: readonly StepStatus[];
75
+ /** The stage the part is at. */
76
+ stage: ReactNode;
77
+ /** Whose move it is: `yourMove` sets the next step in the ink, the others in grey. */
78
+ state: "yourMove" | "waiting" | "done" | "notStarted";
79
+ /** Before the next step, such as a "Your move" badge. */
80
+ badge?: ReactNode;
81
+ next: ReactNode;
82
+ /** The part's one button, for the reader's move or a nudge while waiting. */
83
+ action?: {
84
+ label: ReactNode;
85
+ onClick: () => void;
86
+ };
87
+ selected?: boolean;
88
+ onSelect?: () => void;
89
+ };
90
+ export declare function PartRow({ layout, name, detail, progress, stage, state, badge, next, action, selected, onSelect, className, ...props }: PartRowProps): import("react").JSX.Element;
67
91
  export type RelatedListItem = {
68
92
  id: string;
69
93
  title: ReactNode;
@@ -92,4 +116,4 @@ export type RelatedListProps = Omit<ComponentProps<"div">, "children"> & {
92
116
  /** After the groups, such as a button that links another record. */
93
117
  footer?: ReactNode;
94
118
  };
95
- export declare function RelatedList({ groups, footer, className, ...props }: RelatedListProps): import("@types/react").JSX.Element;
119
+ export declare function RelatedList({ groups, footer, className, ...props }: RelatedListProps): import("react").JSX.Element;
@@ -2,13 +2,15 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  /*
3
3
  * The pieces a record's page is laid out with. `DetailLayout` splits it into the work and a side
4
4
  * column; `PageHeading` (also exported here) is the record's title row; `RelatedTabs` is the tabbed card of what the
5
- * record holds; `ItemCard` is one of a record's parts, such as a shipment or a draw; `RelatedList`
5
+ * record holds; `ItemCard` is one of a record's parts, such as a shipment or a draw, as a card and `PartRow` as
6
+ * a row; `RelatedList`
6
7
  * lists the records and documents it points at.
7
8
  */
8
9
  import { useRender } from "@base-ui/react/use-render";
9
10
  import { CaretRightIcon } from "@phosphor-icons/react";
10
- import { useLayoutEffect, useRef, useState, } from "react";
11
+ import { Fragment, useLayoutEffect, useRef, useState, } from "react";
11
12
  import { css, cx } from "#primitives/css";
13
+ import { Button } from "./button.js";
12
14
  import { useControllableState } from "./controllable-state.js";
13
15
  import { directional, icon } from "./icon.js";
14
16
  import { MutedText } from "./layout.js";
@@ -110,7 +112,10 @@ export function RelatedTabs({ tabs, value, defaultValue, onValueChange, classNam
110
112
  return null;
111
113
  return (_jsxs(TabsRoot, { value: open.value, onValueChange: (next) => setChosen(String(next)), ...props, className: cx(relatedCard, className), "data-ciridae-ui": "", children: [_jsxs("div", { className: relatedHeader, children: [_jsx(TabsList, { variant: "contained", children: tabs.map((tab) => (_jsx(TabsTab, { value: tab.value, count: tab.count, children: tab.label }, tab.value))) }), open.meta !== undefined && _jsx(MutedText, { className: relatedMeta, children: open.meta })] }), tabs.map((tab) => (_jsx(TabsPanel, { value: tab.value, children: tab.content }, tab.value)))] }));
112
114
  }
113
- /* Item card: one of a record's parts, with its progress as a thin segmented bar. */
115
+ /*
116
+ * Item card: one of a record's parts, the kit's Part card, with its progress as a mini strip of
117
+ * step dots. The chosen one lifts onto the solid card inside a green edge.
118
+ */
114
119
  const itemCard = css(cardSurface, {
115
120
  display: "grid",
116
121
  gap: "layout.clusterGap",
@@ -121,7 +126,11 @@ const itemCard = css(cardSurface, {
121
126
  letterSpacing: "compact",
122
127
  textDecoration: "none",
123
128
  "&:is(button, a)": { cursor: "pointer", _hover: { borderColor: "border.glass" } },
124
- "&[data-selected]": { borderColor: "accent.green", _hover: { borderColor: "accent.green" } },
129
+ "&[data-selected]": {
130
+ borderColor: "accent.green",
131
+ boxShadow: "soft",
132
+ _hover: { borderColor: "accent.green" },
133
+ },
125
134
  _focusVisible: { focusRing: "outer" },
126
135
  });
127
136
  const itemHeader = css({
@@ -131,20 +140,27 @@ const itemHeader = css({
131
140
  gap: "layout.controlGap",
132
141
  fontSize: "body",
133
142
  fontWeight: "medium",
143
+ lineHeight: "tight",
134
144
  whiteSpace: "nowrap",
135
145
  });
136
- const progressBar = css({ display: "inline-flex", alignItems: "center", gap: "2px" });
137
- const progressSegment = css({
138
- width: "14px",
139
- height: "4px",
140
- borderRadius: "1px",
141
- background: "bg.fill",
142
- "&[data-status=done]": { background: "accent.green" },
143
- "&[data-status=current]": { background: "accent.yellow" },
144
- "&[data-status=agent]": { background: "accent.blue" },
145
- "&[data-status=blocked]": { background: "accent.red" },
146
- "&[data-status=waiting]": { background: "fg.muted" },
146
+ const progressStrip = css({
147
+ display: "inline-flex",
148
+ flexShrink: "0",
149
+ alignItems: "center",
150
+ gap: "layout.tightGap",
151
+ });
152
+ // 16px between dots, green out of a finished step as the stage strip's connectors are.
153
+ const progressConnector = css({
154
+ width: "token(spacing.layout.clusterGap)",
155
+ height: "border.hairline",
156
+ borderRadius: "round",
157
+ background: "border.divider",
158
+ "&[data-after=done]": { background: "accent.green" },
147
159
  });
160
+ /** A part's progress: one 12px dot a step, joined by 16px connectors. */
161
+ function MiniStrip({ progress }) {
162
+ return (_jsx("span", { className: progressStrip, "aria-hidden": "true", children: progress.map((step, index) => (_jsxs(Fragment, { children: [index > 0 && (_jsx("span", { className: progressConnector, "data-after": progress[index - 1] === "done" ? "done" : undefined })), _jsx(StepDot, { status: step, size: "chip" })] }, index))) }));
163
+ }
148
164
  const itemFields = css({
149
165
  display: "grid",
150
166
  gap: "layout.controlGap",
@@ -155,7 +171,7 @@ const itemFields = css({
155
171
  const itemFieldLabel = css({
156
172
  display: "block",
157
173
  marginBottom: "layout.controlGap",
158
- color: "fg.muted",
174
+ color: "fg.subtle",
159
175
  fontWeight: "regular",
160
176
  letterSpacing: "normal",
161
177
  });
@@ -188,10 +204,117 @@ export function ItemCard({ title, progress, fields, status, footer, selected = f
188
204
  "data-ciridae-ui": "",
189
205
  "data-selected": selected || undefined,
190
206
  "aria-pressed": onSelect !== undefined && href === undefined ? selected : undefined,
191
- children: (_jsxs(_Fragment, { children: [_jsxs("span", { className: itemHeader, children: [title, progress && (_jsx("span", { className: progressBar, "aria-hidden": "true", children: progress.map((segment, index) => (_jsx("span", { className: progressSegment, "data-status": segment }, index))) }))] }), _jsxs("span", { className: css({ display: "grid" }), children: [_jsx("span", { className: itemFields, style: columns, children: fields.map((field, index) => (_jsxs("span", { children: [_jsx("span", { className: itemFieldLabel, children: field.label }), field.value] }, index))) }), _jsxs("span", { className: itemFooter, children: [_jsxs("span", { className: itemStatus, children: [_jsx(StepDot, { status: status.status, size: "small" }), status.label] }), footer] })] })] })),
207
+ children: (_jsxs(_Fragment, { children: [_jsxs("span", { className: itemHeader, children: [title, progress && _jsx(MiniStrip, { progress: progress })] }), _jsxs("span", { className: css({ display: "grid" }), children: [_jsx("span", { className: itemFields, style: columns, children: fields.map((field, index) => (_jsxs("span", { children: [_jsx("span", { className: itemFieldLabel, children: field.label }), field.value] }, index))) }), _jsxs("span", { className: itemFooter, children: [_jsxs("span", { className: itemStatus, children: [_jsx(StepDot, { status: status.status, size: "small" }), status.label] }), footer] })] })] })),
192
208
  },
193
209
  });
194
210
  }
211
+ /*
212
+ * Part row: one of a record's parts as a table-like row, the kit's Part in its Wide and Compact
213
+ * layouts: name over detail, the mini strip, the stage, a badge for the reader's move, the next
214
+ * step and at most one action. Wide keeps it on one 56px line, wrapping the detail and next step
215
+ * only when the row is narrow; compact stacks the name and strip over the rest. The whole row chooses the part through its name; the action stays its own button.
216
+ */
217
+ const partRow = css({
218
+ position: "relative",
219
+ display: "flex",
220
+ alignItems: "center",
221
+ gap: "layout.clusterGap",
222
+ minHeight: "calc(token(sizes.control.compact) + token(spacing.panel.default) * 2)",
223
+ paddingBlock: "panel.default",
224
+ paddingInline: "panel.comfortable",
225
+ borderBottom: "1px solid token(colors.border.divider)",
226
+ fontWeight: "medium",
227
+ letterSpacing: "compact",
228
+ lineHeight: "tight",
229
+ "&:has([data-part-name]:hover)": { background: "bg.rowHover" },
230
+ "&[data-selected]": { background: "token(gradients.selected)" },
231
+ // Wide is a grid, so the strips and stages of a list of parts line up. The name and the next
232
+ // step share what the strip, stage and action leave, two parts to three, close to the kit's
233
+ // 240 and 488 in its 1092 row, so a narrow row narrows both rather than starving one.
234
+ "&[data-layout=wide]": {
235
+ display: "grid",
236
+ gridTemplateColumns: "minmax(0, 2fr) max-content 90px minmax(0, 3fr) max-content",
237
+ },
238
+ "&[data-layout=compact]": {
239
+ flexDirection: "column",
240
+ alignItems: "stretch",
241
+ gap: "layout.tightGap",
242
+ },
243
+ });
244
+ const partLine = css({
245
+ display: "flex",
246
+ alignItems: "center",
247
+ gap: "layout.contentGap",
248
+ minWidth: "0",
249
+ "[data-layout=wide] > &": { display: "contents" },
250
+ });
251
+ const partName = css({
252
+ display: "grid",
253
+ gap: "control.trackInset",
254
+ flex: "1 1 0",
255
+ minWidth: "0",
256
+ textAlign: "start",
257
+ "& > *": { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
258
+ });
259
+ // The name is the row's button: its box stretches over the whole row.
260
+ const partNameButton = css({
261
+ padding: "none",
262
+ border: "none",
263
+ background: "transparent",
264
+ color: "fg.primary",
265
+ font: "inherit",
266
+ fontSize: "body",
267
+ textAlign: "start",
268
+ cursor: "pointer",
269
+ _after: { content: '""', position: "absolute", inset: "0" },
270
+ _focusVisible: { outline: "none", _after: { focusRing: "inset" } },
271
+ });
272
+ // A narrow wide row wraps the detail rather than cut off its amount.
273
+ const partDetail = css({
274
+ color: "fg.subtle",
275
+ fontSize: "code",
276
+ "[data-layout=wide] &": { whiteSpace: "normal", lineHeight: "compact" },
277
+ });
278
+ const partStage = css({
279
+ flexShrink: "0",
280
+ color: "fg.subtle",
281
+ fontSize: "code",
282
+ whiteSpace: "nowrap",
283
+ "[data-layout=wide] &": { overflow: "hidden", textOverflow: "ellipsis" },
284
+ });
285
+ const partStatus = css({
286
+ display: "flex",
287
+ alignItems: "center",
288
+ gap: "layout.controlGap",
289
+ flexShrink: "0",
290
+ "[data-layout=wide] > * > &": { display: "contents" },
291
+ });
292
+ // Wide sets the badge after the stage, in the next step's cell; compact leads the status with it.
293
+ const partNextCell = css({
294
+ display: "flex",
295
+ alignItems: "center",
296
+ gap: "layout.clusterGap",
297
+ minWidth: "0",
298
+ "[data-layout=compact] &": { display: "contents" },
299
+ });
300
+ const partBadge = css({
301
+ display: "inline-flex",
302
+ flexShrink: "0",
303
+ "[data-layout=compact] &": { order: "-1" },
304
+ });
305
+ // The step the reader acts on wraps in a narrow row, never cut short.
306
+ const partNext = css({
307
+ minWidth: "0",
308
+ color: "fg.secondary",
309
+ fontSize: "caption",
310
+ lineHeight: "compact",
311
+ "[data-state=yourMove] &": { color: "fg.primary" },
312
+ });
313
+ // The action sits over the stretched name, so it stays its own button.
314
+ const partAction = css({ position: "relative", flexShrink: "0" });
315
+ export function PartRow({ layout = "wide", name, detail, progress, stage, state, badge, next, action, selected = false, onSelect, className, ...props }) {
316
+ return (_jsxs("div", { ...props, className: cx(partRow, className), "data-ciridae-ui": "", "data-layout": layout, "data-state": state, "data-selected": selected || undefined, children: [_jsxs("span", { className: partLine, children: [_jsxs("span", { className: partName, children: [onSelect ? (_jsx("button", { type: "button", className: partNameButton, "data-part-name": "", "aria-pressed": selected, onClick: onSelect, children: name })) : (_jsx("span", { className: css({ fontSize: "body" }), children: name })), layout === "wide" && detail !== undefined && (_jsx("span", { className: partDetail, children: detail }))] }), _jsx(MiniStrip, { progress: progress })] }), _jsxs("span", { className: partLine, children: [layout === "compact" && _jsx("span", { className: cx(partName, partDetail), children: detail }), _jsxs("span", { className: partStatus, children: [_jsx("span", { className: partStage, children: stage }), _jsxs("span", { className: partNextCell, children: [badge !== undefined && _jsx("span", { className: partBadge, children: badge }), _jsx("span", { className: partNext, children: next })] }), action && (_jsx(Button, { variant: "secondary", className: partAction, onClick: action.onClick, children: action.label }))] })] })] }));
317
+ }
195
318
  /* Related list: the records and documents a record points at, grouped by relation. */
196
319
  const groupHeader = css({
197
320
  display: "flex",
@@ -221,7 +344,11 @@ const relatedRow = css({
221
344
  font: "inherit",
222
345
  textAlign: "start",
223
346
  textDecoration: "none",
224
- "&:is(button, a)": { cursor: "pointer", _hover: { background: "bg.rowHover" } },
347
+ // The kit's Linked record hovers to the selected glass in dark and the row wash in light.
348
+ "&:is(button, a)": {
349
+ cursor: "pointer",
350
+ _hover: { background: "token(gradients.selected)", _light: { background: "bg.rowHover" } },
351
+ },
225
352
  _focusVisible: { focusRing: "outer" },
226
353
  });
227
354
  const tile = css({
@@ -234,6 +361,7 @@ const tile = css({
234
361
  borderRadius: "action",
235
362
  background: "bg.panel",
236
363
  color: "fg.secondary",
364
+ _light: { background: "bg.field" },
237
365
  "& svg": { fontSize: "icon.small" },
238
366
  });
239
367
  const rowTitle = css({
@@ -251,6 +379,7 @@ const rowMeta = css({
251
379
  color: "fg.secondary",
252
380
  fontSize: "code",
253
381
  fontWeight: "medium",
382
+ lineHeight: "tight",
254
383
  "& [data-separator]": { color: "fg.muted" },
255
384
  "& [data-tone=info]": { color: "accent.blue" },
256
385
  "& [data-tone=success]": { color: "accent.green" },
@@ -0,0 +1,19 @@
1
+ /** A file whose bytes load from `url`, or from what the resolver hands back when it has none. */
2
+ export type ResolvableFile = {
3
+ id: string;
4
+ url?: string | null;
5
+ };
6
+ /**
7
+ * Hands back a browser-loadable link for a file without one, such as one served behind a bearer
8
+ * token, which the app downloads and serves from an object URL. Keep the function stable: its
9
+ * links are cached per function and file id, so a redraw does not load the file again.
10
+ */
11
+ export type ResolveFileUrl<File extends ResolvableFile = ResolvableFile> = (file: File) => Promise<string>;
12
+ /**
13
+ * The file's link: its own `url`, else the resolver's once it settles. `state` is `failed` when the
14
+ * resolver rejected, and `pending` while it runs or while `enabled` is false.
15
+ */
16
+ export declare function useResolvedFileUrl<File extends ResolvableFile>(file: File | undefined, resolve: ResolveFileUrl<File> | undefined, enabled?: boolean): {
17
+ url: string | null;
18
+ state: "ready" | "pending" | "failed" | "none";
19
+ };
@@ -0,0 +1,49 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ const resolvedUrls = new WeakMap();
3
+ function resolveOnce(resolve, file) {
4
+ let cache = resolvedUrls.get(resolve);
5
+ if (!cache) {
6
+ cache = new Map();
7
+ resolvedUrls.set(resolve, cache);
8
+ }
9
+ const cached = cache.get(file.id);
10
+ if (cached)
11
+ return cached;
12
+ const pending = resolve(file);
13
+ cache.set(file.id, pending);
14
+ // A failed load is not kept, so the next look at the file tries again.
15
+ pending.catch(() => cache.delete(file.id));
16
+ return pending;
17
+ }
18
+ /**
19
+ * The file's link: its own `url`, else the resolver's once it settles. `state` is `failed` when the
20
+ * resolver rejected, and `pending` while it runs or while `enabled` is false.
21
+ */
22
+ export function useResolvedFileUrl(file, resolve, enabled = true) {
23
+ const direct = file?.url ?? null;
24
+ const [resolved, setResolved] = useState(null);
25
+ const fileId = file?.id;
26
+ // The file's id names it: a new object for the same file is not a new file to load.
27
+ const fileRef = useRef(file);
28
+ useEffect(() => {
29
+ fileRef.current = file;
30
+ });
31
+ useEffect(() => {
32
+ const file = fileRef.current;
33
+ if (!file || direct || !resolve || !enabled)
34
+ return;
35
+ let current = true;
36
+ resolveOnce(resolve, file).then((url) => current && setResolved({ id: file.id, url, failed: false }), () => current && setResolved({ id: file.id, url: null, failed: true }));
37
+ return () => {
38
+ current = false;
39
+ };
40
+ }, [fileId, direct, resolve, enabled]);
41
+ if (direct)
42
+ return { url: direct, state: "ready" };
43
+ if (!file || !resolve)
44
+ return { url: null, state: "none" };
45
+ const settled = resolved?.id === file.id ? resolved : null;
46
+ if (settled?.url)
47
+ return { url: settled.url, state: "ready" };
48
+ return { url: null, state: settled?.failed ? "failed" : "pending" };
49
+ }
@@ -13,4 +13,4 @@ export declare function ScrollArea({ className, viewportClassName, scrollDirecti
13
13
  scrollDirections?: "vertical" | "vertical-and-horizontal";
14
14
  children: ReactNode;
15
15
  "aria-label"?: string;
16
- }): import("@types/react").JSX.Element;
16
+ }): import("react").JSX.Element;
@@ -7,4 +7,4 @@ export type IssuedSecret = {
7
7
  export declare function OneTimeSecretDialog({ issued, onClose, }: {
8
8
  issued: IssuedSecret | null;
9
9
  onClose: () => void;
10
- }): import("@types/react").JSX.Element;
10
+ }): import("react").JSX.Element;
@@ -1,11 +1,13 @@
1
1
  import { type ComponentProps, type ReactNode } from "react";
2
2
  import type { Tone } from "./badge.js";
3
+ /** A segment's hue: a tone by meaning, or `indigo`, the chart's category no status hue covers. */
4
+ export type SegmentedBarHue = Tone | "indigo";
3
5
  export type SegmentedBarSegment = {
4
6
  id: string;
5
7
  label: string;
6
8
  value: number;
7
9
  /** The segment's color by meaning; `neutral` by default. */
8
- tone?: Tone;
10
+ tone?: SegmentedBarHue;
9
11
  /** A color of its own, such as a CSS variable the app themes, over `tone`. */
10
12
  color?: string;
11
13
  };
@@ -20,4 +22,4 @@ export type SegmentedBarProps = Omit<ComponentProps<"div">, "children"> & {
20
22
  /** How a value reads in the legend and a segment's name; the locale's number by default. */
21
23
  formatValue?: (value: number) => string;
22
24
  };
23
- export declare function SegmentedBar({ segments, legend, renderDetail, onSegmentSelect, formatValue, className, ...props }: SegmentedBarProps): import("@types/react").JSX.Element;
25
+ export declare function SegmentedBar({ segments, legend, renderDetail, onSegmentSelect, formatValue, className, ...props }: SegmentedBarProps): import("react").JSX.Element;
@@ -11,14 +11,16 @@ import { useCiridaeLocale } from "./locale.js";
11
11
  import { Popover } from "./overlays.js";
12
12
  const root = css({ display: "flex", flexDirection: "column", gap: "layout.sectionGap" });
13
13
  const bar = css({ display: "flex", gap: "layout.tightGap", height: "8px" });
14
+ // The chart's data marks, so a segment and its swatch match the series in a chart.
14
15
  const toneColor = cva({
15
16
  variants: {
16
17
  tone: {
17
- neutral: { background: "fg.subtle" },
18
- info: { background: "accent.blue" },
19
- success: { background: "accent.green" },
20
- warning: { background: "accent.yellow" },
21
- danger: { background: "accent.red" },
18
+ neutral: { background: "chart.neutral" },
19
+ info: { background: "chart.trend" },
20
+ success: { background: "chart.category2" },
21
+ warning: { background: "chart.category1" },
22
+ indigo: { background: "chart.category3" },
23
+ danger: { background: "chart.category4" },
22
24
  },
23
25
  },
24
26
  });
@@ -42,7 +44,15 @@ const legendRow = css({
42
44
  paddingTop: "panel.comfortable",
43
45
  borderTop: "1px solid token(colors.border.panel)",
44
46
  });
45
- const legendItem = css({ display: "inline-flex", alignItems: "center", gap: "layout.contentGap" });
47
+ const legendItem = css({
48
+ display: "inline-flex",
49
+ alignItems: "center",
50
+ gap: "layout.contentGap",
51
+ color: "fg.primary",
52
+ fontSize: "body",
53
+ fontWeight: "medium",
54
+ lineHeight: "tight",
55
+ });
46
56
  const legendKey = css({
47
57
  display: "inline-flex",
48
58
  alignItems: "center",
@@ -18,20 +18,23 @@ export type SelectProps = {
18
18
  label?: string;
19
19
  /** `medium` is the Round 2 field height; `small` is the pill beside other filters. */
20
20
  size?: ControlSize;
21
- /** Defaults to the flat `field` at medium and the glass `raised` face when small. */
22
- variant?: "field" | "raised";
21
+ /**
22
+ * Defaults to the flat `field` at medium and the glass `raised` face when small. `underline` is
23
+ * a 34px row control at the body size, such as a table footer's rows per page, whatever `size`.
24
+ */
25
+ variant?: "field" | "raised" | "underline";
23
26
  /** Submits the value with an enclosing form under this name. */
24
27
  name?: string;
25
28
  /** Blocks the enclosing form's submission until a value is chosen. */
26
29
  required?: boolean;
27
30
  disabled?: boolean;
28
31
  };
29
- export declare function Select({ options, value, onValueChange, placeholder, label, size: controlSize, variant, name, required, disabled, }: SelectProps): import("@types/react").JSX.Element;
32
+ export declare function Select({ options, value, onValueChange, placeholder, label, size: controlSize, variant, name, required, disabled, }: SelectProps): import("react").JSX.Element;
30
33
  export type SlicerProps = Omit<SelectProps, "size" | "variant" | "placeholder"> & {
31
34
  /** What the slicer filters by, shown muted before the chosen value. */
32
35
  label: string;
33
36
  };
34
- export declare function Slicer({ options, value, onValueChange, label, name, required, disabled, }: SlicerProps): import("@types/react").JSX.Element;
37
+ export declare function Slicer({ options, value, onValueChange, label, name, required, disabled, }: SlicerProps): import("react").JSX.Element;
35
38
  export type ComboboxProps<Option extends SelectOption> = {
36
39
  options: readonly Option[];
37
40
  value?: string;
@@ -69,7 +72,7 @@ export type ComboboxProps<Option extends SelectOption> = {
69
72
  * itself. With `onSearch`, the caller owns the options: typing reports the query once it pauses,
70
73
  * and the list shows whatever `options` the caller passes back, with `loading` while it fetches.
71
74
  */
72
- export declare function Combobox<Option extends SelectOption>({ options, value, onValueChange, placeholder: ownPlaceholder, label: ownLabel, size: controlSize, renderOption, emptyMessage, name, required, disabled, onSearch, loading, defaultOpen, onOpenChange, autoFocus, }: ComboboxProps<Option>): import("@types/react").JSX.Element;
75
+ export declare function Combobox<Option extends SelectOption>({ options, value, onValueChange, placeholder: ownPlaceholder, label: ownLabel, size: controlSize, renderOption, emptyMessage, name, required, disabled, onSearch, loading, defaultOpen, onOpenChange, autoFocus, }: ComboboxProps<Option>): import("react").JSX.Element;
73
76
  export declare function FilterPopover({ label, count, open, onOpenChange, onClear, children, }: {
74
77
  /** The locale's "Filters" by default. */
75
78
  label?: ReactNode;
@@ -81,4 +84,4 @@ export declare function FilterPopover({ label, count, open, onOpenChange, onClea
81
84
  onClear?: () => void;
82
85
  /** The filters, such as compact `Combobox` and `Slicer` pills. */
83
86
  children: ReactNode;
84
- }): import("@types/react").JSX.Element;
87
+ }): import("react").JSX.Element;