@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
@@ -82,7 +82,7 @@ const trigger = css({
82
82
  paddingInline: "control.compactInline",
83
83
  border: "1px solid transparent",
84
84
  borderRadius: "action",
85
- background: "token(gradients.selected)",
85
+ background: "[token(gradients.selected)]",
86
86
  color: "fg.primary",
87
87
  fontFamily: "sans",
88
88
  fontSize: "body",
@@ -90,16 +90,15 @@ const trigger = css({
90
90
  letterSpacing: "compact",
91
91
  whiteSpace: "nowrap",
92
92
  cursor: "pointer",
93
- _hover: { background: "token(gradients.raisedHover)" },
93
+ _hover: { background: "[token(gradients.raisedHover)]" },
94
94
  "&[data-popup-open]": { borderColor: "fg.primary" },
95
95
  _focusVisible: { focusRing: "outer" },
96
96
  });
97
- const options = css({ display: "grid", width: "222px" });
98
- // A menu row on the popover's glass sheet.
97
+ const options = css({ display: "grid", width: "[222px]" });
99
98
  const option = css(glassMenuRow, {
100
99
  border: "0",
101
100
  background: "transparent",
102
- fontFamily: "inherit",
101
+ fontFamily: "[inherit]",
103
102
  textAlign: "start",
104
103
  });
105
104
  const optionsDivider = css(glassMenuDivider);
@@ -38,8 +38,8 @@ const viewer = css(cardSurface, {
38
38
  gridTemplateRows: "auto minmax(0, 1fr)",
39
39
  minWidth: "0",
40
40
  overflow: "hidden",
41
- outline: "none",
42
- "&:fullscreen": { borderRadius: "0", height: "100dvh" },
41
+ outline: "0",
42
+ "&:fullscreen": { borderRadius: "none", height: "[100dvh]" },
43
43
  });
44
44
  const toolbar = css({
45
45
  display: "flex",
@@ -77,10 +77,10 @@ const zoomPill = css({
77
77
  cursor: "pointer",
78
78
  _hover: { background: "bg.hover" },
79
79
  _focusVisible: { focusRing: "outer" },
80
- _disabled: { opacity: "0.5", cursor: "default" },
80
+ _disabled: { opacity: "[0.5]", cursor: "default" },
81
81
  },
82
82
  "& > output": {
83
- minWidth: "52px",
83
+ minWidth: "[52px]",
84
84
  textAlign: "center",
85
85
  fontSize: "body",
86
86
  fontWeight: "medium",
@@ -90,7 +90,7 @@ const zoomPill = css({
90
90
  const body = css({
91
91
  display: "grid",
92
92
  gridTemplateColumns: "104px minmax(0, 1fr)",
93
- height: "min(693px, 80dvh)",
93
+ height: "[min(693px, 80dvh)]",
94
94
  minHeight: "0",
95
95
  _phone: { gridTemplateColumns: "minmax(0, 1fr)" },
96
96
  "[data-full-screen] > &": { height: "auto" },
@@ -118,11 +118,11 @@ const thumbnail = css({
118
118
  fontWeight: "medium",
119
119
  cursor: "pointer",
120
120
  "&[aria-current=page]": { color: "fg.primary" },
121
- _focusVisible: { outline: "none", "& > span": { focusRing: "outer" } },
121
+ _focusVisible: { outline: "0", "& > span": { focusRing: "outer" } },
122
122
  "& > span": {
123
123
  position: "relative",
124
124
  overflow: "hidden",
125
- borderRadius: "2px",
125
+ borderRadius: "[2px]",
126
126
  outline: "1px solid token(colors.border.control)",
127
127
  pointerEvents: "none",
128
128
  },
@@ -130,28 +130,28 @@ const thumbnail = css({
130
130
  });
131
131
  const well = css({
132
132
  display: "flex",
133
- justifyContent: "safe center",
134
- alignItems: "safe center",
135
- padding: "24px",
133
+ justifyContent: "[safe center]",
134
+ alignItems: "[safe center]",
135
+ padding: "[24px]",
136
136
  background: "bg.canvas",
137
137
  overflow: "auto",
138
- outline: "none",
138
+ outline: "0",
139
139
  _focusVisible: { focusRing: "inset" },
140
140
  });
141
141
  const pageBox = css({ position: "relative", flexShrink: "0", boxShadow: "card" });
142
- const pageLayer = css({ position: "absolute", top: "0", left: "0", transformOrigin: "0 0" });
142
+ const pageLayer = css({ position: "absolute", top: "none", left: "none", transformOrigin: "0 0" });
143
143
  const pageContent = css({
144
144
  position: "absolute",
145
- top: "0",
146
- left: "0",
145
+ top: "none",
146
+ left: "none",
147
147
  transformOrigin: "0 0",
148
- "& > img": { display: "block", width: "100%", height: "100%" },
148
+ "& > img": { display: "block", width: "full", height: "full" },
149
149
  });
150
150
  const regionButton = css({
151
151
  position: "absolute",
152
152
  padding: "none",
153
153
  border: "1.5px solid transparent",
154
- borderRadius: "3px",
154
+ borderRadius: "[3px]",
155
155
  background: "transparent",
156
156
  cursor: "pointer",
157
157
  "--region-ink": "token(colors.accent.blue)",
@@ -175,16 +175,16 @@ const regionButton = css({
175
175
  "&[data-marked], &:focus-visible": {
176
176
  borderColor: "var(--region-ink)",
177
177
  background: "var(--region-wash)",
178
- outline: "none",
178
+ outline: "0",
179
179
  },
180
180
  "& > span": {
181
181
  position: "absolute",
182
- insetInlineStart: "-1.5px",
183
- bottom: "calc(100% + 4px)",
182
+ insetInlineStart: "[-1.5px]",
183
+ bottom: "[calc(100% + 4px)]",
184
184
  display: "none",
185
185
  alignItems: "center",
186
- height: "22px",
187
- paddingInline: "6px",
186
+ height: "[22px]",
187
+ paddingInline: "[6px]",
188
188
  borderRadius: "control",
189
189
  background: "var(--region-ink)",
190
190
  color: "fg.onAccent",
@@ -194,11 +194,11 @@ const regionButton = css({
194
194
  whiteSpace: "nowrap",
195
195
  pointerEvents: "none",
196
196
  },
197
- "&[data-near-top] > span": { bottom: "auto", top: "calc(100% + 4px)" },
197
+ "&[data-near-top] > span": { bottom: "[auto]", top: "[calc(100% + 4px)]" },
198
198
  "&[data-marked] > span, &:focus-visible > span": { display: "inline-flex" },
199
199
  });
200
200
  const field = css({
201
- width: "100%",
201
+ width: "full",
202
202
  padding: "none",
203
203
  border: "0",
204
204
  borderRadius: "keycap",
@@ -17,7 +17,8 @@ export type DrawerProps = Omit<ComponentProps<typeof BaseDrawer.Root>, "children
17
17
  /**
18
18
  * A sheet docked at the window's right edge beside the page, which stays usable: it is not modal
19
19
  * and a click outside leaves it open, so Escape or its close button closes it. Pass `modal` or
20
- * `disablePointerDismissal` to change either.
20
+ * `disablePointerDismissal` to change either. Closing gives the focus back to what had it when
21
+ * `open` turned on, such as a button outside the drawer or the page link a hotkey opened it from.
21
22
  */
22
23
  export declare function Drawer({ title, icon: titleIcon, eyebrow, subtitle, titleAccessory, actions, size, children, ...rootProps }: DrawerProps): import("react").JSX.Element;
23
24
  export declare function DrawerBody({ flush, className, ...props }: ComponentProps<"div"> & {
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Drawer as BaseDrawer } from "@base-ui/react/drawer";
3
3
  import { XIcon } from "@phosphor-icons/react";
4
- import { useId, useMemo } from "react";
4
+ import { useId, useLayoutEffect, useMemo, useRef } from "react";
5
5
  import { css, cva, cx } from "#primitives/css";
6
6
  import { IconButton } from "./button.js";
7
7
  import { FieldControlContext } from "./field-context.js";
@@ -11,9 +11,9 @@ import { Eyebrow, heading } from "./layout.js";
11
11
  import { useCiridaeLocale } from "./locale.js";
12
12
  const viewport = css({ position: "fixed", inset: "none", zIndex: "drawer", pointerEvents: "none" });
13
13
  /*
14
- * A drawer sits beside the page, which stays usable: no scrim, docked to the window's right edge
15
- * at full height, a glass shell holding the sheet. The shell's padding is what keeps the sheet off
16
- * the window's edges, level with the main panel; a phone takes the sheet to the edges.
14
+ * A drawer sits beside the page, which stays usable: no scrim. The shell's padding is what keeps
15
+ * the sheet off the window's edges, level with the main panel; a phone takes the sheet to the
16
+ * edges.
17
17
  */
18
18
  const popup = cva({
19
19
  base: {
@@ -23,41 +23,48 @@ const popup = cva({
23
23
  display: "flex",
24
24
  padding: "panel.compact",
25
25
  pointerEvents: "auto",
26
- outline: "none",
26
+ outline: "0",
27
27
  textStyle: "body",
28
28
  border: "1px solid token(colors.border.divider)",
29
29
  borderRadius: "shell",
30
30
  background: "bg.drawerShell",
31
- backdropFilter: "blur(token(blurs.drawerShell))",
31
+ backdropFilter: "[blur(token(blurs.drawerShell))]",
32
32
  boxShadow: "drawerShell",
33
- _phone: { padding: "none", border: "0", borderRadius: "0" },
33
+ // A phone's drawer covers the page, so it is opaque there rather than glass the page shows through.
34
+ _phone: {
35
+ padding: "none",
36
+ border: "0",
37
+ borderRadius: "none",
38
+ background: "bg.canvas",
39
+ backdropFilter: "[none]",
40
+ },
34
41
  // Base UI drives live swipe drag through this custom property; the resting
35
42
  // transform must reference it or dragging won't visually track the pointer.
36
43
  transform: "translateX(var(--drawer-swipe-movement-x, 0px))",
37
- transitionProperty: "transform",
44
+ transitionProperty: "[transform]",
38
45
  transitionDuration: "default",
39
46
  "&[data-starting-style], &[data-ending-style]": {
40
47
  transform: "translateX(100%)",
41
48
  _rtl: { transform: "translateX(-100%)" },
42
49
  },
43
- "&[data-swiping]": { transitionDuration: "0ms" },
44
- _motionReduce: { transitionDuration: "0ms" },
50
+ "&[data-swiping]": { transitionDuration: "[0ms]" },
51
+ _motionReduce: { transitionDuration: "[0ms]" },
45
52
  },
46
53
  // The sheet's width, plus the shell's padding and its 1px edge on each side.
47
54
  variants: {
48
55
  size: {
49
56
  // The assistant and a preview.
50
57
  narrow: {
51
- width: "min(100vw, calc(token(sizes.overlay.sheetNarrow) + token(spacing.panel.compact) * 2 + 2px))",
52
- _phone: { width: "100vw" },
58
+ width: "[min(100vw, calc(token(sizes.overlay.sheetNarrow) + token(spacing.panel.compact) * 2 + 2px))]",
59
+ _phone: { width: "[100vw]" },
53
60
  },
54
61
  // Create, edit and act.
55
62
  regular: {
56
- width: "min(100vw, calc(token(sizes.overlay.sheet) + token(spacing.panel.compact) * 2 + 2px))",
57
- _phone: { width: "100vw" },
63
+ width: "[min(100vw, calc(token(sizes.overlay.sheet) + token(spacing.panel.compact) * 2 + 2px))]",
64
+ _phone: { width: "[100vw]" },
58
65
  },
59
66
  // Near the full viewport, for content such as logs that needs the room.
60
- large: { width: "calc(100vw - token(spacing.layout.pageGap) * 2)" },
67
+ large: { width: "[calc(100vw - token(spacing.layout.pageGap) * 2)]" },
61
68
  },
62
69
  },
63
70
  defaultVariants: { size: "regular" },
@@ -74,7 +81,7 @@ const panel = css({
74
81
  background: "bg.drawerSheet",
75
82
  boxShadow: "soft",
76
83
  color: "fg.primary",
77
- _phone: { border: "0", borderRadius: "0" },
84
+ _phone: { border: "0", borderRadius: "none" },
78
85
  });
79
86
  // At least the app header's height, so on a desktop a title-only sheet's header rule lines up with
80
87
  // the main panel's beside it: both start one shell gap from the window's top. Under a subtitle it
@@ -137,8 +144,7 @@ const subtitleStyle = css({
137
144
  letterSpacing: "compact",
138
145
  lineHeight: "tight",
139
146
  });
140
- // The sheet's mark before its title, muted like the agent sheet's sparkle. A flex row of its own,
141
- // so the heading stays the title's line high rather than an inline box's.
147
+ // The sheet's mark is a flex row of its own, so the heading stays the title's line high rather than an inline box's.
142
148
  const titleMark = css({
143
149
  display: "flex",
144
150
  alignItems: "center",
@@ -199,16 +205,35 @@ const footerActions = css({ display: "flex", alignItems: "center", gap: "layout.
199
205
  /**
200
206
  * A sheet docked at the window's right edge beside the page, which stays usable: it is not modal
201
207
  * and a click outside leaves it open, so Escape or its close button closes it. Pass `modal` or
202
- * `disablePointerDismissal` to change either.
208
+ * `disablePointerDismissal` to change either. Closing gives the focus back to what had it when
209
+ * `open` turned on, such as a button outside the drawer or the page link a hotkey opened it from.
203
210
  */
204
211
  export function Drawer({ title, icon: titleIcon, eyebrow, subtitle, titleAccessory, actions, size = "regular", children, ...rootProps }) {
205
212
  const { labels, dir } = useCiridaeLocale();
213
+ const popupRef = useRef(null);
214
+ const focusedBeforeOpen = useRef(null);
215
+ useLayoutEffect(() => {
216
+ if (!rootProps.open)
217
+ return;
218
+ const active = document.activeElement;
219
+ focusedBeforeOpen.current =
220
+ active instanceof HTMLElement && !popupRef.current?.contains(active) ? active : null;
221
+ }, [rootProps.open]);
222
+ // Back where it was, unless something outside has taken it since, such as a field on the page.
223
+ const returnFocus = () => {
224
+ const active = document.activeElement;
225
+ const takenOver = active instanceof HTMLElement &&
226
+ active !== document.body &&
227
+ !popupRef.current?.contains(active);
228
+ const before = focusedBeforeOpen.current;
229
+ return !takenOver && before?.isConnected ? before : true;
230
+ };
206
231
  // The narrow sheet's title is body size, as the app header's is, beside a 34px close.
207
232
  const narrow = size === "narrow";
208
233
  const titleClassName = cx(heading({ size: narrow ? "small" : "medium" }), titleStyle);
209
234
  const close = (_jsx(BaseDrawer.Close, { render: _jsx(IconButton, { "aria-label": labels.common.close, size: narrow ? "medium" : "small" }), children: _jsx(XIcon, { className: icon({ size: "small" }) }) }));
210
235
  const titleContent = titleIcon ? (_jsxs("span", { className: titleMark, children: [titleIcon, title] })) : (title);
211
- return (_jsx(BaseDrawer.Root, { modal: false, disablePointerDismissal: true, ...rootProps, swipeDirection: dir === "rtl" ? "left" : "right", children: _jsx(BaseDrawer.Portal, { children: _jsx(HotkeyLayer, { children: _jsx(BaseDrawer.Viewport, { className: viewport, children: _jsx(BaseDrawer.Popup, { className: popup({ size }), "data-ciridae-ui": "", children: _jsxs("div", { className: panel, children: [_jsx("header", { className: header({ size }), children: eyebrow ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: eyebrowLine, children: [eyebrow, _jsxs("div", { className: headerActions, children: [actions, close] })] }), _jsxs("div", { className: css({ display: "grid", gap: "layout.controlGap" }), children: [_jsx(BaseDrawer.Title, { className: displayTitle, children: title }), subtitle && _jsx("p", { className: displaySubtitle, children: subtitle })] })] })) : (_jsxs("div", { className: headerLine({ size }), "data-header-line": "", children: [_jsxs("div", { className: titleBlock, children: [titleAccessory ? (_jsxs("div", { className: titleLine, children: [_jsx(BaseDrawer.Title, { className: titleClassName, children: titleContent }), titleAccessory] })) : (_jsx(BaseDrawer.Title, { className: titleClassName, children: titleContent })), subtitle && (_jsx("p", { className: subtitleStyle, "data-sheet-subtitle": "", children: subtitle }))] }), _jsxs("div", { className: headerActions, children: [actions, close] })] })) }), children] }) }) }) }) }) }));
236
+ return (_jsx(BaseDrawer.Root, { modal: false, disablePointerDismissal: true, ...rootProps, swipeDirection: dir === "rtl" ? "left" : "right", children: _jsx(BaseDrawer.Portal, { children: _jsx(HotkeyLayer, { children: _jsx(BaseDrawer.Viewport, { className: viewport, children: _jsx(BaseDrawer.Popup, { ref: popupRef, className: popup({ size }), "data-ciridae-ui": "", finalFocus: returnFocus, children: _jsxs("div", { className: panel, children: [_jsx("header", { className: header({ size }), children: eyebrow ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: eyebrowLine, children: [eyebrow, _jsxs("div", { className: headerActions, children: [actions, close] })] }), _jsxs("div", { className: css({ display: "grid", gap: "layout.controlGap" }), children: [titleAccessory ? (_jsxs("div", { className: titleLine, children: [_jsx(BaseDrawer.Title, { className: displayTitle, children: titleContent }), titleAccessory] })) : (_jsx(BaseDrawer.Title, { className: displayTitle, children: titleContent })), subtitle && _jsx("p", { className: displaySubtitle, children: subtitle })] })] })) : (_jsxs("div", { className: headerLine({ size }), "data-header-line": "", children: [_jsxs("div", { className: titleBlock, children: [titleAccessory ? (_jsxs("div", { className: titleLine, children: [_jsx(BaseDrawer.Title, { className: titleClassName, children: titleContent }), titleAccessory] })) : (_jsx(BaseDrawer.Title, { className: titleClassName, children: titleContent })), subtitle && (_jsx("p", { className: subtitleStyle, "data-sheet-subtitle": "", children: subtitle }))] }), _jsxs("div", { className: headerActions, children: [actions, close] })] })) }), children] }) }) }) }) }) }));
212
237
  }
213
238
  export function DrawerBody({ flush = false, className, ...props }) {
214
239
  return (_jsx(BaseDrawer.Content, { ...props, className: cx(body({ flush }), className), "data-ciridae-ui": "" }));
@@ -16,12 +16,12 @@ const zone = css({ position: "relative" });
16
16
  // While files are over it, the zone dims under a dashed frame that names what a drop does.
17
17
  const dropOverlay = css({
18
18
  position: "absolute",
19
- inset: "0",
19
+ inset: "none",
20
20
  zIndex: "raised",
21
21
  display: "grid",
22
22
  placeItems: "center",
23
23
  padding: "layout.controlGap",
24
- background: "color-mix(in srgb, token(colors.bg.surface) 88%, transparent)",
24
+ background: "[color-mix(in srgb, token(colors.bg.surface) 88%, transparent)]",
25
25
  pointerEvents: "none",
26
26
  "& > span": {
27
27
  display: "flex",
@@ -29,8 +29,8 @@ const dropOverlay = css({
29
29
  alignItems: "center",
30
30
  justifyContent: "center",
31
31
  gap: "layout.controlGap",
32
- width: "100%",
33
- height: "100%",
32
+ width: "full",
33
+ height: "full",
34
34
  border: "1px dashed token(colors.border.selected)",
35
35
  borderRadius: "action",
36
36
  background: "bg.selected",
@@ -56,7 +56,7 @@ const pad = css({
56
56
  fontSize: "caption",
57
57
  fontWeight: "medium",
58
58
  letterSpacing: "compact",
59
- transitionProperty: "border-color, color",
59
+ transitionProperty: "[border-color, color]",
60
60
  transitionDuration: "fast",
61
61
  "& > svg": { flexShrink: "0" },
62
62
  _hover: { borderColor: "border.selected", color: "fg.secondary" },
@@ -99,8 +99,8 @@ const fileMark = css({
99
99
  height: "control.mark",
100
100
  color: "fg.muted",
101
101
  "& img": {
102
- width: "100%",
103
- height: "100%",
102
+ width: "full",
103
+ height: "full",
104
104
  objectFit: "cover",
105
105
  borderRadius: "control",
106
106
  },
@@ -140,10 +140,10 @@ export const fileSquare = css({
140
140
  fontSize: "avatar.small",
141
141
  lineHeight: "compact",
142
142
  textAlign: "center",
143
- "& > img": { display: "block", width: "100%", height: "100%", objectFit: "cover" },
143
+ "& > img": { display: "block", width: "full", height: "full", objectFit: "cover" },
144
144
  "&[data-image]": { padding: "none", background: "bg.fill" },
145
145
  "& > span": {
146
- maxWidth: "100%",
146
+ maxWidth: "full",
147
147
  overflow: "hidden",
148
148
  textOverflow: "ellipsis",
149
149
  whiteSpace: "nowrap",
@@ -185,10 +185,10 @@ const fileChip = css({
185
185
  display: "inline-flex",
186
186
  alignItems: "center",
187
187
  gap: "layout.tightGap",
188
- maxWidth: "100%",
188
+ maxWidth: "full",
189
189
  height: "control.shortcut",
190
190
  paddingInlineStart: "control.trackInset",
191
- paddingInlineEnd: "1px",
191
+ paddingInlineEnd: "[1px]",
192
192
  border: "1px solid token(colors.border.subtle)",
193
193
  borderRadius: "control",
194
194
  background: "bg.card",
@@ -206,8 +206,8 @@ const fileChip = css({
206
206
  },
207
207
  "& > [data-mark] > svg": { fontSize: "icon.compact" },
208
208
  "& > [data-mark] > img": {
209
- width: "100%",
210
- height: "100%",
209
+ width: "full",
210
+ height: "full",
211
211
  objectFit: "cover",
212
212
  borderRadius: "control",
213
213
  },
@@ -65,18 +65,14 @@ export type EditableFieldProps = Omit<ComponentProps<"div">, "children"> & {
65
65
  badge?: ReactNode;
66
66
  /** Under the value while the row is idle. */
67
67
  note?: ReactNode;
68
- /** The field needs the reader: the row lifts on the selected glass and this button sits at its end. */
68
+ /** With `emphasis="highlighted"` the row keeps the yellow band. */
69
69
  action?: {
70
70
  label: ReactNode;
71
71
  onClick: () => void;
72
72
  disabled?: boolean;
73
73
  };
74
- /** `bottom` by default; `none` for the last row of a list whose container draws its own edge. */
75
74
  divider?: "bottom" | "none";
76
- /**
77
- * `selected` washes the row with the selected glass, such as the field a side panel is
78
- * showing; `inset` sets it into the list between hairlines, such as a field set apart.
79
- */
75
+ /** `highlighted` is the yellow band while the agent points at the field. */
80
76
  emphasis?: "selected" | "inset" | "highlighted";
81
77
  edit?: FieldEdit;
82
78
  labels?: Partial<CiridaeLabels["editableField"]>;
@@ -99,7 +95,6 @@ export type SourceConflictProps = Omit<ComponentProps<"div">, "children"> & {
99
95
  };
100
96
  /** At the effective row's end, such as a Resolve button. */
101
97
  action?: ReactNode;
102
- /** `highlighted` while the agent points at the field; `neutral` by default. */
103
98
  tone?: "highlighted" | "neutral";
104
99
  labels?: Partial<{
105
100
  effectiveValue: string;
@@ -19,12 +19,6 @@ import { Tooltip } from "./overlays.js";
19
19
  import { Combobox } from "./select.js";
20
20
  /* The row stacks its label over the value in a narrow box, so each field is its own container. */
21
21
  const fieldBox = css({ containerType: "inline-size" });
22
- /*
23
- * The kit's Detail field: 12 · 16 padding, a hairline under it. A field that needs the reader
24
- * (the inline edit's Needs confirm) and an inset row wear the selected glass between the selected
25
- * edge's hairlines; a selected row wears the glass alone; a highlighted row, while the agent points
26
- * at it, is the flat yellow band between hairlines.
27
- */
28
22
  const fieldRow = css({
29
23
  position: "relative",
30
24
  display: "grid",
@@ -39,28 +33,27 @@ const fieldRow = css({
39
33
  letterSpacing: "compact",
40
34
  "& > :last-child": { alignSelf: "center" },
41
35
  "&[data-needs]": {
42
- background: "token(gradients.selected)",
36
+ background: "[token(gradients.selected)]",
43
37
  borderBlock: "1px solid",
44
38
  borderImage: "token(gradients.border.selected) 1",
45
39
  },
46
40
  // After the band's hairlines, so a last highlighted row keeps only its top one, as the kit's.
47
41
  "&[data-divider=none]": { borderBottom: "0" },
48
- "&[data-emphasis=selected]": { background: "token(gradients.selected)" },
42
+ "&[data-emphasis=selected]": { background: "[token(gradients.selected)]" },
49
43
  "&[data-emphasis=inset]": {
50
- background: "token(gradients.selected)",
44
+ background: "[token(gradients.selected)]",
51
45
  borderBlock: "1px solid",
52
46
  borderImage: "token(gradients.border.selected) 1",
53
47
  },
54
- // The kit's Highlighted detail field: the yellow band while the agent points at the field.
55
48
  "&[data-emphasis=highlighted]": {
56
49
  background: "bg.warningTint",
57
50
  borderBlock: "1px solid token(colors.border.divider)",
58
51
  },
59
52
  "&[data-editable]": {
60
53
  cursor: "pointer",
61
- _hover: { background: "token(gradients.card)", _light: { background: "bg.rowHover" } },
54
+ _hover: { background: "[token(gradients.card)]", _light: { background: "bg.rowHover" } },
62
55
  },
63
- "&[data-editable]:is(:hover, :focus-within) [data-affordance], &[data-editing] [data-affordance]": { opacity: "1" },
56
+ "&[data-editable]:is(:hover, :focus-within) [data-affordance], &[data-editing] [data-affordance]": { opacity: "[1]" },
64
57
  "@container (max-width: 520px)": {
65
58
  gridTemplateColumns: "minmax(0, 1fr) auto",
66
59
  rowGap: "layout.tightGap",
@@ -91,7 +84,7 @@ const valueButton = css({
91
84
  border: "0",
92
85
  borderRadius: "control",
93
86
  background: "transparent",
94
- color: "inherit",
87
+ color: "[inherit]",
95
88
  font: "inherit",
96
89
  textAlign: "start",
97
90
  cursor: "pointer",
@@ -99,8 +92,8 @@ const valueButton = css({
99
92
  });
100
93
  const affordance = css({
101
94
  color: "fg.muted",
102
- opacity: "0",
103
- transitionProperty: "opacity",
95
+ opacity: "[0]",
96
+ transitionProperty: "[opacity]",
104
97
  transitionDuration: "fast",
105
98
  });
106
99
  const lockMark = css({ display: "inline-flex", color: "fg.muted" });
@@ -143,7 +136,7 @@ const sourceLink = css({
143
136
  padding: "none",
144
137
  border: "0",
145
138
  background: "transparent",
146
- color: "inherit",
139
+ color: "[inherit]",
147
140
  font: "inherit",
148
141
  cursor: "pointer",
149
142
  textAlign: "start",
@@ -161,20 +154,19 @@ const fieldNote = css({
161
154
  fontWeight: "medium",
162
155
  lineHeight: "tight",
163
156
  });
164
- const editor = css({ width: "200px", maxWidth: "100%" });
157
+ const editor = css({ width: "[200px]", maxWidth: "full" });
165
158
  const editorValue = css({ position: "relative", display: "flex", alignItems: "center" });
166
159
  const tooltipTitle = css({ display: "block", fontWeight: "medium" });
167
- const tooltipDetail = css({ display: "block", fontSize: "code", opacity: "0.8" });
160
+ const tooltipDetail = css({ display: "block", fontSize: "code", opacity: "[0.8]" });
168
161
  const trailingActions = css({ display: "inline-flex", gap: "layout.tightGap" });
169
162
  /* The calendar opens above the date editor, on the menus' glass sheet. */
170
163
  const calendarPicker = css(glassMenuSurface, {
171
164
  position: "absolute",
172
- bottom: "calc(100% + token(spacing.control.iconGap))",
173
- insetInlineStart: "0",
165
+ bottom: "[calc(100% + token(spacing.control.iconGap))]",
166
+ insetInlineStart: "none",
174
167
  zIndex: "popover",
175
168
  cursor: "default",
176
169
  });
177
- // Under the days, inset as the calendar is, such as the value it had before.
178
170
  const calendarFooter = css({
179
171
  paddingInline: "panel.compact",
180
172
  paddingBottom: "panel.compact",
@@ -388,13 +380,8 @@ export function EditableField({ label, value, provenance, badge, note, action, d
388
380
  }
389
381
  return _jsx("span", {});
390
382
  };
391
- return (_jsx("div", { ...props, className: cx(fieldBox, className), "data-ciridae-ui": "", children: _jsxs("div", { ref: rowRef, className: fieldRow, "data-needs": action && !editing ? "" : undefined, "data-divider": divider, "data-emphasis": emphasis, "data-editable": editable && !editing ? "" : undefined, "data-editing": editing ? "" : undefined, onClick: begin, children: [_jsx("span", { className: fieldLabel, id: labelId, "data-label": "", children: label }), _jsxs("span", { className: css({ minWidth: "0" }), children: [valueLine(), _jsx("span", { role: "status", children: statusLine() }), note !== undefined && status.mode === "idle" && (_jsx("span", { className: fieldNote, children: note }))] }), trailing()] }) }));
383
+ return (_jsx("div", { ...props, className: cx(fieldBox, className), "data-ciridae-ui": "", children: _jsxs("div", { ref: rowRef, className: fieldRow, "data-needs": action && !editing && emphasis !== "highlighted" ? "" : undefined, "data-divider": divider, "data-emphasis": emphasis, "data-editable": editable && !editing ? "" : undefined, "data-editing": editing ? "" : undefined, onClick: begin, children: [_jsx("span", { className: fieldLabel, id: labelId, "data-label": "", children: label }), _jsxs("span", { className: css({ minWidth: "0" }), children: [valueLine(), _jsx("span", { role: "status", children: statusLine() }), note !== undefined && status.mode === "idle" && (_jsx("span", { className: fieldNote, children: note }))] }), trailing()] }) }));
392
384
  }
393
- /*
394
- * Source conflict: each source's value under a disputed field, then the value in effect. The
395
- * kit's Contested sources: flat and square between hairlines, the yellow band while the agent
396
- * points at the field, the panel's face otherwise (the grey well in light).
397
- */
398
385
  const conflictBlock = css({
399
386
  display: "grid",
400
387
  gap: "layout.controlGap",
@@ -2,7 +2,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { css, cx } from "#primitives/css";
3
3
  import { Chip } from "./chip.js";
4
4
  import { useFieldControl } from "./field-context.js";
5
- // The field face `Input` wears, holding chips that wrap onto more lines as they fill it.
6
5
  const emailField = css({
7
6
  display: "flex",
8
7
  flexWrap: "wrap",
@@ -28,9 +27,9 @@ const draftInput = css({
28
27
  fontSize: "caption",
29
28
  height: "control.shortcut",
30
29
  paddingInline: "control.compactInline",
31
- outline: "none",
30
+ outline: "0",
32
31
  _placeholder: { color: "fg.subtle" },
33
- _focusVisible: { outline: "none", boxShadow: "none" },
32
+ _focusVisible: { outline: "0", boxShadow: "[none]" },
34
33
  });
35
34
  /** Comma, semicolon, whitespace, Enter, Tab, or blur commits addresses; duplicates are ignored. */
36
35
  export function EmailInput({ value, onValueChange, inputValue, onInputValueChange, invalidEmails = [], disabled, className, onKeyDown, onBlur, onPaste, ...props }) {
@@ -6,31 +6,31 @@ import { SiteBanner } from "./site-banner.js";
6
6
  const frame = css({
7
7
  display: "flex",
8
8
  flexDirection: "column",
9
- height: "100dvh",
10
- width: "100%",
9
+ height: "[100dvh]",
10
+ width: "full",
11
11
  });
12
12
  const environmentBanner = css({
13
13
  // Align with the outer edges of the sidebar controls, not their inset labels.
14
- paddingInlineStart: "calc(token(spacing.panel.compact) + token(spacing.panel.default))",
14
+ paddingInlineStart: "[calc(token(spacing.panel.compact) + token(spacing.panel.default))]",
15
15
  _phone: { paddingInlineStart: "panel.default" },
16
16
  });
17
17
  const viewport = css({
18
18
  flex: "1",
19
19
  minHeight: "0",
20
20
  overflow: "hidden",
21
- background: "token(gradients.canvas)",
21
+ background: "[token(gradients.canvas)]",
22
22
  // Only under the environment strip does the app read as inset below it.
23
23
  "&[data-under-banner]": {
24
24
  borderTopRadius: "field",
25
- boxShadow: "inset 0 2px 4px rgba(0, 0, 0, 0.18)",
25
+ boxShadow: "[inset 0 2px 4px rgba(0, 0, 0, 0.18)]",
26
26
  },
27
27
  // Keep the shell and its phone layout within the space below the site banner. On a desktop the
28
28
  // shell's row sizes the main panel inside its block margins, so a full height would push it past
29
29
  // them; a phone's main panel is a full window tall, so there it takes the space under the strip.
30
- "& > [data-ciridae-ui]": { height: "100%", background: "transparent" },
30
+ "& > [data-ciridae-ui]": { height: "full", background: "transparent" },
31
31
  "& > [data-ciridae-ui] > main": {
32
32
  borderRadius: "inset",
33
- _phone: { borderRadius: "0", height: "100%" },
33
+ _phone: { borderRadius: "none", height: "full" },
34
34
  },
35
35
  "& > [data-ciridae-ui] > main > header": {
36
36
  paddingInlineStart: "page.inline",
@@ -12,10 +12,10 @@ const collapsedWrapper = css({
12
12
  const expandedWrapper = css({ display: "grid", justifyItems: "start", minWidth: "0" });
13
13
  const clamped = css({ lineClamp: "2", minWidth: "0" });
14
14
  const toggle = css({
15
- padding: "0",
15
+ padding: "none",
16
16
  border: "0",
17
17
  background: "transparent",
18
- color: "inherit",
18
+ color: "[inherit]",
19
19
  font: "inherit",
20
20
  textDecoration: "underline",
21
21
  whiteSpace: "nowrap",