@oods/components-react 0.4.0 → 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,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React8 = require('react');
3
+ var React9 = require('react');
4
4
  var reactSlot = require('@radix-ui/react-slot');
5
5
  var componentContracts = require('@oods/component-contracts');
6
6
  var jsxRuntime = require('react/jsx-runtime');
@@ -23,7 +23,7 @@ function _interopNamespace(e) {
23
23
  return Object.freeze(n);
24
24
  }
25
25
 
26
- var React8__namespace = /*#__PURE__*/_interopNamespace(React8);
26
+ var React9__namespace = /*#__PURE__*/_interopNamespace(React9);
27
27
 
28
28
  // src/presentational.tsx
29
29
  var REACT_NAMES = {
@@ -38,10 +38,10 @@ var REACT_NAMES = {
38
38
  };
39
39
  var svgProps = Object.fromEntries(Object.entries(componentContracts.STATUS_ICON_SVG_ATTRS).map(([name, value]) => [REACT_NAMES[name] ?? name, value]));
40
40
  function StatusIcon({ name }) {
41
- return /* @__PURE__ */ jsxRuntime.jsx("svg", { ...svgProps, children: componentContracts.STATUS_ICON_SHAPES[name].map((shape, index) => React8__namespace.createElement(shape.tag, { key: index, ...shape.attrs })) });
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 })) });
42
42
  }
43
43
  var classes = (...values) => values.filter(Boolean).join(" ");
44
- var Badge = React8__namespace.forwardRef(
44
+ var Badge = React9__namespace.forwardRef(
45
45
  ({
46
46
  content,
47
47
  status,
@@ -95,7 +95,7 @@ var Badge = React8__namespace.forwardRef(
95
95
  }
96
96
  );
97
97
  Badge.displayName = "OODS.Badge";
98
- var Banner = React8__namespace.forwardRef(
98
+ var Banner = React9__namespace.forwardRef(
99
99
  ({
100
100
  title,
101
101
  detail,
@@ -166,7 +166,7 @@ var Banner = React8__namespace.forwardRef(
166
166
  }
167
167
  );
168
168
  Banner.displayName = "OODS.Banner";
169
- var Button = React8__namespace.forwardRef(
169
+ var Button = React9__namespace.forwardRef(
170
170
  ({
171
171
  asChild = false,
172
172
  content,
@@ -213,10 +213,35 @@ var Button = React8__namespace.forwardRef(
213
213
  );
214
214
  Button.displayName = "OODS.Button";
215
215
  var noSubscription = () => () => void 0;
216
- var useIsomorphicLayoutEffect = typeof window === "undefined" ? React8__namespace.useEffect : React8__namespace.useLayoutEffect;
216
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? React9__namespace.useEffect : React9__namespace.useLayoutEffect;
217
217
  var canShowModal = () => typeof HTMLDialogElement !== "undefined" && typeof HTMLDialogElement.prototype.showModal === "function";
218
218
  var hasContent = (node) => node !== void 0 && node !== null && node !== false && node !== "";
219
- var Dialog = React8__namespace.forwardRef(
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(
220
245
  ({
221
246
  id,
222
247
  open = false,
@@ -230,26 +255,36 @@ var Dialog = React8__namespace.forwardRef(
230
255
  className,
231
256
  onClose,
232
257
  onKeyDown,
258
+ onMouseDown,
259
+ onClick,
233
260
  ...rest
234
261
  }, ref) => {
235
- const generatedId = React8__namespace.useId().replace(/[^\w-]/g, "");
262
+ const generatedId = React9__namespace.useId().replace(/[^\w-]/g, "");
236
263
  const dialogId = id ?? `oods-dialog-${generatedId}`;
237
- const element = React8__namespace.useRef(null);
238
- const openRef = React8__namespace.useRef(open);
239
- const serverMarkup = React8__namespace.useSyncExternalStore(noSubscription, () => false, () => true);
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);
240
269
  const managed = modal && !serverMarkup && canShowModal();
241
- const setRef = React8__namespace.useCallback((node) => {
270
+ const setRef = React9__namespace.useCallback((node) => {
242
271
  element.current = node;
243
272
  if (typeof ref === "function") ref(node);
244
273
  else if (ref) ref.current = node;
245
274
  }, [ref]);
275
+ const releaseScroll = React9__namespace.useCallback(() => {
276
+ scrollLock.current?.();
277
+ scrollLock.current = null;
278
+ }, []);
246
279
  useIsomorphicLayoutEffect(() => {
247
280
  openRef.current = open;
248
281
  const dialog = element.current;
249
282
  if (!dialog || !managed) return;
250
283
  if (open && !dialog.open) dialog.showModal();
251
284
  else if (!open && dialog.open) dialog.close();
285
+ if (open && dialog.open) scrollLock.current ??= lockPageScroll();
252
286
  }, [open, managed]);
287
+ React9__namespace.useEffect(() => releaseScroll, [releaseScroll]);
253
288
  const requestClose = (event) => {
254
289
  event.preventDefault();
255
290
  onClose?.();
@@ -271,7 +306,19 @@ var Dialog = React8__namespace.forwardRef(
271
306
  },
272
307
  onCancel: requestClose,
273
308
  onClose: () => {
274
- if (openRef.current && !element.current?.open) 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?.();
275
322
  },
276
323
  ...rest,
277
324
  children: [
@@ -290,7 +337,7 @@ var Dialog = React8__namespace.forwardRef(
290
337
  }
291
338
  );
292
339
  Dialog.displayName = "OODS.Dialog";
293
- var Card = React8__namespace.forwardRef(
340
+ var Card = React9__namespace.forwardRef(
294
341
  ({ as = "div", elevated = false, className, ...rest }, ref) => {
295
342
  const Element = as;
296
343
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -306,7 +353,7 @@ var Card = React8__namespace.forwardRef(
306
353
  }
307
354
  );
308
355
  Card.displayName = "OODS.Card";
309
- var Text = React8__namespace.forwardRef(
356
+ var Text = React9__namespace.forwardRef(
310
357
  ({
311
358
  as = "span",
312
359
  content,
@@ -415,7 +462,7 @@ var FieldFrame = ({
415
462
  }
416
463
  );
417
464
  };
418
- var InputPrimitive = React8__namespace.forwardRef(
465
+ var InputPrimitive = React9__namespace.forwardRef(
419
466
  ({
420
467
  id,
421
468
  label,
@@ -485,7 +532,7 @@ var InputPrimitive = React8__namespace.forwardRef(
485
532
  );
486
533
  InputPrimitive.displayName = "OODS.Input";
487
534
  var Input = InputPrimitive;
488
- var DatePicker = React8__namespace.forwardRef(
535
+ var DatePicker = React9__namespace.forwardRef(
489
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(
490
537
  Input,
491
538
  {
@@ -498,7 +545,7 @@ var DatePicker = React8__namespace.forwardRef(
498
545
  ) })
499
546
  );
500
547
  DatePicker.displayName = "OODS.DatePicker";
501
- var Checkbox = React8__namespace.forwardRef(
548
+ var Checkbox = React9__namespace.forwardRef(
502
549
  ({
503
550
  id,
504
551
  label,
@@ -561,7 +608,7 @@ var Checkbox = React8__namespace.forwardRef(
561
608
  }
562
609
  );
563
610
  Checkbox.displayName = "OODS.Checkbox";
564
- var Switch = React8__namespace.forwardRef(
611
+ var Switch = React9__namespace.forwardRef(
565
612
  ({
566
613
  id,
567
614
  label,
@@ -579,7 +626,7 @@ var Switch = React8__namespace.forwardRef(
579
626
  "aria-describedby": nativeDescription,
580
627
  ...rest
581
628
  }, ref) => {
582
- const [internalChecked, setInternalChecked] = React8__namespace.useState(defaultChecked);
629
+ const [internalChecked, setInternalChecked] = React9__namespace.useState(defaultChecked);
583
630
  const on = checked ?? internalChecked;
584
631
  const validationId = validation?.id ?? `${id}-validation`;
585
632
  const describedBy = [nativeDescription, help ? `${id}-help` : void 0, validation?.message ? validationId : void 0].filter(Boolean).join(" ") || void 0;
@@ -639,7 +686,7 @@ var Switch = React8__namespace.forwardRef(
639
686
  }
640
687
  );
641
688
  Switch.displayName = "OODS.Switch";
642
- var Select = React8__namespace.forwardRef(
689
+ var Select = React9__namespace.forwardRef(
643
690
  ({
644
691
  id,
645
692
  label,
@@ -707,7 +754,7 @@ var Select = React8__namespace.forwardRef(
707
754
  }
708
755
  );
709
756
  Select.displayName = "OODS.Select";
710
- var Textarea = React8__namespace.forwardRef(
757
+ var Textarea = React9__namespace.forwardRef(
711
758
  ({
712
759
  id,
713
760
  label,
@@ -790,7 +837,7 @@ var maxColumns = (columns) => {
790
837
  const count = Number(columns);
791
838
  return Number.isFinite(count) && count > 0 ? count : void 0;
792
839
  };
793
- var Grid = React8__namespace.forwardRef(
840
+ var Grid = React9__namespace.forwardRef(
794
841
  ({
795
842
  columns = "auto-fit",
796
843
  minColumnWidth = "16rem",
@@ -820,7 +867,7 @@ var Grid = React8__namespace.forwardRef(
820
867
  )
821
868
  );
822
869
  Grid.displayName = "OODS.Grid";
823
- var Stack = React8__namespace.forwardRef(
870
+ var Stack = React9__namespace.forwardRef(
824
871
  ({
825
872
  direction = "column",
826
873
  gap = "md",
@@ -852,19 +899,19 @@ var Stack = React8__namespace.forwardRef(
852
899
  );
853
900
  Stack.displayName = "OODS.Stack";
854
901
  var classes4 = (...values) => values.filter(Boolean).join(" ");
855
- var TableHead = React8__namespace.forwardRef(
902
+ var TableHead = React9__namespace.forwardRef(
856
903
  ({ className, ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className: classes4("oods-table__header", className), ...rest })
857
904
  );
858
905
  TableHead.displayName = "OODS.Table.Head";
859
- var TableBody = React8__namespace.forwardRef(
906
+ var TableBody = React9__namespace.forwardRef(
860
907
  ({ className, ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className: classes4("oods-table__body", className), ...rest })
861
908
  );
862
909
  TableBody.displayName = "OODS.Table.Body";
863
- var TableCaption = React8__namespace.forwardRef(
910
+ var TableCaption = React9__namespace.forwardRef(
864
911
  ({ className, ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx("caption", { ref, className: classes4("oods-table__caption", className), ...rest })
865
912
  );
866
913
  TableCaption.displayName = "OODS.Table.Caption";
867
- var TableRow = React8__namespace.forwardRef(
914
+ var TableRow = React9__namespace.forwardRef(
868
915
  ({
869
916
  selectable = false,
870
917
  selected = false,
@@ -903,7 +950,7 @@ var TableRow = React8__namespace.forwardRef(
903
950
  }
904
951
  );
905
952
  TableRow.displayName = "OODS.Table.Row";
906
- var TableHeaderCell = React8__namespace.forwardRef(
953
+ var TableHeaderCell = React9__namespace.forwardRef(
907
954
  ({ numeric = false, className, scope = "col", ...rest }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
908
955
  "th",
909
956
  {
@@ -920,7 +967,7 @@ var TableHeaderCell = React8__namespace.forwardRef(
920
967
  )
921
968
  );
922
969
  TableHeaderCell.displayName = "OODS.Table.HeaderCell";
923
- var TableCell = React8__namespace.forwardRef(
970
+ var TableCell = React9__namespace.forwardRef(
924
971
  ({
925
972
  numeric = false,
926
973
  status,
@@ -966,7 +1013,7 @@ var TableCell = React8__namespace.forwardRef(
966
1013
  }
967
1014
  );
968
1015
  TableCell.displayName = "OODS.Table.Cell";
969
- var TableRoot = React8__namespace.forwardRef(
1016
+ var TableRoot = React9__namespace.forwardRef(
970
1017
  ({
971
1018
  caption,
972
1019
  showCaption = true,
@@ -1048,7 +1095,7 @@ var partitionForOverflow = (items, visibleCount, selectedId) => {
1048
1095
  overflowItems: items.filter((item) => !visibleIds.has(item.id))
1049
1096
  };
1050
1097
  };
1051
- var Tabs = React8__namespace.forwardRef(
1098
+ var Tabs = React9__namespace.forwardRef(
1052
1099
  ({
1053
1100
  items,
1054
1101
  selectedId,
@@ -1062,22 +1109,22 @@ var Tabs = React8__namespace.forwardRef(
1062
1109
  "aria-label": ariaLabelAttribute,
1063
1110
  ...rest
1064
1111
  }, ref) => {
1065
- const instanceId = React8__namespace.useId().replaceAll(":", "");
1112
+ const instanceId = React9__namespace.useId().replaceAll(":", "");
1066
1113
  const controlled = selectedId !== void 0;
1067
1114
  const firstEnabled = items.find((item) => !item.disabled && !item.isDisabled)?.id ?? "";
1068
- const [internalSelectedId, setInternalSelectedId] = React8__namespace.useState(
1115
+ const [internalSelectedId, setInternalSelectedId] = React9__namespace.useState(
1069
1116
  defaultSelectedId ?? firstEnabled
1070
1117
  );
1071
1118
  const activeId = controlled ? selectedId : internalSelectedId;
1072
- const [focusedId, setFocusedId] = React8__namespace.useState(activeId);
1073
- const [visibleCount, setVisibleCount] = React8__namespace.useState(items.length);
1074
- const [menuOpen, setMenuOpen] = React8__namespace.useState(false);
1075
- const listRef = React8__namespace.useRef(null);
1076
- const tabRefs = React8__namespace.useRef(/* @__PURE__ */ new Map());
1077
- const itemWidths = React8__namespace.useRef(/* @__PURE__ */ new Map());
1078
- const focusRequestedByUser = React8__namespace.useRef(false);
1079
- React8__namespace.useEffect(() => setFocusedId(activeId), [activeId]);
1080
- const select = React8__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(
1081
1128
  (id) => {
1082
1129
  const item = items.find((candidate) => candidate.id === id);
1083
1130
  if (!item || item.disabled || item.isDisabled) return;
@@ -1089,7 +1136,7 @@ var Tabs = React8__namespace.forwardRef(
1089
1136
  },
1090
1137
  [controlled, items, onChange, onUpdate]
1091
1138
  );
1092
- const measure = React8__namespace.useCallback(() => {
1139
+ const measure = React9__namespace.useCallback(() => {
1093
1140
  const list = listRef.current;
1094
1141
  if (!list || items.length < 2) return;
1095
1142
  const available = list.offsetWidth;
@@ -1113,7 +1160,7 @@ var Tabs = React8__namespace.forwardRef(
1113
1160
  }
1114
1161
  setVisibleCount(Math.max(1, count));
1115
1162
  }, [items.length]);
1116
- React8__namespace.useLayoutEffect(() => {
1163
+ React9__namespace.useLayoutEffect(() => {
1117
1164
  measure();
1118
1165
  const list = listRef.current;
1119
1166
  if (!list || typeof ResizeObserver === "undefined") return void 0;
@@ -1141,7 +1188,7 @@ var Tabs = React8__namespace.forwardRef(
1141
1188
  if (!nextId) return;
1142
1189
  select(nextId);
1143
1190
  };
1144
- React8__namespace.useEffect(() => {
1191
+ React9__namespace.useEffect(() => {
1145
1192
  if (focusRequestedByUser.current && visibleItems.some((item) => item.id === focusedId)) {
1146
1193
  focusRequestedByUser.current = false;
1147
1194
  tabRefs.current.get(focusedId)?.focus();
@@ -1263,9 +1310,73 @@ var Tabs = React8__namespace.forwardRef(
1263
1310
  }
1264
1311
  );
1265
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";
1266
1377
  var classes6 = (...values) => values.filter(Boolean).join(" ");
1267
1378
  var humanize = (value) => value.split(/[_-]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
1268
- var StatusBadge = React8__namespace.forwardRef(
1379
+ var StatusBadge = React9__namespace.forwardRef(
1269
1380
  ({
1270
1381
  status,
1271
1382
  value,
@@ -1321,7 +1432,7 @@ function formatPrice(amount, currency, fallback) {
1321
1432
  return `${currency.toUpperCase()} ${amount.toFixed(2)}`;
1322
1433
  }
1323
1434
  }
1324
- var PriceBadge = React8__namespace.forwardRef(
1435
+ var PriceBadge = React9__namespace.forwardRef(
1325
1436
  ({
1326
1437
  amountCents,
1327
1438
  unitAmountCents,
@@ -1396,7 +1507,7 @@ function normalizeTimelineEvents(values) {
1396
1507
  }];
1397
1508
  });
1398
1509
  }
1399
- var TimelinePrimitive = React8__namespace.forwardRef(
1510
+ var TimelinePrimitive = React9__namespace.forwardRef(
1400
1511
  ({
1401
1512
  componentId,
1402
1513
  defaultTitle,
@@ -1474,7 +1585,7 @@ var TimelinePrimitive = React8__namespace.forwardRef(
1474
1585
  }
1475
1586
  );
1476
1587
  TimelinePrimitive.displayName = "OODS.TimelinePrimitive";
1477
- var StatusTimeline = React8__namespace.forwardRef(
1588
+ var StatusTimeline = React9__namespace.forwardRef(
1478
1589
  (props, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1479
1590
  TimelinePrimitive,
1480
1591
  {
@@ -1487,7 +1598,7 @@ var StatusTimeline = React8__namespace.forwardRef(
1487
1598
  )
1488
1599
  );
1489
1600
  StatusTimeline.displayName = "OODS.StatusTimeline";
1490
- var AuditTimeline = React8__namespace.forwardRef(
1601
+ var AuditTimeline = React9__namespace.forwardRef(
1491
1602
  ({ auditLog, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1492
1603
  TimelinePrimitive,
1493
1604
  {
@@ -1501,7 +1612,7 @@ var AuditTimeline = React8__namespace.forwardRef(
1501
1612
  )
1502
1613
  );
1503
1614
  AuditTimeline.displayName = "OODS.AuditTimeline";
1504
- var CancellationSummary = React8__namespace.forwardRef(
1615
+ var CancellationSummary = React9__namespace.forwardRef(
1505
1616
  ({
1506
1617
  label,
1507
1618
  title = label ?? "Cancellation Summary",
@@ -1558,7 +1669,7 @@ var CancellationSummary = React8__namespace.forwardRef(
1558
1669
  }
1559
1670
  );
1560
1671
  CancellationSummary.displayName = "OODS.CancellationSummary";
1561
- var SearchInput = React8__namespace.forwardRef(
1672
+ var SearchInput = React9__namespace.forwardRef(
1562
1673
  ({
1563
1674
  id,
1564
1675
  label = "Search",
@@ -1584,13 +1695,13 @@ var SearchInput = React8__namespace.forwardRef(
1584
1695
  onKeyDown,
1585
1696
  ...rest
1586
1697
  }, ref) => {
1587
- const generatedId = React8__namespace.useId();
1698
+ const generatedId = React9__namespace.useId();
1588
1699
  const resolvedId = id ?? `oods-search-${generatedId.replace(/:/g, "")}`;
1589
- const [uncontrolledValue, setUncontrolledValue] = React8__namespace.useState(defaultValue);
1700
+ const [uncontrolledValue, setUncontrolledValue] = React9__namespace.useState(defaultValue);
1590
1701
  const currentValue = value ?? uncontrolledValue;
1591
- const timerRef = React8__namespace.useRef(void 0);
1702
+ const timerRef = React9__namespace.useRef(void 0);
1592
1703
  const delay = Math.max(0, debounceMs ?? debounce ?? 0);
1593
- React8__namespace.useEffect(() => () => {
1704
+ React9__namespace.useEffect(() => () => {
1594
1705
  if (timerRef.current !== void 0) clearTimeout(timerRef.current);
1595
1706
  }, []);
1596
1707
  const publish = (nextValue) => {
@@ -1674,7 +1785,7 @@ function visiblePages(page, totalPages) {
1674
1785
  }
1675
1786
  return result;
1676
1787
  }
1677
- var PaginationBar = React8__namespace.forwardRef(
1788
+ var PaginationBar = React9__namespace.forwardRef(
1678
1789
  ({
1679
1790
  page = 1,
1680
1791
  pageSize = 25,
@@ -1815,7 +1926,7 @@ function relativeLabel(date, now) {
1815
1926
  unit
1816
1927
  );
1817
1928
  }
1818
- var RelativeTimestamp = React8__namespace.forwardRef(
1929
+ var RelativeTimestamp = React9__namespace.forwardRef(
1819
1930
  ({
1820
1931
  datetime,
1821
1932
  timestamp,
@@ -1863,8 +1974,8 @@ RelativeTimestamp.displayName = "OODS.RelativeTimestamp";
1863
1974
  var classes7 = (...values) => values.filter(Boolean).join(" ");
1864
1975
  var firstText = (...values) => values.find((value) => typeof value === "string" && value.trim().length > 0);
1865
1976
  function childContent(children) {
1866
- const flatten = (value) => React8__namespace.Children.toArray(value).flatMap((node) => {
1867
- if (React8__namespace.isValidElement(node) && node.type === React8__namespace.Fragment) {
1977
+ const flatten = (value) => React9__namespace.Children.toArray(value).flatMap((node) => {
1978
+ if (React9__namespace.isValidElement(node) && node.type === React9__namespace.Fragment) {
1868
1979
  return flatten(node.props.children);
1869
1980
  }
1870
1981
  return [node];
@@ -1885,7 +1996,7 @@ function notEcho(supporting, heading) {
1885
1996
  if (!supporting || !heading) return supporting;
1886
1997
  return supporting.trim() === heading.trim() ? void 0 : supporting;
1887
1998
  }
1888
- var DetailHeader = React8__namespace.forwardRef(
1999
+ var DetailHeader = React9__namespace.forwardRef(
1889
2000
  ({ title, label, text, subtitle, sublabel, description, metadata, meta, level, as, children, className, ...rest }, ref) => {
1890
2001
  const Heading = headingElement(as, level, 2);
1891
2002
  const content = childContent(children);
@@ -1900,7 +2011,7 @@ var DetailHeader = React8__namespace.forwardRef(
1900
2011
  }
1901
2012
  );
1902
2013
  DetailHeader.displayName = "OODS.DetailHeader";
1903
- var CardHeader = React8__namespace.forwardRef(
2014
+ var CardHeader = React9__namespace.forwardRef(
1904
2015
  ({ title, label, text, supporting, supportingText, subtitle, description, level, as, children, className, ...rest }, ref) => {
1905
2016
  const Heading = headingElement(as, level, 2);
1906
2017
  const content = childContent(children);
@@ -1913,7 +2024,7 @@ var CardHeader = React8__namespace.forwardRef(
1913
2024
  }
1914
2025
  );
1915
2026
  CardHeader.displayName = "OODS.CardHeader";
1916
- var ColorSwatch = React8__namespace.forwardRef(
2027
+ var ColorSwatch = React9__namespace.forwardRef(
1917
2028
  ({ color, value, state, label, children, className, style, ...rest }, ref) => {
1918
2029
  const resolvedColor = firstText(color, value, state);
1919
2030
  const content = childContent(children);
@@ -1938,7 +2049,7 @@ var ColorSwatch = React8__namespace.forwardRef(
1938
2049
  }
1939
2050
  );
1940
2051
  ColorSwatch.displayName = "OODS.ColorSwatch";
1941
- var ColorizedBadge = React8__namespace.forwardRef(
2052
+ var ColorizedBadge = React9__namespace.forwardRef(
1942
2053
  ({ label, text, state, value, status, color, hue, swatch, variant, tone, emphasis, children, className, style, ...rest }, ref) => {
1943
2054
  const content = childContent(children);
1944
2055
  const resolvedLabel = content.scalar ?? firstText(label, text, state, value) ?? "Color";
@@ -1968,7 +2079,7 @@ var ColorizedBadge = React8__namespace.forwardRef(
1968
2079
  }
1969
2080
  );
1970
2081
  ColorizedBadge.displayName = "OODS.ColorizedBadge";
1971
- var VizAreaPreview = React8__namespace.forwardRef(
2082
+ var VizAreaPreview = React9__namespace.forwardRef(
1972
2083
  ({ width = 640, height = 360, svg, svgNarrow, svgWide, svgDark, svgDarkNarrow, svgDarkWide, svgHc, svgHcNarrow, svgHcWide, title, description, children, className, style, ...rest }, ref) => {
1973
2084
  const content = childContent(children);
1974
2085
  if (svg !== void 0) {
@@ -2037,7 +2148,7 @@ var descriptorLabel = (descriptor) => firstText(
2037
2148
  typeof descriptor.field === "string" ? descriptor.field : void 0
2038
2149
  ) ?? "Filter";
2039
2150
  function createPanelSection(component, className, panelType, defaultTitle) {
2040
- const Panel = React8__namespace.forwardRef(
2151
+ const Panel = React9__namespace.forwardRef(
2041
2152
  ({ title, label, heading, name, subtitle, description, metadata, summary: summary2, text, body, emptyMessage, children, className: consumerClassName, ...rest }, ref) => {
2042
2153
  const content = childContent(children);
2043
2154
  const authored = content.authored || content.scalar !== void 0;
@@ -2070,7 +2181,7 @@ var ClassificationPanel = createPanelSection("ClassificationPanel", "oods-classi
2070
2181
  var AddressCollectionPanel = createPanelSection("AddressCollectionPanel", "oods-address-collection-panel", "address", "Addresses");
2071
2182
  var MembershipPanel = createPanelSection("MembershipPanel", "oods-membership-panel", "membership", "Membership");
2072
2183
  var PreferencePanel = createPanelSection("PreferencePanel", "oods-preference-panel", "preference", "Preferences");
2073
- var FilterPanel = React8__namespace.forwardRef(
2184
+ var FilterPanel = React9__namespace.forwardRef(
2074
2185
  ({ filters, activeFilters, mode, collapsible = true, children, className, ...rest }, ref) => {
2075
2186
  const content = childContent(children);
2076
2187
  const authored = content.authored || content.scalar !== void 0;
@@ -2104,7 +2215,7 @@ var FilterPanel = React8__namespace.forwardRef(
2104
2215
  }
2105
2216
  );
2106
2217
  FilterPanel.displayName = "OODS.FilterPanel";
2107
- var PriceSummary = React8__namespace.forwardRef(
2218
+ var PriceSummary = React9__namespace.forwardRef(
2108
2219
  ({
2109
2220
  title,
2110
2221
  label,
@@ -2177,7 +2288,7 @@ var normalizeTagItems = (value) => {
2177
2288
  }
2178
2289
  return items.filter((item) => item.length > 0);
2179
2290
  };
2180
- var TagManager = React8__namespace.forwardRef(
2291
+ var TagManager = React9__namespace.forwardRef(
2181
2292
  ({ title, label, heading, name, description, subtitle, hint, tags, value, children, className, onSubmit, ...rest }, ref) => {
2182
2293
  const content = childContent(children);
2183
2294
  const authored = content.authored || content.scalar !== void 0;
@@ -2223,10 +2334,12 @@ var asCount = (value) => {
2223
2334
  return void 0;
2224
2335
  };
2225
2336
  function createBadgeFamily(options) {
2226
- const consumed = /* @__PURE__ */ new Set([...options.labelKeys, ...options.statusKeys, "variant", "tone", "emphasis"]);
2227
- const Family = React8__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) => {
2228
2339
  const { children, className, ...rest } = allProps;
2229
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;
2230
2343
  const scalar = (key) => {
2231
2344
  const value = record[key];
2232
2345
  if (typeof value === "boolean" && options.booleanProps?.includes(key)) return String(value);
@@ -2284,7 +2397,7 @@ var PreferenceSummaryBadge = createBadgeFamily({
2284
2397
  labelKeys: ["label", "text", "namespace", "value"],
2285
2398
  statusKeys: ["status", "state", "version"]
2286
2399
  });
2287
- var RoleBadgeList = React8__namespace.forwardRef(
2400
+ var RoleBadgeList = React9__namespace.forwardRef(
2288
2401
  ({ roles, badges, roleLabels, value, variant, tone, label, text, children, className, ...rest }, ref) => {
2289
2402
  const content = childContent(children);
2290
2403
  const authored = content.authored || content.scalar !== void 0;
@@ -2304,7 +2417,7 @@ var RoleBadgeList = React8__namespace.forwardRef(
2304
2417
  }
2305
2418
  );
2306
2419
  RoleBadgeList.displayName = "OODS.RoleBadgeList";
2307
- var TagPills = React8__namespace.forwardRef(
2420
+ var TagPills = React9__namespace.forwardRef(
2308
2421
  ({ tags, value, maxVisible, overflowLabel, children, className, ...rest }, ref) => {
2309
2422
  const content = childContent(children);
2310
2423
  const authored = content.authored || content.scalar !== void 0;
@@ -2356,7 +2469,7 @@ var normalizeTimelineItems = (raw) => {
2356
2469
  };
2357
2470
  function createTimelineFamily(options) {
2358
2471
  const consumed = /* @__PURE__ */ new Set(["title", "label", "heading", "name", ...options.eventKeys]);
2359
- const Family = React8__namespace.forwardRef((allProps, ref) => {
2472
+ const Family = React9__namespace.forwardRef((allProps, ref) => {
2360
2473
  const { children, className, ...rest } = allProps;
2361
2474
  const record = rest;
2362
2475
  const text = (key) => {
@@ -2421,7 +2534,7 @@ var PreferenceTimeline = createTimelineFamily({
2421
2534
  timelineType: "preference",
2422
2535
  eventKeys: ["events", "changes", "history"]
2423
2536
  });
2424
- var AuditEvent = React8__namespace.forwardRef(
2537
+ var AuditEvent = React9__namespace.forwardRef(
2425
2538
  ({
2426
2539
  label,
2427
2540
  title,
@@ -2507,7 +2620,7 @@ var addressRecord = (form) => {
2507
2620
  };
2508
2621
  return { street: read("street"), city: read("city"), region: read("region"), postalCode: read("postalCode") };
2509
2622
  };
2510
- var AddressEditor = React8__namespace.forwardRef(
2623
+ var AddressEditor = React9__namespace.forwardRef(
2511
2624
  ({
2512
2625
  title,
2513
2626
  label,
@@ -2565,8 +2678,8 @@ var AddressEditor = React8__namespace.forwardRef(
2565
2678
  }
2566
2679
  );
2567
2680
  AddressEditor.displayName = "OODS.AddressEditor";
2568
- var PreferenceEditor = React8__namespace.forwardRef(
2569
- ({ 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) => {
2570
2683
  const content = childContent(children);
2571
2684
  const authored = content.authored || content.scalar !== void 0;
2572
2685
  const resolvedTitle = firstText(title, label, heading, name) ?? "Preference Editor";
@@ -2593,7 +2706,7 @@ var PreferenceEditor = React8__namespace.forwardRef(
2593
2706
  ] }),
2594
2707
  /* @__PURE__ */ jsxRuntime.jsxs("label", { "data-form-control": "textarea", children: [
2595
2708
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Preference Document" }),
2596
- /* @__PURE__ */ jsxRuntime.jsx("textarea", { name: "preferenceDocument", defaultValue: firstScalar(document, json, value) ?? "" })
2709
+ /* @__PURE__ */ jsxRuntime.jsx("textarea", { name: "preferenceDocument", defaultValue: firstScalar(document2, json, value) ?? "" })
2597
2710
  ] })
2598
2711
  ] }) })
2599
2712
  ]
@@ -2602,7 +2715,7 @@ var PreferenceEditor = React8__namespace.forwardRef(
2602
2715
  }
2603
2716
  );
2604
2717
  PreferenceEditor.displayName = "OODS.PreferenceEditor";
2605
- var RoleAssignmentForm = React8__namespace.forwardRef(
2718
+ var RoleAssignmentForm = React9__namespace.forwardRef(
2606
2719
  ({ title, label, heading, name, description, subtitle, hint, roles, availableRoles, role, defaultRoleId, assignee, member, children, className, onSubmit, ...rest }, ref) => {
2607
2720
  const content = childContent(children);
2608
2721
  const authored = content.authored || content.scalar !== void 0;
@@ -2639,7 +2752,7 @@ var RoleAssignmentForm = React8__namespace.forwardRef(
2639
2752
  }
2640
2753
  );
2641
2754
  RoleAssignmentForm.displayName = "OODS.RoleAssignmentForm";
2642
- var StatusSelector = React8__namespace.forwardRef(
2755
+ var StatusSelector = React9__namespace.forwardRef(
2643
2756
  ({ label, title, help, options, states, value, status, children, className, onChange, onValueChange, onUpdate, ...rest }, ref) => {
2644
2757
  const content = childContent(children);
2645
2758
  const authored = content.authored || content.scalar !== void 0;
@@ -2681,7 +2794,7 @@ var StatusSelector = React8__namespace.forwardRef(
2681
2794
  }
2682
2795
  );
2683
2796
  StatusSelector.displayName = "OODS.StatusSelector";
2684
- var TagInput = React8__namespace.forwardRef(
2797
+ var TagInput = React9__namespace.forwardRef(
2685
2798
  ({ title, label, heading, name, description, subtitle, hint, tags, value, placeholder, children, className, onChange, onValueChange, onUpdate, ...rest }, ref) => {
2686
2799
  const content = childContent(children);
2687
2800
  const authored = content.authored || content.scalar !== void 0;
@@ -2728,7 +2841,7 @@ var TagInput = React8__namespace.forwardRef(
2728
2841
  }
2729
2842
  );
2730
2843
  TagInput.displayName = "OODS.TagInput";
2731
- var TemplatePicker = React8__namespace.forwardRef(
2844
+ var TemplatePicker = React9__namespace.forwardRef(
2732
2845
  ({ title, label, heading, name, description, subtitle, hint, templates, options, templateId, value, channels, channel, children, className, ...rest }, ref) => {
2733
2846
  const content = childContent(children);
2734
2847
  const authored = content.authored || content.scalar !== void 0;
@@ -2766,14 +2879,14 @@ var truncateLabel = (value, maxLength) => {
2766
2879
  const limit = typeof maxLength === "number" ? maxLength : Number(maxLength);
2767
2880
  return !Number.isFinite(limit) || limit <= 0 || value.length <= limit ? value : `${value.slice(0, Math.max(0, limit - 1)).trimEnd()}...`;
2768
2881
  };
2769
- var InlineLabel = React8__namespace.forwardRef(
2882
+ var InlineLabel = React9__namespace.forwardRef(
2770
2883
  ({ label, text, value, maxLength, children, className, ...rest }, ref) => {
2771
2884
  const content = childContent(children);
2772
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) });
2773
2886
  }
2774
2887
  );
2775
2888
  InlineLabel.displayName = "OODS.InlineLabel";
2776
- var LabelCell = React8__namespace.forwardRef(
2889
+ var LabelCell = React9__namespace.forwardRef(
2777
2890
  ({ label, text, value, description, subtitle, sublabel, supporting, truncate, maxLength, children, className, ...rest }, ref) => {
2778
2891
  const content = childContent(children);
2779
2892
  const limit = truncate ? maxLength ?? 40 : maxLength;
@@ -2786,7 +2899,7 @@ var LabelCell = React8__namespace.forwardRef(
2786
2899
  }
2787
2900
  );
2788
2901
  LabelCell.displayName = "OODS.LabelCell";
2789
- var FormLabelGroup = React8__namespace.forwardRef(
2902
+ var FormLabelGroup = React9__namespace.forwardRef(
2790
2903
  ({ label, text, title, placeholder, hint, description, htmlFor, for: forId, inputId, children, className, ...rest }, ref) => {
2791
2904
  const detail = firstText(placeholder, hint, description);
2792
2905
  return /* @__PURE__ */ jsxRuntime.jsxs("label", { ref, className: classes7("oods-form-label-group", className), "data-oods-component": "FormLabelGroup", htmlFor: htmlFor ?? forId ?? inputId, ...rest, children: [
@@ -2805,7 +2918,7 @@ var ClassificationBadge = createBadgeFamily({
2805
2918
  labelKeys: ["label", "text", "category", "value"],
2806
2919
  statusKeys: ["status", "state", "mode"]
2807
2920
  });
2808
- var ClassificationEditor = React8__namespace.forwardRef(
2921
+ var ClassificationEditor = React9__namespace.forwardRef(
2809
2922
  ({ title, label, heading, name, description, subtitle, hint, category, primaryCategory, tags, modes, mode, classificationMode, children, className, onSubmit, ...rest }, ref) => {
2810
2923
  const content = childContent(children);
2811
2924
  const tagText = typeof tags === "string" ? tags : tags === void 0 ? "" : JSON.stringify(tags);
@@ -2851,7 +2964,7 @@ var OwnerBadge = createBadgeFamily({
2851
2964
  labelKeys: ["label", "text", "owner", "ownerType", "value"],
2852
2965
  statusKeys: ["status", "state"]
2853
2966
  });
2854
- var OwnershipSummary = React8__namespace.forwardRef(
2967
+ var OwnershipSummary = React9__namespace.forwardRef(
2855
2968
  ({ title, label, heading, name, ownerLabel, ownerId, owner_id, ownerType, owner_type, role, ownershipRole, summary: summary2, text, description, children, className, ...rest }, ref) => {
2856
2969
  const content = childContent(children);
2857
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);
@@ -2866,7 +2979,7 @@ var OwnershipSummary = React8__namespace.forwardRef(
2866
2979
  }
2867
2980
  );
2868
2981
  OwnershipSummary.displayName = "OODS.OwnershipSummary";
2869
- var TagSummary = React8__namespace.forwardRef(
2982
+ var TagSummary = React9__namespace.forwardRef(
2870
2983
  ({ title, label, heading, name, tagCount, count, tags, summary: summary2, text, description, children, className, ...rest }, ref) => {
2871
2984
  const content = childContent(children);
2872
2985
  const tagText = Array.isArray(tags) ? normalizeTagItems(tags).join(", ") || void 0 : firstText(tags);
@@ -2882,11 +2995,12 @@ var TagSummary = React8__namespace.forwardRef(
2882
2995
  }
2883
2996
  );
2884
2997
  TagSummary.displayName = "OODS.TagSummary";
2885
- var OwnershipMeta = React8__namespace.forwardRef(
2886
- ({ 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) => {
2887
3000
  const content = childContent(children);
2888
3001
  const terms = [["Owner Type", firstScalar(ownerType, owner_type)], ["Role", firstScalar(role, ownershipRole)]].filter((entry) => entry[1] !== void 0);
2889
- 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: [
2890
3004
  /* @__PURE__ */ jsxRuntime.jsx("span", { "data-meta-title": "true", children: firstText(title, label, heading, name) ?? "Ownership" }),
2891
3005
  terms.map(([term, value]) => /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-meta-item": "true", children: [
2892
3006
  /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
@@ -2920,7 +3034,7 @@ var CancellationBadge = createBadgeFamily({
2920
3034
  booleanProps: ["cancelAtPeriodEnd", "isCancelled", "value"],
2921
3035
  booleanLabels: ["Cancellation scheduled", "No cancellation scheduled"]
2922
3036
  });
2923
- var ArchiveSummary = React8__namespace.forwardRef(
3037
+ var ArchiveSummary = React9__namespace.forwardRef(
2924
3038
  ({ title, label, heading, name, isArchived, archived, status, archivedAt, reason, archiveReason, summary: summary2, text, description, children, className, ...rest }, ref) => {
2925
3039
  const content = childContent(children);
2926
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);
@@ -2935,7 +3049,7 @@ var ArchiveSummary = React8__namespace.forwardRef(
2935
3049
  }
2936
3050
  );
2937
3051
  ArchiveSummary.displayName = "OODS.ArchiveSummary";
2938
- var PriceCardMeta = React8__namespace.forwardRef(
3052
+ var PriceCardMeta = React9__namespace.forwardRef(
2939
3053
  ({ title, label, heading, name, model, pricingModel, interval, billingInterval, children, className, ...rest }, ref) => {
2940
3054
  const content = childContent(children);
2941
3055
  const terms = [["Model", componentContracts.formatPriceCode(firstText(model, pricingModel))], ["Interval", componentContracts.formatPriceCode(firstText(interval, billingInterval))]].filter((entry) => entry[1] !== void 0);
@@ -2953,12 +3067,12 @@ var PriceCardMeta = React8__namespace.forwardRef(
2953
3067
  }
2954
3068
  );
2955
3069
  PriceCardMeta.displayName = "OODS.PriceCardMeta";
2956
- var CancellationForm = React8__namespace.forwardRef(
3070
+ var CancellationForm = React9__namespace.forwardRef(
2957
3071
  ({ title, label, heading, name, description, subtitle, hint, allowedReasons, reasonCode, reason, cancellationReason, embedded, reasonHelp, codeHelp, children, className, onSubmit, ...rest }, ref) => {
2958
3072
  const content = childContent(children);
2959
3073
  const choices = normalizeSelectOptions(allowedReasons ?? ["no_longer_needed", "budget", "duplicate"]);
2960
3074
  if (reasonCode && !choices.some((choice) => choice.value === reasonCode)) choices.unshift({ value: reasonCode, label: reasonCode });
2961
- return React8__namespace.createElement(embedded ? "fieldset" : "form", {
3075
+ return React9__namespace.createElement(embedded ? "fieldset" : "form", {
2962
3076
  ...rest,
2963
3077
  ref,
2964
3078
  className: classes7("oods-cancellation-form", className),
@@ -2990,11 +3104,11 @@ function BillingSummaryBadge({ id, amount, currency, minorUnits, interval, showI
2990
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) });
2991
3105
  }
2992
3106
  function BillingAmountInput({ id, amount, currency = "usd", minorUnits = componentContracts.BILLING_MINOR_UNITS, label = "Billing amount", name, disabled, className, help, onChange }) {
2993
- const generatedId = React8__namespace.useId();
3107
+ const generatedId = React9__namespace.useId();
2994
3108
  const controlId = id ?? `billing-amount-${generatedId}`;
2995
- const [text, setText] = React8__namespace.useState(() => componentContracts.billingAmountText(amount, minorUnits));
2996
- const [error, setError] = React8__namespace.useState(() => componentContracts.billingAmountMessage(amount, minorUnits));
2997
- React8__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(() => {
2998
3112
  setText(componentContracts.billingAmountText(amount, minorUnits));
2999
3113
  setError(componentContracts.billingAmountMessage(amount, minorUnits));
3000
3114
  }, [amount, minorUnits]);
@@ -3028,10 +3142,10 @@ function BillingAmountInput({ id, amount, currency = "usd", minorUnits = compone
3028
3142
  ] });
3029
3143
  }
3030
3144
  function BillingIntervalSelector({ id, interval, intervals = componentContracts.BILLING_INTERVALS, label = "Billing interval", name, disabled, className, help, onChange }) {
3031
- const generatedId = React8__namespace.useId();
3145
+ const generatedId = React9__namespace.useId();
3032
3146
  const controlId = id ?? `billing-interval-${generatedId}`;
3033
- const [value, setValue] = React8__namespace.useState(interval ?? "");
3034
- React8__namespace.useEffect(() => {
3147
+ const [value, setValue] = React9__namespace.useState(interval ?? "");
3148
+ React9__namespace.useEffect(() => {
3035
3149
  setValue(interval ?? "");
3036
3150
  }, [interval]);
3037
3151
  const error = componentContracts.billingIntervalMessage(value || void 0, intervals);
@@ -3139,8 +3253,8 @@ function AuditSummaryCard({ id, title = "Audit summary", showTransitionCount = t
3139
3253
  ] });
3140
3254
  }
3141
3255
  function SortIndicator({ id, label = "Sort", onChange, "data-oods-action": action, ...values }) {
3142
- const [state, setState] = React8__namespace.useState(() => componentContracts.initialSort(values));
3143
- React8__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]);
3144
3258
  const sort = componentContracts.ariaSort(state);
3145
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: () => {
3146
3260
  const next = componentContracts.nextSort(state, values.triStateSort);
@@ -3148,14 +3262,15 @@ function SortIndicator({ id, label = "Sort", onChange, "data-oods-action": actio
3148
3262
  onChange?.(next);
3149
3263
  }, children: `${state.field}: ${sort}` }) }) }) }) });
3150
3264
  }
3151
- var TimelineEntryLabel = React8__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 }));
3152
3266
  TimelineEntryLabel.displayName = "OODS.TimelineEntryLabel";
3153
3267
  function eventRecipe(id, kind, title) {
3154
3268
  return function TraitEvent({ id: elementId, title: heading = title, ...values }) {
3155
3269
  const rows = componentContracts.traitEventRows(kind, values);
3270
+ if (!rows.length) return null;
3156
3271
  return /* @__PURE__ */ jsxRuntime.jsxs("article", { id: elementId, className: "oods-trait-recipe", "data-oods-component": id, "aria-label": heading, children: [
3157
3272
  /* @__PURE__ */ jsxRuntime.jsx("h2", { children: heading }),
3158
- 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: [
3159
3274
  /* @__PURE__ */ jsxRuntime.jsx("strong", { children: row.title }),
3160
3275
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: row.at ? /* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: row.at, children: row.time }) : row.time }),
3161
3276
  row.actor && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
@@ -3170,7 +3285,7 @@ function eventRecipe(id, kind, title) {
3170
3285
  "Code: ",
3171
3286
  row.code
3172
3287
  ] })
3173
- ] }, index)) }) : /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No events recorded." })
3288
+ ] }, index)) })
3174
3289
  ] });
3175
3290
  };
3176
3291
  }
@@ -3191,9 +3306,9 @@ function CommunicationDetailPanel({ id, title = "Communication", channels = [],
3191
3306
  ] });
3192
3307
  }
3193
3308
  function ColorStatePicker({ id, title = "Color state", colorStates = componentContracts.DEFAULT_COLOR_STATES, value, disabled, onChange }) {
3194
- const generatedId = React8__namespace.useId();
3195
- const [selected, setSelected] = React8__namespace.useState(value ?? colorStates[0] ?? "");
3196
- React8__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]);
3197
3312
  return /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { id, className: "oods-trait-recipe", "data-oods-component": "ColorStatePicker", children: [
3198
3313
  /* @__PURE__ */ jsxRuntime.jsx("legend", { children: title }),
3199
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) => {
@@ -3215,9 +3330,9 @@ function StatusColorLegend({ id, title = "Status colors", colorStates = componen
3215
3330
  ] });
3216
3331
  }
3217
3332
  function GeoFieldMappingForm({ id, title = "Geographic fields", embedded = false, disabled, onChange, ...values }) {
3218
- const generatedId = React8__namespace.useId();
3219
- const [value, setValue] = React8__namespace.useState(() => componentContracts.geoFieldMapping(values));
3220
- React8__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]);
3221
3336
  const update = (patch) => {
3222
3337
  const next = { ...value, ...patch };
3223
3338
  setValue(next);
@@ -3251,11 +3366,11 @@ function GeocodablePreview({ id, title = "Geographic data", resolution, requires
3251
3366
  }
3252
3367
  function controls(id) {
3253
3368
  const Component = ({ id: htmlId, title = componentContracts.VIZ_CONTROL_TITLES[id], value, channel = "x", disabled, onChange }) => {
3254
- const generatedId = React8__namespace.useId();
3255
- const [current, setCurrent] = React8__namespace.useState(value ?? {});
3256
- const [drafts, setDrafts] = React8__namespace.useState({});
3257
- const [errors, setErrors] = React8__namespace.useState({});
3258
- React8__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(() => {
3259
3374
  setCurrent(value ?? {});
3260
3375
  setDrafts({});
3261
3376
  setErrors({});
@@ -3329,6 +3444,215 @@ var VizLinePreview = preview("VizLinePreview", "line");
3329
3444
  var VizMarkPreview = preview("VizMarkPreview", "bar");
3330
3445
  var VizPointPreview = preview("VizPointPreview", "scatter");
3331
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";
3332
3656
 
3333
3657
  exports.AddressCollectionPanel = AddressCollectionPanel;
3334
3658
  exports.AddressEditor = AddressEditor;
@@ -3361,6 +3685,7 @@ exports.ClassificationPanel = ClassificationPanel;
3361
3685
  exports.ColorStatePicker = ColorStatePicker;
3362
3686
  exports.ColorSwatch = ColorSwatch;
3363
3687
  exports.ColorizedBadge = ColorizedBadge;
3688
+ exports.Combobox = Combobox;
3364
3689
  exports.CommunicationDetailPanel = CommunicationDetailPanel;
3365
3690
  exports.CycleProgressCard = CycleProgressCard;
3366
3691
  exports.DatePicker = DatePicker;
@@ -3396,6 +3721,7 @@ exports.RelativeTimestamp = RelativeTimestamp;
3396
3721
  exports.RoleAssignmentForm = RoleAssignmentForm;
3397
3722
  exports.RoleBadgeList = RoleBadgeList;
3398
3723
  exports.SearchInput = SearchInput;
3724
+ exports.SegmentedControl = SegmentedControl;
3399
3725
  exports.Select = Select;
3400
3726
  exports.SortIndicator = SortIndicator;
3401
3727
  exports.Stack = Stack;