@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
@@ -7,14 +7,13 @@ import { IconButton, IconButtonSizeContext } from "./button.js";
7
7
  import { PageHotkeys, useHotkey } from "./hotkeys.js";
8
8
  import { icon } from "./icon.js";
9
9
  import { useCiridaeLocale } from "./locale.js";
10
+ import { singleLineTextClass } from "./single-line-text.js";
10
11
  // The sidebar sits flush against the window; only the main panel is inset from the edges.
11
12
  const shell = css({
12
13
  display: "flex",
13
14
  height: "100dvh",
14
- paddingBlock: "panel.compact",
15
- paddingInlineEnd: "panel.compact",
16
15
  overflow: "hidden",
17
- background: "bg.canvas",
16
+ background: "token(gradients.canvas)",
18
17
  color: "fg.primary",
19
18
  // Compact line height leaves clipped text room for its descenders throughout the app frame.
20
19
  textStyle: "body",
@@ -23,24 +22,23 @@ const shell = css({
23
22
  const sidebar = css({
24
23
  display: "flex",
25
24
  flexDirection: "column",
26
- gap: "sidebar.groupGap",
27
- paddingBlock: "panel.sidebarBlock",
28
- // The first row, a control's height such as the workspace switcher, centres on the header's
29
- // line beside it: half the difference, plus the main panel's 1px edge.
30
- _notPhone: {
31
- paddingTop: "calc((token(sizes.shell.header) - token(sizes.control.default)) / 2 + 1px)",
32
- },
25
+ // Between the navigation and the footer; the navigation's own groups stand `sidebar.groupGap` apart.
26
+ gap: "sidebar.footerGap",
27
+ paddingBlock: "sidebar.block",
33
28
  paddingInline: "sidebar.inline",
34
29
  width: "shell.sidebar",
35
30
  flexShrink: "0",
36
31
  overflowY: "auto",
37
32
  // The rail swaps every expanded control for its `data-compact-sidebar` icon twin.
38
33
  "& [data-compact-sidebar]": { display: "none" },
39
- "&[data-collapsed]": {
40
- width: "shell.collapsed",
41
- alignItems: "center",
42
- "& [data-expanded-sidebar]": { display: "none" },
43
- "& [data-compact-sidebar]": { display: "flex" },
34
+ // A phone's menu always shows the labelled navigation, whatever the desktop sidebar's state.
35
+ _notPhone: {
36
+ "&[data-collapsed]": {
37
+ width: "shell.collapsed",
38
+ alignItems: "center",
39
+ "& [data-expanded-sidebar]": { display: "none" },
40
+ "& [data-compact-sidebar]": { display: "flex" },
41
+ },
44
42
  },
45
43
  _rail: {
46
44
  width: "shell.collapsed",
@@ -60,7 +58,7 @@ const sidebar = css({
60
58
  zIndex: "drawer",
61
59
  width: "shell.sidebar",
62
60
  alignItems: "stretch",
63
- background: "bg.canvas",
61
+ background: "token(gradients.canvas)",
64
62
  borderInlineEnd: "1px solid token(colors.border.panel)",
65
63
  boxShadow: "card",
66
64
  transform: "translateX(-100%)",
@@ -87,12 +85,15 @@ const main = css({
87
85
  flexDirection: "column",
88
86
  flex: "1",
89
87
  minWidth: "0",
90
- border: "1px solid token(colors.border.panel)",
88
+ marginBlock: "panel.compact",
89
+ marginInlineEnd: "panel.compact",
90
+ border: "1px solid token(colors.border.canvas)",
91
91
  borderRadius: "action",
92
- background: "bg.panel",
92
+ background: "token(gradients.panel)",
93
93
  overflow: "hidden",
94
94
  // Only once the panel spans the whole window does rounding read as a gap.
95
95
  _phone: {
96
+ margin: "none",
96
97
  borderRadius: "0",
97
98
  height: "100dvh",
98
99
  border: "0",
@@ -107,7 +108,7 @@ const header = css({
107
108
  flexShrink: "0",
108
109
  paddingInlineEnd: "control.compactInline",
109
110
  paddingInlineStart: "control.inline",
110
- borderBottom: "1px solid token(colors.border.panel)",
111
+ borderBottom: "1px solid token(colors.border.divider)",
111
112
  "& > :last-child": { minWidth: "0", maxWidth: "100%" },
112
113
  // Once the sidebar is gone the header stays one row: the title truncates, the actions keep
113
114
  // their width.
@@ -116,22 +117,25 @@ const header = css({
116
117
  padding: "panel.default",
117
118
  "& > [data-header-title]": {
118
119
  minWidth: "0",
119
- overflow: "hidden",
120
- whiteSpace: "nowrap",
120
+ overflowX: "clip",
121
+ overflowY: "visible",
121
122
  textOverflow: "ellipsis",
122
- lineHeight: "compact",
123
+ whiteSpace: "nowrap",
123
124
  },
124
125
  // The actions hold one line: a slicer keeps its value and drops the dimension it names.
125
126
  "& > :last-child": { flexShrink: "0", flexWrap: "nowrap" },
126
127
  "& [data-slicer-label]": { srOnly: true },
127
128
  },
128
129
  });
130
+ // The trail's parents; the page itself, last, is in the primary text.
129
131
  const headerTitle = css({
130
132
  flex: "1",
131
133
  minWidth: "0",
132
134
  color: "fg.muted",
135
+ _light: { color: "fg.secondary" },
133
136
  fontSize: "caption",
134
137
  fontWeight: "medium",
138
+ lineHeight: "tight",
135
139
  });
136
140
  const content = css({
137
141
  flex: "1",
@@ -199,14 +203,14 @@ const sidebarRail = css({
199
203
  display: "flex",
200
204
  flexDirection: "column",
201
205
  alignItems: "center",
202
- gap: "layout.tightGap",
206
+ gap: "sidebar.groupGap",
203
207
  });
204
208
  /* One sidebar's content stacks at its container's own gap, so a footer's controls keep their room. */
205
209
  const sidebarOnly = css({ display: "flex", flexDirection: "column", gap: "inherit" });
206
210
  const sidebarNav = css({
207
211
  display: "flex",
208
212
  flexDirection: "column",
209
- gap: "layout.controlGap",
213
+ gap: "sidebar.groupGap",
210
214
  minHeight: "0",
211
215
  overflowY: "auto",
212
216
  // Scrolling would clip the ring of anything outer-ringed placed among the items.
@@ -214,11 +218,9 @@ const sidebarNav = css({
214
218
  });
215
219
  const sidebarFooter = css({
216
220
  marginTop: "auto",
217
- // Room above the footer's first control, so it never sits tight under the last nav row.
218
- paddingTop: "layout.contentGap",
219
221
  display: "flex",
220
222
  flexDirection: "column",
221
- gap: "layout.contentGap",
223
+ gap: "layout.controlGap",
222
224
  // A phone shows the footer in its menu at full width, as the expanded sidebar does.
223
225
  _rail: { _notPhone: { alignItems: "center" } },
224
226
  });
@@ -268,7 +270,7 @@ const headerActions = css({
268
270
  display: "flex",
269
271
  alignItems: "center",
270
272
  justifyContent: "flex-end",
271
- gap: "layout.contentGap",
273
+ gap: "layout.tightGap",
272
274
  minWidth: "0",
273
275
  });
274
276
  /** The header's copy of the rail, for widths where the sidebar is gone altogether. */
@@ -288,9 +290,9 @@ const crumbs = css({
288
290
  whiteSpace: "nowrap",
289
291
  "& > :last-child": {
290
292
  minWidth: "0",
291
- overflow: "hidden",
293
+ overflowX: "clip",
294
+ overflowY: "visible",
292
295
  textOverflow: "ellipsis",
293
- lineHeight: "compact",
294
296
  },
295
297
  _phone: { gap: "layout.tightGap" },
296
298
  "& a:hover": { textDecoration: "underline" },
@@ -329,7 +331,7 @@ export function AppBreadcrumbs({ className, ...props }) {
329
331
  const { labels } = useCiridaeLocale();
330
332
  return _jsx("nav", { "aria-label": labels.shell.breadcrumb, ...props, className: cx(crumbs, className) });
331
333
  }
332
- const crumbSeparator = css({ color: "fg.muted" });
334
+ const crumbSeparator = css({ color: "fg.subtle" });
333
335
  // The page's title, as its one h1, set in the trail's own type.
334
336
  const crumbCurrent = css({
335
337
  margin: "none",
@@ -371,9 +373,9 @@ const account = css({
371
373
  alignItems: "center",
372
374
  gap: "sidebar.markGap",
373
375
  width: "100%",
374
- padding: "layout.tightGap",
376
+ padding: "control.compactBlock",
375
377
  border: "0",
376
- borderRadius: "action",
378
+ borderRadius: "keycap",
377
379
  background: "transparent",
378
380
  color: "inherit",
379
381
  font: "inherit",
@@ -391,25 +393,23 @@ const accountAvatarOnly = css({
391
393
  cursor: "pointer",
392
394
  _focusVisible: { focusRing: "outer" },
393
395
  });
396
+ // The name and the detail under it, 4px apart as the design's account row stacks them: each line
397
+ // sits at its type's own height, so without the gap the two would touch.
394
398
  const accountCopy = css({
395
399
  display: "grid",
400
+ gap: "layout.tightGap",
396
401
  flex: "1",
397
402
  minWidth: "0",
398
- "& > *": {
399
- overflow: "hidden",
400
- textOverflow: "ellipsis",
401
- whiteSpace: "nowrap",
402
- lineHeight: "compact",
403
- },
404
- "& > :last-child": { color: "fg.muted", fontSize: "caption" },
403
+ "& > strong": { fontWeight: "medium" },
404
+ "& > :nth-child(2)": { color: "fg.muted", fontSize: "caption" },
405
405
  });
406
406
  /**
407
- * The signed-in account as a menu trigger: avatar, name, and a detail line, or with `compact` the
408
- * avatar alone.
407
+ * The signed-in account as a menu trigger: avatar, name, and a detail line if given, or with
408
+ * `compact` the avatar alone.
409
409
  */
410
410
  export function AppAccountButton({ avatar, name, detail, trailing, compact = false, className, ...props }) {
411
411
  if (compact) {
412
412
  return (_jsx("button", { type: "button", ...props, className: cx(accountAvatarOnly, className), children: avatar }));
413
413
  }
414
- return (_jsxs("button", { type: "button", ...props, className: cx(account, className), children: [avatar, _jsxs("span", { className: accountCopy, children: [_jsx("strong", { children: name }), _jsx("span", { children: detail })] }), trailing] }));
414
+ return (_jsxs("button", { type: "button", ...props, className: cx(account, className), children: [avatar, _jsxs("span", { className: accountCopy, children: [_jsx("strong", { className: singleLineTextClass, children: name }), detail && _jsx("span", { className: singleLineTextClass, children: detail })] }), trailing] }));
415
415
  }
@@ -27,10 +27,10 @@ export type SidePanelProps = Omit<ComponentProps<"aside">, "title"> & {
27
27
  * optional previous / next stepper, actions and close, a scrolling body and a footer. Put it beside
28
28
  * the list in a `SidePanelLayout`.
29
29
  */
30
- export declare function SidePanel({ title, eyebrow, subtitle, titleAccessory, actions, headerContent, footer, onClose, stepper, onPrevious, onNext, flushBody, bodyClassName, className, children, ...props }: SidePanelProps): import("@types/react").JSX.Element;
30
+ export declare function SidePanel({ title, eyebrow, subtitle, titleAccessory, actions, headerContent, footer, onClose, stepper, onPrevious, onNext, flushBody, bodyClassName, className, children, ...props }: SidePanelProps): import("react").JSX.Element;
31
31
  /** A list and its `SidePanel` side by side; the list takes the room the panel leaves. */
32
- export declare function SidePanelLayout({ className, ...props }: ComponentProps<"div">): import("@types/react").JSX.Element;
32
+ export declare function SidePanelLayout({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
33
33
  /** A labelled block of a side panel's body. */
34
34
  export declare function SidePanelSection({ label, className, children, ...props }: Omit<ComponentProps<"section">, "title"> & {
35
35
  label: ReactNode;
36
- }): import("@types/react").JSX.Element;
36
+ }): import("react").JSX.Element;
@@ -1,17 +1,19 @@
1
1
  import { useRender } from "@base-ui/react/use-render";
2
2
  import type { ComponentProps, ReactNode } from "react";
3
- export declare function SidebarNavigation({ className, ...props }: ComponentProps<"nav">): import("@types/react").JSX.Element;
4
- export declare function SidebarDivider({ className, ...props }: ComponentProps<"hr">): import("@types/react").JSX.Element;
5
- export declare function SidebarPanel({ className, ...props }: ComponentProps<"div">): import("@types/react").JSX.Element;
3
+ export declare function SidebarNavigation({ className, ...props }: ComponentProps<"nav">): import("react").JSX.Element;
4
+ export declare function SidebarDivider({ className, ...props }: ComponentProps<"hr">): import("react").JSX.Element;
5
+ /** Opens a labelled section in the rail, as its label does in the expanded sidebar. */
6
+ export declare function SidebarRailRule({ className, ...props }: ComponentProps<"hr">): import("react").JSX.Element;
7
+ export declare function SidebarPanel({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
6
8
  export declare function SidebarSection({ label, action, iconTone, className, children, ...props }: ComponentProps<"div"> & {
7
9
  label?: ReactNode;
8
10
  action?: ReactNode;
9
11
  iconTone?: "bronze";
10
- }): import("@types/react").JSX.Element;
12
+ }): import("react").JSX.Element;
11
13
  /** The subject a sidebar is scoped to, such as the open project. */
12
14
  export declare function SidebarHeading({ icon, className, children, ...props }: ComponentProps<"button"> & {
13
15
  icon?: ReactNode;
14
- }): import("@types/react").JSX.Element;
16
+ }): import("react").JSX.Element;
15
17
  /**
16
18
  * A sidebar row. Without children it renders icon-only, for the rail; give it an `aria-label`
17
19
  * then, since the label is what names it.
@@ -29,7 +31,10 @@ export type SidebarItemProps = useRender.ComponentProps<"button"> & {
29
31
  active?: boolean;
30
32
  /** Tint the leading icon bronze while inactive, as the Projects hub sidebar does. */
31
33
  iconTone?: "bronze";
32
- /** `compact` is a secondary list's row, such as recently opened records. */
33
- size?: "regular" | "compact";
34
+ /**
35
+ * `compact` is a secondary list's row, such as recently opened records; `short` a shorter row
36
+ * in the body type, such as the settings sidebar's Back to app.
37
+ */
38
+ size?: "regular" | "compact" | "short";
34
39
  };
35
- export declare function SidebarItem({ icon, trailing, action, active, iconTone, size, href, render, className, children, ...props }: SidebarItemProps): import("@types/react").JSX.Element;
40
+ export declare function SidebarItem({ icon, trailing, action, active, iconTone, size, href, render, className, children, ...props }: SidebarItemProps): import("react").JSX.Element;
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useRender } from "@base-ui/react/use-render";
3
3
  import { css, cx } from "#primitives/css";
4
4
  import { IconButtonSizeContext } from "./button.js";
5
+ import { singleLineText } from "./single-line-text.js";
5
6
  // Navigation sits in the shell's sidebar; it is not a panel of its own.
6
7
  const navigation = css({
7
8
  display: "flex",
@@ -33,6 +34,17 @@ const sectionLabel = css({
33
34
  "&[data-icon-tone=bronze] > svg": { color: "accent.bronze" },
34
35
  });
35
36
  const sectionAction = css({ display: "inline-flex", marginInlineStart: "auto" });
37
+ // A labelled section's mark in the rail, where there is no room for its label: a short rule.
38
+ const railRule = css({
39
+ flexShrink: "0",
40
+ width: "sidebar.railRule",
41
+ height: "border.hairline",
42
+ marginTop: "none",
43
+ marginInline: "auto",
44
+ marginBottom: "panel.default",
45
+ border: "0",
46
+ background: "border.divider",
47
+ });
36
48
  const divider = css({
37
49
  width: "100%",
38
50
  height: "border.hairline",
@@ -40,15 +52,20 @@ const divider = css({
40
52
  border: "0",
41
53
  background: "border.hairline",
42
54
  });
55
+ /*
56
+ * A row is square-cornered at rest; hovered, open or focused it rounds into a pill. The open page
57
+ * sits on the canvas's field face inside its edge; a hover is a faint wash in light and the
58
+ * selected glass in dark.
59
+ */
43
60
  const item = css({
44
61
  display: "flex",
45
62
  alignItems: "center",
46
63
  gap: "layout.controlGap",
47
64
  width: "100%",
48
- height: "control.small",
65
+ height: "control.row",
49
66
  paddingInline: "control.compactInline",
50
67
  border: "0",
51
- borderRadius: "action",
68
+ borderRadius: "nav",
52
69
  background: "transparent",
53
70
  // Muted against the dark canvas; light keeps every item at full contrast, as Round 2 does.
54
71
  color: "fg.muted",
@@ -60,24 +77,30 @@ const item = css({
60
77
  lineHeight: "tight",
61
78
  textAlign: "start",
62
79
  cursor: "pointer",
63
- transitionProperty: "background, color",
80
+ transitionProperty: "background, color, border-radius",
64
81
  transitionDuration: "fast",
65
82
  "& > svg:first-child": { opacity: ".7" },
66
83
  "&[data-icon-tone=bronze] > svg:first-child": { color: "accent.bronze" },
67
84
  "&:hover, &[aria-pressed=true]": {
68
- background: "bg.hover",
85
+ borderRadius: "shell",
86
+ background: "token(gradients.selected)",
87
+ _light: { background: "bg.rowHover" },
69
88
  color: "fg.primary",
70
89
  "& > svg:first-child": { color: "inherit" },
71
90
  },
72
- // The open page keeps the hover shape and size, so moving between pages shifts nothing; the
73
- // accent wash and the panel's own edge are what mark it.
91
+ // The open page keeps the hover shape and size; the field face and the canvas's edge mark it.
92
+ // The design counts that edge inside the row, so its content sits a hairline further in.
74
93
  "&[aria-current=page]": {
75
- background: "bg.selected",
76
- boxShadow: "inset 0 0 0 1px token(colors.border.panel)",
94
+ borderRadius: "shell",
95
+ background: "bg.field",
96
+ boxShadow: "inset 0 0 0 1px token(colors.border.canvas)",
77
97
  color: "fg.primary",
78
98
  "& > svg:first-child": { color: "inherit", opacity: "1" },
99
+ "&:not([data-icon-only])": {
100
+ paddingInline: "calc(token(spacing.control.compactInline) + token(sizes.border.hairline))",
101
+ },
79
102
  },
80
- _focusVisible: { focusRing: "inset" },
103
+ _focusVisible: { borderRadius: "shell", focusRing: "outer" },
81
104
  // A secondary list under the navigation, such as recently opened records: a shorter row in
82
105
  // smaller, quieter text, so it reads apart from the pages above it.
83
106
  "&[data-size=compact]": {
@@ -85,23 +108,19 @@ const item = css({
85
108
  color: "fg.secondary",
86
109
  fontSize: "caption",
87
110
  },
88
- // With no label it is the rail's square: the same hover, open-page fill and edge, icon only.
111
+ // A shorter row in the body type, such as the settings sidebar's way back to the app.
112
+ "&[data-size=short]": { height: "sidebar.shortRow" },
113
+ // With no label it is the rail's round button: the same hover, open-page face and edge, icon only.
89
114
  "&[data-icon-only]": {
90
115
  justifyContent: "center",
91
- width: "control.default",
92
- height: "control.default",
116
+ width: "control.compact",
117
+ height: "control.compact",
93
118
  paddingInline: "none",
94
- "& > svg:first-child": { opacity: "1", fontSize: "icon.rail" },
119
+ borderRadius: "round",
120
+ "& > svg:first-child": { opacity: "1", fontSize: "icon.small" },
95
121
  },
96
122
  });
97
- const label = css({
98
- minWidth: "0",
99
- flex: "1",
100
- overflow: "hidden",
101
- textOverflow: "ellipsis",
102
- whiteSpace: "nowrap",
103
- lineHeight: "compact",
104
- });
123
+ const label = css(singleLineText, { flex: "1" });
105
124
  const trailingStyle = css({ display: "inline-flex", flexShrink: "0", color: "fg.subtle" });
106
125
  // A row with an action: the group draws the row's hover, open-page fill and edge, so they span the
107
126
  // action too, and the row inside it stays transparent.
@@ -110,21 +129,26 @@ const itemGroup = css({
110
129
  alignItems: "center",
111
130
  width: "100%",
112
131
  minWidth: "0",
113
- borderRadius: "action",
114
- transitionProperty: "background",
132
+ borderRadius: "nav",
133
+ transitionProperty: "background, border-radius",
115
134
  transitionDuration: "fast",
116
- "&:hover": { background: "bg.hover" },
135
+ "&:hover": {
136
+ borderRadius: "shell",
137
+ background: "token(gradients.selected)",
138
+ _light: { background: "bg.rowHover" },
139
+ },
117
140
  "&:hover > [data-sidebar-row]": { color: "fg.primary" },
118
141
  "&:has(> [data-sidebar-row][aria-current=page])": {
119
- background: "bg.selected",
120
- boxShadow: "inset 0 0 0 1px token(colors.border.panel)",
142
+ borderRadius: "shell",
143
+ background: "bg.field",
144
+ boxShadow: "inset 0 0 0 1px token(colors.border.canvas)",
121
145
  },
122
146
  // The group draws the one wash; the row inside never adds its own on hover or when current.
123
147
  "& > [data-sidebar-row]": { minWidth: "0" },
124
148
  "& > [data-sidebar-row], & > [data-sidebar-row]:is(:hover, [aria-current=page], [aria-pressed=true])": { background: "transparent", boxShadow: "none" },
125
149
  // Focus rings the whole row, action included, not just the link inside it.
126
150
  "& > [data-sidebar-row]:focus-visible": { outline: "none" },
127
- "&:has(> [data-sidebar-row]:focus-visible)": { focusRing: "inset" },
151
+ "&:has(> [data-sidebar-row]:focus-visible)": { borderRadius: "shell", focusRing: "outer" },
128
152
  "&:hover > [data-sidebar-action], & > [data-sidebar-action]:focus-within": { opacity: "1" },
129
153
  });
130
154
  // Revealed on hover or focus; always shown where there is no hover to reveal it.
@@ -171,6 +195,10 @@ export function SidebarNavigation({ className, ...props }) {
171
195
  export function SidebarDivider({ className, ...props }) {
172
196
  return _jsx("hr", { ...props, className: cx(divider, className), "data-ciridae-ui": "" });
173
197
  }
198
+ /** Opens a labelled section in the rail, as its label does in the expanded sidebar. */
199
+ export function SidebarRailRule({ className, ...props }) {
200
+ return _jsx("hr", { ...props, className: cx(railRule, className), "data-ciridae-ui": "" });
201
+ }
174
202
  export function SidebarPanel({ className, ...props }) {
175
203
  return _jsx("div", { ...props, className: cx(panel, className), "data-ciridae-ui": "" });
176
204
  }
@@ -0,0 +1,2 @@
1
+ export declare const singleLineText: import("../styled-system/types/index.js").SystemStyleObject;
2
+ export declare const singleLineTextClass: string;
@@ -0,0 +1,16 @@
1
+ import { css } from "#primitives/css";
2
+ /*
3
+ * One line of text at the type's own height, as the design sets every single-line label, cut
4
+ * with an ellipsis when it runs out of room. It clips sideways only, so the descenders that reach
5
+ * below a line box that tight stay whole. Compose it at the top level of a `css()` call, or as the
6
+ * class `singleLineTextClass`: Panda does not extract it from under a nested selector.
7
+ */
8
+ export const singleLineText = css.raw({
9
+ minWidth: "0",
10
+ overflowX: "clip",
11
+ overflowY: "visible",
12
+ textOverflow: "ellipsis",
13
+ whiteSpace: "nowrap",
14
+ lineHeight: "tight",
15
+ });
16
+ export const singleLineTextClass = css(singleLineText);
@@ -19,7 +19,10 @@ declare const banner: import("../styled-system/types/index.js").RecipeRuntimeFn<
19
19
  };
20
20
  };
21
21
  }>;
22
- export type SiteBannerProps = ComponentProps<"div"> & RecipeVariantProps<typeof banner>;
22
+ export type SiteBannerProps = ComponentProps<"div"> & RecipeVariantProps<typeof banner> & {
23
+ /** Adds a close button at the strip's end. */
24
+ onDismiss?: () => void;
25
+ };
23
26
  /** A quiet, full-width site notice, separate from page-level status banners. */
24
- export declare function SiteBanner({ tone, className, ...props }: SiteBannerProps): import("@types/react").JSX.Element;
27
+ export declare function SiteBanner({ tone, onDismiss, className, children, ...props }: SiteBannerProps): import("react").JSX.Element;
25
28
  export {};
@@ -1,12 +1,19 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { cva, cx } from "#primitives/css";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { XIcon } from "@phosphor-icons/react";
3
+ import { css, cva, cx } from "#primitives/css";
4
+ import { IconButton } from "./button.js";
5
+ import { icon } from "./icon.js";
6
+ import { useCiridaeLocale } from "./locale.js";
3
7
  const banner = cva({
4
8
  base: {
9
+ display: "flex",
10
+ alignItems: "center",
11
+ gap: "layout.controlGap",
5
12
  flexShrink: "0",
6
13
  width: "100%",
7
14
  boxSizing: "border-box",
8
- paddingBlock: "2px",
9
- paddingInline: "16px",
15
+ paddingBlock: "control.trackInset",
16
+ paddingInline: "control.inline",
10
17
  textAlign: "start",
11
18
  fontSize: "11px",
12
19
  fontWeight: "medium",
@@ -24,7 +31,11 @@ const banner = cva({
24
31
  },
25
32
  defaultVariants: { tone: "info" },
26
33
  });
34
+ const message = css({ flex: "1", minWidth: "0" });
35
+ // The strip keeps its height: the button reaches past the line by as much as it is taller.
36
+ const dismissButton = css({ marginBlock: "calc((1lh - token(sizes.control.shortcut)) / 2)" });
27
37
  /** A quiet, full-width site notice, separate from page-level status banners. */
28
- export function SiteBanner({ tone, className, ...props }) {
29
- return _jsx("div", { ...props, className: cx(banner({ tone }), className) });
38
+ export function SiteBanner({ tone, onDismiss, className, children, ...props }) {
39
+ const { labels } = useCiridaeLocale();
40
+ return (_jsxs("div", { ...props, className: cx(banner({ tone }), className), children: [_jsx("span", { className: message, children: children }), onDismiss && (_jsx(IconButton, { "aria-label": labels.common.dismiss, variant: "ghost", size: "compact", className: dismissButton, onClick: onDismiss, children: _jsx(XIcon, { className: icon({ size: "compact" }) }) }))] }));
30
41
  }
@@ -1,15 +1,16 @@
1
1
  import type { ComponentProps } from "react";
2
2
  export type SkeletonWidth = "short" | "medium" | "long" | "full" | `${number}%`;
3
- export type SkeletonHeight = "text" | "caption" | "control" | "row" | "block" | "chart" | "chart.small" | "chart.medium" | "chart.large";
3
+ export type SkeletonHeight = "text" | "caption" | "line" | "smallLine" | "bar" | "badge" | "control" | "row" | "block" | "chart" | "chart.small" | "chart.medium" | "chart.large";
4
4
  /**
5
- * Loading placeholder with a shimmer. `block` fills its box, `text` takes one line of the
6
- * surrounding text, `circle` stands in for avatars and icons, and `square` for logos and tiles. Size it with `width` (a token
7
- * length, `full`, or a percentage of its box) and `height` (a line of text or caption, a control,
8
- * a list row, the whole box, or a chart's height).
5
+ * Loading placeholder. `block` fills its box, `text` takes one line of the surrounding text,
6
+ * `circle` stands in for an avatar, `square` for a checkbox, and `pill` for a status chip. Size it
7
+ * with `width` (a token length, `full`, or a percentage of its box) and `height` (a line of text
8
+ * or small print, the design's fixed line or small line, a bar, a small badge, a control, a list
9
+ * row, the whole box, or a chart's height).
9
10
  */
10
11
  export declare function Skeleton({ shape, width, height, className, style, ...props }: ComponentProps<"span"> & {
11
- shape?: "block" | "text" | "circle" | "square";
12
+ shape?: "block" | "text" | "circle" | "square" | "pill";
12
13
  /** A token width, for a value of roughly known length, or a share of the box such as `"60%"`. */
13
14
  width?: SkeletonWidth;
14
15
  height?: SkeletonHeight;
15
- }): import("@types/react").JSX.Element;
16
+ }): import("react").JSX.Element;
@@ -1,43 +1,54 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { css, cx } from "#primitives/css";
3
+ // The design draws placeholders flat, with no shimmer: the canvas's gradient in light, a white
4
+ // wash in dark. Every bar is fully rounded except the block, the box and the bar.
3
5
  const skeleton = css({
4
6
  display: "block",
5
7
  flexShrink: "0",
6
- background: "token(gradients.skeleton)",
7
- backgroundSize: "200% 100%",
8
- animation: "skeletonShimmer 1.6s ease-in-out infinite",
9
- _motionReduce: { animation: "none" },
10
- "&[data-shape=block]": { minHeight: "skeleton.line", borderRadius: "action" },
8
+ background: "token(gradients.skeletonFill)",
9
+ "&[data-shape=block]": { minHeight: "skeleton.line", borderRadius: "control" },
11
10
  // One line of the surrounding text: the bar is shorter than the line box and centered in it.
12
11
  "&[data-shape=text]": {
13
12
  width: "100%",
14
13
  height: "0.75em",
15
14
  marginBlock: "calc((1lh - 0.75em) / 2)",
16
- borderRadius: "keycap",
15
+ borderRadius: "round",
17
16
  },
18
17
  "&[data-shape=circle]": {
19
- width: "control.compact",
18
+ width: "avatar.menu",
20
19
  aspectRatio: "1",
21
20
  borderRadius: "round",
22
21
  },
23
22
  "&[data-shape=square]": {
24
- width: "control.compact",
23
+ width: "control.checkbox",
25
24
  aspectRatio: "1",
26
- borderRadius: "action",
25
+ borderRadius: "control",
26
+ },
27
+ // A status chip's or a badge's placeholder.
28
+ "&[data-shape=pill]": {
29
+ width: "skeleton.pill",
30
+ height: "skeleton.bar",
31
+ borderRadius: "round",
27
32
  },
28
33
  "&[data-shape][data-width=short]": { width: "skeleton.short" },
29
34
  "&[data-shape][data-width=medium]": { width: "skeleton.medium" },
30
35
  "&[data-shape][data-width=long]": { width: "skeleton.long" },
31
36
  "&[data-shape][data-width=full]": { width: "100%" },
32
- // A line of caption text, as `text` is a line of the surrounding text.
37
+ // A line of small print, such as a row's meta line, under a line of text.
33
38
  "&[data-shape][data-height=caption]": {
34
- height: "calc(token(fontSizes.caption) * 0.75)",
35
- marginBlock: "calc((1lh - token(fontSizes.caption) * 0.75) / 2)",
39
+ height: "skeleton.caption",
40
+ marginBlock: "calc((1lh - token(sizes.skeleton.caption)) / 2)",
36
41
  },
37
42
  "&[data-shape][data-height=text]": {
38
43
  height: "0.75em",
39
44
  marginBlock: "calc((1lh - 0.75em) / 2)",
40
45
  },
46
+ // The design's fixed text bars, with no line box round them: a line, and a small one.
47
+ "&[data-shape][data-height=line]": { height: "skeleton.textLine", marginBlock: "0" },
48
+ "&[data-shape][data-height=smallLine]": { height: "skeleton.caption", marginBlock: "0" },
49
+ // A bar in a chart's or a breakdown's placeholder, and a small badge's.
50
+ "&[data-shape][data-height=bar]": { height: "skeleton.bar", marginBlock: "0" },
51
+ "&[data-shape][data-height=badge]": { height: "skeleton.badge", marginBlock: "0" },
41
52
  "&[data-shape][data-height=control]": { height: "control.default", marginBlock: "0" },
42
53
  "&[data-shape][data-height=row]": { height: "control.field", marginBlock: "0" },
43
54
  "&[data-shape][data-height=block]": { height: "100%", marginBlock: "0" },
@@ -49,10 +60,11 @@ const skeleton = css({
49
60
  "&[data-shape][data-height='chart.large']": { height: "chart.large", marginBlock: "0" },
50
61
  });
51
62
  /**
52
- * Loading placeholder with a shimmer. `block` fills its box, `text` takes one line of the
53
- * surrounding text, `circle` stands in for avatars and icons, and `square` for logos and tiles. Size it with `width` (a token
54
- * length, `full`, or a percentage of its box) and `height` (a line of text or caption, a control,
55
- * a list row, the whole box, or a chart's height).
63
+ * Loading placeholder. `block` fills its box, `text` takes one line of the surrounding text,
64
+ * `circle` stands in for an avatar, `square` for a checkbox, and `pill` for a status chip. Size it
65
+ * with `width` (a token length, `full`, or a percentage of its box) and `height` (a line of text
66
+ * or small print, the design's fixed line or small line, a bar, a small badge, a control, a list
67
+ * row, the whole box, or a chart's height).
56
68
  */
57
69
  export function Skeleton({ shape = "block", width, height, className, style, ...props }) {
58
70
  const percent = width?.endsWith("%") ? width : undefined;