@oods/components-react 0.3.3 → 0.4.1

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.
package/dist/index.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var React7 = require('react');
3
+ var React9 = require('react');
4
4
  var reactSlot = require('@radix-ui/react-slot');
5
- var jsxRuntime = require('react/jsx-runtime');
6
5
  var componentContracts = require('@oods/component-contracts');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
7
 
8
8
  function _interopNamespace(e) {
9
9
  if (e && e.__esModule) return e;
@@ -23,342 +23,25 @@ function _interopNamespace(e) {
23
23
  return Object.freeze(n);
24
24
  }
25
25
 
26
- var React7__namespace = /*#__PURE__*/_interopNamespace(React7);
26
+ var React9__namespace = /*#__PURE__*/_interopNamespace(React9);
27
27
 
28
28
  // src/presentational.tsx
29
-
30
- // src/status-map.json
31
- var status_map_default = {
32
- domains: {
33
- subscription: {
34
- future: {
35
- description: "Subscription is scheduled but not yet active.",
36
- chip: {
37
- foreground: "color.text.info",
38
- background: "color.background.info.subtle",
39
- border: "color.border.info",
40
- icon: "icon.status.scheduled"
41
- },
42
- banner: {
43
- foreground: "color.text.info",
44
- background: "color.background.surface.default",
45
- border: "color.border.info",
46
- icon: "icon.status.scheduled"
47
- }
48
- },
49
- trialing: {
50
- description: "Subscription is in a trial period before billing begins.",
51
- chip: {
52
- foreground: "color.text.accent",
53
- background: "color.background.accent.subtle",
54
- border: "color.border.accent",
55
- icon: "icon.status.trial"
56
- },
57
- banner: {
58
- foreground: "color.text.accent",
59
- background: "color.background.surface.default",
60
- border: "color.border.accent",
61
- icon: "icon.status.trial"
62
- }
63
- },
64
- active: {
65
- description: "Subscription is paid and service is provisioned.",
66
- chip: {
67
- foreground: "color.text.positive",
68
- background: "color.background.positive.subtle",
69
- border: "color.border.positive",
70
- icon: "icon.status.success"
71
- },
72
- banner: {
73
- foreground: "color.text.positive",
74
- background: "color.background.surface.default",
75
- border: "color.border.positive",
76
- icon: "icon.status.success"
77
- }
78
- },
79
- paused: {
80
- description: "Billing paused temporarily by finance or customer request.",
81
- chip: {
82
- foreground: "color.text.neutral",
83
- background: "color.background.neutral.subtle",
84
- border: "color.border.neutral",
85
- icon: "icon.status.paused"
86
- },
87
- banner: {
88
- foreground: "color.text.neutral",
89
- background: "color.background.surface.muted",
90
- border: "color.border.neutral",
91
- icon: "icon.status.paused"
92
- }
93
- },
94
- pending_cancellation: {
95
- description: "Subscription will cancel at period end but remains active now.",
96
- chip: {
97
- foreground: "color.text.info",
98
- background: "color.background.info.subtle",
99
- border: "color.border.info",
100
- icon: "icon.status.pending"
101
- },
102
- banner: {
103
- foreground: "color.text.info",
104
- background: "color.background.surface.default",
105
- border: "color.border.info",
106
- icon: "icon.status.pending"
107
- }
108
- },
109
- past_due: {
110
- description: "Renewal payment failed; smart retries ongoing and access retained during the grace window.",
111
- chip: {
112
- foreground: "color.text.danger",
113
- background: "color.background.danger.subtle",
114
- border: "color.border.danger",
115
- icon: "icon.status.warning"
116
- },
117
- banner: {
118
- foreground: "color.text.onbold",
119
- background: "color.background.danger.bold",
120
- border: "color.border.danger",
121
- icon: "icon.status.warning"
122
- }
123
- },
124
- unpaid: {
125
- description: "Payment retries exhausted; service access revoked.",
126
- chip: {
127
- foreground: "color.text.danger",
128
- background: "color.background.danger.subtle",
129
- border: "color.border.danger",
130
- icon: "icon.status.error"
131
- },
132
- banner: {
133
- foreground: "color.text.onbold",
134
- background: "color.background.danger.bold",
135
- border: "color.border.danger",
136
- icon: "icon.status.error"
137
- }
138
- },
139
- terminated: {
140
- description: "Subscription ended; service access revoked and billing stopped.",
141
- chip: {
142
- foreground: "color.text.disabled",
143
- background: "color.background.disabled",
144
- border: "color.border.disabled",
145
- icon: "icon.status.canceled"
146
- },
147
- banner: {
148
- foreground: "color.text.neutral",
149
- background: "color.background.neutral.subtle",
150
- border: "color.border.neutral",
151
- icon: "icon.status.canceled"
152
- }
153
- }
154
- },
155
- invoice: {
156
- draft: {
157
- description: "Invoice is editable and not yet finalized.",
158
- chip: {
159
- foreground: "color.text.neutral",
160
- background: "color.background.neutral.subtle",
161
- border: "color.border.neutral",
162
- icon: "icon.status.draft"
163
- },
164
- banner: {
165
- foreground: "color.text.neutral",
166
- background: "color.background.surface.muted",
167
- border: "color.border.neutral",
168
- icon: "icon.status.draft"
169
- }
170
- },
171
- posted: {
172
- description: "Invoice finalized with terms before collection.",
173
- chip: {
174
- foreground: "color.text.info",
175
- background: "color.background.info.subtle",
176
- border: "color.border.info",
177
- icon: "icon.status.pending"
178
- },
179
- banner: {
180
- foreground: "color.text.info",
181
- background: "color.background.surface.default",
182
- border: "color.border.info",
183
- icon: "icon.status.pending"
184
- }
185
- },
186
- paid: {
187
- description: "Invoice collected successfully in full.",
188
- chip: {
189
- foreground: "color.text.positive",
190
- background: "color.background.positive.subtle",
191
- border: "color.border.positive",
192
- icon: "icon.status.success"
193
- },
194
- banner: {
195
- foreground: "color.text.positive",
196
- background: "color.background.surface.default",
197
- border: "color.border.positive",
198
- icon: "icon.status.success"
199
- }
200
- },
201
- past_due: {
202
- description: "Invoice is unpaid past its due date.",
203
- chip: {
204
- foreground: "color.text.danger",
205
- background: "color.background.danger.subtle",
206
- border: "color.border.danger",
207
- icon: "icon.status.error"
208
- },
209
- banner: {
210
- foreground: "color.text.onbold",
211
- background: "color.background.danger.bold",
212
- border: "color.border.danger",
213
- icon: "icon.status.error"
214
- }
215
- },
216
- void: {
217
- description: "Invoice canceled and no longer payable.",
218
- chip: {
219
- foreground: "color.text.disabled",
220
- background: "color.background.disabled",
221
- border: "color.border.disabled",
222
- icon: "icon.status.void"
223
- },
224
- banner: {
225
- foreground: "color.text.neutral",
226
- background: "color.background.neutral.subtle",
227
- border: "color.border.neutral",
228
- icon: "icon.status.void"
229
- }
230
- }
231
- }
232
- }
233
- };
234
-
235
- // src/status.ts
236
- var TONE_ALIASES = {
237
- info: "info",
238
- informational: "info",
239
- accent: "accent",
240
- highlight: "accent",
241
- positive: "success",
242
- success: "success",
243
- ok: "success",
244
- warning: "warning",
245
- caution: "warning",
246
- danger: "critical",
247
- critical: "critical",
248
- error: "critical",
249
- negative: "critical",
250
- neutral: "neutral",
251
- pending: "info"
252
- };
253
- var toLabel = (status) => status.split(/[_-]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
254
- var inferTone = (entry) => {
255
- if (!entry) return "neutral";
256
- for (const reference of [entry.foreground, entry.background, entry.border]) {
257
- const segments = reference.replace(/^\{|\}$/g, "").split(/[\s./_-]+/).reverse();
258
- for (const segment of segments) {
259
- const tone = TONE_ALIASES[segment.toLowerCase()];
260
- if (tone) return tone;
261
- }
262
- }
263
- return "neutral";
264
- };
265
- var componentTokenSet = (tone) => {
266
- const normalized = tone === "positive" ? "success" : tone === "danger" ? "critical" : tone;
267
- return {
268
- background: `var(--sys-status-${normalized}-surface)`,
269
- border: `var(--sys-status-${normalized}-border)`,
270
- foreground: `var(--sys-status-${normalized}-text)`
271
- };
272
- };
273
- var rawTokenSet = (entry) => {
274
- const tone = inferTone(entry);
275
- return componentTokenSet(tone);
276
- };
277
- var bannerFallback = (tone) => tone === "neutral" ? {
278
- background: "var(--cmp-banner-background)",
279
- border: "var(--cmp-banner-border)",
280
- foreground: "var(--cmp-banner-text)"
281
- } : componentTokenSet(tone);
282
- var fallback = (domain, status, tone = "neutral") => ({
283
- domain,
284
- status,
285
- label: toLabel(status || "Unknown"),
286
- description: "Status not found in registry; falling back to the requested token set.",
287
- tone,
288
- badge: { subtle: componentTokenSet(tone), solid: componentTokenSet(tone) },
289
- banner: { subtle: bannerFallback(tone), solid: componentTokenSet(tone) }
290
- });
291
- var registry = /* @__PURE__ */ new Map();
292
- for (const [domain, entries] of Object.entries(status_map_default.domains)) {
293
- const domainEntries = /* @__PURE__ */ new Map();
294
- for (const [status, entry] of Object.entries(entries)) {
295
- const tone = inferTone(entry.chip);
296
- domainEntries.set(status.toLowerCase(), {
297
- domain,
298
- status,
299
- label: toLabel(status),
300
- description: entry.description,
301
- tone,
302
- iconName: entry.chip.icon ?? entry.banner?.icon,
303
- badge: { subtle: rawTokenSet(entry.chip), solid: componentTokenSet(tone) },
304
- banner: {
305
- subtle: entry.banner ? rawTokenSet(entry.banner) : bannerFallback(tone),
306
- solid: componentTokenSet(tone)
307
- }
308
- });
309
- }
310
- registry.set(domain, domainEntries);
311
- }
312
- var LEGACY_STATUS_ALIASES = {
313
- subscription: { delinquent: "unpaid" }
29
+ var REACT_NAMES = {
30
+ viewBox: "viewBox",
31
+ fill: "fill",
32
+ stroke: "stroke",
33
+ "stroke-width": "strokeWidth",
34
+ "stroke-linecap": "strokeLinecap",
35
+ "stroke-linejoin": "strokeLinejoin",
36
+ "aria-hidden": "aria-hidden",
37
+ focusable: "focusable"
314
38
  };
315
- Object.freeze([...registry.keys()]);
316
- function getStatusPresentation(domain, status) {
317
- const entries = registry.get(domain);
318
- if (!entries) return fallback(domain, status);
319
- const normalized = status.toLowerCase();
320
- const direct = entries.get(normalized);
321
- if (direct) return direct;
322
- const alias = LEGACY_STATUS_ALIASES[domain]?.[normalized];
323
- const aliased = alias ? entries.get(alias) : void 0;
324
- return aliased ? { ...aliased, status, label: toLabel(status) } : fallback(domain, status);
325
- }
326
- function getToneTokenSet(tone) {
327
- return componentTokenSet(tone);
328
- }
329
- function getBannerToneTokenSet(tone) {
330
- return bannerFallback(tone);
331
- }
332
- var ICON_GLYPHS = {
333
- success: "\u2714\uFE0E",
334
- warning: "\u26A0\uFE0E",
335
- critical: "\u2A2F",
336
- danger: "\u2A2F",
337
- error: "\u2A2F",
338
- negative: "\u2A2F",
339
- pending: "\u2026",
340
- processing: "\u27F3",
341
- paused: "\u23F8",
342
- canceled: "\u2205",
343
- cancelled: "\u2205",
344
- draft: "\u270E",
345
- void: "\u2205",
346
- paid: "\u2714\uFE0E",
347
- info: "\u2139\uFE0E",
348
- trial: "\u2605",
349
- future: "\u23F2",
350
- scheduled: "\u23F2",
351
- refunded: "\u21BA",
352
- locked: "\u{1F512}",
353
- unlocked: "\u{1F513}",
354
- default: "\u2022"
355
- };
356
- function resolveStatusGlyph(iconName) {
357
- const segment = iconName?.split(".").pop()?.toLowerCase();
358
- return segment ? ICON_GLYPHS[segment] ?? ICON_GLYPHS.default : void 0;
39
+ var svgProps = Object.fromEntries(Object.entries(componentContracts.STATUS_ICON_SVG_ATTRS).map(([name, value]) => [REACT_NAMES[name] ?? name, value]));
40
+ function StatusIcon({ name }) {
41
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { ...svgProps, children: componentContracts.STATUS_ICON_SHAPES[name].map((shape, index) => React9__namespace.createElement(shape.tag, { key: index, ...shape.attrs })) });
359
42
  }
360
43
  var classes = (...values) => values.filter(Boolean).join(" ");
361
- var Badge = React7__namespace.forwardRef(
44
+ var Badge = React9__namespace.forwardRef(
362
45
  ({
363
46
  content,
364
47
  status,
@@ -375,11 +58,12 @@ var Badge = React7__namespace.forwardRef(
375
58
  "aria-label": ariaLabel,
376
59
  ...rest
377
60
  }, ref) => {
378
- const presentation = status ? getStatusPresentation(domain, status) : void 0;
61
+ const presentation = status ? componentContracts.getStatusPresentation(domain, status) : void 0;
379
62
  const tone = toneOverride ?? presentation?.tone ?? "neutral";
380
- const tokenSet = toneOverride !== void 0 ? getToneTokenSet(tone) : emphasis === "solid" ? presentation?.badge.solid ?? getToneTokenSet(tone) : presentation?.badge.subtle ?? getToneTokenSet(tone);
63
+ const tokenSet = toneOverride !== void 0 ? componentContracts.getToneTokenSet(tone) : emphasis === "solid" ? presentation?.badge.solid ?? componentContracts.getToneTokenSet(tone) : presentation?.badge.subtle ?? componentContracts.getToneTokenSet(tone);
381
64
  const resolvedContent = children ?? content ?? presentation?.label ?? status;
382
- const resolvedIcon = icon ?? resolveStatusGlyph(presentation?.iconName);
65
+ const statusIcon = componentContracts.resolveStatusIcon(presentation?.iconName);
66
+ const resolvedIcon = icon ?? (statusIcon ? /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { name: statusIcon }) : void 0);
383
67
  const resolvedShowIcon = showIcon ?? resolvedIcon !== void 0;
384
68
  const iconNode = resolvedShowIcon && resolvedIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oods-badge__icon", "aria-hidden": "true", children: resolvedIcon }) : null;
385
69
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -411,7 +95,7 @@ var Badge = React7__namespace.forwardRef(
411
95
  }
412
96
  );
413
97
  Badge.displayName = "OODS.Badge";
414
- var Banner = React7__namespace.forwardRef(
98
+ var Banner = React9__namespace.forwardRef(
415
99
  ({
416
100
  title,
417
101
  detail,
@@ -431,13 +115,14 @@ var Banner = React7__namespace.forwardRef(
431
115
  style,
432
116
  ...rest
433
117
  }, ref) => {
434
- const presentation = status ? getStatusPresentation(domain, status) : void 0;
118
+ const presentation = status ? componentContracts.getStatusPresentation(domain, status) : void 0;
435
119
  const tone = toneOverride ?? presentation?.tone ?? "neutral";
436
- const tokenSet = emphasis === "solid" ? presentation?.banner.solid ?? getToneTokenSet(tone) : presentation?.banner.subtle ?? getBannerToneTokenSet(tone);
120
+ const tokenSet = emphasis === "solid" ? presentation?.banner.solid ?? componentContracts.getToneTokenSet(tone) : presentation?.banner.subtle ?? componentContracts.getBannerToneTokenSet(tone);
437
121
  const heading = title ?? presentation?.label ?? status;
438
122
  const body = detail ?? description ?? children ?? content ?? presentation?.description;
439
123
  const role = tone === "critical" || tone === "danger" ? "alert" : "status";
440
- const resolvedIcon = icon ?? resolveStatusGlyph(presentation?.iconName);
124
+ const statusIcon = componentContracts.resolveStatusIcon(presentation?.iconName);
125
+ const resolvedIcon = icon ?? (statusIcon ? /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { name: statusIcon }) : void 0);
441
126
  const resolvedShowIcon = showIcon ?? resolvedIcon !== void 0;
442
127
  return /* @__PURE__ */ jsxRuntime.jsxs(
443
128
  "div",
@@ -472,7 +157,7 @@ var Banner = React7__namespace.forwardRef(
472
157
  className: "oods-banner-dismiss oods-banner__dismiss",
473
158
  "aria-label": dismissLabel,
474
159
  onClick: () => onDismiss(),
475
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\xD7" })
160
+ children: /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { name: "x" })
476
161
  }
477
162
  ) : null
478
163
  ]
@@ -481,7 +166,7 @@ var Banner = React7__namespace.forwardRef(
481
166
  }
482
167
  );
483
168
  Banner.displayName = "OODS.Banner";
484
- var Button = React7__namespace.forwardRef(
169
+ var Button = React9__namespace.forwardRef(
485
170
  ({
486
171
  asChild = false,
487
172
  content,
@@ -527,7 +212,132 @@ var Button = React7__namespace.forwardRef(
527
212
  }
528
213
  );
529
214
  Button.displayName = "OODS.Button";
530
- var Card = React7__namespace.forwardRef(
215
+ var noSubscription = () => () => void 0;
216
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? React9__namespace.useEffect : React9__namespace.useLayoutEffect;
217
+ var canShowModal = () => typeof HTMLDialogElement !== "undefined" && typeof HTMLDialogElement.prototype.showModal === "function";
218
+ var hasContent = (node) => node !== void 0 && node !== null && node !== false && node !== "";
219
+ var pageLocks = 0;
220
+ var pageStyle;
221
+ function lockPageScroll() {
222
+ const page = document.documentElement;
223
+ if (pageLocks++ === 0) {
224
+ const scrollbar = window.innerWidth - page.clientWidth;
225
+ pageStyle = { overflow: page.style.overflow, paddingRight: page.style.paddingRight };
226
+ if (scrollbar > 0) page.style.paddingRight = `${parseFloat(getComputedStyle(page).paddingRight) + scrollbar}px`;
227
+ page.style.overflow = "hidden";
228
+ }
229
+ let held = true;
230
+ return () => {
231
+ if (!held) return;
232
+ held = false;
233
+ if (--pageLocks === 0 && pageStyle) {
234
+ page.style.overflow = pageStyle.overflow;
235
+ page.style.paddingRight = pageStyle.paddingRight;
236
+ pageStyle = void 0;
237
+ }
238
+ };
239
+ }
240
+ var outsideBox = (event, dialog) => {
241
+ const box = dialog.getBoundingClientRect();
242
+ return event.clientX < box.left || event.clientX > box.right || event.clientY < box.top || event.clientY > box.bottom;
243
+ };
244
+ var Dialog = React9__namespace.forwardRef(
245
+ ({
246
+ id,
247
+ open = false,
248
+ modal = true,
249
+ title,
250
+ description,
251
+ dismissLabel = "Close",
252
+ size = "md",
253
+ actions,
254
+ children,
255
+ className,
256
+ onClose,
257
+ onKeyDown,
258
+ onMouseDown,
259
+ onClick,
260
+ ...rest
261
+ }, ref) => {
262
+ const generatedId = React9__namespace.useId().replace(/[^\w-]/g, "");
263
+ const dialogId = id ?? `oods-dialog-${generatedId}`;
264
+ const element = React9__namespace.useRef(null);
265
+ const openRef = React9__namespace.useRef(open);
266
+ const scrollLock = React9__namespace.useRef(null);
267
+ const pressedBackdrop = React9__namespace.useRef(false);
268
+ const serverMarkup = React9__namespace.useSyncExternalStore(noSubscription, () => false, () => true);
269
+ const managed = modal && !serverMarkup && canShowModal();
270
+ const setRef = React9__namespace.useCallback((node) => {
271
+ element.current = node;
272
+ if (typeof ref === "function") ref(node);
273
+ else if (ref) ref.current = node;
274
+ }, [ref]);
275
+ const releaseScroll = React9__namespace.useCallback(() => {
276
+ scrollLock.current?.();
277
+ scrollLock.current = null;
278
+ }, []);
279
+ useIsomorphicLayoutEffect(() => {
280
+ openRef.current = open;
281
+ const dialog = element.current;
282
+ if (!dialog || !managed) return;
283
+ if (open && !dialog.open) dialog.showModal();
284
+ else if (!open && dialog.open) dialog.close();
285
+ if (open && dialog.open) scrollLock.current ??= lockPageScroll();
286
+ }, [open, managed]);
287
+ React9__namespace.useEffect(() => releaseScroll, [releaseScroll]);
288
+ const requestClose = (event) => {
289
+ event.preventDefault();
290
+ onClose?.();
291
+ };
292
+ return /* @__PURE__ */ jsxRuntime.jsxs(
293
+ "dialog",
294
+ {
295
+ ref: setRef,
296
+ id: dialogId,
297
+ className: classes("oods-dialog", className),
298
+ "data-oods-component": "Dialog",
299
+ "data-size": size,
300
+ "aria-labelledby": `${dialogId}-title`,
301
+ "aria-describedby": hasContent(description) ? `${dialogId}-description` : void 0,
302
+ open: managed ? void 0 : open,
303
+ onKeyDown: (event) => {
304
+ onKeyDown?.(event);
305
+ if (event.key === "Escape" && !event.defaultPrevented) requestClose(event);
306
+ },
307
+ onCancel: requestClose,
308
+ onClose: () => {
309
+ if (element.current?.open) return;
310
+ releaseScroll();
311
+ if (openRef.current) onClose?.();
312
+ },
313
+ onMouseDown: (event) => {
314
+ onMouseDown?.(event);
315
+ pressedBackdrop.current = managed && event.target === event.currentTarget && outsideBox(event, event.currentTarget);
316
+ },
317
+ onClick: (event) => {
318
+ onClick?.(event);
319
+ const backdrop = pressedBackdrop.current && event.target === event.currentTarget && outsideBox(event, event.currentTarget);
320
+ pressedBackdrop.current = false;
321
+ if (backdrop && !event.defaultPrevented) onClose?.();
322
+ },
323
+ ...rest,
324
+ children: [
325
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oods-dialog__header", children: [
326
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oods-dialog__heading", children: [
327
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { id: `${dialogId}-title`, className: "oods-dialog__title", children: title }),
328
+ hasContent(description) ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: `${dialogId}-description`, className: "oods-dialog__description", children: description }) : null
329
+ ] }),
330
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "oods-dialog__close", "aria-label": dismissLabel, onClick: () => onClose?.(), children: /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { name: "x" }) })
331
+ ] }),
332
+ hasContent(children) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oods-dialog__body", children }) : null,
333
+ hasContent(actions) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oods-dialog__footer", children: actions }) : null
334
+ ]
335
+ }
336
+ );
337
+ }
338
+ );
339
+ Dialog.displayName = "OODS.Dialog";
340
+ var Card = React9__namespace.forwardRef(
531
341
  ({ as = "div", elevated = false, className, ...rest }, ref) => {
532
342
  const Element = as;
533
343
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -543,7 +353,7 @@ var Card = React7__namespace.forwardRef(
543
353
  }
544
354
  );
545
355
  Card.displayName = "OODS.Card";
546
- var Text = React7__namespace.forwardRef(
356
+ var Text = React9__namespace.forwardRef(
547
357
  ({
548
358
  as = "span",
549
359
  content,
@@ -598,7 +408,7 @@ var FieldFrame = ({
598
408
  }) => {
599
409
  const resolvedHelp = help ?? description;
600
410
  const validationTone = validation?.state === "error" ? "critical" : validation?.state === "warning" ? "warning" : validation?.state;
601
- const validationTokens = validationTone ? getToneTokenSet(validationTone) : void 0;
411
+ const validationTokens = validationTone ? componentContracts.getToneTokenSet(validationTone) : void 0;
602
412
  const validationStyle = validationTokens ? {
603
413
  "--cmp-input-message-border": validationTokens.border,
604
414
  "--cmp-input-message-text": validationTokens.foreground,
@@ -652,7 +462,7 @@ var FieldFrame = ({
652
462
  }
653
463
  );
654
464
  };
655
- var InputPrimitive = React7__namespace.forwardRef(
465
+ var InputPrimitive = React9__namespace.forwardRef(
656
466
  ({
657
467
  id,
658
468
  label,
@@ -722,7 +532,7 @@ var InputPrimitive = React7__namespace.forwardRef(
722
532
  );
723
533
  InputPrimitive.displayName = "OODS.Input";
724
534
  var Input = InputPrimitive;
725
- var DatePicker = React7__namespace.forwardRef(
535
+ var DatePicker = React9__namespace.forwardRef(
726
536
  ({ pickerClassName, pickerStyle, inputClassName, inputStyle, className, style, ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: classes2("oods-date-picker", className), style, "data-oods-component": "DatePicker", children: /* @__PURE__ */ jsxRuntime.jsx(
727
537
  Input,
728
538
  {
@@ -735,7 +545,7 @@ var DatePicker = React7__namespace.forwardRef(
735
545
  ) })
736
546
  );
737
547
  DatePicker.displayName = "OODS.DatePicker";
738
- var Checkbox = React7__namespace.forwardRef(
548
+ var Checkbox = React9__namespace.forwardRef(
739
549
  ({
740
550
  id,
741
551
  label,
@@ -798,7 +608,85 @@ var Checkbox = React7__namespace.forwardRef(
798
608
  }
799
609
  );
800
610
  Checkbox.displayName = "OODS.Checkbox";
801
- var Select = React7__namespace.forwardRef(
611
+ var Switch = React9__namespace.forwardRef(
612
+ ({
613
+ id,
614
+ label,
615
+ checked,
616
+ defaultChecked = false,
617
+ required,
618
+ help,
619
+ validation,
620
+ size = "md",
621
+ className,
622
+ style,
623
+ onClick,
624
+ onCheckedChange,
625
+ onUpdate,
626
+ "aria-describedby": nativeDescription,
627
+ ...rest
628
+ }, ref) => {
629
+ const [internalChecked, setInternalChecked] = React9__namespace.useState(defaultChecked);
630
+ const on = checked ?? internalChecked;
631
+ const validationId = validation?.id ?? `${id}-validation`;
632
+ const describedBy = [nativeDescription, help ? `${id}-help` : void 0, validation?.message ? validationId : void 0].filter(Boolean).join(" ") || void 0;
633
+ const tone = validation ? validation.state === "error" ? "critical" : validation.state : void 0;
634
+ const handleClick = (event) => {
635
+ onClick?.(event);
636
+ if (event.defaultPrevented) return;
637
+ const next = !on;
638
+ if (checked === void 0) setInternalChecked(next);
639
+ onCheckedChange?.(next);
640
+ onUpdate?.(next);
641
+ };
642
+ return /* @__PURE__ */ jsxRuntime.jsxs(
643
+ "div",
644
+ {
645
+ className: classes2("oods-field", "oods-switch", className),
646
+ style: {
647
+ ...tone ? {
648
+ "--cmp-input-message-border": `var(--sys-status-${tone}-border)`,
649
+ "--cmp-input-message-text": `var(--sys-status-${tone}-text)`
650
+ } : {},
651
+ ...style
652
+ },
653
+ "data-oods-component": "Switch",
654
+ "data-size": size,
655
+ "data-validation-state": validation?.state,
656
+ children: [
657
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oods-switch__row", children: [
658
+ /* @__PURE__ */ jsxRuntime.jsx(
659
+ "button",
660
+ {
661
+ ref,
662
+ id,
663
+ type: "button",
664
+ role: "switch",
665
+ className: "oods-switch__control",
666
+ "aria-checked": on,
667
+ "aria-labelledby": `${id}-label`,
668
+ "aria-describedby": describedBy,
669
+ "aria-required": required || void 0,
670
+ "aria-invalid": validation?.state === "error" || void 0,
671
+ onClick: handleClick,
672
+ ...rest,
673
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oods-switch__thumb", "aria-hidden": "true" })
674
+ }
675
+ ),
676
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { id: `${id}-label`, className: "oods-field-label oods-switch__label", htmlFor: id, children: [
677
+ label,
678
+ required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oods-field-required", "aria-hidden": "true", children: "*" }) : null
679
+ ] })
680
+ ] }),
681
+ help ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: `${id}-help`, className: "oods-field-help", children: help }) : null,
682
+ validation?.message ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: validationId, className: "oods-field-error", role: validation.state === "error" ? "alert" : void 0, children: validation.message }) : null
683
+ ]
684
+ }
685
+ );
686
+ }
687
+ );
688
+ Switch.displayName = "OODS.Switch";
689
+ var Select = React9__namespace.forwardRef(
802
690
  ({
803
691
  id,
804
692
  label,
@@ -866,7 +754,7 @@ var Select = React7__namespace.forwardRef(
866
754
  }
867
755
  );
868
756
  Select.displayName = "OODS.Select";
869
- var Textarea = React7__namespace.forwardRef(
757
+ var Textarea = React9__namespace.forwardRef(
870
758
  ({
871
759
  id,
872
760
  label,
@@ -949,7 +837,7 @@ var maxColumns = (columns) => {
949
837
  const count = Number(columns);
950
838
  return Number.isFinite(count) && count > 0 ? count : void 0;
951
839
  };
952
- var Grid = React7__namespace.forwardRef(
840
+ var Grid = React9__namespace.forwardRef(
953
841
  ({
954
842
  columns = "auto-fit",
955
843
  minColumnWidth = "16rem",
@@ -979,7 +867,7 @@ var Grid = React7__namespace.forwardRef(
979
867
  )
980
868
  );
981
869
  Grid.displayName = "OODS.Grid";
982
- var Stack = React7__namespace.forwardRef(
870
+ var Stack = React9__namespace.forwardRef(
983
871
  ({
984
872
  direction = "column",
985
873
  gap = "md",
@@ -1011,19 +899,19 @@ var Stack = React7__namespace.forwardRef(
1011
899
  );
1012
900
  Stack.displayName = "OODS.Stack";
1013
901
  var classes4 = (...values) => values.filter(Boolean).join(" ");
1014
- var TableHead = React7__namespace.forwardRef(
902
+ var TableHead = React9__namespace.forwardRef(
1015
903
  ({ className, ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className: classes4("oods-table__header", className), ...rest })
1016
904
  );
1017
905
  TableHead.displayName = "OODS.Table.Head";
1018
- var TableBody = React7__namespace.forwardRef(
906
+ var TableBody = React9__namespace.forwardRef(
1019
907
  ({ className, ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className: classes4("oods-table__body", className), ...rest })
1020
908
  );
1021
909
  TableBody.displayName = "OODS.Table.Body";
1022
- var TableCaption = React7__namespace.forwardRef(
910
+ var TableCaption = React9__namespace.forwardRef(
1023
911
  ({ className, ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx("caption", { ref, className: classes4("oods-table__caption", className), ...rest })
1024
912
  );
1025
913
  TableCaption.displayName = "OODS.Table.Caption";
1026
- var TableRow = React7__namespace.forwardRef(
914
+ var TableRow = React9__namespace.forwardRef(
1027
915
  ({
1028
916
  selectable = false,
1029
917
  selected = false,
@@ -1062,7 +950,7 @@ var TableRow = React7__namespace.forwardRef(
1062
950
  }
1063
951
  );
1064
952
  TableRow.displayName = "OODS.Table.Row";
1065
- var TableHeaderCell = React7__namespace.forwardRef(
953
+ var TableHeaderCell = React9__namespace.forwardRef(
1066
954
  ({ numeric = false, className, scope = "col", ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1067
955
  "th",
1068
956
  {
@@ -1079,7 +967,7 @@ var TableHeaderCell = React7__namespace.forwardRef(
1079
967
  )
1080
968
  );
1081
969
  TableHeaderCell.displayName = "OODS.Table.HeaderCell";
1082
- var TableCell = React7__namespace.forwardRef(
970
+ var TableCell = React9__namespace.forwardRef(
1083
971
  ({
1084
972
  numeric = false,
1085
973
  status,
@@ -1092,9 +980,9 @@ var TableCell = React7__namespace.forwardRef(
1092
980
  title,
1093
981
  ...rest
1094
982
  }, ref) => {
1095
- const presentation = status ? getStatusPresentation(statusDomain, status) : void 0;
983
+ const presentation = status ? componentContracts.getStatusPresentation(statusDomain, status) : void 0;
1096
984
  const tone = toneOverride ?? presentation?.tone;
1097
- const tokens = tone ? getToneTokenSet(tone) : void 0;
985
+ const tokens = tone ? componentContracts.getToneTokenSet(tone) : void 0;
1098
986
  const statusStyle = tokens ? statusEmphasis === "text" ? { "--table-cell-status-foreground": tokens.foreground } : {
1099
987
  "--table-cell-status-background": tokens.background,
1100
988
  "--table-cell-status-border": tokens.border,
@@ -1125,9 +1013,10 @@ var TableCell = React7__namespace.forwardRef(
1125
1013
  }
1126
1014
  );
1127
1015
  TableCell.displayName = "OODS.Table.Cell";
1128
- var TableRoot = React7__namespace.forwardRef(
1016
+ var TableRoot = React9__namespace.forwardRef(
1129
1017
  ({
1130
1018
  caption,
1019
+ showCaption = true,
1131
1020
  columns,
1132
1021
  rows,
1133
1022
  density = "comfortable",
@@ -1153,7 +1042,7 @@ var TableRoot = React7__namespace.forwardRef(
1153
1042
  "data-density": density,
1154
1043
  ...rest,
1155
1044
  children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1156
- caption ? /* @__PURE__ */ jsxRuntime.jsx(TableCaption, { children: caption }) : null,
1045
+ caption ? /* @__PURE__ */ jsxRuntime.jsx(TableCaption, { "data-visually-hidden": showCaption ? void 0 : "true", children: caption }) : null,
1157
1046
  /* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "oods-table__row", children: columns?.map((column) => /* @__PURE__ */ jsxRuntime.jsx(TableHeaderCell, { numeric: column.numeric, children: column.label }, column.key)) }) }),
1158
1047
  /* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: (rows?.length ?? 0) === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "oods-table__row", children: /* @__PURE__ */ jsxRuntime.jsx(TableCell, { colSpan: Math.max(columns?.length ?? 0, 1), children: "No rows available." }) }) : rows?.map((row) => /* @__PURE__ */ jsxRuntime.jsx(
1159
1048
  "tr",
@@ -1206,7 +1095,7 @@ var partitionForOverflow = (items, visibleCount, selectedId) => {
1206
1095
  overflowItems: items.filter((item) => !visibleIds.has(item.id))
1207
1096
  };
1208
1097
  };
1209
- var Tabs = React7__namespace.forwardRef(
1098
+ var Tabs = React9__namespace.forwardRef(
1210
1099
  ({
1211
1100
  items,
1212
1101
  selectedId,
@@ -1220,22 +1109,22 @@ var Tabs = React7__namespace.forwardRef(
1220
1109
  "aria-label": ariaLabelAttribute,
1221
1110
  ...rest
1222
1111
  }, ref) => {
1223
- const instanceId = React7__namespace.useId().replaceAll(":", "");
1112
+ const instanceId = React9__namespace.useId().replaceAll(":", "");
1224
1113
  const controlled = selectedId !== void 0;
1225
1114
  const firstEnabled = items.find((item) => !item.disabled && !item.isDisabled)?.id ?? "";
1226
- const [internalSelectedId, setInternalSelectedId] = React7__namespace.useState(
1115
+ const [internalSelectedId, setInternalSelectedId] = React9__namespace.useState(
1227
1116
  defaultSelectedId ?? firstEnabled
1228
1117
  );
1229
1118
  const activeId = controlled ? selectedId : internalSelectedId;
1230
- const [focusedId, setFocusedId] = React7__namespace.useState(activeId);
1231
- const [visibleCount, setVisibleCount] = React7__namespace.useState(items.length);
1232
- const [menuOpen, setMenuOpen] = React7__namespace.useState(false);
1233
- const listRef = React7__namespace.useRef(null);
1234
- const tabRefs = React7__namespace.useRef(/* @__PURE__ */ new Map());
1235
- const itemWidths = React7__namespace.useRef(/* @__PURE__ */ new Map());
1236
- const focusRequestedByUser = React7__namespace.useRef(false);
1237
- React7__namespace.useEffect(() => setFocusedId(activeId), [activeId]);
1238
- const select = React7__namespace.useCallback(
1119
+ const [focusedId, setFocusedId] = React9__namespace.useState(activeId);
1120
+ const [visibleCount, setVisibleCount] = React9__namespace.useState(items.length);
1121
+ const [menuOpen, setMenuOpen] = React9__namespace.useState(false);
1122
+ const listRef = React9__namespace.useRef(null);
1123
+ const tabRefs = React9__namespace.useRef(/* @__PURE__ */ new Map());
1124
+ const itemWidths = React9__namespace.useRef(/* @__PURE__ */ new Map());
1125
+ const focusRequestedByUser = React9__namespace.useRef(false);
1126
+ React9__namespace.useEffect(() => setFocusedId(activeId), [activeId]);
1127
+ const select = React9__namespace.useCallback(
1239
1128
  (id) => {
1240
1129
  const item = items.find((candidate) => candidate.id === id);
1241
1130
  if (!item || item.disabled || item.isDisabled) return;
@@ -1247,7 +1136,7 @@ var Tabs = React7__namespace.forwardRef(
1247
1136
  },
1248
1137
  [controlled, items, onChange, onUpdate]
1249
1138
  );
1250
- const measure = React7__namespace.useCallback(() => {
1139
+ const measure = React9__namespace.useCallback(() => {
1251
1140
  const list = listRef.current;
1252
1141
  if (!list || items.length < 2) return;
1253
1142
  const available = list.offsetWidth;
@@ -1271,7 +1160,7 @@ var Tabs = React7__namespace.forwardRef(
1271
1160
  }
1272
1161
  setVisibleCount(Math.max(1, count));
1273
1162
  }, [items.length]);
1274
- React7__namespace.useLayoutEffect(() => {
1163
+ React9__namespace.useLayoutEffect(() => {
1275
1164
  measure();
1276
1165
  const list = listRef.current;
1277
1166
  if (!list || typeof ResizeObserver === "undefined") return void 0;
@@ -1299,7 +1188,7 @@ var Tabs = React7__namespace.forwardRef(
1299
1188
  if (!nextId) return;
1300
1189
  select(nextId);
1301
1190
  };
1302
- React7__namespace.useEffect(() => {
1191
+ React9__namespace.useEffect(() => {
1303
1192
  if (focusRequestedByUser.current && visibleItems.some((item) => item.id === focusedId)) {
1304
1193
  focusRequestedByUser.current = false;
1305
1194
  tabRefs.current.get(focusedId)?.focus();
@@ -1421,9 +1310,73 @@ var Tabs = React7__namespace.forwardRef(
1421
1310
  }
1422
1311
  );
1423
1312
  Tabs.displayName = "OODS.Tabs";
1313
+ var SegmentedControl = React9__namespace.forwardRef(
1314
+ ({
1315
+ id,
1316
+ label,
1317
+ options,
1318
+ value,
1319
+ defaultValue,
1320
+ name,
1321
+ size = "md",
1322
+ disabled,
1323
+ className,
1324
+ style,
1325
+ onChange,
1326
+ onValueChange,
1327
+ onUpdate,
1328
+ ...rest
1329
+ }, ref) => {
1330
+ const handleChange = (event) => {
1331
+ onChange?.(event);
1332
+ if (event.defaultPrevented) return;
1333
+ onValueChange?.(event.currentTarget.value);
1334
+ onUpdate?.(event.currentTarget.value);
1335
+ };
1336
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1337
+ "div",
1338
+ {
1339
+ className: className ? `oods-field oods-segmented-control ${className}` : "oods-field oods-segmented-control",
1340
+ style,
1341
+ "data-oods-component": "SegmentedControl",
1342
+ "data-size": size,
1343
+ children: [
1344
+ /* @__PURE__ */ jsxRuntime.jsx("span", { id: `${id}-label`, className: "oods-field-label", children: label }),
1345
+ /* @__PURE__ */ jsxRuntime.jsx(
1346
+ "div",
1347
+ {
1348
+ ref,
1349
+ id,
1350
+ role: "radiogroup",
1351
+ "aria-labelledby": `${id}-label`,
1352
+ className: "oods-segmented-control__track",
1353
+ ...rest,
1354
+ children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "oods-segmented-control__option", children: [
1355
+ /* @__PURE__ */ jsxRuntime.jsx(
1356
+ "input",
1357
+ {
1358
+ type: "radio",
1359
+ className: "oods-segmented-control__input",
1360
+ name: name || id,
1361
+ value: option.value,
1362
+ ...value === void 0 ? { defaultChecked: option.value === defaultValue } : { checked: option.value === value },
1363
+ disabled: disabled || option.disabled,
1364
+ onChange: handleChange
1365
+ }
1366
+ ),
1367
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oods-segmented-control__label", children: option.label })
1368
+ ] }, option.value))
1369
+ }
1370
+ )
1371
+ ]
1372
+ }
1373
+ );
1374
+ }
1375
+ );
1376
+ SegmentedControl.displayName = "OODS.SegmentedControl";
1424
1377
  var classes6 = (...values) => values.filter(Boolean).join(" ");
1425
1378
  var humanize = (value) => value.split(/[_-]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
1426
- var StatusBadge = React7__namespace.forwardRef(
1379
+ var StatusBadge = React9__namespace.forwardRef(
1427
1380
  ({
1428
1381
  status,
1429
1382
  value,
@@ -1446,7 +1399,7 @@ var StatusBadge = React7__namespace.forwardRef(
1446
1399
  ...rest
1447
1400
  }, ref) => {
1448
1401
  const resolvedStatus = status ?? value ?? "unknown";
1449
- const presentation = getStatusPresentation(domain, resolvedStatus);
1402
+ const presentation = componentContracts.getStatusPresentation(domain, resolvedStatus);
1450
1403
  return /* @__PURE__ */ jsxRuntime.jsx(
1451
1404
  Badge,
1452
1405
  {
@@ -1467,8 +1420,8 @@ var StatusBadge = React7__namespace.forwardRef(
1467
1420
  }
1468
1421
  );
1469
1422
  StatusBadge.displayName = "OODS.StatusBadge";
1470
- function formatPrice(amount, currency, fallback2) {
1471
- if (amount === void 0 || !Number.isFinite(amount)) return fallback2;
1423
+ function formatPrice(amount, currency, fallback) {
1424
+ if (amount === void 0 || !Number.isFinite(amount)) return fallback;
1472
1425
  if (!currency) return new Intl.NumberFormat(void 0, { maximumFractionDigits: 2 }).format(amount);
1473
1426
  try {
1474
1427
  return new Intl.NumberFormat(void 0, {
@@ -1479,7 +1432,7 @@ function formatPrice(amount, currency, fallback2) {
1479
1432
  return `${currency.toUpperCase()} ${amount.toFixed(2)}`;
1480
1433
  }
1481
1434
  }
1482
- var PriceBadge = React7__namespace.forwardRef(
1435
+ var PriceBadge = React9__namespace.forwardRef(
1483
1436
  ({
1484
1437
  amountCents,
1485
1438
  unitAmountCents,
@@ -1554,7 +1507,7 @@ function normalizeTimelineEvents(values) {
1554
1507
  }];
1555
1508
  });
1556
1509
  }
1557
- var TimelinePrimitive = React7__namespace.forwardRef(
1510
+ var TimelinePrimitive = React9__namespace.forwardRef(
1558
1511
  ({
1559
1512
  componentId,
1560
1513
  defaultTitle,
@@ -1632,7 +1585,7 @@ var TimelinePrimitive = React7__namespace.forwardRef(
1632
1585
  }
1633
1586
  );
1634
1587
  TimelinePrimitive.displayName = "OODS.TimelinePrimitive";
1635
- var StatusTimeline = React7__namespace.forwardRef(
1588
+ var StatusTimeline = React9__namespace.forwardRef(
1636
1589
  (props, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1637
1590
  TimelinePrimitive,
1638
1591
  {
@@ -1645,7 +1598,7 @@ var StatusTimeline = React7__namespace.forwardRef(
1645
1598
  )
1646
1599
  );
1647
1600
  StatusTimeline.displayName = "OODS.StatusTimeline";
1648
- var AuditTimeline = React7__namespace.forwardRef(
1601
+ var AuditTimeline = React9__namespace.forwardRef(
1649
1602
  ({ auditLog, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1650
1603
  TimelinePrimitive,
1651
1604
  {
@@ -1659,7 +1612,7 @@ var AuditTimeline = React7__namespace.forwardRef(
1659
1612
  )
1660
1613
  );
1661
1614
  AuditTimeline.displayName = "OODS.AuditTimeline";
1662
- var CancellationSummary = React7__namespace.forwardRef(
1615
+ var CancellationSummary = React9__namespace.forwardRef(
1663
1616
  ({
1664
1617
  label,
1665
1618
  title = label ?? "Cancellation Summary",
@@ -1716,7 +1669,7 @@ var CancellationSummary = React7__namespace.forwardRef(
1716
1669
  }
1717
1670
  );
1718
1671
  CancellationSummary.displayName = "OODS.CancellationSummary";
1719
- var SearchInput = React7__namespace.forwardRef(
1672
+ var SearchInput = React9__namespace.forwardRef(
1720
1673
  ({
1721
1674
  id,
1722
1675
  label = "Search",
@@ -1742,13 +1695,13 @@ var SearchInput = React7__namespace.forwardRef(
1742
1695
  onKeyDown,
1743
1696
  ...rest
1744
1697
  }, ref) => {
1745
- const generatedId = React7__namespace.useId();
1698
+ const generatedId = React9__namespace.useId();
1746
1699
  const resolvedId = id ?? `oods-search-${generatedId.replace(/:/g, "")}`;
1747
- const [uncontrolledValue, setUncontrolledValue] = React7__namespace.useState(defaultValue);
1700
+ const [uncontrolledValue, setUncontrolledValue] = React9__namespace.useState(defaultValue);
1748
1701
  const currentValue = value ?? uncontrolledValue;
1749
- const timerRef = React7__namespace.useRef(void 0);
1702
+ const timerRef = React9__namespace.useRef(void 0);
1750
1703
  const delay = Math.max(0, debounceMs ?? debounce ?? 0);
1751
- React7__namespace.useEffect(() => () => {
1704
+ React9__namespace.useEffect(() => () => {
1752
1705
  if (timerRef.current !== void 0) clearTimeout(timerRef.current);
1753
1706
  }, []);
1754
1707
  const publish = (nextValue) => {
@@ -1811,7 +1764,7 @@ var SearchInput = React7__namespace.forwardRef(
1811
1764
  "aria-label": "Clear search",
1812
1765
  disabled,
1813
1766
  onClick: clear,
1814
- children: "\xD7"
1767
+ children: /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { name: "x" })
1815
1768
  }
1816
1769
  ) : null
1817
1770
  ]
@@ -1832,7 +1785,7 @@ function visiblePages(page, totalPages) {
1832
1785
  }
1833
1786
  return result;
1834
1787
  }
1835
- var PaginationBar = React7__namespace.forwardRef(
1788
+ var PaginationBar = React9__namespace.forwardRef(
1836
1789
  ({
1837
1790
  page = 1,
1838
1791
  pageSize = 25,
@@ -1973,7 +1926,7 @@ function relativeLabel(date, now) {
1973
1926
  unit
1974
1927
  );
1975
1928
  }
1976
- var RelativeTimestamp = React7__namespace.forwardRef(
1929
+ var RelativeTimestamp = React9__namespace.forwardRef(
1977
1930
  ({
1978
1931
  datetime,
1979
1932
  timestamp,
@@ -1999,7 +1952,7 @@ var RelativeTimestamp = React7__namespace.forwardRef(
1999
1952
  const date = asDate(raw);
2000
1953
  if (hideWhenEmpty && !date) return null;
2001
1954
  const nowDate = asDate(now) ?? /* @__PURE__ */ new Date();
2002
- const iso = date?.toISOString() ?? (raw === void 0 ? void 0 : String(raw));
1955
+ const iso = date?.toISOString() ?? (raw === void 0 || raw === "" ? void 0 : String(raw));
2003
1956
  const absolute = componentContracts.formatDateTime(date, { timeZone: timezone });
2004
1957
  const content = relative ?? label ?? text ?? (now !== void 0 && date ? relativeLabel(date, nowDate) : absolute || children || "Unknown time");
2005
1958
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2021,8 +1974,8 @@ RelativeTimestamp.displayName = "OODS.RelativeTimestamp";
2021
1974
  var classes7 = (...values) => values.filter(Boolean).join(" ");
2022
1975
  var firstText = (...values) => values.find((value) => typeof value === "string" && value.trim().length > 0);
2023
1976
  function childContent(children) {
2024
- const flatten = (value) => React7__namespace.Children.toArray(value).flatMap((node) => {
2025
- if (React7__namespace.isValidElement(node) && node.type === React7__namespace.Fragment) {
1977
+ const flatten = (value) => React9__namespace.Children.toArray(value).flatMap((node) => {
1978
+ if (React9__namespace.isValidElement(node) && node.type === React9__namespace.Fragment) {
2026
1979
  return flatten(node.props.children);
2027
1980
  }
2028
1981
  return [node];
@@ -2034,16 +1987,16 @@ function childContent(children) {
2034
1987
  }
2035
1988
  return { authored: nodes.length > 0 };
2036
1989
  }
2037
- function headingElement(as, level, fallback2) {
1990
+ function headingElement(as, level, fallback) {
2038
1991
  if (as && /^h[1-6]$/.test(as)) return as;
2039
- const bounded = Number.isFinite(level) ? Math.max(1, Math.min(6, Math.trunc(level))) : fallback2;
1992
+ const bounded = Number.isFinite(level) ? Math.max(1, Math.min(6, Math.trunc(level))) : fallback;
2040
1993
  return `h${bounded}`;
2041
1994
  }
2042
1995
  function notEcho(supporting, heading) {
2043
1996
  if (!supporting || !heading) return supporting;
2044
1997
  return supporting.trim() === heading.trim() ? void 0 : supporting;
2045
1998
  }
2046
- var DetailHeader = React7__namespace.forwardRef(
1999
+ var DetailHeader = React9__namespace.forwardRef(
2047
2000
  ({ title, label, text, subtitle, sublabel, description, metadata, meta, level, as, children, className, ...rest }, ref) => {
2048
2001
  const Heading = headingElement(as, level, 2);
2049
2002
  const content = childContent(children);
@@ -2058,7 +2011,7 @@ var DetailHeader = React7__namespace.forwardRef(
2058
2011
  }
2059
2012
  );
2060
2013
  DetailHeader.displayName = "OODS.DetailHeader";
2061
- var CardHeader = React7__namespace.forwardRef(
2014
+ var CardHeader = React9__namespace.forwardRef(
2062
2015
  ({ title, label, text, supporting, supportingText, subtitle, description, level, as, children, className, ...rest }, ref) => {
2063
2016
  const Heading = headingElement(as, level, 2);
2064
2017
  const content = childContent(children);
@@ -2071,7 +2024,7 @@ var CardHeader = React7__namespace.forwardRef(
2071
2024
  }
2072
2025
  );
2073
2026
  CardHeader.displayName = "OODS.CardHeader";
2074
- var ColorSwatch = React7__namespace.forwardRef(
2027
+ var ColorSwatch = React9__namespace.forwardRef(
2075
2028
  ({ color, value, state, label, children, className, style, ...rest }, ref) => {
2076
2029
  const resolvedColor = firstText(color, value, state);
2077
2030
  const content = childContent(children);
@@ -2096,7 +2049,7 @@ var ColorSwatch = React7__namespace.forwardRef(
2096
2049
  }
2097
2050
  );
2098
2051
  ColorSwatch.displayName = "OODS.ColorSwatch";
2099
- var ColorizedBadge = React7__namespace.forwardRef(
2052
+ var ColorizedBadge = React9__namespace.forwardRef(
2100
2053
  ({ label, text, state, value, status, color, hue, swatch, variant, tone, emphasis, children, className, style, ...rest }, ref) => {
2101
2054
  const content = childContent(children);
2102
2055
  const resolvedLabel = content.scalar ?? firstText(label, text, state, value) ?? "Color";
@@ -2126,10 +2079,12 @@ var ColorizedBadge = React7__namespace.forwardRef(
2126
2079
  }
2127
2080
  );
2128
2081
  ColorizedBadge.displayName = "OODS.ColorizedBadge";
2129
- var VizAreaPreview = React7__namespace.forwardRef(
2130
- ({ width = 640, height = 360, svg, svgNarrow, svgWide, title, description, children, className, style, ...rest }, ref) => {
2082
+ var VizAreaPreview = React9__namespace.forwardRef(
2083
+ ({ width = 640, height = 360, svg, svgNarrow, svgWide, svgDark, svgDarkNarrow, svgDarkWide, svgHc, svgHcNarrow, svgHcWide, title, description, children, className, style, ...rest }, ref) => {
2131
2084
  const content = childContent(children);
2132
2085
  if (svg !== void 0) {
2086
+ const layers = componentContracts.vizPreviewLayers({ svg, svgNarrow, svgWide, svgDark, svgDarkNarrow, svgDarkWide, svgHc, svgHcNarrow, svgHcWide });
2087
+ const renders = (layer) => layer.renders.map(([attribute, markup]) => /* @__PURE__ */ jsxRuntime.jsx("div", { ...{ [attribute]: "true" }, dangerouslySetInnerHTML: { __html: markup } }, attribute));
2133
2088
  return /* @__PURE__ */ jsxRuntime.jsxs(
2134
2089
  "figure",
2135
2090
  {
@@ -2148,9 +2103,7 @@ var VizAreaPreview = React7__namespace.forwardRef(
2148
2103
  ...rest,
2149
2104
  children: [
2150
2105
  title && !componentContracts.svgCarriesTitle(svg, title) ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { children: title }) : null,
2151
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-viz-svg": "true", dangerouslySetInnerHTML: { __html: componentContracts.assertStaticSvg(svg) } }),
2152
- svgNarrow !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-viz-svg-narrow": "true", dangerouslySetInnerHTML: { __html: componentContracts.assertStaticSvg(svgNarrow) } }) : null,
2153
- svgWide !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-viz-svg-wide": "true", dangerouslySetInnerHTML: { __html: componentContracts.assertStaticSvg(svgWide) } }) : null,
2106
+ layers.map((layer) => layer.theme === void 0 ? renders(layer) : /* @__PURE__ */ jsxRuntime.jsx("div", { "data-viz-theme": layer.theme, "data-viz-narrow": layer.narrow ? "true" : void 0, "data-viz-wide": layer.wide ? "true" : void 0, children: renders(layer) }, layer.theme)),
2154
2107
  description ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-viz-description": "true", children: description }) : null
2155
2108
  ]
2156
2109
  }
@@ -2195,13 +2148,13 @@ var descriptorLabel = (descriptor) => firstText(
2195
2148
  typeof descriptor.field === "string" ? descriptor.field : void 0
2196
2149
  ) ?? "Filter";
2197
2150
  function createPanelSection(component, className, panelType, defaultTitle) {
2198
- const Panel = React7__namespace.forwardRef(
2151
+ const Panel = React9__namespace.forwardRef(
2199
2152
  ({ title, label, heading, name, subtitle, description, metadata, summary: summary2, text, body, emptyMessage, children, className: consumerClassName, ...rest }, ref) => {
2200
2153
  const content = childContent(children);
2201
2154
  const authored = content.authored || content.scalar !== void 0;
2202
2155
  const resolvedTitle = firstText(title, label, heading, name) ?? defaultTitle;
2203
2156
  const resolvedSubtitle = firstText(subtitle, description, metadata);
2204
- const fallback2 = firstText(summary2, text, body, emptyMessage);
2157
+ const fallback = firstText(summary2, text, body, emptyMessage);
2205
2158
  return /* @__PURE__ */ jsxRuntime.jsxs(
2206
2159
  "section",
2207
2160
  {
@@ -2215,7 +2168,7 @@ function createPanelSection(component, className, panelType, defaultTitle) {
2215
2168
  /* @__PURE__ */ jsxRuntime.jsx("h2", { children: resolvedTitle }),
2216
2169
  resolvedSubtitle ? /* @__PURE__ */ jsxRuntime.jsx("span", { "data-panel-subtitle": "true", children: resolvedSubtitle }) : null
2217
2170
  ] }),
2218
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-panel-content": "true", children: authored ? children : fallback2 ? /* @__PURE__ */ jsxRuntime.jsx("span", { "data-panel-summary": "true", children: fallback2 }) : null })
2171
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-panel-content": "true", children: authored ? children : fallback ? /* @__PURE__ */ jsxRuntime.jsx("span", { "data-panel-summary": "true", children: fallback }) : null })
2219
2172
  ]
2220
2173
  }
2221
2174
  );
@@ -2228,7 +2181,7 @@ var ClassificationPanel = createPanelSection("ClassificationPanel", "oods-classi
2228
2181
  var AddressCollectionPanel = createPanelSection("AddressCollectionPanel", "oods-address-collection-panel", "address", "Addresses");
2229
2182
  var MembershipPanel = createPanelSection("MembershipPanel", "oods-membership-panel", "membership", "Membership");
2230
2183
  var PreferencePanel = createPanelSection("PreferencePanel", "oods-preference-panel", "preference", "Preferences");
2231
- var FilterPanel = React7__namespace.forwardRef(
2184
+ var FilterPanel = React9__namespace.forwardRef(
2232
2185
  ({ filters, activeFilters, mode, collapsible = true, children, className, ...rest }, ref) => {
2233
2186
  const content = childContent(children);
2234
2187
  const authored = content.authored || content.scalar !== void 0;
@@ -2262,7 +2215,7 @@ var FilterPanel = React7__namespace.forwardRef(
2262
2215
  }
2263
2216
  );
2264
2217
  FilterPanel.displayName = "OODS.FilterPanel";
2265
- var PriceSummary = React7__namespace.forwardRef(
2218
+ var PriceSummary = React9__namespace.forwardRef(
2266
2219
  ({
2267
2220
  title,
2268
2221
  label,
@@ -2295,7 +2248,7 @@ var PriceSummary = React7__namespace.forwardRef(
2295
2248
  ["Interval", componentContracts.formatPriceCode(interval ?? billingInterval)]
2296
2249
  ];
2297
2250
  const terms = entries.filter((entry) => entry[1] !== void 0);
2298
- const fallback2 = firstText(summary2, text, description);
2251
+ const fallback = firstText(summary2, text, description);
2299
2252
  return /* @__PURE__ */ jsxRuntime.jsxs(
2300
2253
  "section",
2301
2254
  {
@@ -2309,7 +2262,7 @@ var PriceSummary = React7__namespace.forwardRef(
2309
2262
  authored ? children : terms.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("dl", { children: terms.map(([term, value]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-summary-item": "true", children: [
2310
2263
  /* @__PURE__ */ jsxRuntime.jsx("dt", { children: term }),
2311
2264
  /* @__PURE__ */ jsxRuntime.jsx("dd", { children: value })
2312
- ] }, term)) }) : fallback2 ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-summary-fallback": "true", children: fallback2 }) : /* @__PURE__ */ jsxRuntime.jsx("dl", {})
2265
+ ] }, term)) }) : fallback ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-summary-fallback": "true", children: fallback }) : /* @__PURE__ */ jsxRuntime.jsx("dl", {})
2313
2266
  ]
2314
2267
  }
2315
2268
  );
@@ -2335,7 +2288,7 @@ var normalizeTagItems = (value) => {
2335
2288
  }
2336
2289
  return items.filter((item) => item.length > 0);
2337
2290
  };
2338
- var TagManager = React7__namespace.forwardRef(
2291
+ var TagManager = React9__namespace.forwardRef(
2339
2292
  ({ title, label, heading, name, description, subtitle, hint, tags, value, children, className, onSubmit, ...rest }, ref) => {
2340
2293
  const content = childContent(children);
2341
2294
  const authored = content.authored || content.scalar !== void 0;
@@ -2381,10 +2334,12 @@ var asCount = (value) => {
2381
2334
  return void 0;
2382
2335
  };
2383
2336
  function createBadgeFamily(options) {
2384
- const consumed = /* @__PURE__ */ new Set([...options.labelKeys, ...options.statusKeys, "variant", "tone", "emphasis"]);
2385
- const Family = React7__namespace.forwardRef((allProps, ref) => {
2337
+ const consumed = /* @__PURE__ */ new Set([...options.labelKeys, ...options.statusKeys, "variant", "tone", "emphasis", ...options.booleanProps ? ["hideWhenFalse"] : []]);
2338
+ const Family = React9__namespace.forwardRef((allProps, ref) => {
2386
2339
  const { children, className, ...rest } = allProps;
2387
2340
  const record = rest;
2341
+ const flag = options.booleanProps?.map((key) => record[key]).find((value) => typeof value === "boolean");
2342
+ if (record.hideWhenFalse === true && flag === false) return null;
2388
2343
  const scalar = (key) => {
2389
2344
  const value = record[key];
2390
2345
  if (typeof value === "boolean" && options.booleanProps?.includes(key)) return String(value);
@@ -2442,7 +2397,7 @@ var PreferenceSummaryBadge = createBadgeFamily({
2442
2397
  labelKeys: ["label", "text", "namespace", "value"],
2443
2398
  statusKeys: ["status", "state", "version"]
2444
2399
  });
2445
- var RoleBadgeList = React7__namespace.forwardRef(
2400
+ var RoleBadgeList = React9__namespace.forwardRef(
2446
2401
  ({ roles, badges, roleLabels, value, variant, tone, label, text, children, className, ...rest }, ref) => {
2447
2402
  const content = childContent(children);
2448
2403
  const authored = content.authored || content.scalar !== void 0;
@@ -2462,7 +2417,7 @@ var RoleBadgeList = React7__namespace.forwardRef(
2462
2417
  }
2463
2418
  );
2464
2419
  RoleBadgeList.displayName = "OODS.RoleBadgeList";
2465
- var TagPills = React7__namespace.forwardRef(
2420
+ var TagPills = React9__namespace.forwardRef(
2466
2421
  ({ tags, value, maxVisible, overflowLabel, children, className, ...rest }, ref) => {
2467
2422
  const content = childContent(children);
2468
2423
  const authored = content.authored || content.scalar !== void 0;
@@ -2514,7 +2469,7 @@ var normalizeTimelineItems = (raw) => {
2514
2469
  };
2515
2470
  function createTimelineFamily(options) {
2516
2471
  const consumed = /* @__PURE__ */ new Set(["title", "label", "heading", "name", ...options.eventKeys]);
2517
- const Family = React7__namespace.forwardRef((allProps, ref) => {
2472
+ const Family = React9__namespace.forwardRef((allProps, ref) => {
2518
2473
  const { children, className, ...rest } = allProps;
2519
2474
  const record = rest;
2520
2475
  const text = (key) => {
@@ -2579,7 +2534,7 @@ var PreferenceTimeline = createTimelineFamily({
2579
2534
  timelineType: "preference",
2580
2535
  eventKeys: ["events", "changes", "history"]
2581
2536
  });
2582
- var AuditEvent = React7__namespace.forwardRef(
2537
+ var AuditEvent = React9__namespace.forwardRef(
2583
2538
  ({
2584
2539
  label,
2585
2540
  title,
@@ -2665,7 +2620,7 @@ var addressRecord = (form) => {
2665
2620
  };
2666
2621
  return { street: read("street"), city: read("city"), region: read("region"), postalCode: read("postalCode") };
2667
2622
  };
2668
- var AddressEditor = React7__namespace.forwardRef(
2623
+ var AddressEditor = React9__namespace.forwardRef(
2669
2624
  ({
2670
2625
  title,
2671
2626
  label,
@@ -2723,8 +2678,8 @@ var AddressEditor = React7__namespace.forwardRef(
2723
2678
  }
2724
2679
  );
2725
2680
  AddressEditor.displayName = "OODS.AddressEditor";
2726
- var PreferenceEditor = React7__namespace.forwardRef(
2727
- ({ title, label, heading, name, description, subtitle, hint, namespaces, namespace, document, json, value, children, className, onSubmit, ...rest }, ref) => {
2681
+ var PreferenceEditor = React9__namespace.forwardRef(
2682
+ ({ title, label, heading, name, description, subtitle, hint, namespaces, namespace, document: document2, json, value, children, className, onSubmit, ...rest }, ref) => {
2728
2683
  const content = childContent(children);
2729
2684
  const authored = content.authored || content.scalar !== void 0;
2730
2685
  const resolvedTitle = firstText(title, label, heading, name) ?? "Preference Editor";
@@ -2751,7 +2706,7 @@ var PreferenceEditor = React7__namespace.forwardRef(
2751
2706
  ] }),
2752
2707
  /* @__PURE__ */ jsxRuntime.jsxs("label", { "data-form-control": "textarea", children: [
2753
2708
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Preference Document" }),
2754
- /* @__PURE__ */ jsxRuntime.jsx("textarea", { name: "preferenceDocument", defaultValue: firstScalar(document, json, value) ?? "" })
2709
+ /* @__PURE__ */ jsxRuntime.jsx("textarea", { name: "preferenceDocument", defaultValue: firstScalar(document2, json, value) ?? "" })
2755
2710
  ] })
2756
2711
  ] }) })
2757
2712
  ]
@@ -2760,7 +2715,7 @@ var PreferenceEditor = React7__namespace.forwardRef(
2760
2715
  }
2761
2716
  );
2762
2717
  PreferenceEditor.displayName = "OODS.PreferenceEditor";
2763
- var RoleAssignmentForm = React7__namespace.forwardRef(
2718
+ var RoleAssignmentForm = React9__namespace.forwardRef(
2764
2719
  ({ title, label, heading, name, description, subtitle, hint, roles, availableRoles, role, defaultRoleId, assignee, member, children, className, onSubmit, ...rest }, ref) => {
2765
2720
  const content = childContent(children);
2766
2721
  const authored = content.authored || content.scalar !== void 0;
@@ -2797,7 +2752,7 @@ var RoleAssignmentForm = React7__namespace.forwardRef(
2797
2752
  }
2798
2753
  );
2799
2754
  RoleAssignmentForm.displayName = "OODS.RoleAssignmentForm";
2800
- var StatusSelector = React7__namespace.forwardRef(
2755
+ var StatusSelector = React9__namespace.forwardRef(
2801
2756
  ({ label, title, help, options, states, value, status, children, className, onChange, onValueChange, onUpdate, ...rest }, ref) => {
2802
2757
  const content = childContent(children);
2803
2758
  const authored = content.authored || content.scalar !== void 0;
@@ -2839,7 +2794,7 @@ var StatusSelector = React7__namespace.forwardRef(
2839
2794
  }
2840
2795
  );
2841
2796
  StatusSelector.displayName = "OODS.StatusSelector";
2842
- var TagInput = React7__namespace.forwardRef(
2797
+ var TagInput = React9__namespace.forwardRef(
2843
2798
  ({ title, label, heading, name, description, subtitle, hint, tags, value, placeholder, children, className, onChange, onValueChange, onUpdate, ...rest }, ref) => {
2844
2799
  const content = childContent(children);
2845
2800
  const authored = content.authored || content.scalar !== void 0;
@@ -2886,7 +2841,7 @@ var TagInput = React7__namespace.forwardRef(
2886
2841
  }
2887
2842
  );
2888
2843
  TagInput.displayName = "OODS.TagInput";
2889
- var TemplatePicker = React7__namespace.forwardRef(
2844
+ var TemplatePicker = React9__namespace.forwardRef(
2890
2845
  ({ title, label, heading, name, description, subtitle, hint, templates, options, templateId, value, channels, channel, children, className, ...rest }, ref) => {
2891
2846
  const content = childContent(children);
2892
2847
  const authored = content.authored || content.scalar !== void 0;
@@ -2924,14 +2879,14 @@ var truncateLabel = (value, maxLength) => {
2924
2879
  const limit = typeof maxLength === "number" ? maxLength : Number(maxLength);
2925
2880
  return !Number.isFinite(limit) || limit <= 0 || value.length <= limit ? value : `${value.slice(0, Math.max(0, limit - 1)).trimEnd()}...`;
2926
2881
  };
2927
- var InlineLabel = React7__namespace.forwardRef(
2882
+ var InlineLabel = React9__namespace.forwardRef(
2928
2883
  ({ label, text, value, maxLength, children, className, ...rest }, ref) => {
2929
2884
  const content = childContent(children);
2930
2885
  return /* @__PURE__ */ jsxRuntime.jsx("span", { ref, className: classes7("oods-inline-label", className), "data-oods-component": "InlineLabel", ...rest, children: content.authored || content.scalar !== void 0 ? children : truncateLabel(firstText(label, text, value) ?? "", maxLength) });
2931
2886
  }
2932
2887
  );
2933
2888
  InlineLabel.displayName = "OODS.InlineLabel";
2934
- var LabelCell = React7__namespace.forwardRef(
2889
+ var LabelCell = React9__namespace.forwardRef(
2935
2890
  ({ label, text, value, description, subtitle, sublabel, supporting, truncate, maxLength, children, className, ...rest }, ref) => {
2936
2891
  const content = childContent(children);
2937
2892
  const limit = truncate ? maxLength ?? 40 : maxLength;
@@ -2944,7 +2899,7 @@ var LabelCell = React7__namespace.forwardRef(
2944
2899
  }
2945
2900
  );
2946
2901
  LabelCell.displayName = "OODS.LabelCell";
2947
- var FormLabelGroup = React7__namespace.forwardRef(
2902
+ var FormLabelGroup = React9__namespace.forwardRef(
2948
2903
  ({ label, text, title, placeholder, hint, description, htmlFor, for: forId, inputId, children, className, ...rest }, ref) => {
2949
2904
  const detail = firstText(placeholder, hint, description);
2950
2905
  return /* @__PURE__ */ jsxRuntime.jsxs("label", { ref, className: classes7("oods-form-label-group", className), "data-oods-component": "FormLabelGroup", htmlFor: htmlFor ?? forId ?? inputId, ...rest, children: [
@@ -2963,7 +2918,7 @@ var ClassificationBadge = createBadgeFamily({
2963
2918
  labelKeys: ["label", "text", "category", "value"],
2964
2919
  statusKeys: ["status", "state", "mode"]
2965
2920
  });
2966
- var ClassificationEditor = React7__namespace.forwardRef(
2921
+ var ClassificationEditor = React9__namespace.forwardRef(
2967
2922
  ({ title, label, heading, name, description, subtitle, hint, category, primaryCategory, tags, modes, mode, classificationMode, children, className, onSubmit, ...rest }, ref) => {
2968
2923
  const content = childContent(children);
2969
2924
  const tagText = typeof tags === "string" ? tags : tags === void 0 ? "" : JSON.stringify(tags);
@@ -3009,42 +2964,43 @@ var OwnerBadge = createBadgeFamily({
3009
2964
  labelKeys: ["label", "text", "owner", "ownerType", "value"],
3010
2965
  statusKeys: ["status", "state"]
3011
2966
  });
3012
- var OwnershipSummary = React7__namespace.forwardRef(
2967
+ var OwnershipSummary = React9__namespace.forwardRef(
3013
2968
  ({ title, label, heading, name, ownerLabel, ownerId, owner_id, ownerType, owner_type, role, ownershipRole, summary: summary2, text, description, children, className, ...rest }, ref) => {
3014
2969
  const content = childContent(children);
3015
2970
  const terms = [["Owner", ownerId === void 0 && owner_id === void 0 && ownerLabel === void 0 ? void 0 : componentContracts.formatReferenceLabel(ownerId ?? owner_id, ownerLabel, "Owner")], ["Owner Type", firstScalar(ownerType, owner_type)], ["Role", firstScalar(role, ownershipRole)]].filter((entry) => entry[1] !== void 0);
3016
- const fallback2 = firstText(summary2, text, description);
2971
+ const fallback = firstText(summary2, text, description);
3017
2972
  return /* @__PURE__ */ jsxRuntime.jsxs("section", { ref, className: classes7("oods-ownership-summary", className), "data-oods-component": "OwnershipSummary", "data-summary-type": "ownership", ...rest, children: [
3018
2973
  /* @__PURE__ */ jsxRuntime.jsx("h2", { "data-summary-title": "true", children: firstText(title, label, heading, name) ?? "Ownership Summary" }),
3019
2974
  content.authored || content.scalar !== void 0 ? children : terms.length ? /* @__PURE__ */ jsxRuntime.jsx("dl", { children: terms.map(([term, value]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-summary-item": "true", children: [
3020
2975
  /* @__PURE__ */ jsxRuntime.jsx("dt", { children: term }),
3021
2976
  /* @__PURE__ */ jsxRuntime.jsx("dd", { children: value })
3022
- ] }, term)) }) : fallback2 ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-summary-fallback": "true", children: fallback2 }) : /* @__PURE__ */ jsxRuntime.jsx("dl", {})
2977
+ ] }, term)) }) : fallback ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-summary-fallback": "true", children: fallback }) : /* @__PURE__ */ jsxRuntime.jsx("dl", {})
3023
2978
  ] });
3024
2979
  }
3025
2980
  );
3026
2981
  OwnershipSummary.displayName = "OODS.OwnershipSummary";
3027
- var TagSummary = React7__namespace.forwardRef(
2982
+ var TagSummary = React9__namespace.forwardRef(
3028
2983
  ({ title, label, heading, name, tagCount, count, tags, summary: summary2, text, description, children, className, ...rest }, ref) => {
3029
2984
  const content = childContent(children);
3030
2985
  const tagText = Array.isArray(tags) ? normalizeTagItems(tags).join(", ") || void 0 : firstText(tags);
3031
2986
  const terms = [["Tag Count", firstScalar(tagCount, count)], ["Tags", tagText]].filter((entry) => entry[1] !== void 0);
3032
- const fallback2 = firstText(summary2, text, description);
2987
+ const fallback = firstText(summary2, text, description);
3033
2988
  return /* @__PURE__ */ jsxRuntime.jsxs("section", { ref, className: classes7("oods-tags-summary", className), "data-oods-component": "TagSummary", "data-summary-type": "tags", ...rest, children: [
3034
2989
  /* @__PURE__ */ jsxRuntime.jsx("h2", { "data-summary-title": "true", children: firstText(title, label, heading, name) ?? "Tag Summary" }),
3035
2990
  content.authored || content.scalar !== void 0 ? children : terms.length ? /* @__PURE__ */ jsxRuntime.jsx("dl", { children: terms.map(([term, value]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-summary-item": "true", children: [
3036
2991
  /* @__PURE__ */ jsxRuntime.jsx("dt", { children: term }),
3037
2992
  /* @__PURE__ */ jsxRuntime.jsx("dd", { children: value })
3038
- ] }, term)) }) : fallback2 ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-summary-fallback": "true", children: fallback2 }) : /* @__PURE__ */ jsxRuntime.jsx("dl", {})
2993
+ ] }, term)) }) : fallback ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-summary-fallback": "true", children: fallback }) : /* @__PURE__ */ jsxRuntime.jsx("dl", {})
3039
2994
  ] });
3040
2995
  }
3041
2996
  );
3042
2997
  TagSummary.displayName = "OODS.TagSummary";
3043
- var OwnershipMeta = React7__namespace.forwardRef(
3044
- ({ title, label, heading, name, ownerType, owner_type, role, ownershipRole, children, className, ...rest }, ref) => {
2998
+ var OwnershipMeta = React9__namespace.forwardRef(
2999
+ ({ title, label, heading, name, ownerType, owner_type, role, ownershipRole, ownerLabel, children, className, ...rest }, ref) => {
3045
3000
  const content = childContent(children);
3046
3001
  const terms = [["Owner Type", firstScalar(ownerType, owner_type)], ["Role", firstScalar(role, ownershipRole)]].filter((entry) => entry[1] !== void 0);
3047
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: classes7("oods-ownership-meta", className), "data-oods-component": "OwnershipMeta", "data-meta-type": "ownership", ...rest, children: content.authored || content.scalar !== void 0 ? children : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3002
+ const phrase = ownerLabel !== void 0 ? componentContracts.ownershipPhrase(ownerLabel, firstScalar(ownerType, owner_type), firstScalar(role, ownershipRole)) : void 0;
3003
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: classes7("oods-ownership-meta", className), "data-oods-component": "OwnershipMeta", "data-meta-type": "ownership", ...rest, children: content.authored || content.scalar !== void 0 ? children : phrase ? /* @__PURE__ */ jsxRuntime.jsx("span", { "data-meta-item": "true", children: phrase }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3048
3004
  /* @__PURE__ */ jsxRuntime.jsx("span", { "data-meta-title": "true", children: firstText(title, label, heading, name) ?? "Ownership" }),
3049
3005
  terms.map(([term, value]) => /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-meta-item": "true", children: [
3050
3006
  /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
@@ -3078,22 +3034,22 @@ var CancellationBadge = createBadgeFamily({
3078
3034
  booleanProps: ["cancelAtPeriodEnd", "isCancelled", "value"],
3079
3035
  booleanLabels: ["Cancellation scheduled", "No cancellation scheduled"]
3080
3036
  });
3081
- var ArchiveSummary = React7__namespace.forwardRef(
3037
+ var ArchiveSummary = React9__namespace.forwardRef(
3082
3038
  ({ title, label, heading, name, isArchived, archived, status, archivedAt, reason, archiveReason, summary: summary2, text, description, children, className, ...rest }, ref) => {
3083
3039
  const content = childContent(children);
3084
3040
  const terms = [["Archived", componentContracts.summaryValue(isArchived ?? archived ?? status)], ["Archived At", archivedAt ? componentContracts.formatDateTime(archivedAt) : void 0], ["Reason", firstText(reason, archiveReason)]].filter((entry) => entry[1] !== void 0);
3085
- const fallback2 = firstText(summary2, text, description);
3041
+ const fallback = firstText(summary2, text, description);
3086
3042
  return /* @__PURE__ */ jsxRuntime.jsxs("section", { ref, className: classes7("oods-archive-summary", className), "data-oods-component": "ArchiveSummary", "data-summary-type": "archive", ...rest, children: [
3087
3043
  /* @__PURE__ */ jsxRuntime.jsx("h2", { "data-summary-title": "true", children: firstText(title, label, heading, name) ?? "Archive Summary" }),
3088
3044
  content.authored || content.scalar !== void 0 ? children : terms.length ? /* @__PURE__ */ jsxRuntime.jsx("dl", { children: terms.map(([term, value]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-summary-item": "true", children: [
3089
3045
  /* @__PURE__ */ jsxRuntime.jsx("dt", { children: term }),
3090
3046
  /* @__PURE__ */ jsxRuntime.jsx("dd", { children: value })
3091
- ] }, term)) }) : fallback2 ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-summary-fallback": "true", children: fallback2 }) : /* @__PURE__ */ jsxRuntime.jsx("dl", {})
3047
+ ] }, term)) }) : fallback ? /* @__PURE__ */ jsxRuntime.jsx("p", { "data-summary-fallback": "true", children: fallback }) : /* @__PURE__ */ jsxRuntime.jsx("dl", {})
3092
3048
  ] });
3093
3049
  }
3094
3050
  );
3095
3051
  ArchiveSummary.displayName = "OODS.ArchiveSummary";
3096
- var PriceCardMeta = React7__namespace.forwardRef(
3052
+ var PriceCardMeta = React9__namespace.forwardRef(
3097
3053
  ({ title, label, heading, name, model, pricingModel, interval, billingInterval, children, className, ...rest }, ref) => {
3098
3054
  const content = childContent(children);
3099
3055
  const terms = [["Model", componentContracts.formatPriceCode(firstText(model, pricingModel))], ["Interval", componentContracts.formatPriceCode(firstText(interval, billingInterval))]].filter((entry) => entry[1] !== void 0);
@@ -3111,12 +3067,12 @@ var PriceCardMeta = React7__namespace.forwardRef(
3111
3067
  }
3112
3068
  );
3113
3069
  PriceCardMeta.displayName = "OODS.PriceCardMeta";
3114
- var CancellationForm = React7__namespace.forwardRef(
3070
+ var CancellationForm = React9__namespace.forwardRef(
3115
3071
  ({ title, label, heading, name, description, subtitle, hint, allowedReasons, reasonCode, reason, cancellationReason, embedded, reasonHelp, codeHelp, children, className, onSubmit, ...rest }, ref) => {
3116
3072
  const content = childContent(children);
3117
3073
  const choices = normalizeSelectOptions(allowedReasons ?? ["no_longer_needed", "budget", "duplicate"]);
3118
3074
  if (reasonCode && !choices.some((choice) => choice.value === reasonCode)) choices.unshift({ value: reasonCode, label: reasonCode });
3119
- return React7__namespace.createElement(embedded ? "fieldset" : "form", {
3075
+ return React9__namespace.createElement(embedded ? "fieldset" : "form", {
3120
3076
  ...rest,
3121
3077
  ref,
3122
3078
  className: classes7("oods-cancellation-form", className),
@@ -3148,11 +3104,11 @@ function BillingSummaryBadge({ id, amount, currency, minorUnits, interval, showI
3148
3104
  return /* @__PURE__ */ jsxRuntime.jsx("span", { id, className: `oods-billing-summary ${className ?? ""}`.trim(), "data-oods-component": "BillingSummaryBadge", children: showInterval ? componentContracts.billingSummary(amount, currency, minorUnits, interval) : componentContracts.formatBillingAmount(amount, currency, minorUnits) });
3149
3105
  }
3150
3106
  function BillingAmountInput({ id, amount, currency = "usd", minorUnits = componentContracts.BILLING_MINOR_UNITS, label = "Billing amount", name, disabled, className, help, onChange }) {
3151
- const generatedId = React7__namespace.useId();
3107
+ const generatedId = React9__namespace.useId();
3152
3108
  const controlId = id ?? `billing-amount-${generatedId}`;
3153
- const [text, setText] = React7__namespace.useState(() => componentContracts.billingAmountText(amount, minorUnits));
3154
- const [error, setError] = React7__namespace.useState(() => componentContracts.billingAmountMessage(amount, minorUnits));
3155
- React7__namespace.useEffect(() => {
3109
+ const [text, setText] = React9__namespace.useState(() => componentContracts.billingAmountText(amount, minorUnits));
3110
+ const [error, setError] = React9__namespace.useState(() => componentContracts.billingAmountMessage(amount, minorUnits));
3111
+ React9__namespace.useEffect(() => {
3156
3112
  setText(componentContracts.billingAmountText(amount, minorUnits));
3157
3113
  setError(componentContracts.billingAmountMessage(amount, minorUnits));
3158
3114
  }, [amount, minorUnits]);
@@ -3186,10 +3142,10 @@ function BillingAmountInput({ id, amount, currency = "usd", minorUnits = compone
3186
3142
  ] });
3187
3143
  }
3188
3144
  function BillingIntervalSelector({ id, interval, intervals = componentContracts.BILLING_INTERVALS, label = "Billing interval", name, disabled, className, help, onChange }) {
3189
- const generatedId = React7__namespace.useId();
3145
+ const generatedId = React9__namespace.useId();
3190
3146
  const controlId = id ?? `billing-interval-${generatedId}`;
3191
- const [value, setValue] = React7__namespace.useState(interval ?? "");
3192
- React7__namespace.useEffect(() => {
3147
+ const [value, setValue] = React9__namespace.useState(interval ?? "");
3148
+ React9__namespace.useEffect(() => {
3193
3149
  setValue(interval ?? "");
3194
3150
  }, [interval]);
3195
3151
  const error = componentContracts.billingIntervalMessage(value || void 0, intervals);
@@ -3297,8 +3253,8 @@ function AuditSummaryCard({ id, title = "Audit summary", showTransitionCount = t
3297
3253
  ] });
3298
3254
  }
3299
3255
  function SortIndicator({ id, label = "Sort", onChange, "data-oods-action": action, ...values }) {
3300
- const [state, setState] = React7__namespace.useState(() => componentContracts.initialSort(values));
3301
- React7__namespace.useEffect(() => setState(componentContracts.initialSort(values)), [values.sortField, values.sortDirection, values.sortActive, values.defaultSortField, values.defaultSortDirection]);
3256
+ const [state, setState] = React9__namespace.useState(() => componentContracts.initialSort(values));
3257
+ React9__namespace.useEffect(() => setState(componentContracts.initialSort(values)), [values.sortField, values.sortDirection, values.sortActive, values.defaultSortField, values.defaultSortDirection]);
3302
3258
  const sort = componentContracts.ariaSort(state);
3303
3259
  return /* @__PURE__ */ jsxRuntime.jsx("table", { id, className: "oods-sort-indicator", "data-oods-component": "SortIndicator", "aria-label": label, children: /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", "aria-sort": sort, children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", "data-oods-action": action, "aria-label": `${label} ${state.field}`, onClick: () => {
3304
3260
  const next = componentContracts.nextSort(state, values.triStateSort);
@@ -3306,14 +3262,15 @@ function SortIndicator({ id, label = "Sort", onChange, "data-oods-action": actio
3306
3262
  onChange?.(next);
3307
3263
  }, children: `${state.field}: ${sort}` }) }) }) }) });
3308
3264
  }
3309
- var TimelineEntryLabel = React7__namespace.forwardRef(({ compact = true, maxLength, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(InlineLabel, { ...props, ref, maxLength: maxLength ?? (compact ? 40 : void 0), "data-oods-component": "TimelineEntryLabel", "data-timeline-label": "true", "data-compact": compact }));
3265
+ var TimelineEntryLabel = React9__namespace.forwardRef(({ compact = true, maxLength, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(InlineLabel, { ...props, ref, maxLength: maxLength ?? (compact ? 40 : void 0), "data-oods-component": "TimelineEntryLabel", "data-timeline-label": "true", "data-compact": compact }));
3310
3266
  TimelineEntryLabel.displayName = "OODS.TimelineEntryLabel";
3311
3267
  function eventRecipe(id, kind, title) {
3312
3268
  return function TraitEvent({ id: elementId, title: heading = title, ...values }) {
3313
3269
  const rows = componentContracts.traitEventRows(kind, values);
3270
+ if (!rows.length) return null;
3314
3271
  return /* @__PURE__ */ jsxRuntime.jsxs("article", { id: elementId, className: "oods-trait-recipe", "data-oods-component": id, "aria-label": heading, children: [
3315
3272
  /* @__PURE__ */ jsxRuntime.jsx("h2", { children: heading }),
3316
- rows.length ? /* @__PURE__ */ jsxRuntime.jsx("ol", { children: rows.map((row, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
3273
+ /* @__PURE__ */ jsxRuntime.jsx("ol", { children: rows.map((row, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
3317
3274
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: row.title }),
3318
3275
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: row.at ? /* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: row.at, children: row.time }) : row.time }),
3319
3276
  row.actor && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
@@ -3328,7 +3285,7 @@ function eventRecipe(id, kind, title) {
3328
3285
  "Code: ",
3329
3286
  row.code
3330
3287
  ] })
3331
- ] }, index)) }) : /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No events recorded." })
3288
+ ] }, index)) })
3332
3289
  ] });
3333
3290
  };
3334
3291
  }
@@ -3349,9 +3306,9 @@ function CommunicationDetailPanel({ id, title = "Communication", channels = [],
3349
3306
  ] });
3350
3307
  }
3351
3308
  function ColorStatePicker({ id, title = "Color state", colorStates = componentContracts.DEFAULT_COLOR_STATES, value, disabled, onChange }) {
3352
- const generatedId = React7__namespace.useId();
3353
- const [selected, setSelected] = React7__namespace.useState(value ?? colorStates[0] ?? "");
3354
- React7__namespace.useEffect(() => setSelected(value ?? colorStates[0] ?? ""), [value, colorStates]);
3309
+ const generatedId = React9__namespace.useId();
3310
+ const [selected, setSelected] = React9__namespace.useState(value ?? colorStates[0] ?? "");
3311
+ React9__namespace.useEffect(() => setSelected(value ?? colorStates[0] ?? ""), [value, colorStates]);
3355
3312
  return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { id, className: "oods-trait-recipe", "data-oods-component": "ColorStatePicker", children: [
3356
3313
  /* @__PURE__ */ jsxRuntime.jsx("legend", { children: title }),
3357
3314
  /* @__PURE__ */ jsxRuntime.jsx(Select, { id: `${id ?? generatedId}-state`, label: "Color state", name: "color_state", value: selected, disabled, options: [...!colorStates.includes(selected) ? [{ value: selected, label: selected || "Choose state", disabled: true }] : [], ...colorStates.map((value2) => ({ value: value2, label: componentContracts.formatReadOnlyValue(value2, "string", true) }))], onValueChange: (next) => {
@@ -3373,9 +3330,9 @@ function StatusColorLegend({ id, title = "Status colors", colorStates = componen
3373
3330
  ] });
3374
3331
  }
3375
3332
  function GeoFieldMappingForm({ id, title = "Geographic fields", embedded = false, disabled, onChange, ...values }) {
3376
- const generatedId = React7__namespace.useId();
3377
- const [value, setValue] = React7__namespace.useState(() => componentContracts.geoFieldMapping(values));
3378
- React7__namespace.useEffect(() => setValue(componentContracts.geoFieldMapping(values)), [values.latitude, values.longitude, values.identifier, values.autoDetect]);
3333
+ const generatedId = React9__namespace.useId();
3334
+ const [value, setValue] = React9__namespace.useState(() => componentContracts.geoFieldMapping(values));
3335
+ React9__namespace.useEffect(() => setValue(componentContracts.geoFieldMapping(values)), [values.latitude, values.longitude, values.identifier, values.autoDetect]);
3379
3336
  const update = (patch) => {
3380
3337
  const next = { ...value, ...patch };
3381
3338
  setValue(next);
@@ -3409,11 +3366,11 @@ function GeocodablePreview({ id, title = "Geographic data", resolution, requires
3409
3366
  }
3410
3367
  function controls(id) {
3411
3368
  const Component = ({ id: htmlId, title = componentContracts.VIZ_CONTROL_TITLES[id], value, channel = "x", disabled, onChange }) => {
3412
- const generatedId = React7__namespace.useId();
3413
- const [current, setCurrent] = React7__namespace.useState(value ?? {});
3414
- const [drafts, setDrafts] = React7__namespace.useState({});
3415
- const [errors, setErrors] = React7__namespace.useState({});
3416
- React7__namespace.useEffect(() => {
3369
+ const generatedId = React9__namespace.useId();
3370
+ const [current, setCurrent] = React9__namespace.useState(value ?? {});
3371
+ const [drafts, setDrafts] = React9__namespace.useState({});
3372
+ const [errors, setErrors] = React9__namespace.useState({});
3373
+ React9__namespace.useEffect(() => {
3417
3374
  setCurrent(value ?? {});
3418
3375
  setDrafts({});
3419
3376
  setErrors({});
@@ -3487,6 +3444,215 @@ var VizLinePreview = preview("VizLinePreview", "line");
3487
3444
  var VizMarkPreview = preview("VizMarkPreview", "bar");
3488
3445
  var VizPointPreview = preview("VizPointPreview", "scatter");
3489
3446
  var VizScatterPreview = preview("VizScatterPreview", "scatter");
3447
+ var classes8 = (...values) => values.filter(Boolean).join(" ");
3448
+ var Combobox = React9__namespace.forwardRef(
3449
+ ({
3450
+ id,
3451
+ label,
3452
+ options = [],
3453
+ value,
3454
+ defaultValue = "",
3455
+ placeholder,
3456
+ name,
3457
+ required,
3458
+ disabled,
3459
+ help,
3460
+ validation,
3461
+ size = "md",
3462
+ className,
3463
+ style,
3464
+ onValueChange,
3465
+ onUpdate,
3466
+ onKeyDown,
3467
+ onBlur,
3468
+ onClick,
3469
+ "aria-describedby": nativeDescription,
3470
+ ...rest
3471
+ }, ref) => {
3472
+ const [internalValue, setInternalValue] = React9__namespace.useState(defaultValue);
3473
+ const [query, setQuery] = React9__namespace.useState(null);
3474
+ const [open, setOpen] = React9__namespace.useState(false);
3475
+ const [active, setActive] = React9__namespace.useState(-1);
3476
+ const rootRef = React9__namespace.useRef(null);
3477
+ const listboxRef = React9__namespace.useRef(null);
3478
+ const chosenValue = value ?? internalValue;
3479
+ const chosen = options.find((option) => option.value === chosenValue);
3480
+ const text = query ?? chosen?.label ?? "";
3481
+ const needle = (query ?? "").trim().toLowerCase();
3482
+ const matches = options.map((option) => needle === "" || option.label.toLowerCase().includes(needle));
3483
+ const matchCount = matches.filter(Boolean).length;
3484
+ const reachable = options.flatMap((option, index) => matches[index] && !option.disabled ? [index] : []);
3485
+ const optionId = (index) => `${id}-option-${index}`;
3486
+ const validationId = validation?.id ?? `${id}-validation`;
3487
+ const describedBy = [nativeDescription, help ? `${id}-help` : void 0, validation?.message ? validationId : void 0].filter(Boolean).join(" ") || void 0;
3488
+ const tone = validation ? validation.state === "error" ? "critical" : validation.state : void 0;
3489
+ const close = () => {
3490
+ setOpen(false);
3491
+ setActive(-1);
3492
+ };
3493
+ const emit = (next) => {
3494
+ if (value === void 0) setInternalValue(next);
3495
+ onValueChange?.(next);
3496
+ onUpdate?.(next);
3497
+ };
3498
+ const pick = (index) => {
3499
+ const option = options[index];
3500
+ if (!option || option.disabled) return;
3501
+ setQuery(null);
3502
+ close();
3503
+ if (option.value !== chosenValue) emit(option.value);
3504
+ };
3505
+ React9__namespace.useEffect(() => {
3506
+ if (!open) return void 0;
3507
+ const outside = (event) => {
3508
+ if (!rootRef.current?.contains(event.target)) close();
3509
+ };
3510
+ document.addEventListener("pointerdown", outside);
3511
+ return () => document.removeEventListener("pointerdown", outside);
3512
+ }, [open]);
3513
+ React9__namespace.useEffect(() => {
3514
+ if (!open || active < 0) return;
3515
+ const element = listboxRef.current?.children[active];
3516
+ element?.scrollIntoView?.({ block: "nearest" });
3517
+ }, [open, active]);
3518
+ const handleKeyDown = (event) => {
3519
+ onKeyDown?.(event);
3520
+ if (event.defaultPrevented || disabled || event.nativeEvent.isComposing) return;
3521
+ const first = reachable[0] ?? -1;
3522
+ const last = reachable[reachable.length - 1] ?? -1;
3523
+ const at = reachable.indexOf(active);
3524
+ switch (event.key) {
3525
+ case "ArrowDown":
3526
+ event.preventDefault();
3527
+ setOpen(true);
3528
+ setActive(!open || at === -1 ? first : reachable[(at + 1) % reachable.length]);
3529
+ return;
3530
+ case "ArrowUp":
3531
+ event.preventDefault();
3532
+ setOpen(true);
3533
+ setActive(!open || at <= 0 ? last : reachable[at - 1]);
3534
+ return;
3535
+ case "Home":
3536
+ case "End":
3537
+ if (!open) return;
3538
+ event.preventDefault();
3539
+ setActive(event.key === "Home" ? first : last);
3540
+ return;
3541
+ case "Enter":
3542
+ if (!open) return;
3543
+ event.preventDefault();
3544
+ if (active >= 0) pick(active);
3545
+ return;
3546
+ case "Escape":
3547
+ if (open) {
3548
+ event.preventDefault();
3549
+ close();
3550
+ return;
3551
+ }
3552
+ if (text === "" && chosenValue === "") return;
3553
+ event.preventDefault();
3554
+ setQuery(null);
3555
+ if (chosenValue !== "") emit("");
3556
+ return;
3557
+ case "Tab":
3558
+ if (open) close();
3559
+ return;
3560
+ }
3561
+ };
3562
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3563
+ "div",
3564
+ {
3565
+ ref: rootRef,
3566
+ className: classes8("oods-field", "oods-combobox", className),
3567
+ style: {
3568
+ ...tone ? {
3569
+ "--cmp-input-message-border": `var(--sys-status-${tone}-border)`,
3570
+ "--cmp-input-message-text": `var(--sys-status-${tone}-text)`
3571
+ } : {},
3572
+ ...style
3573
+ },
3574
+ "data-oods-component": "Combobox",
3575
+ "data-size": size,
3576
+ "data-validation-state": validation?.state,
3577
+ children: [
3578
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { id: `${id}-label`, className: "oods-field-label", htmlFor: id, children: [
3579
+ label,
3580
+ required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oods-field-required", "aria-hidden": "true", children: "*" }) : null
3581
+ ] }),
3582
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oods-combobox__control", children: [
3583
+ /* @__PURE__ */ jsxRuntime.jsx(
3584
+ "input",
3585
+ {
3586
+ ...rest,
3587
+ ref,
3588
+ id,
3589
+ type: "text",
3590
+ role: "combobox",
3591
+ className: "oods-field-control oods-combobox__input",
3592
+ value: text,
3593
+ placeholder,
3594
+ autoComplete: "off",
3595
+ "aria-autocomplete": "list",
3596
+ "aria-expanded": open,
3597
+ "aria-controls": `${id}-listbox`,
3598
+ "aria-activedescendant": open && active >= 0 ? optionId(active) : void 0,
3599
+ "aria-describedby": describedBy,
3600
+ "aria-invalid": validation?.state === "error" || void 0,
3601
+ required,
3602
+ disabled,
3603
+ onChange: (event) => {
3604
+ setQuery(event.currentTarget.value);
3605
+ setOpen(true);
3606
+ setActive(-1);
3607
+ },
3608
+ onKeyDown: handleKeyDown,
3609
+ onClick: (event) => {
3610
+ onClick?.(event);
3611
+ if (!event.defaultPrevented && !disabled) setOpen(true);
3612
+ },
3613
+ onBlur: (event) => {
3614
+ onBlur?.(event);
3615
+ setQuery(null);
3616
+ close();
3617
+ }
3618
+ }
3619
+ ),
3620
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oods-combobox__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { name: "chevron-down" }) }),
3621
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oods-combobox__popup", hidden: !open, onMouseDown: (event) => event.preventDefault(), children: [
3622
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { ref: listboxRef, id: `${id}-listbox`, className: "oods-combobox__listbox", role: "listbox", "aria-labelledby": `${id}-label`, children: options.map((option, index) => /* @__PURE__ */ jsxRuntime.jsxs(
3623
+ "li",
3624
+ {
3625
+ id: optionId(index),
3626
+ className: "oods-combobox__option",
3627
+ role: "option",
3628
+ "aria-selected": option.value === chosenValue,
3629
+ "aria-disabled": option.disabled || void 0,
3630
+ "data-value": option.value,
3631
+ "data-active": index === active ? "true" : void 0,
3632
+ hidden: !matches[index],
3633
+ onClick: () => pick(index),
3634
+ onPointerMove: () => {
3635
+ if (!option.disabled && index !== active) setActive(index);
3636
+ },
3637
+ children: [
3638
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oods-combobox__option-label", children: option.label }),
3639
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oods-combobox__check", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { name: "check" }) })
3640
+ ]
3641
+ },
3642
+ option.value
3643
+ )) }),
3644
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oods-combobox__empty", role: "status", children: open && matchCount === 0 ? "No matches" : "" })
3645
+ ] })
3646
+ ] }),
3647
+ name ? /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: chosenValue }) : null,
3648
+ help ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: `${id}-help`, className: "oods-field-help", children: help }) : null,
3649
+ validation?.message ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: validationId, className: "oods-field-error", role: validation.state === "error" ? "alert" : void 0, children: validation.message }) : null
3650
+ ]
3651
+ }
3652
+ );
3653
+ }
3654
+ );
3655
+ Combobox.displayName = "OODS.Combobox";
3490
3656
 
3491
3657
  exports.AddressCollectionPanel = AddressCollectionPanel;
3492
3658
  exports.AddressEditor = AddressEditor;
@@ -3519,10 +3685,12 @@ exports.ClassificationPanel = ClassificationPanel;
3519
3685
  exports.ColorStatePicker = ColorStatePicker;
3520
3686
  exports.ColorSwatch = ColorSwatch;
3521
3687
  exports.ColorizedBadge = ColorizedBadge;
3688
+ exports.Combobox = Combobox;
3522
3689
  exports.CommunicationDetailPanel = CommunicationDetailPanel;
3523
3690
  exports.CycleProgressCard = CycleProgressCard;
3524
3691
  exports.DatePicker = DatePicker;
3525
3692
  exports.DetailHeader = DetailHeader;
3693
+ exports.Dialog = Dialog;
3526
3694
  exports.FilterPanel = FilterPanel;
3527
3695
  exports.FormLabelGroup = FormLabelGroup;
3528
3696
  exports.GeoFieldMappingForm = GeoFieldMappingForm;
@@ -3553,6 +3721,7 @@ exports.RelativeTimestamp = RelativeTimestamp;
3553
3721
  exports.RoleAssignmentForm = RoleAssignmentForm;
3554
3722
  exports.RoleBadgeList = RoleBadgeList;
3555
3723
  exports.SearchInput = SearchInput;
3724
+ exports.SegmentedControl = SegmentedControl;
3556
3725
  exports.Select = Select;
3557
3726
  exports.SortIndicator = SortIndicator;
3558
3727
  exports.Stack = Stack;
@@ -3561,6 +3730,7 @@ exports.StatusBadge = StatusBadge;
3561
3730
  exports.StatusColorLegend = StatusColorLegend;
3562
3731
  exports.StatusSelector = StatusSelector;
3563
3732
  exports.StatusTimeline = StatusTimeline;
3733
+ exports.Switch = Switch;
3564
3734
  exports.Table = Table;
3565
3735
  exports.Tabs = Tabs;
3566
3736
  exports.TagInput = TagInput;