@ciridae/ui 1.0.5 → 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 +65 -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 +109 -51
  25. package/dist/components/chat.d.ts +27 -56
  26. package/dist/components/chat.js +151 -129
  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 -12
  48. package/dist/components/editable-field.js +13 -26
  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 +39 -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 +805 -1279
  129. package/dist/styled-system/tokens/index.mjs +74 -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 +38 -92
  146. package/package.json +1 -1
  147. package/dist/theme/palettes.js +0 -254
@@ -18,8 +18,8 @@ export const MAX_SCREENSHOT_POINTERS = 7;
18
18
  const stage = css({
19
19
  position: "relative",
20
20
  justifySelf: "center",
21
- width: "fit-content",
22
- maxWidth: "100%",
21
+ width: "[fit-content]",
22
+ maxWidth: "full",
23
23
  overflow: "hidden",
24
24
  border: "1px solid token(colors.border.control)",
25
25
  borderRadius: "control",
@@ -33,7 +33,7 @@ const stageButton = css({
33
33
  cursor: "crosshair",
34
34
  "&[data-full]": { cursor: "default" },
35
35
  _focusVisible: { focusRing: "inset" },
36
- "& img": { display: "block", maxWidth: "100%", maxHeight: "56dvh" },
36
+ "& img": { display: "block", maxWidth: "full", maxHeight: "[56dvh]" },
37
37
  });
38
38
  /* A pointer's number: on the image, and again before its note. */
39
39
  const pointerNumber = css.raw({
@@ -74,7 +74,7 @@ const pointerRow = css({
74
74
  const thumbnail = css({
75
75
  position: "relative",
76
76
  flexShrink: "0",
77
- width: "96px",
77
+ width: "[96px]",
78
78
  padding: "none",
79
79
  border: "1px solid token(colors.border.control)",
80
80
  borderRadius: "keycap",
@@ -82,7 +82,7 @@ const thumbnail = css({
82
82
  cursor: "pointer",
83
83
  _focusVisible: { focusRing: "outer" },
84
84
  _disabled: { opacity: "disabled", cursor: "not-allowed" },
85
- "& img": { display: "block", width: "100%", height: "auto", borderRadius: "keycap" },
85
+ "& img": { display: "block", width: "full", height: "auto", borderRadius: "keycap" },
86
86
  });
87
87
  const thumbnailDot = css({
88
88
  position: "absolute",
@@ -94,8 +94,8 @@ const thumbnailDot = css({
94
94
  });
95
95
  const thumbnailCount = css({
96
96
  position: "absolute",
97
- top: "calc(token(spacing.layout.tightGap) * -1)",
98
- insetInlineEnd: "calc(token(spacing.layout.tightGap) * -1)",
97
+ top: "[calc(token(spacing.layout.tightGap) * -1)]",
98
+ insetInlineEnd: "[calc(token(spacing.layout.tightGap) * -1)]",
99
99
  display: "grid",
100
100
  placeItems: "center",
101
101
  minWidth: "indicator.count",
@@ -98,7 +98,7 @@ const whereDetail = css({
98
98
  letterSpacing: "compact",
99
99
  lineHeight: "tight",
100
100
  });
101
- const message = css({ minHeight: "132px" });
101
+ const message = css({ minHeight: "[132px]" });
102
102
  const screenshotRow = css({
103
103
  display: "flex",
104
104
  alignItems: "flex-start",
@@ -117,8 +117,8 @@ const screenshotPreview = css({
117
117
  display: "grid",
118
118
  placeItems: "center",
119
119
  flexShrink: "0",
120
- width: "96px",
121
- height: "60px",
120
+ width: "[96px]",
121
+ height: "[60px]",
122
122
  border: "1px solid token(colors.border.control)",
123
123
  borderRadius: "keycap",
124
124
  background: "bg.field",
@@ -133,15 +133,15 @@ const sent = css({
133
133
  alignItems: "center",
134
134
  justifyContent: "center",
135
135
  gap: "layout.clusterGap",
136
- maxWidth: "320px",
136
+ maxWidth: "[320px]",
137
137
  marginInline: "auto",
138
138
  textAlign: "center",
139
139
  });
140
140
  const sentIcon = css({
141
141
  display: "grid",
142
142
  placeItems: "center",
143
- width: "48px",
144
- height: "48px",
143
+ width: "[48px]",
144
+ height: "[48px]",
145
145
  border: "1px solid token(colors.border.control)",
146
146
  borderRadius: "round",
147
147
  background: "bg.field",
@@ -160,7 +160,7 @@ const sentRow = css({
160
160
  gridTemplateColumns: "minmax(0, 1fr) auto",
161
161
  alignItems: "center",
162
162
  gap: "layout.contentGap",
163
- width: "100%",
163
+ width: "full",
164
164
  paddingBlock: "panel.default",
165
165
  paddingInline: "panel.comfortable",
166
166
  border: "0",
@@ -218,7 +218,7 @@ const listToolbar = css({
218
218
  /* An item: its subject and status pinned over the thread, which scrolls; the reply below. */
219
219
  const itemHeader = css({
220
220
  position: "sticky",
221
- top: "0",
221
+ top: "none",
222
222
  zIndex: "raised",
223
223
  display: "flex",
224
224
  alignItems: "flex-start",
@@ -45,7 +45,7 @@ export function matchesFilter(value, filter) {
45
45
  if (values.length === 0)
46
46
  return true;
47
47
  const own = (Array.isArray(value) ? value : value === null || value === undefined ? [] : [value]).map(String);
48
- const [first = "", second = ""] = values;
48
+ const [first = ""] = values;
49
49
  const number = (text) => Number(text);
50
50
  switch (filter.operator) {
51
51
  case "is":
@@ -68,10 +68,14 @@ export function matchesFilter(value, filter) {
68
68
  return own.some((candidate) => candidate < first);
69
69
  case "after":
70
70
  return own.some((candidate) => candidate > first);
71
- case "between":
72
- return own.some((candidate) => typeof value === "number" || (Array.isArray(value) && typeof value[0] === "number")
73
- ? number(candidate) >= number(first) && (!second || number(candidate) <= number(second))
74
- : candidate >= first && (!second || candidate <= second));
71
+ case "between": {
72
+ const [rangeStart = "", rangeEnd = ""] = filter.values;
73
+ const isNumeric = typeof value === "number" || (Array.isArray(value) && typeof value[0] === "number");
74
+ return own.some((candidate) => isNumeric
75
+ ? (!rangeStart || number(candidate) >= number(rangeStart)) &&
76
+ (!rangeEnd || number(candidate) <= number(rangeEnd))
77
+ : (!rangeStart || candidate >= rangeStart) && (!rangeEnd || candidate <= rangeEnd));
78
+ }
75
79
  }
76
80
  }
77
81
  /** A `yyyy-mm-dd` date as a local day, so it reads as the day it names in every zone. */
@@ -84,6 +88,19 @@ export function describeFilter(field, filter, locale) {
84
88
  const labelOf = (value) => field.options?.find((option) => option.value === value)?.label ??
85
89
  (field.kind === "date" ? locale.formatDate(localDay(value)) : value);
86
90
  const values = filter.values.filter((value) => value !== "").map(labelOf);
91
+ if (filter.operator === "between" && values.length === 1) {
92
+ // A range with one end typed keeps that end, as `matchesFilter` does.
93
+ const [rangeStart = "", rangeEnd = ""] = filter.values;
94
+ const oneEndedRangeOperators = locale.labels.filters.oneEndedRangeOperators;
95
+ const operator = field.kind === "number"
96
+ ? rangeStart !== ""
97
+ ? oneEndedRangeOperators.atLeast
98
+ : oneEndedRangeOperators.atMost
99
+ : rangeStart !== ""
100
+ ? oneEndedRangeOperators.onOrAfter
101
+ : oneEndedRangeOperators.onOrBefore;
102
+ return { operator, values: rangeEnd !== "" ? labelOf(rangeEnd) : labelOf(rangeStart) };
103
+ }
87
104
  return {
88
105
  operator: locale.labels.filters.chipOperators[filter.operator],
89
106
  values: filter.operator === "between"
@@ -91,21 +108,17 @@ export function describeFilter(field, filter, locale) {
91
108
  : values.join(", "),
92
109
  };
93
110
  }
94
- /*
95
- * The slicer's face: the selected tint, hovering to the raised face. The field reads in the
96
- * secondary grey, the operator a step quieter.
97
- */
98
111
  const chip = css({
99
112
  display: "inline-flex",
100
113
  alignItems: "center",
101
114
  gap: "layout.tightGap",
102
- maxWidth: "100%",
115
+ maxWidth: "full",
103
116
  height: "control.compact",
104
117
  paddingInlineStart: "control.compactInline",
105
118
  paddingInlineEnd: "control.iconGap",
106
119
  borderRadius: "pill",
107
- background: "token(gradients.selected)",
108
- _hover: { background: "token(gradients.raisedHover)" },
120
+ background: "[token(gradients.selected)]",
121
+ _hover: { background: "[token(gradients.raisedHover)]" },
109
122
  _light: { color: "fg.secondary" },
110
123
  color: "fg.muted",
111
124
  fontSize: "caption",
@@ -121,9 +134,9 @@ const chipBody = css({
121
134
  padding: "none",
122
135
  border: "0",
123
136
  background: "transparent",
124
- color: "inherit",
137
+ color: "[inherit]",
125
138
  font: "inherit",
126
- letterSpacing: "inherit",
139
+ letterSpacing: "[inherit]",
127
140
  cursor: "pointer",
128
141
  borderRadius: "control",
129
142
  _focusVisible: { focusRing: "outer" },
@@ -183,22 +196,21 @@ const builder = css({
183
196
  display: "flex",
184
197
  flexDirection: "column",
185
198
  width: "overlay.popover",
186
- maxWidth: "100%",
199
+ maxWidth: "full",
187
200
  });
188
- // A menu row: the field's icon, its name, and an arrow on to its operator and values.
189
201
  const fieldItem = css(glassMenuRow, {
190
- width: "100%",
202
+ width: "full",
191
203
  border: "0",
192
204
  background: "transparent",
193
- fontFamily: "inherit",
205
+ fontFamily: "[inherit]",
194
206
  textAlign: "start",
195
207
  "& > span": { flex: "1", minWidth: "0" },
196
208
  "& svg": {
197
209
  flexShrink: "0",
198
210
  color: "fg.muted",
199
211
  fontSize: "icon.small",
200
- width: "1em",
201
- height: "1em",
212
+ width: "[1em]",
213
+ height: "[1em]",
202
214
  },
203
215
  });
204
216
  const menuDivider = css(glassMenuDivider);
@@ -211,7 +223,6 @@ const groupLabel = css({
211
223
  fontWeight: "medium",
212
224
  letterSpacing: "compact",
213
225
  });
214
- // The quiet search's hairline is inset as the dividers are.
215
226
  const searchWrap = css({ paddingInline: "menu.itemInline", paddingBlockEnd: "layout.tightGap" });
216
227
  const noMatches = css({
217
228
  paddingBlock: "control.block",
@@ -299,7 +310,7 @@ const operatorTrigger = css({
299
310
  _focusVisible: { focusRing: "outer" },
300
311
  });
301
312
  const fixedOperator = css({ color: "fg.muted", fontSize: "caption" });
302
- const valueList = css({ display: "grid", maxHeight: "240px", overflowY: "auto" });
313
+ const valueList = css({ display: "grid", maxHeight: "[240px]", overflowY: "auto" });
303
314
  const inputs = css({ display: "grid", gap: "layout.tightGap", padding: "layout.tightGap" });
304
315
  const editorFooter = css({
305
316
  display: "flex",
@@ -333,12 +344,16 @@ export function FilterValueEditor({ field, value, onChange, onBack, }) {
333
344
  const options = field.options?.filter((option) => option.label.toLowerCase().includes(query.trim().toLowerCase()));
334
345
  const operatorLabel = labels.filters.operators[operator];
335
346
  const picked = values.filter((candidate) => candidate !== "").length;
336
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: editorHeader, children: [onBack && (_jsx(IconButton, { "aria-label": labels.filters.backToFields, size: "compact", variant: "ghost", onClick: onBack, children: _jsx(CaretLeftIcon, { className: icon({ size: "small" }) }) })), _jsx("span", { className: css({ paddingInlineStart: onBack ? "0" : "menu.itemInline" }), children: field.label }), operators.length > 1 ? (_jsx(Menu, { trigger: _jsxs("button", { type: "button", className: operatorTrigger, "data-ciridae-ui": "", "data-edge": "glass", children: [operatorLabel, _jsx(CaretDownIcon, { className: icon({ size: "small" }) })] }), items: operators.map((candidate) => ({
347
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: editorHeader, children: [onBack && (_jsx(IconButton, { "aria-label": labels.filters.backToFields, size: "compact", variant: "ghost", onClick: onBack, children: _jsx(CaretLeftIcon, { className: icon({ size: "small" }) }) })), _jsx("span", { className: css({ paddingInlineStart: onBack ? "none" : "menu.itemInline" }), children: field.label }), operators.length > 1 ? (_jsx(Menu, { trigger: _jsxs("button", { type: "button", className: operatorTrigger, "data-ciridae-ui": "", "data-edge": "glass", children: [operatorLabel, _jsx(CaretDownIcon, { className: icon({ size: "small" }) })] }), items: operators.map((candidate) => ({
337
348
  label: labels.filters.operators[candidate],
338
349
  checked: candidate === operator,
339
350
  onSelect: () => {
340
- const keepsValues = multiValueOperators.includes(candidate) === multiple && candidate !== "between";
341
- report(candidate, keepsValues ? values : values.slice(0, 1));
351
+ // A range's two values fit only a range: moving into or out of one keeps the first.
352
+ const keepsValues = multiValueOperators.includes(candidate) === multiple &&
353
+ (candidate === "between") === (operator === "between");
354
+ report(candidate, keepsValues
355
+ ? values
356
+ : values.filter((typedValue) => typedValue !== "").slice(0, 1));
342
357
  },
343
358
  })) })) : (_jsx("span", { className: fixedOperator, children: operatorLabel }))] }), options ? (_jsxs(_Fragment, { children: [field.options && field.options.length > 6 && (_jsx("div", { className: searchWrap, children: _jsx(SearchField, { size: "compact", quiet: true, "aria-label": labels.filters.searchValues(field.label), placeholder: labels.filters.searchValues(field.label), value: query, onChange: (event) => setQuery(event.target.value) }) })), _jsxs("div", { className: valueList, children: [options.map((option) => (_jsxs(CheckboxItem, { checked: values.includes(option.value), onCheckedChange: (checked) => report(operator, multiple
344
359
  ? checked
@@ -355,8 +370,7 @@ export function FilterValueEditor({ field, value, onChange, onBack, }) {
355
370
  ? labels.filters.from
356
371
  : labels.filters.to
357
372
  : labels.filters.value, value: values[index] ?? "", onChange: (event) => {
358
- const next = [...values];
359
- next[index] = event.target.value;
373
+ const next = Array.from({ length: operator === "between" ? 2 : 1 }, (_, position) => position === index ? event.target.value : (values[position] ?? ""));
360
374
  report(operator, next);
361
375
  } }, index))) })), _jsx("div", { className: menuDivider, role: "separator" }), _jsxs("div", { className: editorFooter, children: [options
362
376
  ? `${labels.filters.selectedCount(picked)} · ${labels.filters.updatesAsYouPick}`
@@ -18,18 +18,16 @@ export declare const checkMark: import("../styled-system/types/index.js").Recipe
18
18
  };
19
19
  row: {
20
20
  _focusVisible: {
21
- outline: "none";
21
+ outline: "0";
22
22
  };
23
23
  };
24
24
  };
25
25
  }>;
26
- /** What a check mark's element carries, so its filled face can draw the gradient edge. */
27
26
  export declare const checkMarkEdge: {
28
27
  readonly "data-ciridae-ui": "";
29
28
  readonly "data-edge": "gradient";
30
29
  };
31
30
  export declare const checkIndicator: string;
32
- /** The tick, or the dash of a mixed checkbox. */
33
31
  export declare function CheckGlyph({ mixed }: {
34
32
  mixed: boolean | undefined;
35
33
  }): import("react").JSX.Element;
@@ -42,7 +40,7 @@ export declare function Textarea({ className, ...props }: ComponentProps<"textar
42
40
  export declare const radioDot: string;
43
41
  export type RadioGroupProps = Omit<ComponentProps<typeof BaseRadioGroup>, "children" | "defaultValue" | "name" | "onValueChange" | "value"> & {
44
42
  name: string;
45
- options: readonly (SelectOption & {
43
+ options: readonly (RadioOption & {
46
44
  meta?: ReactNode;
47
45
  })[];
48
46
  label: string;
@@ -54,9 +52,8 @@ export type RadioGroupProps = Omit<ComponentProps<typeof BaseRadioGroup>, "child
54
52
  onValueChange?: (value: string) => void;
55
53
  };
56
54
  export declare function RadioGroup({ name, options, label: groupLabel, defaultValue, value, onValueChange, layout, className, ...props }: RadioGroupProps): import("react").JSX.Element;
57
- type SelectOption = {
55
+ export type RadioOption = {
58
56
  label: string;
59
57
  value: string;
60
58
  disabled?: boolean;
61
59
  };
62
- export {};
@@ -6,12 +6,8 @@ import { CheckIcon } from "@phosphor-icons/react";
6
6
  import { css, cva, cx } from "#primitives/css";
7
7
  import { useFieldControl } from "./field-context.js";
8
8
  /*
9
- * The one mark for a checkbox and a radio: the selected tint in dark, a near-white well in light,
10
- * that fills with the primary button's face and gradient edge once on. The edge is the `[data-edge]`
11
- * ring the element carries through `checkMarkEdge`: the selected face's gradient in dark, the
12
- * control hairline in light. Hover darkens the edge of an empty mark, washes it in light, and fades
13
- * a filled one in dark. The ring is a variant, because a row that holds the mark draws its own
14
- * ring instead.
9
+ * Hover darkens the edge of an empty mark, washes it in light, and fades a filled one in dark.
10
+ * The ring is a variant, because a row that holds the mark draws its own ring instead.
15
11
  */
16
12
  export const checkMark = cva({
17
13
  base: {
@@ -22,14 +18,14 @@ export const checkMark = cva({
22
18
  placeItems: "center",
23
19
  padding: "none",
24
20
  border: "1px solid transparent",
25
- background: "token(gradients.selected)",
21
+ background: "[token(gradients.selected)]",
26
22
  color: "bg.canvas",
27
23
  _light: { color: "fg.onAccent", background: "bg.check" },
28
24
  cursor: "pointer",
29
- transitionProperty: "background, opacity",
25
+ transitionProperty: "[background, opacity]",
30
26
  transitionDuration: "fast",
31
27
  _before: {
32
- background: "token(gradients.border.selected)",
28
+ background: "[token(gradients.border.selected)]",
33
29
  _light: { background: "border.control" },
34
30
  },
35
31
  // Pointing anywhere at a row's label marks the box it would tick, while it is empty: a filled
@@ -37,15 +33,15 @@ export const checkMark = cva({
37
33
  "&:not([data-checked], [data-indeterminate], [data-checked] > *):is(label:hover > *, label:hover *, :hover):not([data-disabled])": {
38
34
  _before: { background: "fg.muted", _light: { background: "fg.secondary" } },
39
35
  _light: {
40
- background: "linear-gradient(token(colors.bg.controlHover), token(colors.bg.controlHover)), token(colors.bg.check)",
36
+ background: "[linear-gradient(token(colors.bg.controlHover), token(colors.bg.controlHover)), token(colors.bg.check)]",
41
37
  },
42
38
  },
43
39
  "&[data-checked], &[data-indeterminate]": {
44
- background: "token(gradients.primary)",
45
- _light: { background: "token(gradients.primary)" },
46
- _before: { background: "token(gradients.border.primary)" },
40
+ background: "[token(gradients.primary)]",
41
+ _light: { background: "[token(gradients.primary)]" },
42
+ _before: { background: "[token(gradients.border.primary)]" },
47
43
  },
48
- "&:is([data-checked], [data-indeterminate]):is(label:hover > *, label:hover *, :hover):not([data-disabled])": { opacity: "checkedHover", _light: { opacity: "1" } },
44
+ "&:is([data-checked], [data-indeterminate]):is(label:hover > *, label:hover *, :hover):not([data-disabled])": { opacity: "checkedHover", _light: { opacity: "[1]" } },
49
45
  "&[data-disabled]": { opacity: "disabled", cursor: "not-allowed" },
50
46
  },
51
47
  variants: {
@@ -53,7 +49,7 @@ export const checkMark = cva({
53
49
  focus: {
54
50
  ring: { _focusVisible: { focusRing: "outer" } },
55
51
  /* The row around the mark shows focus, so the mark itself draws nothing. */
56
- row: { _focusVisible: { outline: "none" } },
52
+ row: { _focusVisible: { outline: "0" } },
57
53
  },
58
54
  },
59
55
  defaultVariants: { shape: "box", focus: "ring" },
@@ -64,23 +60,20 @@ const label = css({
64
60
  gap: "layout.controlGap",
65
61
  color: "fg.primary",
66
62
  fontSize: "caption",
67
- fontWeight: "normal",
63
+ fontWeight: "[normal]",
68
64
  cursor: "pointer",
69
65
  });
70
- /** What a check mark's element carries, so its filled face can draw the gradient edge. */
71
66
  export const checkMarkEdge = { "data-ciridae-ui": "", "data-edge": "gradient" };
72
67
  export const checkIndicator = css({
73
68
  display: "inline-flex",
74
- lineHeight: "1",
69
+ lineHeight: "tight",
75
70
  fontSize: "icon.small",
76
71
  });
77
- // A mixed checkbox's mark: a short dash rather than a minus glyph.
78
72
  const mixedDash = css({
79
73
  width: "indicator.swatch",
80
74
  height: "border.hairline",
81
75
  background: "currentColor",
82
76
  });
83
- /** The tick, or the dash of a mixed checkbox. */
84
77
  export function CheckGlyph({ mixed }) {
85
78
  return mixed ? _jsx("span", { className: mixedDash }) : _jsx(CheckIcon, { weight: "bold" });
86
79
  }
@@ -88,7 +81,7 @@ export function Checkbox({ children, className, wrapperClassName, ...props }) {
88
81
  return (_jsxs("label", { className: cx(label, wrapperClassName), "data-ciridae-ui": "", children: [_jsx(BaseCheckbox.Root, { ...props, ...checkMarkEdge, className: cx(checkMark(), className), children: _jsx(BaseCheckbox.Indicator, { className: checkIndicator, children: _jsx(CheckGlyph, { mixed: props.indeterminate }) }) }), children] }));
89
82
  }
90
83
  const textarea = css({
91
- width: "100%",
84
+ width: "full",
92
85
  minHeight: "field.textarea",
93
86
  resize: "vertical",
94
87
  paddingBlock: "field.block",
@@ -131,7 +124,7 @@ const menuRadio = css({
131
124
  cursor: "pointer",
132
125
  _hover: {
133
126
  background: "bg.hover",
134
- boxShadow: "inset 0 0 0 1px token(colors.border.menuHover)",
127
+ boxShadow: "[inset 0 0 0 1px token(colors.border.menuHover)]",
135
128
  },
136
129
  "&:has([data-disabled])": { opacity: "disabled", cursor: "not-allowed" },
137
130
  });
@@ -6,15 +6,16 @@ import type { ComponentProps, ReactNode } from "react";
6
6
  */
7
7
  export declare function Form({ className, ...props }: ComponentProps<"form">): import("react").JSX.Element;
8
8
  export declare function FormActions({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
9
- /** Fields in one row of a `Form`, sharing its width equally. */
10
9
  export declare function FieldRow({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
11
10
  /**
12
- * A label round a `FieldLabel`, its control and any `FieldError`: the label names the control it
13
- * holds, and while `invalid` the control is marked and described by the error, so `Input`,
11
+ * A group round a `FieldLabel`, its control and any `FieldError`: the label names the control by
12
+ * its id, and while `invalid` the control is marked and described by the error, so `Input`,
14
13
  * `Textarea`, `Select` and `Combobox` inside need no ids of their own. A `hint` sits under the
15
- * control and describes it until the error takes its place.
14
+ * control and describes it until the error takes its place. `htmlFor` is the control's id when
15
+ * the control has its own.
16
16
  */
17
- export declare function Field({ className, htmlFor, invalid, hint, children, ...props }: ComponentProps<"label"> & {
17
+ export declare function Field({ className, htmlFor, invalid, hint, children, ...props }: ComponentProps<"div"> & {
18
+ htmlFor?: string;
18
19
  invalid?: boolean;
19
20
  hint?: ReactNode;
20
21
  }): import("react").JSX.Element;
@@ -32,5 +33,4 @@ export type SegmentedOptionProps = Omit<ButtonProps, "variant" | "type" | "aria-
32
33
  /** Shown muted after the label, such as how many items the option lists. */
33
34
  count?: number;
34
35
  };
35
- /** One option of a `SegmentedControl`: the selected one is raised, the others bare. */
36
36
  export declare function SegmentedOption({ selected, count, children, ...props }: SegmentedOptionProps): import("react").JSX.Element;
@@ -14,7 +14,6 @@ const labelText = css({
14
14
  lineHeight: "tight",
15
15
  letterSpacing: "compact",
16
16
  });
17
- // Help and error lines under the control, which can wrap.
18
17
  const noteText = css({
19
18
  margin: "none",
20
19
  fontSize: "code",
@@ -24,11 +23,7 @@ const noteText = css({
24
23
  });
25
24
  const hintText = css({ color: "fg.muted" });
26
25
  const errorText = css({ color: "accent.red" });
27
- /*
28
- * A grey well holding its options, the selected one raised on the secondary button's face. The
29
- * track is a default button's height, or in a toolbar a small one's on a thinner inset, and each
30
- * option clears it by the inset and a hairline.
31
- */
26
+ /* The track is a default button's height, or in a toolbar a small one's on a thinner inset, and each option clears it by the inset and a hairline. */
32
27
  const segmented = css({
33
28
  "--track-inset": "token(spacing.layout.tightGap)",
34
29
  "--track-height": "token(sizes.control.default)",
@@ -47,7 +42,7 @@ const segmented = css({
47
42
  "--track-height": "token(sizes.control.compact)",
48
43
  },
49
44
  "& > *": {
50
- height: "calc(var(--track-height) - 2 * (var(--track-inset) + token(sizes.border.hairline)))!",
45
+ height: "[calc(var(--track-height) - 2 * (var(--track-inset) + token(sizes.border.hairline)))!]",
51
46
  borderRadius: "action!",
52
47
  },
53
48
  "& > [aria-pressed=false]:not(:hover)": { color: "fg.muted" },
@@ -55,11 +50,10 @@ const segmented = css({
55
50
  });
56
51
  const countText = css({ color: "fg.muted", fontVariantNumeric: "tabular-nums" });
57
52
  const formStack = css({ display: "grid", gap: "layout.clusterGap", minWidth: "0" });
58
- // Fields side by side sit closer than stacked ones.
59
53
  const fieldRow = css({
60
54
  display: "grid",
61
55
  gridAutoFlow: "column",
62
- gridAutoColumns: "minmax(0, 1fr)",
56
+ gridAutoColumns: "[minmax(0, 1fr)]",
63
57
  gap: "layout.contentGap",
64
58
  });
65
59
  const formActions = css({
@@ -77,15 +71,15 @@ export function Form({ className, ...props }) {
77
71
  export function FormActions({ className, ...props }) {
78
72
  return _jsx("div", { ...props, className: cx(formActions, className), "data-ciridae-ui": "" });
79
73
  }
80
- /** Fields in one row of a `Form`, sharing its width equally. */
81
74
  export function FieldRow({ className, ...props }) {
82
75
  return _jsx("div", { ...props, className: cx(fieldRow, className), "data-ciridae-ui": "" });
83
76
  }
84
77
  /**
85
- * A label round a `FieldLabel`, its control and any `FieldError`: the label names the control it
86
- * holds, and while `invalid` the control is marked and described by the error, so `Input`,
78
+ * A group round a `FieldLabel`, its control and any `FieldError`: the label names the control by
79
+ * its id, and while `invalid` the control is marked and described by the error, so `Input`,
87
80
  * `Textarea`, `Select` and `Combobox` inside need no ids of their own. A `hint` sits under the
88
- * control and describes it until the error takes its place.
81
+ * control and describes it until the error takes its place. `htmlFor` is the control's id when
82
+ * the control has its own.
89
83
  */
90
84
  export function Field({ className, htmlFor, invalid = false, hint, children, ...props }) {
91
85
  const generatedId = useId();
@@ -96,10 +90,11 @@ export function Field({ className, htmlFor, invalid = false, hint, children, ...
96
90
  descriptionId: invalid ? `${controlId}-error` : showsHint ? `${controlId}-hint` : undefined,
97
91
  invalid,
98
92
  }), [controlId, invalid, showsHint]);
99
- return (_jsx(FieldControlContext, { value: fieldControl, children: _jsxs("label", { ...props, htmlFor: htmlFor, className: cx(field, className), "data-ciridae-ui": "", children: [children, showsHint && (_jsx("span", { id: `${controlId}-hint`, className: cx(noteText, hintText), children: hint }))] }) }));
93
+ return (_jsx(FieldControlContext, { value: fieldControl, children: _jsxs("div", { ...props, className: cx(field, className), "data-ciridae-ui": "", children: [children, showsHint && (_jsx("span", { id: `${controlId}-hint`, className: cx(noteText, hintText), children: hint }))] }) }));
100
94
  }
101
95
  export function FieldLabel({ children }) {
102
- return _jsx("span", { className: labelText, children: children });
96
+ const field = useContext(FieldControlContext);
97
+ return (_jsx("label", { htmlFor: field?.controlId, className: labelText, children: children }));
103
98
  }
104
99
  /** The field's error; its id is the one the field's control is described by. */
105
100
  export function FieldError({ id, children }) {
@@ -111,7 +106,6 @@ export function SegmentedControl({ className, ...props }) {
111
106
  const edge = faceEdge("raised");
112
107
  return (_jsx("div", { ...props, className: cx(segmented, edge.className, className), "data-density": inToolbar ? "compact" : undefined, "data-ciridae-ui": "", "data-edge": edge["data-edge"] }));
113
108
  }
114
- /** One option of a `SegmentedControl`: the selected one is raised, the others bare. */
115
109
  export function SegmentedOption({ selected, count, children, ...props }) {
116
110
  return (_jsxs(Button, { ...props, type: "button", variant: selected ? "secondary" : "ghost", "aria-pressed": selected, children: [children, count !== undefined && _jsx("span", { className: countText, children: count })] }));
117
111
  }
@@ -1,3 +1,5 @@
1
+ /** How far a menu, popover or select list floats from its trigger, in pixels. */
2
+ export declare const glassMenuOffsetFromTrigger = 4;
1
3
  export declare const glassMenuSurface: import("../styled-system/types/index.js").SystemStyleObject;
2
4
  export declare const glassMenuRow: import("../styled-system/types/index.js").SystemStyleObject;
3
5
  export declare const glassMenuDivider: import("../styled-system/types/index.js").SystemStyleObject;
@@ -1,26 +1,26 @@
1
1
  import { css } from "#primitives/css";
2
+ /** How far a menu, popover or select list floats from its trigger, in pixels. */
3
+ export const glassMenuOffsetFromTrigger = 4;
2
4
  /*
3
5
  * The glass sheet every menu, popover and select list floats on, and the rows inside it, as raw
4
- * styles for `css()` to merge with each popup's own: an 8-round sheet padded 4px all round that
5
- * blurs what lies under it, holding 4-round rows 32px tall.
6
+ * styles for `css()` to merge with each popup's own.
6
7
  */
7
8
  export const glassMenuSurface = css.raw({
8
9
  padding: "menu.inset",
9
- border: "1px solid token(colors.border.control)",
10
+ border: "1px solid token(colors.border.popover)",
10
11
  borderRadius: "action",
11
12
  background: "bg.popover",
12
- backdropFilter: "blur(token(blurs.popover))",
13
+ backdropFilter: "[blur(token(blurs.popover))]",
13
14
  boxShadow: "soft",
14
15
  color: "fg.primary",
15
16
  textStyle: "body",
16
17
  // The popup takes focus as it opens; it is a container, not a control, so it draws no ring.
17
- outline: "none",
18
+ outline: "0",
18
19
  });
19
20
  /*
20
- * A row: hovered, it takes a wash inside the menu hover hairline, the raised glass in dark and the
21
- * row's hover wash in light. A row that is a plain button has no highlight state, so it takes the
22
- * wash on hover. Reached by the keyboard, away from the pointer, it draws the focus ring inside its
23
- * own edge in place of the wash and the hairline.
21
+ * A row that is a plain button has no highlight state, so it takes the wash on hover. Reached by the
22
+ * keyboard, away from the pointer, it draws the focus ring inside its own edge in place of the wash
23
+ * and the hairline.
24
24
  */
25
25
  export const glassMenuRow = css.raw({
26
26
  display: "flex",
@@ -35,28 +35,24 @@ export const glassMenuRow = css.raw({
35
35
  lineHeight: "tight",
36
36
  letterSpacing: "compact",
37
37
  cursor: "pointer",
38
- outline: "none",
38
+ outline: "0",
39
39
  "&[data-highlighted], &:is(button):hover": {
40
- background: "token(gradients.raised)",
41
- boxShadow: "inset 0 0 0 1px token(colors.border.menuHover)",
40
+ background: "[token(gradients.raised)]",
41
+ boxShadow: "[inset 0 0 0 1px token(colors.border.menuHover)]",
42
42
  _light: { background: "bg.rowHover" },
43
43
  },
44
44
  // Under the pointer the row keeps the wash, so the ring marks only the row the keys reached.
45
45
  "&:focus-visible:not(:hover), &[data-highlighted]:focus-visible:not(:hover)": {
46
46
  focusRing: "inset",
47
47
  background: "transparent",
48
- boxShadow: "none",
48
+ boxShadow: "[none]",
49
49
  _light: { background: "transparent" },
50
50
  },
51
51
  "&[data-disabled]": { opacity: "disabled", cursor: "not-allowed" },
52
52
  });
53
- /*
54
- * The rule between groups of rows, inset 8px from the sheet's sides with 4px above and below: a
55
- * hairline along the top of a 2px band, as the design draws it.
56
- */
57
53
  export const glassMenuDivider = css.raw({
58
54
  flexShrink: "0",
59
- height: "calc(token(sizes.border.hairline) * 2)",
55
+ height: "[calc(token(sizes.border.hairline) * 2)]",
60
56
  marginBlock: "layout.tightGap",
61
57
  marginInline: "menu.itemInline",
62
58
  borderTop: "1px solid token(colors.border.divider)",
@@ -1,5 +1,4 @@
1
1
  type GradientEdge = "raised" | "primary" | "danger" | "tinted" | "toolbar";
2
- /** A face's edge: a flat hairline ciridae.css paints by name, or one of the gradient edges. */
3
2
  export type FaceEdge = "glass" | "control" | GradientEdge;
4
3
  /** The class and `data-edge` that draw `edge`; nothing for a face with no edge. */
5
4
  export declare function faceEdge(edge: FaceEdge | undefined): {
@@ -1,20 +1,19 @@
1
1
  import { cva } from "#primitives/css";
2
2
  /*
3
3
  * The 1px edge a face draws as a gradient. A gradient cannot be a border color, so it paints the
4
- * `[data-edge]` ring ciridae.css draws inside the element's box, which also keeps its corners:
5
- * `faceEdge` gives the class that paints the ring and the `data-edge` that turns it on. Dark draws
6
- * no edge on the primary or destructive face. A toolbar control's edge is the selected face's: the
7
- * raised gradient in dark and a paler grey gradient in light.
4
+ * `[data-edge]` ring ciridae.css draws inside the element's box, which also keeps its corners. Dark
5
+ * draws no edge on the primary or destructive face. A toolbar control's edge is the selected face's:
6
+ * the raised gradient in dark and a paler grey gradient in light.
8
7
  */
9
8
  const gradientEdge = cva({
10
9
  base: {},
11
10
  variants: {
12
11
  edge: {
13
- raised: { _before: { background: "token(gradients.border.raised)" } },
14
- primary: { _before: { background: "token(gradients.border.primary)" } },
15
- danger: { _before: { background: "token(gradients.border.danger)" } },
16
- tinted: { _before: { background: "token(gradients.border.tinted)" } },
17
- toolbar: { _before: { background: "token(gradients.border.selected)" } },
12
+ raised: { _before: { background: "[token(gradients.border.raised)]" } },
13
+ primary: { _before: { background: "[token(gradients.border.primary)]" } },
14
+ danger: { _before: { background: "[token(gradients.border.danger)]" } },
15
+ tinted: { _before: { background: "[token(gradients.border.tinted)]" } },
16
+ toolbar: { _before: { background: "[token(gradients.border.selected)]" } },
18
17
  },
19
18
  },
20
19
  });