@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
@@ -3,8 +3,11 @@ import { CheckIcon, CopyIcon } from "@phosphor-icons/react";
3
3
  import { useEffect, useRef, useState } from "react";
4
4
  import { css, cx } from "#primitives/css";
5
5
  import { IconButton } from "./button.js";
6
+ import { Field, FieldLabel } from "./form-layout.js";
6
7
  import { icon } from "./icon.js";
8
+ import { Input } from "./input.js";
7
9
  import { useCiridaeLocale } from "./locale.js";
10
+ import { useToast } from "./toast.js";
8
11
  const copyableId = css({
9
12
  display: "inline-flex",
10
13
  alignItems: "center",
@@ -23,20 +26,41 @@ const shownLength = 8;
23
26
  const copiedFeedbackMs = 1500;
24
27
  /**
25
28
  * Copies `value` (or what it returns, read at the moment of copying) and reports `copied` for a
26
- * moment afterwards, for a check-mark confirmation.
29
+ * moment afterwards, for a check-mark confirmation. A copy the browser refuses, such as a denied
30
+ * permission or an insecure origin with no clipboard, goes to `onError`, or without one raises the
31
+ * kit's error toast, so a reader never pastes a stale clipboard thinking it holds the value.
27
32
  */
28
- export function useCopy(value, onCopied) {
33
+ export function useCopy(value, onCopied, onError) {
29
34
  const [copied, setCopied] = useState(false);
35
+ const { labels } = useCiridaeLocale();
36
+ const toast = useToast();
30
37
  useEffect(() => {
31
38
  if (!copied)
32
39
  return;
33
40
  const timer = setTimeout(() => setCopied(false), copiedFeedbackMs);
34
41
  return () => clearTimeout(timer);
35
42
  }, [copied]);
36
- const copy = () => void navigator.clipboard.writeText(typeof value === "function" ? value() : value).then(() => {
43
+ // `await` rather than `.catch`: an insecure origin has no `navigator.clipboard` at all and
44
+ // throws before a promise exists.
45
+ const writeValue = async () => {
46
+ try {
47
+ await navigator.clipboard.writeText(typeof value === "function" ? value() : value);
48
+ }
49
+ catch (error) {
50
+ if (onError)
51
+ onError(error);
52
+ else
53
+ toast.add({
54
+ variant: "error",
55
+ title: labels.clipboard.copyFailed,
56
+ description: labels.clipboard.copyByHand,
57
+ });
58
+ return;
59
+ }
37
60
  setCopied(true);
38
61
  onCopied?.();
39
- });
62
+ };
63
+ const copy = () => void writeValue();
40
64
  return { copied, copy };
41
65
  }
42
66
  const inlineCopy = css({
@@ -51,8 +75,8 @@ const inlineCopy = css({
51
75
  _focusVisible: { focusRing: "outer", borderRadius: "control" },
52
76
  });
53
77
  /** A button that copies `value`, its icon turning into a check once copied. */
54
- export function CopyButton({ value, label, variant = "raised", size, onCopied, className, }) {
55
- const { copied, copy } = useCopy(value, onCopied);
78
+ export function CopyButton({ value, label, variant = "raised", size, onCopied, onError, className, }) {
79
+ const { copied, copy } = useCopy(value, onCopied, onError);
56
80
  const { labels } = useCiridaeLocale();
57
81
  const name = copied
58
82
  ? labels.common.copied
@@ -134,3 +158,19 @@ export function CopyableText({ text, label, className, }) {
134
158
  };
135
159
  return (_jsxs("span", { className: copyableText, "data-ciridae-ui": "", onMouseEnter: measureOverflow, children: [_jsx("span", { ref: box, className: cx(marqueeBox, className), title: text, children: _jsx("span", { children: text }) }), _jsx("button", { type: "button", className: copyTextButton, "aria-label": labels.common.copy(label), "data-copied": copied || undefined, onClick: copy, children: copied ? (_jsx(CheckIcon, { className: icon({ size: "small" }) })) : (_jsx(CopyIcon, { className: icon({ size: "small" }) })) })] }));
136
160
  }
161
+ const copyFieldRow = css({
162
+ display: "grid",
163
+ gridTemplateColumns: "minmax(0, 1fr) auto",
164
+ alignItems: "end",
165
+ gap: "layout.tightGap",
166
+ });
167
+ const copyFieldValue = css({ fontFamily: "mono", fontSize: "code" });
168
+ /**
169
+ * A value to paste elsewhere, such as a command or a connection code, as a labelled read-only
170
+ * field with a copy button: it selects on focus and reads like the field it is pasted into. The
171
+ * row stays while there is no value yet, showing `placeholder`. The value is masked from session
172
+ * recorders, since such values are often credentials.
173
+ */
174
+ export function CopyField({ label, value, placeholder, className, }) {
175
+ return (_jsxs("div", { className: cx(copyFieldRow, className), "data-ciridae-ui": "", children: [_jsxs(Field, { children: [_jsx(FieldLabel, { children: label }), _jsx(Input, { className: cx("ph-no-capture", copyFieldValue), "data-sentry-mask": true, onFocus: (event) => event.target.select(), placeholder: placeholder, readOnly: true, value: value ?? "" })] }), value !== undefined && _jsx(CopyButton, { label: label, value: value, variant: "ghost" })] }));
176
+ }
@@ -1,8 +1,11 @@
1
1
  import { Separator as BaseSeparator } from "@base-ui/react/separator";
2
2
  import type { ComponentProps, ReactNode } from "react";
3
3
  export type AvatarColor = "neutral" | "blue" | "violet" | "green" | "teal" | "yellow" | "orange" | "pink" | "red";
4
- /** 12, 16, 20, 24, 26, 32, and 44 pixels; the Round 2 set is `menu` through `large`. */
5
- export type AvatarSize = "micro" | "mark" | "small" | "menu" | "row" | "medium" | "large";
4
+ /**
5
+ * 12, 14, 20, 24, 26, 28, 32 (`row` and `medium`) and 44 pixels; the kit's set is `menu` through
6
+ * `large`.
7
+ */
8
+ export type AvatarSize = "micro" | "mark" | "small" | "menu" | "agent" | "owner" | "row" | "medium" | "large";
6
9
  /**
7
10
  * The one mark for a person, an organization, a project, or the agent: `src` shows the photo or
8
11
  * logo, and the initials derived from `label` stand in until it loads or when there is none. A
@@ -19,24 +22,30 @@ export declare function Avatar({ label, src, size, kind, icon, badge, color, cla
19
22
  icon?: ReactNode;
20
23
  badge?: ReactNode;
21
24
  color?: AvatarColor;
22
- }): import("@types/react").JSX.Element;
25
+ }): import("react").JSX.Element;
26
+ /** The slot where an owner's avatar goes, before anyone owns the record. */
27
+ export declare function UnassignedAvatar({ size, className, ...props }: ComponentProps<"span"> & {
28
+ size?: "small" | "owner" | "row";
29
+ }): import("react").JSX.Element;
23
30
  export declare function Divider({ inset, className, ...props }: Omit<ComponentProps<typeof BaseSeparator>, "className"> & {
24
31
  className?: string;
25
32
  /** `menu` insets it to a menu's or a popover's rows. */
26
33
  inset?: "none" | "menu";
27
- }): import("@types/react").JSX.Element;
34
+ }): import("react").JSX.Element;
28
35
  export type DescriptionRow = [label: string, value: ReactNode];
29
36
  /**
30
37
  * Label-value pairs in two columns. Rows whose value is `null` or `undefined` are left out, so
31
- * callers can list every field a record may carry. `compact` tightens the rows for dense output.
38
+ * callers can list every field a record may carry. `compact` sets them as key-value pairs;
39
+ * `layout="facts"` as fact rows, each value at the far edge over a hairline.
32
40
  * `loading` keeps every row's label and draws a placeholder for its value, so the list arrives at
33
41
  * the size it loads to; build the rows from the record that may not have loaded yet.
34
42
  */
35
- export declare function DescriptionList({ rows, density, loading, className, ...props }: ComponentProps<"dl"> & {
43
+ export declare function DescriptionList({ rows, density, layout, loading, className, ...props }: ComponentProps<"dl"> & {
36
44
  rows: DescriptionRow[];
37
45
  density?: "default" | "compact";
46
+ layout?: "columns" | "facts";
38
47
  loading?: boolean;
39
- }): import("@types/react").JSX.Element;
48
+ }): import("react").JSX.Element;
40
49
  /**
41
50
  * Scrollable block of literal text, such as a command or a generated file. `copy` adds a copy
42
51
  * button with that text, which can differ from what is shown (e.g. masked secrets).
@@ -44,4 +53,26 @@ export declare function DescriptionList({ rows, density, loading, className, ...
44
53
  export declare function CodeBlock({ className, copy, copyLabel, ...props }: ComponentProps<"pre"> & {
45
54
  copy?: string;
46
55
  copyLabel?: string;
47
- }): import("@types/react").JSX.Element;
56
+ }): import("react").JSX.Element;
57
+ /** Where a field's value came from, or who vouches for it: a 14px icon and a line. */
58
+ export type DetailFieldNote = {
59
+ icon?: ReactNode;
60
+ label: ReactNode;
61
+ };
62
+ export type DetailFieldProps = Omit<ComponentProps<"div">, "children"> & {
63
+ label: ReactNode;
64
+ value: ReactNode;
65
+ /** Where the value came from, such as "Net 30 from Aug 22". */
66
+ source?: DetailFieldNote;
67
+ /** Who or what vouches for it, such as "Checked by Dana R.". */
68
+ assurance?: DetailFieldNote;
69
+ /** Beside the value, such as a Contested badge; its line under the value is `description`. */
70
+ badge?: ReactNode;
71
+ description?: ReactNode;
72
+ /** A trailing button, such as Resolve. */
73
+ action?: ReactNode;
74
+ state?: "default" | "selected" | "inset" | "highlighted";
75
+ /** A hairline under the row; the last row of a list leaves it out. Defaults to true. */
76
+ divider?: boolean;
77
+ };
78
+ export declare function DetailField({ label, value, source, assurance, badge, description, action, state, divider, className, ...props }: DetailFieldProps): import("react").JSX.Element;
@@ -6,10 +6,11 @@ import { Fragment } from "react";
6
6
  import { css, cva, cx } from "#primitives/css";
7
7
  import { CopyButton } from "./copyable-id.js";
8
8
  import { Skeleton } from "./skeleton.js";
9
- // The neutral avatar is the Round 2 one: a person or the agent on the raised glass face, an
10
- // organization as the text-colored tile the workspace switcher shows. A colored one derives its
11
- // fill, text, and border from one `--avatar-hue`, mixed toward the surface or the text color so it
12
- // holds in both themes. The hues are brighter than the accent tokens so avatars read apart.
9
+ // The neutral avatar is a person or the agent on the raised glass gradient inside its gradient
10
+ // hairline, an organization the text-colored tile the workspace switcher shows. A colored one
11
+ // derives its fill, text, and border from one `--avatar-hue`, mixed toward the opaque surface or
12
+ // the text color so it holds in both themes. The hues are brighter than the accent tokens so
13
+ // avatars read apart.
13
14
  const avatar = css({
14
15
  display: "inline-grid",
15
16
  placeItems: "center",
@@ -41,24 +42,25 @@ const avatar = css({
41
42
  // A person, or the agent: a circle on the glass face, or a pale circle in its hue.
42
43
  "&[data-kind=user], &[data-kind=agent]": {
43
44
  borderRadius: "round",
44
- background: "bg.raised",
45
+ background: "token(gradients.raised)",
45
46
  color: "fg.primary",
46
47
  },
48
+ "--edge": "token(gradients.border.raised)",
47
49
  "&[data-kind=agent], &[data-icon]": { color: "fg.secondary" },
48
50
  // An icon fills the same share of every size, so marks match whatever avatar they sit beside.
49
51
  "&:is([data-kind=agent], [data-icon]) svg": { width: "58%", height: "58%" },
50
52
  // An icon stands on its own, with no circle or ring, so it fills most of its box.
51
53
  "&[data-icon]": { background: "transparent", "& svg": { width: "80%", height: "80%" } },
52
54
  "&:is([data-kind=user], [data-kind=agent]):not([data-color=neutral])": {
53
- borderColor: "color-mix(in srgb, var(--avatar-hue) 30%, token(colors.bg.card))",
54
- background: "color-mix(in srgb, var(--avatar-hue) 16%, token(colors.bg.card))",
55
+ borderColor: "color-mix(in srgb, var(--avatar-hue) 30%, token(colors.bg.surface))",
56
+ background: "color-mix(in srgb, var(--avatar-hue) 16%, token(colors.bg.surface))",
55
57
  color: "color-mix(in srgb, var(--avatar-hue) 70%, token(colors.fg.primary))",
56
58
  },
57
59
  // A project: a pale tile edged and lettered in the hue's strong shade.
58
60
  "&[data-kind=project]": {
59
61
  borderRadius: "20%",
60
- borderColor: "color-mix(in srgb, var(--avatar-hue) 70%, token(colors.bg.card))",
61
- background: "color-mix(in srgb, var(--avatar-hue) 14%, token(colors.bg.card))",
62
+ borderColor: "color-mix(in srgb, var(--avatar-hue) 70%, token(colors.bg.surface))",
63
+ background: "color-mix(in srgb, var(--avatar-hue) 14%, token(colors.bg.surface))",
62
64
  color: "color-mix(in srgb, var(--avatar-hue) 75%, token(colors.fg.primary))",
63
65
  fontWeight: "semibold",
64
66
  },
@@ -81,12 +83,16 @@ const avatar = css({
81
83
  "&[data-size=large]": {
82
84
  width: "avatar.large",
83
85
  height: "avatar.large",
84
- fontSize: "heading",
86
+ fontSize: "body",
85
87
  },
86
88
  // A list row's owner, and the workspace switcher's mark.
87
89
  "&[data-size=row]": { width: "avatar.row", height: "avatar.row" },
90
+ // A record's owner, and the empty slot where one goes.
91
+ "&[data-size=owner]": { width: "avatar.owner", height: "avatar.owner" },
88
92
  // A menu item's leading avatar.
89
93
  "&[data-size=menu]": { width: "avatar.menu", height: "avatar.menu" },
94
+ // The agent standing on its own, the kit's Agent avatar.
95
+ "&[data-size=agent]": { width: "avatar.agent", height: "avatar.agent" },
90
96
  "&[data-size=small]": { width: "avatar.small", height: "avatar.small", fontSize: "avatar.small" },
91
97
  // The inline mark's size, so a project's tile lines up with icons and provider logos.
92
98
  "&[data-size=mark]": { width: "mark.inline", height: "mark.inline", fontSize: "avatar.mark" },
@@ -125,7 +131,22 @@ const avatarBadge = css({
125
131
  export function Avatar({ label, src, size = "medium", kind = "user", icon, badge, color = "neutral", className, ...props }) {
126
132
  const initials = labelInitials(label, kind === "organization" ? 1 : 2);
127
133
  const glass = !icon && color === "neutral" && (kind === "user" || kind === "agent");
128
- return (_jsxs(BaseAvatar.Root, { ...props, "aria-label": label, "data-ciridae-ui": "", "data-size": size, "data-kind": kind, "data-color": color, "data-icon": icon ? "" : undefined, "data-edge": glass ? "glass" : undefined, className: cx(avatar, className), children: [src && _jsx(BaseAvatar.Image, { src: src, alt: "", className: avatarImage }), _jsx(BaseAvatar.Fallback, { className: avatarFallback, children: icon ?? (kind === "agent" ? _jsx(SparkleIcon, { weight: "fill" }) : initials) }), badge && _jsx("span", { className: avatarBadge, children: badge })] }));
134
+ return (_jsxs(BaseAvatar.Root, { ...props, "aria-label": label, "data-ciridae-ui": "", "data-size": size, "data-kind": kind, "data-color": color, "data-icon": icon ? "" : undefined, "data-edge": glass ? "gradient" : undefined, className: cx(avatar, className), children: [src && _jsx(BaseAvatar.Image, { src: src, alt: "", className: avatarImage }), _jsx(BaseAvatar.Fallback, { className: avatarFallback, children: icon ?? (kind === "agent" ? _jsx(SparkleIcon, { weight: "fill" }) : initials) }), badge && _jsx("span", { className: avatarBadge, children: badge })] }));
135
+ }
136
+ // No owner yet: the avatar's circle as a dashed ring, empty.
137
+ const unassignedAvatar = css({
138
+ display: "inline-block",
139
+ flexShrink: "0",
140
+ width: "avatar.owner",
141
+ height: "avatar.owner",
142
+ border: "1px dashed token(colors.border.control)",
143
+ borderRadius: "round",
144
+ "&[data-size=small]": { width: "avatar.small", height: "avatar.small" },
145
+ "&[data-size=row]": { width: "avatar.row", height: "avatar.row" },
146
+ });
147
+ /** The slot where an owner's avatar goes, before anyone owns the record. */
148
+ export function UnassignedAvatar({ size = "owner", className, ...props }) {
149
+ return (_jsx("span", { ...props, className: cx(unassignedAvatar, className), "data-ciridae-ui": "", "data-size": size }));
129
150
  }
130
151
  /** Up to `count` capital initials from a name's first words. */
131
152
  function labelInitials(label, count) {
@@ -141,13 +162,13 @@ const divider = cva({
141
162
  variants: {
142
163
  inset: {
143
164
  none: {},
144
- // Between a menu's or a popover's groups: inset to its rows' text, a little room above and
145
- // below.
165
+ // Between a menu's or a popover's groups, as the glass menu's divider: inset to its rows'
166
+ // text, a little room above and below.
146
167
  menu: {
147
168
  width: "auto",
148
169
  marginBlock: "layout.tightGap",
149
170
  marginInline: "menu.itemInline",
150
- background: "border.panel",
171
+ background: "border.divider",
151
172
  },
152
173
  },
153
174
  },
@@ -155,31 +176,60 @@ const divider = cva({
155
176
  export function Divider({ inset = "none", className, ...props }) {
156
177
  return (_jsx(BaseSeparator, { ...props, "data-ciridae-ui": "", className: cx(divider({ inset }), className) }));
157
178
  }
179
+ /*
180
+ * Labels are the muted grey, values the text color. `facts` sets each label against its value at
181
+ * the far edge, a hairline under every row but the last; `compact` is the key-value pair, its
182
+ * labels a 120px column of 12px type.
183
+ */
158
184
  const descriptionList = cva({
159
185
  base: {
160
186
  display: "grid",
161
187
  gridTemplateColumns: "max-content minmax(0, 1fr)",
162
188
  margin: "none",
163
- "& dt": { color: "fg.muted" },
189
+ "& dt": { color: "fg.label" },
164
190
  "& dd": { margin: "none", overflowWrap: "anywhere" },
165
191
  "& a": { color: "inherit" },
166
192
  },
167
193
  variants: {
168
194
  density: {
169
195
  default: { rowGap: "layout.controlGap", columnGap: "layout.sectionGap" },
170
- compact: { rowGap: "control.trackInset", columnGap: "layout.clusterGap" },
196
+ compact: {
197
+ gridTemplateColumns: "120px minmax(0, 1fr)",
198
+ rowGap: "layout.clusterGap",
199
+ columnGap: "layout.contentGap",
200
+ "& dt": { fontSize: "code", fontWeight: "medium" },
201
+ "& dd": { fontSize: "body", fontWeight: "medium" },
202
+ },
203
+ },
204
+ layout: {
205
+ columns: {},
206
+ facts: {
207
+ gridTemplateColumns: "minmax(0, 1fr) auto",
208
+ alignItems: "center",
209
+ rowGap: "0",
210
+ columnGap: "layout.contentGap",
211
+ "& dt, & dd": {
212
+ paddingBlock: "panel.default",
213
+ borderBottom: "1px solid token(colors.border.divider)",
214
+ lineHeight: "tight",
215
+ },
216
+ "& > :nth-last-child(-n+2)": { borderBottom: "0" },
217
+ "& dt": { fontSize: "code", fontWeight: "medium" },
218
+ "& dd": { fontSize: "body", fontWeight: "medium", textAlign: "end" },
219
+ },
171
220
  },
172
221
  },
173
222
  });
174
223
  const placeholderValueWidths = [96, 120, 144];
175
224
  /**
176
225
  * Label-value pairs in two columns. Rows whose value is `null` or `undefined` are left out, so
177
- * callers can list every field a record may carry. `compact` tightens the rows for dense output.
226
+ * callers can list every field a record may carry. `compact` sets them as key-value pairs;
227
+ * `layout="facts"` as fact rows, each value at the far edge over a hairline.
178
228
  * `loading` keeps every row's label and draws a placeholder for its value, so the list arrives at
179
229
  * the size it loads to; build the rows from the record that may not have loaded yet.
180
230
  */
181
- export function DescriptionList({ rows, density = "default", loading = false, className, ...props }) {
182
- return (_jsx("dl", { ...props, "aria-busy": loading || undefined, "data-ciridae-ui": "", className: cx(descriptionList({ density }), className), children: rows.map(([label, value], index) => loading ? (_jsxs(Fragment, { children: [_jsx("dt", { children: label }), _jsx("dd", { children: _jsx(Skeleton, { shape: "text", style: { width: placeholderValueWidths[index % placeholderValueWidths.length] } }) })] }, label)) : value === null || value === undefined ? null : (_jsxs(Fragment, { children: [_jsx("dt", { children: label }), _jsx("dd", { children: value })] }, label))) }));
231
+ export function DescriptionList({ rows, density = "default", layout = "columns", loading = false, className, ...props }) {
232
+ return (_jsx("dl", { ...props, "aria-busy": loading || undefined, "data-ciridae-ui": "", className: cx(descriptionList({ density, layout }), className), children: rows.map(([label, value], index) => loading ? (_jsxs(Fragment, { children: [_jsx("dt", { children: label }), _jsx("dd", { children: _jsx(Skeleton, { shape: "text", style: { width: placeholderValueWidths[index % placeholderValueWidths.length] } }) })] }, label)) : value === null || value === undefined ? null : (_jsxs(Fragment, { children: [_jsx("dt", { children: label }), _jsx("dd", { children: value })] }, label))) }));
183
233
  }
184
234
  const codeBlock = css({
185
235
  margin: "none",
@@ -219,3 +269,72 @@ export function CodeBlock({ className, copy, copyLabel = "text", ...props }) {
219
269
  return block;
220
270
  return (_jsxs("div", { className: codeBlockFrame, children: [block, _jsx("span", { className: codeBlockCopy, children: _jsx(CopyButton, { value: copy, label: copyLabel }) })] }));
221
271
  }
272
+ /*
273
+ * Detail field: one field of a record as a row, the kit's Detail field. A 150px label column of
274
+ * 12px grey beside the 14px value and, under it, where the value came from and who vouches for it,
275
+ * or a description when a badge rides beside the value. `selected` is the open field; `inset`
276
+ * sets it in the selected glass between hairlines; `highlighted` is the warm band for a field that
277
+ * needs a look, such as two sources that disagree.
278
+ */
279
+ const detailField = css({
280
+ display: "flex",
281
+ alignItems: "flex-start",
282
+ gap: "layout.contentGap",
283
+ paddingBlock: "panel.default",
284
+ paddingInline: "panel.comfortable",
285
+ fontWeight: "medium",
286
+ letterSpacing: "compact",
287
+ lineHeight: "tight",
288
+ "&[data-divider]": { borderBottom: "1px solid token(colors.border.divider)" },
289
+ "&[data-state=default]:hover": { background: "bg.rowHover" },
290
+ "&[data-state=selected]": { background: "token(gradients.selected)" },
291
+ "&:is([data-state=inset], [data-state=highlighted])": {
292
+ borderBlock: "1px solid token(colors.border.divider)",
293
+ },
294
+ "&[data-state=inset]": { background: "token(gradients.selected)" },
295
+ "&[data-state=highlighted]": { background: "bg.warningTint" },
296
+ });
297
+ // The label sits on the value's first line: 14px of text, or the badge's 24.
298
+ const detailFieldLabel = css({
299
+ display: "flex",
300
+ alignItems: "center",
301
+ flexShrink: "0",
302
+ width: "150px",
303
+ minHeight: "token(fontSizes.body)",
304
+ color: "fg.label",
305
+ fontSize: "code",
306
+ "[data-badge] > &": { minHeight: "control.shortcut" },
307
+ });
308
+ const detailFieldValue = css({ display: "grid", gap: "control.iconGap", flex: "1", minWidth: "0" });
309
+ // A badge that does not fit beside the value drops under it.
310
+ const detailFieldValueLine = css({
311
+ display: "flex",
312
+ alignItems: "center",
313
+ flexWrap: "wrap",
314
+ gap: "layout.controlGap",
315
+ minWidth: "0",
316
+ color: "fg.primary",
317
+ fontSize: "body",
318
+ "[data-badge] &": { minHeight: "control.shortcut" },
319
+ });
320
+ const detailFieldNote = css({
321
+ display: "flex",
322
+ alignItems: "center",
323
+ flexWrap: "wrap",
324
+ columnGap: "layout.contentGap",
325
+ rowGap: "layout.tightGap",
326
+ color: "fg.muted",
327
+ fontSize: "code",
328
+ _light: { color: "fg.secondary" },
329
+ });
330
+ const detailFieldNoteItem = css({
331
+ display: "inline-flex",
332
+ alignItems: "center",
333
+ gap: "layout.tightGap",
334
+ "& > svg": { flexShrink: "0", fontSize: "icon.small" },
335
+ });
336
+ const detailFieldAction = css({ flexShrink: "0", alignSelf: "center" });
337
+ export function DetailField({ label, value, source, assurance, badge, description, action, state = "default", divider = true, className, ...props }) {
338
+ const notes = [source, assurance].filter((note) => note !== undefined);
339
+ return (_jsxs("div", { ...props, className: cx(detailField, className), "data-ciridae-ui": "", "data-state": state, "data-divider": divider || undefined, "data-badge": badge !== undefined || undefined, children: [_jsx("span", { className: detailFieldLabel, children: label }), _jsxs("span", { className: detailFieldValue, children: [_jsxs("span", { className: detailFieldValueLine, children: [value, badge] }), notes.length > 0 && (_jsx("span", { className: detailFieldNote, children: notes.map((note, index) => (_jsxs("span", { className: detailFieldNoteItem, children: [note.icon, note.label] }, index))) })), description !== undefined && _jsx("span", { className: detailFieldNote, children: description })] }), action !== undefined && _jsx("span", { className: detailFieldAction, children: action })] }));
340
+ }
@@ -33,15 +33,19 @@ export type TableColumnMeta = {
33
33
  locked?: boolean;
34
34
  /** Holds the row's own link instead of the first column, when the first holds links of its own. */
35
35
  rowLink?: boolean;
36
- skeleton?: ReactNode;
36
+ /**
37
+ * What the column draws while the list loads, shaped like its cells: `lines` a primary line over
38
+ * a smaller one, `pill` a badge, `person` an avatar and a name, or any node. A line by default.
39
+ */
40
+ skeleton?: "lines" | "pill" | "person" | ReactNode;
37
41
  /** Drops the column on phone-width screens, so the columns that identify a row keep their room. */
38
42
  hideOnNarrow?: boolean;
39
43
  };
40
44
  declare const tableFeatureSet: {
41
- rowSortingFeature: import("@tanstack/react-table/dist").TableFeature;
42
- columnVisibilityFeature: import("@tanstack/react-table/dist").TableFeature;
43
- columnOrderingFeature: import("@tanstack/react-table/dist").TableFeature;
44
- sortedRowModel: (table: import("@tanstack/react-table/dist").Table<any, any>) => () => import("@tanstack/react-table/dist").RowModel<any, any>;
45
+ rowSortingFeature: import("@tanstack/react-table").TableFeature;
46
+ columnVisibilityFeature: import("@tanstack/react-table").TableFeature;
47
+ columnOrderingFeature: import("@tanstack/react-table").TableFeature;
48
+ sortedRowModel: (table: import("@tanstack/react-table").Table<any, any>) => () => import("@tanstack/react-table").RowModel<any, any>;
45
49
  columnMeta: TableColumnMeta;
46
50
  };
47
51
  export type TableFeatureSet = typeof tableFeatureSet;
@@ -52,10 +56,10 @@ export type TableColumns<Row extends RowData> = ReturnType<ColumnHelper<TableFea
52
56
  * columns render without one. See `TableColumnMeta` for the per-column options.
53
57
  */
54
58
  export declare function createTableColumns<Row extends RowData>(): ColumnHelper<{
55
- rowSortingFeature: import("@tanstack/react-table/dist").TableFeature;
56
- columnVisibilityFeature: import("@tanstack/react-table/dist").TableFeature;
57
- columnOrderingFeature: import("@tanstack/react-table/dist").TableFeature;
58
- sortedRowModel: (table: import("@tanstack/react-table/dist").Table<any, any>) => () => import("@tanstack/react-table/dist").RowModel<any, any>;
59
+ rowSortingFeature: import("@tanstack/react-table").TableFeature;
60
+ columnVisibilityFeature: import("@tanstack/react-table").TableFeature;
61
+ columnOrderingFeature: import("@tanstack/react-table").TableFeature;
62
+ sortedRowModel: (table: import("@tanstack/react-table").Table<any, any>) => () => import("@tanstack/react-table").RowModel<any, any>;
59
63
  columnMeta: TableColumnMeta;
60
64
  }, Row>;
61
65
  /** A column's id and name as column settings list them. */
@@ -87,6 +91,14 @@ export type DataGridProps<Row extends RowData> = Omit<ComponentProps<"div">, "ch
87
91
  onSortingChange?: (sorting: SortingState) => void;
88
92
  /** The rows arrive in the order `sorting` asks for, such as from a server. */
89
93
  manualSorting?: boolean;
94
+ /**
95
+ * Shows one page of the sorted rows, `number` counting from 1, for a list paged in the browser
96
+ * under a `Pagination`. Leave it out when `data` is already the page.
97
+ */
98
+ page?: {
99
+ number: number;
100
+ rowsPerPage: number;
101
+ };
90
102
  /** Adds a checkbox column; a function says which rows can be ticked. */
91
103
  enableRowSelection?: boolean | ((row: Row) => boolean);
92
104
  rowSelection?: RowSelectionState;
@@ -156,7 +168,7 @@ export type DataGridProps<Row extends RowData> = Omit<ComponentProps<"div">, "ch
156
168
  * hover-revealed row actions, groups, loading, empty and no-results states. `role="table"`; Enter
157
169
  * on a pressable row opens it.
158
170
  */
159
- export declare function DataGrid<Row extends RowData>({ data, columns, getRowId, variant, density, sorting: sortingProp, defaultSorting, onSortingChange, manualSorting, enableRowSelection, rowSelection: rowSelectionProp, defaultRowSelection, onRowSelectionChange, stickySelectColumn, columnVisibility: columnVisibilityProp, defaultColumnVisibility, onColumnVisibilityChange, columnOrder: columnOrderProp, defaultColumnOrder, onColumnOrderChange, headerMenu, filters, onFiltersChange, getRowHref, renderRowLink, onRowClick, activeRowId, keyboardNavigation, virtualize, rowActions, renderRowDetail, groupBy, renderGroupRow, loading, empty, noResults, filtered, hideHeader, fill, narrowScreenLayout, footer, labels: ownLabels, className, frameClassName, style, ...props }: DataGridProps<Row>): import("@types/react").JSX.Element;
171
+ export declare function DataGrid<Row extends RowData>({ data, columns, getRowId, variant, density, sorting: sortingProp, defaultSorting, onSortingChange, manualSorting, page, enableRowSelection, rowSelection: rowSelectionProp, defaultRowSelection, onRowSelectionChange, stickySelectColumn, columnVisibility: columnVisibilityProp, defaultColumnVisibility, onColumnVisibilityChange, columnOrder: columnOrderProp, defaultColumnOrder, onColumnOrderChange, headerMenu, filters, onFiltersChange, getRowHref, renderRowLink, onRowClick, activeRowId, keyboardNavigation, virtualize, rowActions, renderRowDetail, groupBy, renderGroupRow, loading, empty, noResults, filtered, hideHeader, fill, narrowScreenLayout, footer, labels: ownLabels, className, frameClassName, style, ...props }: DataGridProps<Row>): import("react").JSX.Element;
160
172
  export type TableProps<Row extends RowData> = Omit<DataGridProps<Row>, "defaultSorting" | "empty"> & {
161
173
  /** The sort the table starts with; `defaultSorting` on `DataGrid`. */
162
174
  initialSorting?: SortingState;
@@ -167,4 +179,4 @@ export type TableProps<Row extends RowData> = Omit<DataGridProps<Row>, "defaultS
167
179
  * `DataGrid` with the plain look: flush with its section, heads in caps, rows that light on hover
168
180
  * when they lead somewhere.
169
181
  */
170
- export declare function Table<Row extends RowData>({ variant, initialSorting, emptyMessage, ...props }: TableProps<Row>): import("@types/react").JSX.Element;
182
+ export declare function Table<Row extends RowData>({ variant, initialSorting, emptyMessage, ...props }: TableProps<Row>): import("react").JSX.Element;