@ciridae/ui 1.0.4 → 1.0.9

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 (147) hide show
  1. package/README.md +3 -2
  2. package/dist/chat/conversation-source.d.ts +1 -3
  3. package/dist/chat/message-text.js +6 -6
  4. package/dist/chat/use-chat-conversation.d.ts +7 -2
  5. package/dist/chat/use-chat-conversation.js +2 -1
  6. package/dist/components/activity-feed.d.ts +0 -1
  7. package/dist/components/activity-feed.js +6 -7
  8. package/dist/components/agent-work.d.ts +5 -1
  9. package/dist/components/agent-work.js +27 -13
  10. package/dist/components/app-frame.d.ts +3 -17
  11. package/dist/components/app-frame.js +11 -30
  12. package/dist/components/app-navigation.d.ts +5 -6
  13. package/dist/components/app-navigation.js +70 -40
  14. package/dist/components/badge.d.ts +0 -4
  15. package/dist/components/badge.js +17 -27
  16. package/dist/components/bulk-action-bar.js +2 -2
  17. package/dist/components/button.js +41 -50
  18. package/dist/components/calendar.js +5 -8
  19. package/dist/components/centered-page.js +4 -4
  20. package/dist/components/chart.js +3 -4
  21. package/dist/components/chat-client-source.js +55 -34
  22. package/dist/components/chat-page.js +1 -1
  23. package/dist/components/chat-sheet.d.ts +30 -20
  24. package/dist/components/chat-sheet.js +112 -54
  25. package/dist/components/chat.d.ts +27 -56
  26. package/dist/components/chat.js +153 -132
  27. package/dist/components/checkbox-item.js +4 -4
  28. package/dist/components/checkbox-list.js +6 -6
  29. package/dist/components/chip.js +2 -2
  30. package/dist/components/collapsible.js +3 -3
  31. package/dist/components/color-theme.d.ts +3 -6
  32. package/dist/components/color-theme.js +10 -11
  33. package/dist/components/column-settings.js +3 -3
  34. package/dist/components/command-menu.d.ts +1 -2
  35. package/dist/components/command-menu.js +56 -77
  36. package/dist/components/command-palette.js +5 -2
  37. package/dist/components/copyable-id.js +5 -5
  38. package/dist/components/data-display.d.ts +1 -7
  39. package/dist/components/data-display.js +32 -55
  40. package/dist/components/data-grid.d.ts +4 -7
  41. package/dist/components/data-grid.js +106 -90
  42. package/dist/components/date-range-picker.js +4 -5
  43. package/dist/components/document-viewer.js +23 -23
  44. package/dist/components/drawer.d.ts +2 -1
  45. package/dist/components/drawer.js +45 -20
  46. package/dist/components/dropzone.js +13 -13
  47. package/dist/components/editable-field.d.ts +2 -7
  48. package/dist/components/editable-field.js +14 -27
  49. package/dist/components/email-input.js +2 -3
  50. package/dist/components/environment-frame.js +7 -7
  51. package/dist/components/expandable-text.js +2 -2
  52. package/dist/components/feedback-screenshot.js +7 -7
  53. package/dist/components/feedback-sheet.js +8 -8
  54. package/dist/components/filter-bar.js +41 -27
  55. package/dist/components/form-controls.d.ts +3 -6
  56. package/dist/components/form-controls.js +15 -22
  57. package/dist/components/form-layout.d.ts +6 -6
  58. package/dist/components/form-layout.js +10 -16
  59. package/dist/components/glass-menu.d.ts +2 -0
  60. package/dist/components/glass-menu.js +14 -18
  61. package/dist/components/gradient-edge.d.ts +0 -1
  62. package/dist/components/gradient-edge.js +8 -9
  63. package/dist/components/icon.js +1 -1
  64. package/dist/components/input.js +18 -17
  65. package/dist/components/keycap.d.ts +2 -6
  66. package/dist/components/keycap.js +4 -12
  67. package/dist/components/layout.js +11 -10
  68. package/dist/components/lightbox.js +8 -8
  69. package/dist/components/link.js +1 -1
  70. package/dist/components/locale.d.ts +23 -7
  71. package/dist/components/locale.js +19 -7
  72. package/dist/components/log-entry.d.ts +2 -14
  73. package/dist/components/log-entry.js +11 -22
  74. package/dist/components/log-list.js +1 -1
  75. package/dist/components/mention-input.js +13 -14
  76. package/dist/components/menu.d.ts +7 -4
  77. package/dist/components/menu.js +23 -10
  78. package/dist/components/meter.d.ts +2 -3
  79. package/dist/components/meter.js +12 -16
  80. package/dist/components/navigation.d.ts +0 -7
  81. package/dist/components/navigation.js +3 -12
  82. package/dist/components/notification-tray.js +7 -7
  83. package/dist/components/overlays.d.ts +5 -2
  84. package/dist/components/overlays.js +24 -24
  85. package/dist/components/panel.js +3 -3
  86. package/dist/components/progress.js +2 -2
  87. package/dist/components/radio-card.d.ts +1 -1
  88. package/dist/components/radio-card.js +9 -9
  89. package/dist/components/record.d.ts +2 -4
  90. package/dist/components/record.js +19 -32
  91. package/dist/components/scroll-area.js +10 -10
  92. package/dist/components/segmented-bar.js +9 -9
  93. package/dist/components/select.d.ts +3 -5
  94. package/dist/components/select.js +26 -44
  95. package/dist/components/settings.js +1 -1
  96. package/dist/components/shell-skeleton.js +1 -1
  97. package/dist/components/shell.d.ts +1 -1
  98. package/dist/components/shell.js +69 -24
  99. package/dist/components/side-panel.js +3 -3
  100. package/dist/components/sidebar.d.ts +0 -5
  101. package/dist/components/sidebar.js +25 -33
  102. package/dist/components/single-line-text.js +3 -4
  103. package/dist/components/site-banner.js +4 -4
  104. package/dist/components/skeleton.js +19 -22
  105. package/dist/components/skeletons.d.ts +0 -3
  106. package/dist/components/skeletons.js +5 -10
  107. package/dist/components/stages.d.ts +6 -3
  108. package/dist/components/stages.js +77 -105
  109. package/dist/components/stat-card.d.ts +2 -5
  110. package/dist/components/stat-card.js +23 -31
  111. package/dist/components/status-banner.js +6 -6
  112. package/dist/components/status.js +3 -3
  113. package/dist/components/steps.js +2 -2
  114. package/dist/components/switch.js +1 -1
  115. package/dist/components/tabs.js +15 -18
  116. package/dist/components/theme-customizer.d.ts +5 -8
  117. package/dist/components/theme-customizer.js +9 -41
  118. package/dist/components/theme-toggle.d.ts +0 -1
  119. package/dist/components/theme-toggle.js +6 -11
  120. package/dist/components/toast.d.ts +1 -7
  121. package/dist/components/toast.js +19 -22
  122. package/dist/components/user-chip.js +8 -8
  123. package/dist/components/wizard.js +6 -4
  124. package/dist/preset.d.ts +1 -2
  125. package/dist/preset.js +41 -89
  126. package/dist/styled-system/css/conditions.mjs +1 -1
  127. package/dist/styled-system/css/css.mjs +1 -1
  128. package/dist/styled-system/styles.css +820 -1297
  129. package/dist/styled-system/tokens/index.mjs +78 -1926
  130. package/dist/styled-system/tokens/tokens.d.ts +18 -33
  131. package/dist/styled-system/types/conditions.d.ts +0 -74
  132. package/dist/styled-system/types/prop-type.d.ts +15 -40
  133. package/dist/styled-system/types/style-props.d.ts +705 -705
  134. package/dist/theme/color.d.ts +0 -1
  135. package/dist/theme/color.js +0 -16
  136. package/dist/theme/derive.d.ts +3 -3
  137. package/dist/theme/derive.js +9 -32
  138. package/dist/theme/index.d.ts +1 -2
  139. package/dist/theme/index.js +3 -5
  140. package/dist/theme/options.d.ts +2 -4
  141. package/dist/theme/options.js +0 -1
  142. package/dist/theme/{palettes.d.ts → palette.d.ts} +12 -23
  143. package/dist/theme/palette.js +127 -0
  144. package/dist/theme/tokens.d.ts +8 -13
  145. package/dist/theme/tokens.js +39 -92
  146. package/package.json +1 -1
  147. package/dist/theme/palettes.js +0 -254
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useRender } from "@base-ui/react/use-render";
3
3
  import { ListIcon } from "@phosphor-icons/react";
4
- import { createContext, useContext, useMemo, useState } from "react";
4
+ import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react";
5
5
  import { css, cx } from "#primitives/css";
6
6
  import { IconButton, IconButtonSizeContext } from "./button.js";
7
7
  import { PageHotkeys, useHotkey } from "./hotkeys.js";
@@ -11,9 +11,9 @@ import { singleLineTextClass } from "./single-line-text.js";
11
11
  // The sidebar sits flush against the window; only the main panel is inset from the edges.
12
12
  const shell = css({
13
13
  display: "flex",
14
- height: "100dvh",
14
+ height: "[100dvh]",
15
15
  overflow: "hidden",
16
- background: "token(gradients.canvas)",
16
+ background: "[token(gradients.canvas)]",
17
17
  color: "fg.primary",
18
18
  // Compact line height leaves clipped text room for its descenders throughout the app frame.
19
19
  textStyle: "body",
@@ -53,18 +53,18 @@ const sidebar = css({
53
53
  // button, with its full labelled content rather than the rail.
54
54
  _phone: {
55
55
  position: "fixed",
56
- insetBlock: "0",
57
- insetInlineStart: "0",
56
+ insetBlock: "none",
57
+ insetInlineStart: "none",
58
58
  zIndex: "drawer",
59
59
  width: "shell.sidebar",
60
60
  alignItems: "stretch",
61
- background: "token(gradients.canvas)",
61
+ background: "[token(gradients.canvas)]",
62
62
  borderInlineEnd: "1px solid token(colors.border.panel)",
63
63
  boxShadow: "card",
64
64
  transform: "translateX(-100%)",
65
65
  _rtl: { transform: "translateX(100%)" },
66
66
  visibility: "hidden",
67
- transitionProperty: "transform, visibility",
67
+ transitionProperty: "[transform, visibility]",
68
68
  transitionDuration: "fast",
69
69
  "&[data-menu-open]": { transform: "none", visibility: "visible" },
70
70
  },
@@ -74,7 +74,7 @@ const menuBackdrop = css({
74
74
  _phone: {
75
75
  display: "block",
76
76
  position: "fixed",
77
- inset: "0",
77
+ inset: "none",
78
78
  zIndex: "drawer",
79
79
  background: "bg.backdrop",
80
80
  },
@@ -89,13 +89,13 @@ const main = css({
89
89
  marginInlineEnd: "panel.compact",
90
90
  border: "1px solid token(colors.border.canvas)",
91
91
  borderRadius: "action",
92
- background: "token(gradients.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
96
  margin: "none",
97
- borderRadius: "0",
98
- height: "100dvh",
97
+ borderRadius: "none",
98
+ height: "[100dvh]",
99
99
  border: "0",
100
100
  },
101
101
  });
@@ -109,7 +109,7 @@ const header = css({
109
109
  paddingInlineEnd: "control.compactInline",
110
110
  paddingInlineStart: "control.inline",
111
111
  borderBottom: "1px solid token(colors.border.divider)",
112
- "& > :last-child": { minWidth: "0", maxWidth: "100%" },
112
+ "& > :last-child": { minWidth: "0", maxWidth: "full" },
113
113
  // Once the sidebar is gone the header stays one row: the title truncates, the actions keep
114
114
  // their width.
115
115
  _phone: {
@@ -127,7 +127,6 @@ const header = css({
127
127
  "& [data-slicer-label]": { srOnly: true },
128
128
  },
129
129
  });
130
- // The trail's parents; the page itself, last, is in the primary text.
131
130
  const headerTitle = css({
132
131
  flex: "1",
133
132
  minWidth: "0",
@@ -146,11 +145,18 @@ const content = css({
146
145
  padding: "var(--app-content-inset)",
147
146
  _phone: { "--app-content-inset": "token(spacing.panel.default)" },
148
147
  });
148
+ /** Focuses the Menu button now in the ref, which a page change may have replaced. */
149
+ function focusMenuButton(buttonRef, onlyIfFocusIsLost) {
150
+ if (!onlyIfFocusIsLost || document.activeElement === document.body)
151
+ buttonRef.current?.focus();
152
+ }
149
153
  /** Whether the phone menu (the sidebar slid in over the page) is open. */
150
154
  const ShellMenuContext = createContext({
151
155
  open: false,
152
156
  setOpen: () => undefined,
157
+ buttonRef: { current: null },
153
158
  });
159
+ const menuFocusableSelector = "a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex='-1'])";
154
160
  /** In the page's scope, so Escape in an overlay over the menu closes only the overlay. */
155
161
  function CloseShellMenuOnEscape() {
156
162
  const menu = useContext(ShellMenuContext);
@@ -163,13 +169,50 @@ function CloseShellMenuOnEscape() {
163
169
  }
164
170
  export function AppShell({ className, children, ...props }) {
165
171
  const [menuOpen, setMenuOpen] = useState(false);
166
- const menu = useMemo(() => ({ open: menuOpen, setOpen: setMenuOpen }), [menuOpen]);
172
+ const buttonRef = useRef(null);
173
+ const menu = useMemo(() => ({ open: menuOpen, setOpen: setMenuOpen, buttonRef }), [menuOpen]);
167
174
  return (_jsx(ShellMenuContext, { value: menu, children: _jsxs("div", { ...props, className: cx(shell, className), "data-ciridae-ui": "", children: [menuOpen && _jsx("div", { className: menuBackdrop, onClick: () => setMenuOpen(false) }), _jsxs(PageHotkeys, { children: [_jsx(CloseShellMenuOnEscape, {}), children] })] }) }));
168
175
  }
169
- export function AppSidebar({ className, collapsed, onClickCapture, ...props }) {
176
+ export function AppSidebar({ className, collapsed, onClickCapture, onKeyDown, ...props }) {
170
177
  const menu = useContext(ShellMenuContext);
178
+ const sidebarRef = useRef(null);
179
+ const { buttonRef, open: menuIsOpen } = menu;
180
+ // The open menu takes the focus and gives it back to the Menu button when it closes.
181
+ useEffect(() => {
182
+ if (!menuIsOpen)
183
+ return;
184
+ // The sidebar cannot take focus until its visibility transition has started, a frame later.
185
+ let frame = requestAnimationFrame(() => {
186
+ frame = requestAnimationFrame(() => sidebarRef.current?.querySelector(menuFocusableSelector)?.focus());
187
+ });
188
+ return () => {
189
+ cancelAnimationFrame(frame);
190
+ focusMenuButton(buttonRef, false);
191
+ // A page change replaces the header and its Menu button, which drops the focus again.
192
+ requestAnimationFrame(() => focusMenuButton(buttonRef, true));
193
+ };
194
+ }, [menuIsOpen, buttonRef]);
195
+ const keepTabInsideMenu = (event) => {
196
+ onKeyDown?.(event);
197
+ if (!menu.open || event.key !== "Tab")
198
+ return;
199
+ const focusable = [
200
+ ...event.currentTarget.querySelectorAll(menuFocusableSelector),
201
+ ].filter((element) => element.checkVisibility());
202
+ const first = focusable[0];
203
+ const last = focusable[focusable.length - 1];
204
+ if (event.shiftKey && document.activeElement === first) {
205
+ event.preventDefault();
206
+ last?.focus();
207
+ }
208
+ else if (!event.shiftKey && document.activeElement === last) {
209
+ event.preventDefault();
210
+ first?.focus();
211
+ }
212
+ };
171
213
  // Choosing a page from the phone menu closes it, as does an item of a menu opened from it, such
172
- // as the account menu; a row's action, such as a pin, and a menu's own trigger do not.
214
+ // as the account menu; a row's action, such as a pin, the More and Less row, and a menu's own
215
+ // trigger do not.
173
216
  const closeMenuOnNavigation = (event) => {
174
217
  onClickCapture?.(event);
175
218
  const target = event.target instanceof Element ? event.target : null;
@@ -179,13 +222,13 @@ export function AppSidebar({ className, collapsed, onClickCapture, ...props }) {
179
222
  menu.setOpen(false);
180
223
  }
181
224
  };
182
- return (_jsx("aside", { ...props, className: cx(sidebar, className), "data-collapsed": collapsed || undefined, "data-menu-open": menu.open || undefined, onClickCapture: closeMenuOnNavigation }));
225
+ return (_jsx("aside", { ...props, ref: sidebarRef, className: cx(sidebar, className), "data-collapsed": collapsed || undefined, "data-menu-open": menu.open || undefined, onClickCapture: closeMenuOnNavigation, onKeyDown: keepTabInsideMenu }));
183
226
  }
184
227
  /** Opens the sidebar as a menu on a phone; hidden at any width that shows the sidebar. */
185
228
  function AppMenuButton() {
186
229
  const menu = useContext(ShellMenuContext);
187
230
  const { labels } = useCiridaeLocale();
188
- return (_jsx("span", { className: menuButton, children: _jsx(IconButton, { "aria-label": labels.shell.menu, "aria-expanded": menu.open, variant: "ghost", onClick: () => menu.setOpen(!menu.open), children: _jsx(ListIcon, { className: icon({ size: "small" }) }) }) }));
231
+ return (_jsx("span", { className: menuButton, children: _jsx(IconButton, { ref: menu.buttonRef, "aria-label": labels.shell.menu, "aria-expanded": menu.open, variant: "ghost", onClick: () => menu.setOpen(!menu.open), children: _jsx(ListIcon, { className: icon({ size: "small" }) }) }) }));
189
232
  }
190
233
  export function AppMain({ className, ...props }) {
191
234
  return _jsx("main", { ...props, className: cx(main, className), "data-ciridae-ui": "" });
@@ -206,13 +249,15 @@ const sidebarRail = css({
206
249
  gap: "sidebar.groupGap",
207
250
  });
208
251
  /* One sidebar's content stacks at its container's own gap, so a footer's controls keep their room. */
209
- const sidebarOnly = css({ display: "flex", flexDirection: "column", gap: "inherit" });
252
+ const sidebarOnly = css({ display: "flex", flexDirection: "column", gap: "[inherit]" });
210
253
  const sidebarNav = css({
211
254
  display: "flex",
212
255
  flexDirection: "column",
213
256
  gap: "sidebar.groupGap",
214
257
  minHeight: "0",
215
258
  overflowY: "auto",
259
+ // It scrolls when its items outgrow it, so none of them shrinks to fit, the search field included.
260
+ "& > *": { flexShrink: "0" },
216
261
  // Scrolling would clip the ring of anything outer-ringed placed among the items.
217
262
  ringRoom: true,
218
263
  });
@@ -314,7 +359,7 @@ const crumbButton = css({
314
359
  padding: "none",
315
360
  border: "0",
316
361
  background: "transparent",
317
- color: "inherit",
362
+ color: "[inherit]",
318
363
  font: "inherit",
319
364
  cursor: "pointer",
320
365
  _hover: { textDecoration: "underline" },
@@ -338,9 +383,9 @@ const crumbCurrent = css({
338
383
  // The page's heading, but read as a crumb, so it stays on the body face.
339
384
  fontFamily: "sans",
340
385
  color: "fg.primary",
341
- fontSize: "inherit",
386
+ fontSize: "[inherit]",
342
387
  fontWeight: "medium",
343
- lineHeight: "inherit",
388
+ lineHeight: "[inherit]",
344
389
  });
345
390
  /** The slash between two crumbs. */
346
391
  export function AppBreadcrumbSeparator() {
@@ -372,12 +417,12 @@ const account = css({
372
417
  display: "flex",
373
418
  alignItems: "center",
374
419
  gap: "sidebar.markGap",
375
- width: "100%",
420
+ width: "full",
376
421
  padding: "control.compactBlock",
377
422
  border: "0",
378
423
  borderRadius: "keycap",
379
424
  background: "transparent",
380
- color: "inherit",
425
+ color: "[inherit]",
381
426
  font: "inherit",
382
427
  textAlign: "start",
383
428
  cursor: "pointer",
@@ -17,7 +17,7 @@ const aside = css({
17
17
  display: "flex",
18
18
  flexDirection: "column",
19
19
  flexShrink: "0",
20
- width: "400px",
20
+ width: "overlay.sheetNarrow",
21
21
  minWidth: "0",
22
22
  minHeight: "0",
23
23
  overflow: "hidden",
@@ -31,7 +31,7 @@ const headerRow = css({
31
31
  alignItems: "center",
32
32
  gap: "layout.controlGap",
33
33
  // A list head's height: its block padding round one line of its text.
34
- minHeight: "calc(token(spacing.panel.default) * 2 + 16px + 1px)",
34
+ minHeight: "[calc(token(spacing.panel.default) * 2 + 16px + 1px)]",
35
35
  paddingInlineStart: "panel.comfortable",
36
36
  paddingInlineEnd: "panel.default",
37
37
  borderBottom: "1px solid token(colors.border.panel)",
@@ -88,7 +88,7 @@ const body = css({
88
88
  overflowY: "auto",
89
89
  padding: "panel.comfortable",
90
90
  // A flush body holds its content edge to edge, such as tabs whose panels pad themselves.
91
- "&[data-flush]": { display: "flex", flexDirection: "column", gap: "0", padding: "0" },
91
+ "&[data-flush]": { display: "flex", flexDirection: "column", gap: "none", padding: "none" },
92
92
  });
93
93
  const footerRow = css({
94
94
  display: "flex",
@@ -2,7 +2,6 @@ import { useRender } from "@base-ui/react/use-render";
2
2
  import type { ComponentProps, ReactNode } from "react";
3
3
  export declare function SidebarNavigation({ className, ...props }: ComponentProps<"nav">): import("react").JSX.Element;
4
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
5
  export declare function SidebarRailRule({ className, ...props }: ComponentProps<"hr">): import("react").JSX.Element;
7
6
  export declare function SidebarPanel({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
8
7
  export declare function SidebarSection({ label, action, iconTone, className, children, ...props }: ComponentProps<"div"> & {
@@ -31,10 +30,6 @@ export type SidebarItemProps = useRender.ComponentProps<"button"> & {
31
30
  active?: boolean;
32
31
  /** Tint the leading icon bronze while inactive, as the Projects hub sidebar does. */
33
32
  iconTone?: "bronze";
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
33
  size?: "regular" | "compact" | "short";
39
34
  };
40
35
  export declare function SidebarItem({ icon, trailing, action, active, iconTone, size, href, render, className, children, ...props }: SidebarItemProps): import("react").JSX.Element;
@@ -6,7 +6,7 @@ import { singleLineText } from "./single-line-text.js";
6
6
  // Navigation sits in the shell's sidebar; it is not a panel of its own.
7
7
  const navigation = css({
8
8
  display: "flex",
9
- width: "100%",
9
+ width: "full",
10
10
  minWidth: "0",
11
11
  flexDirection: "column",
12
12
  gap: "layout.clusterGap",
@@ -34,7 +34,6 @@ const sectionLabel = css({
34
34
  "&[data-icon-tone=bronze] > svg": { color: "accent.bronze" },
35
35
  });
36
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
37
  const railRule = css({
39
38
  flexShrink: "0",
40
39
  width: "sidebar.railRule",
@@ -46,22 +45,18 @@ const railRule = css({
46
45
  background: "border.divider",
47
46
  });
48
47
  const divider = css({
49
- width: "100%",
48
+ width: "full",
50
49
  height: "border.hairline",
51
50
  margin: "none",
52
51
  border: "0",
53
52
  background: "border.hairline",
54
53
  });
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
- */
54
+ // A hover is a faint wash in light and the selected glass in dark.
60
55
  const item = css({
61
56
  display: "flex",
62
57
  alignItems: "center",
63
58
  gap: "layout.controlGap",
64
- width: "100%",
59
+ width: "full",
65
60
  height: "control.row",
66
61
  paddingInline: "control.compactInline",
67
62
  border: "0",
@@ -77,27 +72,27 @@ const item = css({
77
72
  lineHeight: "tight",
78
73
  textAlign: "start",
79
74
  cursor: "pointer",
80
- transitionProperty: "background, color, border-radius",
75
+ transitionProperty: "[background, color, border-radius]",
81
76
  transitionDuration: "fast",
82
- "& > svg:first-child": { opacity: ".7" },
77
+ "& > svg:first-child": { opacity: "[.7]" },
83
78
  "&[data-icon-tone=bronze] > svg:first-child": { color: "accent.bronze" },
84
79
  "&:hover, &[aria-pressed=true]": {
85
80
  borderRadius: "shell",
86
- background: "token(gradients.selected)",
81
+ background: "[token(gradients.selected)]",
87
82
  _light: { background: "bg.rowHover" },
88
83
  color: "fg.primary",
89
- "& > svg:first-child": { color: "inherit" },
84
+ "& > svg:first-child": { color: "[inherit]" },
90
85
  },
91
86
  // The open page keeps the hover shape and size; the field face and the canvas's edge mark it.
92
87
  // The design counts that edge inside the row, so its content sits a hairline further in.
93
88
  "&[aria-current=page]": {
94
89
  borderRadius: "shell",
95
90
  background: "bg.field",
96
- boxShadow: "inset 0 0 0 1px token(colors.border.canvas)",
91
+ boxShadow: "[inset 0 0 0 1px token(colors.border.canvas)]",
97
92
  color: "fg.primary",
98
- "& > svg:first-child": { color: "inherit", opacity: "1" },
93
+ "& > svg:first-child": { color: "[inherit]", opacity: "[1]" },
99
94
  "&:not([data-icon-only])": {
100
- paddingInline: "calc(token(spacing.control.compactInline) + token(sizes.border.hairline))",
95
+ paddingInline: "[calc(token(spacing.control.compactInline) + token(sizes.border.hairline))]",
101
96
  },
102
97
  },
103
98
  _focusVisible: { borderRadius: "shell", focusRing: "outer" },
@@ -108,16 +103,14 @@ const item = css({
108
103
  color: "fg.secondary",
109
104
  fontSize: "caption",
110
105
  },
111
- // A shorter row in the body type, such as the settings sidebar's way back to the app.
112
106
  "&[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.
114
107
  "&[data-icon-only]": {
115
108
  justifyContent: "center",
116
109
  width: "control.compact",
117
110
  height: "control.compact",
118
111
  paddingInline: "none",
119
112
  borderRadius: "round",
120
- "& > svg:first-child": { opacity: "1", fontSize: "icon.small" },
113
+ "& > svg:first-child": { opacity: "[1]", fontSize: "icon.small" },
121
114
  },
122
115
  });
123
116
  const label = css(singleLineText, { flex: "1" });
@@ -127,53 +120,53 @@ const trailingStyle = css({ display: "inline-flex", flexShrink: "0", color: "fg.
127
120
  const itemGroup = css({
128
121
  display: "flex",
129
122
  alignItems: "center",
130
- width: "100%",
123
+ width: "full",
131
124
  minWidth: "0",
132
125
  borderRadius: "nav",
133
- transitionProperty: "background, border-radius",
126
+ transitionProperty: "[background, border-radius]",
134
127
  transitionDuration: "fast",
135
128
  "&:hover": {
136
129
  borderRadius: "shell",
137
- background: "token(gradients.selected)",
130
+ background: "[token(gradients.selected)]",
138
131
  _light: { background: "bg.rowHover" },
139
132
  },
140
133
  "&:hover > [data-sidebar-row]": { color: "fg.primary" },
141
134
  "&:has(> [data-sidebar-row][aria-current=page])": {
142
135
  borderRadius: "shell",
143
136
  background: "bg.field",
144
- boxShadow: "inset 0 0 0 1px token(colors.border.canvas)",
137
+ boxShadow: "[inset 0 0 0 1px token(colors.border.canvas)]",
145
138
  },
146
139
  // The group draws the one wash; the row inside never adds its own on hover or when current.
147
140
  "& > [data-sidebar-row]": { minWidth: "0" },
148
- "& > [data-sidebar-row], & > [data-sidebar-row]:is(:hover, [aria-current=page], [aria-pressed=true])": { background: "transparent", boxShadow: "none" },
141
+ "& > [data-sidebar-row], & > [data-sidebar-row]:is(:hover, [aria-current=page], [aria-pressed=true])": { background: "transparent", boxShadow: "[none]" },
149
142
  // Focus rings the whole row, action included, not just the link inside it.
150
- "& > [data-sidebar-row]:focus-visible": { outline: "none" },
143
+ "& > [data-sidebar-row]:focus-visible": { outline: "0" },
151
144
  "&:has(> [data-sidebar-row]:focus-visible)": { borderRadius: "shell", focusRing: "outer" },
152
- "&:hover > [data-sidebar-action], & > [data-sidebar-action]:focus-within": { opacity: "1" },
145
+ "&:hover > [data-sidebar-action], & > [data-sidebar-action]:focus-within": { opacity: "[1]" },
153
146
  });
154
147
  // Revealed on hover or focus; always shown where there is no hover to reveal it.
155
148
  const itemAction = css({
156
149
  display: "inline-flex",
157
150
  flexShrink: "0",
158
151
  paddingInlineEnd: "control.trackInset",
159
- opacity: "0",
160
- transitionProperty: "opacity",
152
+ opacity: "[0]",
153
+ transitionProperty: "[opacity]",
161
154
  transitionDuration: "fast",
162
- _phone: { opacity: "1" },
163
- "@media (hover: none)": { opacity: "1" },
155
+ _phone: { opacity: "[1]" },
156
+ "@media (hover: none)": { opacity: "[1]" },
164
157
  });
165
158
  const heading = css({
166
159
  display: "flex",
167
160
  alignItems: "center",
168
161
  gap: "sidebar.markGap",
169
- width: "100%",
162
+ width: "full",
170
163
  minWidth: "0",
171
164
  paddingBlock: "control.block",
172
165
  paddingInline: "control.block",
173
166
  border: "0",
174
167
  borderRadius: "field",
175
168
  background: "transparent",
176
- color: "inherit",
169
+ color: "[inherit]",
177
170
  font: "inherit",
178
171
  textAlign: "start",
179
172
  cursor: "pointer",
@@ -195,7 +188,6 @@ export function SidebarNavigation({ className, ...props }) {
195
188
  export function SidebarDivider({ className, ...props }) {
196
189
  return _jsx("hr", { ...props, className: cx(divider, className), "data-ciridae-ui": "" });
197
190
  }
198
- /** Opens a labelled section in the rail, as its label does in the expanded sidebar. */
199
191
  export function SidebarRailRule({ className, ...props }) {
200
192
  return _jsx("hr", { ...props, className: cx(railRule, className), "data-ciridae-ui": "" });
201
193
  }
@@ -1,9 +1,8 @@
1
1
  import { css } from "#primitives/css";
2
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.
3
+ * It clips sideways only, so the descenders that reach below a line box that tight stay whole.
4
+ * Compose it at the top level of a `css()` call, or as the class `singleLineTextClass`: Panda does
5
+ * not extract it from under a nested selector.
7
6
  */
8
7
  export const singleLineText = css.raw({
9
8
  minWidth: "0",
@@ -10,14 +10,14 @@ const banner = cva({
10
10
  alignItems: "center",
11
11
  gap: "layout.controlGap",
12
12
  flexShrink: "0",
13
- width: "100%",
13
+ width: "full",
14
14
  boxSizing: "border-box",
15
15
  paddingBlock: "control.trackInset",
16
16
  paddingInline: "control.inline",
17
17
  textAlign: "start",
18
- fontSize: "11px",
18
+ fontSize: "[11px]",
19
19
  fontWeight: "medium",
20
- lineHeight: "16px",
20
+ lineHeight: "[16px]",
21
21
  color: "fg.muted",
22
22
  },
23
23
  variants: {
@@ -33,7 +33,7 @@ const banner = cva({
33
33
  });
34
34
  const message = css({ flex: "1", minWidth: "0" });
35
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)" });
36
+ const dismissButton = css({ marginBlock: "[calc((1lh - token(sizes.control.shortcut)) / 2)]" });
37
37
  /** A quiet, full-width site notice, separate from page-level status banners. */
38
38
  export function SiteBanner({ tone, onDismiss, className, children, ...props }) {
39
39
  const { labels } = useCiridaeLocale();
@@ -1,17 +1,17 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { css, cx } from "#primitives/css";
3
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.
4
+ // wash in dark.
5
5
  const skeleton = css({
6
6
  display: "block",
7
7
  flexShrink: "0",
8
- background: "token(gradients.skeletonFill)",
8
+ background: "[token(gradients.skeletonFill)]",
9
9
  "&[data-shape=block]": { minHeight: "skeleton.line", borderRadius: "control" },
10
10
  // One line of the surrounding text: the bar is shorter than the line box and centered in it.
11
11
  "&[data-shape=text]": {
12
- width: "100%",
13
- height: "0.75em",
14
- marginBlock: "calc((1lh - 0.75em) / 2)",
12
+ width: "full",
13
+ height: "[0.75em]",
14
+ marginBlock: "[calc((1lh - 0.75em) / 2)]",
15
15
  borderRadius: "round",
16
16
  },
17
17
  "&[data-shape=circle]": {
@@ -24,7 +24,6 @@ const skeleton = css({
24
24
  aspectRatio: "1",
25
25
  borderRadius: "control",
26
26
  },
27
- // A status chip's or a badge's placeholder.
28
27
  "&[data-shape=pill]": {
29
28
  width: "skeleton.pill",
30
29
  height: "skeleton.bar",
@@ -33,31 +32,29 @@ const skeleton = css({
33
32
  "&[data-shape][data-width=short]": { width: "skeleton.short" },
34
33
  "&[data-shape][data-width=medium]": { width: "skeleton.medium" },
35
34
  "&[data-shape][data-width=long]": { width: "skeleton.long" },
36
- "&[data-shape][data-width=full]": { width: "100%" },
37
- // A line of small print, such as a row's meta line, under a line of text.
35
+ "&[data-shape][data-width=full]": { width: "full" },
38
36
  "&[data-shape][data-height=caption]": {
39
37
  height: "skeleton.caption",
40
- marginBlock: "calc((1lh - token(sizes.skeleton.caption)) / 2)",
38
+ marginBlock: "[calc((1lh - token(sizes.skeleton.caption)) / 2)]",
41
39
  },
42
40
  "&[data-shape][data-height=text]": {
43
- height: "0.75em",
44
- marginBlock: "calc((1lh - 0.75em) / 2)",
41
+ height: "[0.75em]",
42
+ marginBlock: "[calc((1lh - 0.75em) / 2)]",
45
43
  },
46
44
  // 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" },
52
- "&[data-shape][data-height=control]": { height: "control.default", marginBlock: "0" },
53
- "&[data-shape][data-height=row]": { height: "control.field", marginBlock: "0" },
54
- "&[data-shape][data-height=block]": { height: "100%", marginBlock: "0" },
45
+ "&[data-shape][data-height=line]": { height: "skeleton.textLine", marginBlock: "none" },
46
+ "&[data-shape][data-height=smallLine]": { height: "skeleton.caption", marginBlock: "none" },
47
+ "&[data-shape][data-height=bar]": { height: "skeleton.bar", marginBlock: "none" },
48
+ "&[data-shape][data-height=badge]": { height: "skeleton.badge", marginBlock: "none" },
49
+ "&[data-shape][data-height=control]": { height: "control.default", marginBlock: "none" },
50
+ "&[data-shape][data-height=row]": { height: "control.field", marginBlock: "none" },
51
+ "&[data-shape][data-height=block]": { height: "full", marginBlock: "none" },
55
52
  "&[data-shape][data-height=chart], &[data-shape][data-height='chart.medium']": {
56
53
  height: "chart.medium",
57
- marginBlock: "0",
54
+ marginBlock: "none",
58
55
  },
59
- "&[data-shape][data-height='chart.small']": { height: "chart.small", marginBlock: "0" },
60
- "&[data-shape][data-height='chart.large']": { height: "chart.large", marginBlock: "0" },
56
+ "&[data-shape][data-height='chart.small']": { height: "chart.small", marginBlock: "none" },
57
+ "&[data-shape][data-height='chart.large']": { height: "chart.large", marginBlock: "none" },
61
58
  });
62
59
  /**
63
60
  * Loading placeholder. `block` fills its box, `text` takes one line of the surrounding text,
@@ -13,15 +13,12 @@ export declare function PageHeaderSkeleton({ avatar, actions, }: {
13
13
  export declare function PanelSkeleton({ rows }: {
14
14
  rows?: number;
15
15
  }): import("react").JSX.Element;
16
- /** Stands in for list rows: a line of text over a line of small print, then a status chip. */
17
16
  export declare function ListRowsSkeleton({ rows }: {
18
17
  rows?: number;
19
18
  }): import("react").JSX.Element;
20
- /** Stands in for a stat tile: its label, a small badge for the figure, and a line of small print. */
21
19
  export declare function StatTileSkeleton({ className }: {
22
20
  className?: string;
23
21
  }): import("react").JSX.Element;
24
- /** Stands in for a card: a title and its meta line, labelled bars, and a takeaway under a rule. */
25
22
  export declare function CardSkeleton({ bars }: {
26
23
  bars?: number;
27
24
  }): import("react").JSX.Element;