@oods/components-vue 0.3.2 → 0.4.0

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/README.md CHANGED
@@ -34,4 +34,4 @@ Use matching versions of the OODS packages. These packages are separate from the
34
34
 
35
35
  ## License
36
36
 
37
- Apache License 2.0. See [LICENSE](https://cdn.jsdelivr.net/npm/@oods/components-vue@0.3.2/LICENSE) and [NOTICE](https://cdn.jsdelivr.net/npm/@oods/components-vue@0.3.2/NOTICE). Generated output belongs to its user; installed package dependencies retain their own licenses.
37
+ Apache License 2.0. See [LICENSE](https://cdn.jsdelivr.net/npm/@oods/components-vue@0.4.0/LICENSE) and [NOTICE](https://cdn.jsdelivr.net/npm/@oods/components-vue@0.4.0/NOTICE). Generated output belongs to its user; installed package dependencies retain their own licenses.
package/dist/index.cjs CHANGED
@@ -3,6 +3,11 @@
3
3
  var vue = require('vue');
4
4
  var componentContracts = require('@oods/component-contracts');
5
5
 
6
+ // src/primitives.ts
7
+ function statusIcon(name) {
8
+ return vue.h("svg", { ...componentContracts.STATUS_ICON_SVG_ATTRS }, componentContracts.STATUS_ICON_SHAPES[name].map((shape) => vue.h(shape.tag, { ...shape.attrs })));
9
+ }
10
+
6
11
  // src/primitives.ts
7
12
  var toneProp = String;
8
13
  var emphasisProp = String;
@@ -91,8 +96,8 @@ var Badge = vue.defineComponent({
91
96
  "--cmp-badge-text": `var(--sys-status-${palette}-text)`
92
97
  }
93
98
  }, [
94
- props.icon || slots.icon ? vue.h("span", { class: "oods-badge-icon", "aria-hidden": "true" }, [slotOrValue(slots.icon, props.icon)]) : null,
95
- slotOrValue(slots.default, props.content ?? statusLabel(props.status))
99
+ props.icon || slots.icon ? vue.h("span", { class: "oods-badge__icon", "aria-hidden": "true" }, [slotOrValue(slots.icon, props.icon)]) : null,
100
+ vue.h("span", { class: "oods-badge__label" }, [slotOrValue(slots.default, props.content ?? statusLabel(props.status))])
96
101
  ]);
97
102
  };
98
103
  }
@@ -116,7 +121,7 @@ var Banner = vue.defineComponent({
116
121
  return () => {
117
122
  const tone = resolveTone(props.tone, props.status, props.domain);
118
123
  const palette = tokenTone(tone);
119
- return vue.h("section", {
124
+ return vue.h("div", {
120
125
  class: "oods-banner",
121
126
  "data-oods-component": "Banner",
122
127
  "data-status": props.status,
@@ -131,20 +136,20 @@ var Banner = vue.defineComponent({
131
136
  "--cmp-banner-text": `var(--sys-status-${palette}-text)`
132
137
  }
133
138
  }, [
134
- vue.h("div", { class: "oods-banner-content" }, [
135
- props.title || props.status || slots.title ? vue.h("strong", { class: "oods-banner-title" }, [
139
+ vue.h("div", { class: "oods-banner__content" }, [
140
+ props.title || props.status || slots.title ? vue.h("strong", { class: "oods-banner__title" }, [
136
141
  slotOrValue(slots.title, props.title || statusLabel(props.status))
137
142
  ]) : null,
138
- props.detail ? vue.h("p", { class: "oods-banner-detail" }, props.detail) : null,
139
- slots.default || props.content ? vue.h(slots.default ? "div" : "p", { class: "oods-banner-body" }, [slotOrValue(slots.default, props.content)]) : null,
140
- slots.actions ? vue.h("div", { class: "oods-banner-actions" }, slots.actions()) : null
143
+ props.detail ? vue.h("p", { class: "oods-banner__detail" }, props.detail) : null,
144
+ slots.default || props.content ? vue.h(slots.default ? "div" : "p", { class: "oods-banner__body" }, [slotOrValue(slots.default, props.content)]) : null,
145
+ slots.actions ? vue.h("div", { class: "oods-banner__actions" }, slots.actions()) : null
141
146
  ]),
142
147
  props.dismissLabel ? vue.h("button", {
143
148
  type: "button",
144
- class: "oods-banner-dismiss",
149
+ class: "oods-banner-dismiss oods-banner__dismiss",
145
150
  "aria-label": props.dismissLabel,
146
151
  onClick: () => emit("dismiss")
147
- }, [vue.h("span", { "aria-hidden": "true" }, "\xD7")]) : null
152
+ }, [statusIcon("x")]) : null
148
153
  ]);
149
154
  };
150
155
  }
@@ -154,7 +159,7 @@ var Button = vue.defineComponent({
154
159
  props: {
155
160
  content: { type: [String, Number], default: "" },
156
161
  intent: { type: String, default: "neutral" },
157
- size: { type: sizeProp, default: "md" },
162
+ size: { type: String, default: "md" },
158
163
  disabled: Boolean,
159
164
  type: { type: String, default: "button" }
160
165
  },
@@ -181,6 +186,83 @@ var Button = vue.defineComponent({
181
186
  }, [slotOrValue(slots.default, props.content)]);
182
187
  }
183
188
  });
189
+ var canShowModal = () => typeof HTMLDialogElement !== "undefined" && typeof HTMLDialogElement.prototype.showModal === "function";
190
+ var Dialog = vue.defineComponent({
191
+ name: "OodsDialog",
192
+ props: {
193
+ id: String,
194
+ open: Boolean,
195
+ modal: { type: Boolean, default: true },
196
+ title: { type: String, default: "" },
197
+ description: String,
198
+ dismissLabel: { type: String, default: "Close" },
199
+ size: { type: String, default: "md" },
200
+ actions: { type: [String, Number, Object, Array], default: void 0 }
201
+ },
202
+ emits: {
203
+ close: () => true
204
+ },
205
+ setup(props, { emit, slots }) {
206
+ const generatedId = vue.useId().replace(/[^\w-]/g, "");
207
+ const dialogId = vue.computed(() => props.id || `oods-dialog-${generatedId}`);
208
+ const element = vue.ref(null);
209
+ const mounted = vue.ref(false);
210
+ const managed = vue.computed(() => props.modal && mounted.value && canShowModal());
211
+ const sync = () => {
212
+ const dialog = element.value;
213
+ if (!dialog || !managed.value) return;
214
+ if (props.open && !dialog.open) dialog.showModal();
215
+ else if (!props.open && dialog.open) dialog.close();
216
+ };
217
+ vue.onMounted(() => {
218
+ mounted.value = true;
219
+ });
220
+ vue.watch([() => props.open, managed], sync, { flush: "post" });
221
+ const requestClose = (event) => {
222
+ event.preventDefault();
223
+ emit("close");
224
+ };
225
+ return () => {
226
+ const titleId = `${dialogId.value}-title`;
227
+ const descriptionId = `${dialogId.value}-description`;
228
+ const actions = slotOrValue(slots.actions, props.actions);
229
+ return vue.h("dialog", {
230
+ ref: element,
231
+ id: dialogId.value,
232
+ class: "oods-dialog",
233
+ "data-oods-component": "Dialog",
234
+ "data-size": props.size,
235
+ "aria-labelledby": titleId,
236
+ "aria-describedby": props.description ? descriptionId : void 0,
237
+ open: managed.value ? void 0 : props.open,
238
+ onKeydown: (event) => {
239
+ if (event.key === "Escape" && !event.defaultPrevented) requestClose(event);
240
+ },
241
+ onCancel: requestClose,
242
+ // The browser closed it (a close request it would not let be cancelled) while open is still true. A close event
243
+ // from moving a mounted dialog into the top layer finds it open again, and is not reported.
244
+ onClose: () => {
245
+ if (props.open && !element.value?.open) emit("close");
246
+ }
247
+ }, [
248
+ vue.h("div", { class: "oods-dialog__header" }, [
249
+ vue.h("div", { class: "oods-dialog__heading" }, [
250
+ vue.h("h2", { id: titleId, class: "oods-dialog__title" }, props.title),
251
+ props.description ? vue.h("p", { id: descriptionId, class: "oods-dialog__description" }, props.description) : null
252
+ ]),
253
+ vue.h("button", {
254
+ type: "button",
255
+ class: "oods-dialog__close",
256
+ "aria-label": props.dismissLabel,
257
+ onClick: () => emit("close")
258
+ }, [statusIcon("x")])
259
+ ]),
260
+ slots.default ? vue.h("div", { class: "oods-dialog__body" }, slots.default()) : null,
261
+ actions !== void 0 && actions !== null && actions !== "" ? vue.h("div", { class: "oods-dialog__footer" }, [actions]) : null
262
+ ]);
263
+ };
264
+ }
265
+ });
184
266
  var SAFE_CARD_ELEMENTS = /* @__PURE__ */ new Set(["div", "article", "section", "aside"]);
185
267
  var Card = vue.defineComponent({
186
268
  name: "OodsCard",
@@ -433,6 +515,7 @@ var ColorizedBadge = vue.defineComponent({
433
515
  const color = firstText(props.color, props.hue, props.swatch, props.state);
434
516
  const variant = firstText(props.variant) ?? "colorized";
435
517
  return vue.h(Badge, {
518
+ class: "oods-colorized-badge",
436
519
  status,
437
520
  tone: props.tone,
438
521
  emphasis: props.emphasis,
@@ -459,6 +542,13 @@ var VizAreaPreview = vue.defineComponent({
459
542
  svgNarrow: String,
460
543
  /** The same chart rendered at the wide size; the figure shows it instead of svg when its own inline size is at least 900px. */
461
544
  svgWide: String,
545
+ /** s222-m02 (F7): the dark and high-contrast renders; with any of them, svg* are the light ones (see React's types). */
546
+ svgDark: String,
547
+ svgDarkNarrow: String,
548
+ svgDarkWide: String,
549
+ svgHc: String,
550
+ svgHcNarrow: String,
551
+ svgHcWide: String,
462
552
  title: String,
463
553
  description: String,
464
554
  width: { type: Number, default: 640 },
@@ -467,6 +557,7 @@ var VizAreaPreview = vue.defineComponent({
467
557
  setup(props, { slots }) {
468
558
  return () => {
469
559
  const content = authoredContent(slots.default?.());
560
+ const renders = (layer) => layer.renders.map(([attribute, markup]) => vue.h("div", { [attribute]: "true", innerHTML: markup }));
470
561
  if (props.svg !== void 0) return vue.h("figure", {
471
562
  class: "oods-viz-area-preview",
472
563
  "data-oods-component": "VizAreaPreview",
@@ -481,9 +572,11 @@ var VizAreaPreview = vue.defineComponent({
481
572
  style: { "--oods-viz-width": `${props.width}px` }
482
573
  }, [
483
574
  ...props.title && !componentContracts.svgCarriesTitle(props.svg, props.title) ? [vue.h("figcaption", props.title)] : [],
484
- vue.h("div", { "data-viz-svg": "true", innerHTML: componentContracts.assertStaticSvg(props.svg) }),
485
- ...props.svgNarrow !== void 0 ? [vue.h("div", { "data-viz-svg-narrow": "true", innerHTML: componentContracts.assertStaticSvg(props.svgNarrow) })] : [],
486
- ...props.svgWide !== void 0 ? [vue.h("div", { "data-viz-svg-wide": "true", innerHTML: componentContracts.assertStaticSvg(props.svgWide) })] : [],
575
+ ...componentContracts.vizPreviewLayers(props).flatMap((layer) => layer.theme === void 0 ? renders(layer) : [vue.h("div", {
576
+ "data-viz-theme": layer.theme,
577
+ ...layer.narrow ? { "data-viz-narrow": "true" } : {},
578
+ ...layer.wide ? { "data-viz-wide": "true" } : {}
579
+ }, renders(layer))]),
487
580
  ...props.description ? [vue.h("p", { "data-viz-description": "true" }, props.description)] : []
488
581
  ]);
489
582
  return vue.h("div", {
@@ -1506,7 +1599,9 @@ var Input = vue.defineComponent({
1506
1599
  name: "OodsInput",
1507
1600
  props: {
1508
1601
  ...textFieldProps,
1509
- type: { type: String, default: "text" }
1602
+ type: { type: String, default: "text" },
1603
+ /** A class for the input element itself, as React's inputClassName; the field's own class stays on its frame. */
1604
+ inputClass: String
1510
1605
  },
1511
1606
  emits: {
1512
1607
  "update:modelValue": (_value) => true,
@@ -1524,7 +1619,7 @@ var Input = vue.defineComponent({
1524
1619
  };
1525
1620
  return () => renderField("Input", props, slots, metadata, vue.h("input", {
1526
1621
  id: metadata.controlId.value,
1527
- class: "oods-field-control",
1622
+ class: props.inputClass ? ["oods-field-control", props.inputClass] : "oods-field-control",
1528
1623
  type: props.type,
1529
1624
  name: props.name,
1530
1625
  value: props.type === "datetime-local" ? componentContracts.dateTimeInputValue(currentValue.value) : currentValue.value,
@@ -1724,28 +1819,97 @@ var Checkbox = vue.defineComponent({
1724
1819
  };
1725
1820
  }
1726
1821
  });
1822
+ var Switch = vue.defineComponent({
1823
+ name: "OodsSwitch",
1824
+ props: {
1825
+ id: String,
1826
+ label: String,
1827
+ modelValue: { type: Boolean, default: void 0 },
1828
+ checked: { type: Boolean, default: void 0 },
1829
+ defaultChecked: Boolean,
1830
+ required: Boolean,
1831
+ disabled: Boolean,
1832
+ help: String,
1833
+ validation: Object,
1834
+ size: { type: String, default: "md" }
1835
+ },
1836
+ emits: {
1837
+ "update:modelValue": (_value) => true,
1838
+ change: (_value) => true
1839
+ },
1840
+ setup(props, { emit, slots }) {
1841
+ const internalChecked = vue.ref(props.defaultChecked);
1842
+ const currentChecked = vue.computed(() => props.modelValue ?? props.checked ?? internalChecked.value);
1843
+ const metadata = useFieldMetadata("Switch", props, slots);
1844
+ const toggle = () => {
1845
+ const next = !currentChecked.value;
1846
+ if (props.modelValue === void 0 && props.checked === void 0) internalChecked.value = next;
1847
+ emit("update:modelValue", next);
1848
+ emit("change", next);
1849
+ };
1850
+ return () => {
1851
+ const label = slots.label?.() ?? props.label;
1852
+ const help = slots.help?.() ?? props.help;
1853
+ const validation = slots.validation?.() ?? props.validation?.message;
1854
+ const controlId = metadata.controlId.value;
1855
+ return vue.h("div", {
1856
+ class: "oods-field oods-switch",
1857
+ style: validationStyle(props.validation),
1858
+ "data-oods-component": "Switch",
1859
+ "data-size": props.size,
1860
+ "data-validation-state": props.validation?.state
1861
+ }, [
1862
+ vue.h("div", { class: "oods-switch__row" }, [
1863
+ vue.h("button", {
1864
+ id: controlId,
1865
+ type: "button",
1866
+ role: "switch",
1867
+ class: "oods-switch__control",
1868
+ "aria-checked": currentChecked.value ? "true" : "false",
1869
+ "aria-labelledby": `${controlId}-label`,
1870
+ "aria-describedby": metadata.describedBy.value,
1871
+ "aria-required": props.required ? "true" : void 0,
1872
+ "aria-invalid": props.validation?.state === "error" ? "true" : void 0,
1873
+ disabled: props.disabled,
1874
+ onClick: toggle
1875
+ }, [vue.h("span", { class: "oods-switch__thumb", "aria-hidden": "true" })]),
1876
+ vue.h("label", { id: `${controlId}-label`, class: "oods-field-label oods-switch__label", for: controlId }, [
1877
+ label,
1878
+ props.required ? vue.h("span", { class: "oods-field-required", "aria-hidden": "true" }, "*") : null
1879
+ ])
1880
+ ]),
1881
+ help ? vue.h("p", { id: metadata.helpId.value, class: "oods-field-help" }, help) : null,
1882
+ validation ? vue.h("p", {
1883
+ id: metadata.validationId.value,
1884
+ class: "oods-field-error",
1885
+ role: props.validation?.state === "error" ? "alert" : void 0
1886
+ }, validation) : null
1887
+ ]);
1888
+ };
1889
+ }
1890
+ });
1727
1891
  var TableCaption = vue.defineComponent({
1728
1892
  name: "OodsTableCaption",
1729
1893
  setup(_props, { slots }) {
1730
- return () => vue.h("caption", {}, slots.default?.());
1894
+ return () => vue.h("caption", { class: "oods-table__caption" }, slots.default?.());
1731
1895
  }
1732
1896
  });
1733
1897
  var TableHead = vue.defineComponent({
1734
1898
  name: "OodsTableHead",
1735
1899
  setup(_props, { slots }) {
1736
- return () => vue.h("thead", {}, slots.default?.());
1900
+ return () => vue.h("thead", { class: "oods-table__header" }, slots.default?.());
1737
1901
  }
1738
1902
  });
1739
1903
  var TableBody = vue.defineComponent({
1740
1904
  name: "OodsTableBody",
1741
1905
  setup(_props, { slots }) {
1742
- return () => vue.h("tbody", {}, slots.default?.());
1906
+ return () => vue.h("tbody", { class: "oods-table__body" }, slots.default?.());
1743
1907
  }
1744
1908
  });
1745
1909
  var TableRow = vue.defineComponent({
1746
1910
  name: "OodsTableRow",
1747
1911
  setup(_props, { slots }) {
1748
- return () => vue.h("tr", {}, slots.default?.());
1912
+ return () => vue.h("tr", { class: "oods-table__row" }, slots.default?.());
1749
1913
  }
1750
1914
  });
1751
1915
  var TableHeaderCell = vue.defineComponent({
@@ -1754,19 +1918,22 @@ var TableHeaderCell = vue.defineComponent({
1754
1918
  scope: { type: String, default: "col" }
1755
1919
  },
1756
1920
  setup(props, { slots }) {
1757
- return () => vue.h("th", { scope: props.scope }, slots.default?.());
1921
+ return () => vue.h("th", { class: "oods-table__header-cell", scope: props.scope }, slots.default?.());
1758
1922
  }
1759
1923
  });
1760
1924
  var TableCell = vue.defineComponent({
1761
1925
  name: "OodsTableCell",
1762
1926
  setup(_props, { slots }) {
1763
- return () => vue.h("td", {}, slots.default?.());
1927
+ return () => vue.h("td", { class: "oods-table__cell" }, slots.default?.());
1764
1928
  }
1765
1929
  });
1766
1930
  var Table = vue.defineComponent({
1767
1931
  name: "OodsTable",
1932
+ inheritAttrs: false,
1768
1933
  props: {
1769
1934
  caption: { type: String, default: "" },
1935
+ // s222-m02 (#2502 ruling 11): false keeps the caption as the table's accessible name but hides it visually.
1936
+ showCaption: { type: Boolean, default: true },
1770
1937
  columns: { type: Array, default: () => [] },
1771
1938
  rows: { type: Array, default: () => [] },
1772
1939
  density: { type: String, default: "default" },
@@ -1775,16 +1942,17 @@ var Table = vue.defineComponent({
1775
1942
  emits: {
1776
1943
  rowActivate: (_rowId) => true
1777
1944
  },
1778
- setup(props, { emit, slots }) {
1945
+ setup(props, { attrs, emit, slots }) {
1779
1946
  const activate = (row) => emit("rowActivate", row.id);
1780
- return () => vue.h("table", {
1781
- class: "oods-table",
1947
+ return () => vue.h("div", { class: "oods-table__container", "data-density": props.density }, [vue.h("table", {
1948
+ ...attrs,
1949
+ class: ["oods-table", attrs.class],
1782
1950
  "data-oods-component": "Table",
1783
1951
  "data-density": props.density
1784
1952
  }, [
1785
- vue.h(TableCaption, {}, {
1953
+ slots.caption || props.caption ? vue.h(TableCaption, { "data-visually-hidden": props.showCaption ? void 0 : "true" }, {
1786
1954
  default: () => slots.caption?.() ?? props.caption
1787
- }),
1955
+ }) : null,
1788
1956
  vue.h(TableHead, {}, {
1789
1957
  default: () => slots.head?.() ?? vue.h(TableRow, {}, {
1790
1958
  default: () => props.columns.map((column) => vue.h(TableHeaderCell, { key: column.key }, {
@@ -1799,7 +1967,7 @@ var Table = vue.defineComponent({
1799
1967
  }, {
1800
1968
  default: () => "No rows available."
1801
1969
  })
1802
- }) : props.rows.map((row, rowIndex) => slots.row?.({ row, rowIndex, activate: () => activate(row) }) ?? vue.h(TableRow, { key: row.id }, {
1970
+ }) : props.rows.map((row, rowIndex) => slots.row?.({ row, rowIndex, activate: () => activate(row) }) ?? vue.h(TableRow, { key: row.id, "data-selectable": props.selectable ? "true" : void 0 }, {
1803
1971
  default: () => props.columns.map((column, columnIndex) => {
1804
1972
  const content = slots.cell?.({ row, column, value: row[column.key] }) ?? String(row[column.key] ?? "");
1805
1973
  return vue.h(TableCell, { key: column.key }, {
@@ -1812,7 +1980,7 @@ var Table = vue.defineComponent({
1812
1980
  })
1813
1981
  })))
1814
1982
  })
1815
- ]);
1983
+ ])]);
1816
1984
  }
1817
1985
  });
1818
1986
  function itemDisabled(item) {
@@ -2000,82 +2168,6 @@ var Tabs = vue.defineComponent({
2000
2168
  ]);
2001
2169
  }
2002
2170
  });
2003
-
2004
- // src/ported-core.ts
2005
- var STATUS_METADATA = {
2006
- subscription: {
2007
- future: {
2008
- description: "Subscription is scheduled but not yet active.",
2009
- tone: "info",
2010
- icon: "\u23F2"
2011
- },
2012
- trialing: {
2013
- description: "Subscription is in a trial period before billing begins.",
2014
- tone: "accent",
2015
- icon: "\u2605"
2016
- },
2017
- active: {
2018
- description: "Subscription is paid and service is provisioned.",
2019
- tone: "success",
2020
- icon: "\u2714\uFE0E"
2021
- },
2022
- paused: {
2023
- description: "Billing paused temporarily by finance or customer request.",
2024
- tone: "neutral",
2025
- icon: "\u23F8"
2026
- },
2027
- pending_cancellation: {
2028
- description: "Subscription will cancel at period end but remains active now.",
2029
- tone: "info",
2030
- icon: "\u2026"
2031
- },
2032
- past_due: {
2033
- description: "Renewal payment failed; smart retries ongoing and access retained during the grace window.",
2034
- tone: "critical",
2035
- icon: "\u26A0\uFE0E"
2036
- },
2037
- unpaid: {
2038
- description: "Payment retries exhausted; service access revoked.",
2039
- tone: "critical",
2040
- icon: "\u2A2F"
2041
- },
2042
- terminated: {
2043
- description: "Subscription ended; service access revoked and billing stopped.",
2044
- tone: "neutral",
2045
- icon: "\u2205"
2046
- }
2047
- },
2048
- invoice: {
2049
- draft: {
2050
- description: "Invoice is editable and not yet finalized.",
2051
- tone: "neutral",
2052
- icon: "\u270E"
2053
- },
2054
- posted: {
2055
- description: "Invoice finalized with terms before collection.",
2056
- tone: "info",
2057
- icon: "\u2026"
2058
- },
2059
- paid: {
2060
- description: "Invoice collected successfully in full.",
2061
- tone: "success",
2062
- icon: "\u2714\uFE0E"
2063
- },
2064
- past_due: {
2065
- description: "Invoice is unpaid past its due date.",
2066
- tone: "critical",
2067
- icon: "\u2A2F"
2068
- },
2069
- void: {
2070
- description: "Invoice canceled and no longer payable.",
2071
- tone: "neutral",
2072
- icon: "\u2205"
2073
- }
2074
- }
2075
- };
2076
- var STATUS_ALIASES = {
2077
- subscription: { delinquent: "unpaid" }
2078
- };
2079
2171
  function isRecord2(value) {
2080
2172
  return typeof value === "object" && value !== null && !Array.isArray(value);
2081
2173
  }
@@ -2092,18 +2184,13 @@ function statusLabel2(status) {
2092
2184
  return status.split(/[_-]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
2093
2185
  }
2094
2186
  function getPortedStatusPresentation(domain, status) {
2095
- const normalizedDomain = domain.toLowerCase();
2096
- const normalizedStatus = status.toLowerCase();
2097
- const alias = STATUS_ALIASES[normalizedDomain]?.[normalizedStatus];
2098
- const metadata = STATUS_METADATA[normalizedDomain]?.[alias ?? normalizedStatus];
2099
- if (!metadata) {
2100
- return {
2101
- label: statusLabel2(status || "Unknown"),
2102
- description: "Status not found in registry; falling back to the requested token set.",
2103
- tone: "neutral"
2104
- };
2105
- }
2106
- return { ...metadata, label: statusLabel2(status) };
2187
+ const presentation = componentContracts.getStatusPresentation(domain.toLowerCase(), status);
2188
+ return {
2189
+ label: statusLabel2(status || "Unknown"),
2190
+ description: presentation.description,
2191
+ tone: presentation.tone,
2192
+ icon: componentContracts.resolveStatusIcon(presentation.iconName)
2193
+ };
2107
2194
  }
2108
2195
  function formatPrice(amountCents, amount, currency) {
2109
2196
  const normalizedAmount = amount;
@@ -2247,11 +2334,10 @@ var StatusBadge = vue.defineComponent({
2247
2334
  domain: props.domain,
2248
2335
  tone,
2249
2336
  emphasis: props.variant === "solid" ? "solid" : props.emphasis,
2250
- icon: props.showIcon ? presentation.icon : void 0,
2251
2337
  title: stringValue(attrs.title) ?? presentation.description,
2252
2338
  "aria-label": ariaLabel,
2253
2339
  "data-oods-component": "StatusBadge"
2254
- }, slots);
2340
+ }, props.showIcon && presentation.icon && !slots.icon ? { ...slots, icon: () => statusIcon(presentation.icon) } : slots);
2255
2341
  };
2256
2342
  }
2257
2343
  });
@@ -2334,12 +2420,12 @@ var timelineProps = {
2334
2420
  };
2335
2421
  function renderTimelineEvent(event, index, showActorId, showReason) {
2336
2422
  return vue.h("li", { key: `${event.timestamp ?? "event"}-${index}` }, [
2337
- vue.h("article", { "data-timeline-event": "true" }, [
2338
- vue.h("p", { "data-timeline-label": "true" }, event.label),
2423
+ vue.h("article", { class: "oods-timeline__event", "data-timeline-event": "true" }, [
2424
+ vue.h("p", { class: "oods-timeline__label", "data-timeline-label": "true" }, event.label),
2339
2425
  event.timestamp ? vue.h("time", { "data-timeline-time": "true", datetime: event.timestamp }, componentContracts.formatDateTime(event.timestamp)) : null,
2340
- event.detail ? vue.h("p", { "data-timeline-detail": "true" }, event.detail) : null,
2341
- showActorId && event.actorId ? vue.h("p", { "data-timeline-actor": "true" }, `Actor: ${event.actorId}`) : null,
2342
- showReason && event.reason ? vue.h("p", { "data-timeline-reason": "true" }, `Reason: ${event.reason}`) : null
2426
+ event.detail ? vue.h("p", { class: "oods-timeline__detail", "data-timeline-detail": "true" }, event.detail) : null,
2427
+ showActorId && event.actorId ? vue.h("p", { class: "oods-timeline__actor", "data-timeline-actor": "true" }, `Actor: ${event.actorId}`) : null,
2428
+ showReason && event.reason ? vue.h("p", { class: "oods-timeline__reason", "data-timeline-reason": "true" }, `Reason: ${event.reason}`) : null
2343
2429
  ])
2344
2430
  ]);
2345
2431
  }
@@ -2357,16 +2443,16 @@ function timelineComponent(configuration) {
2357
2443
  const slottedEvents = slots.default?.();
2358
2444
  return vue.h("div", {
2359
2445
  ...attrs,
2360
- class: mergedClass("oods-timeline", attrs.class),
2446
+ class: mergedClass(`oods-timeline oods-${configuration.timelineType}-timeline`, attrs.class),
2361
2447
  role: "log",
2362
2448
  "aria-label": stringValue(attrs["aria-label"]) ?? title,
2363
2449
  "data-oods-component": configuration.componentId,
2364
2450
  "data-timeline-type": configuration.timelineType
2365
2451
  }, [
2366
- vue.h("h2", { "data-timeline-title": "true" }, title),
2367
- props.status ? vue.h("p", { "data-timeline-current": "true" }, `Current status: ${statusLabel2(props.status)}`) : null,
2452
+ vue.h("h2", { class: "oods-timeline__title", "data-timeline-title": "true" }, title),
2453
+ props.status ? vue.h("p", { class: "oods-timeline__current", "data-timeline-current": "true" }, `Current status: ${statusLabel2(props.status)}`) : null,
2368
2454
  props.allowedTransitions?.length ? vue.h("p", { "data-timeline-transitions": "true" }, `Allowed transitions: ${props.allowedTransitions.join(", ")}`) : null,
2369
- vue.h("ol", { "data-timeline-events": "true" }, slottedEvents?.length ? slottedEvents : events.length ? events.map((event, index) => renderTimelineEvent(
2455
+ vue.h("ol", { class: "oods-timeline__events", "data-timeline-events": "true" }, slottedEvents?.length ? slottedEvents : events.length ? events.map((event, index) => renderTimelineEvent(
2370
2456
  event,
2371
2457
  index,
2372
2458
  props.showActorId,
@@ -2522,8 +2608,7 @@ var SearchInput = vue.defineComponent({
2522
2608
  updateValue("");
2523
2609
  emit("clear");
2524
2610
  };
2525
- const submit = (event) => {
2526
- event.preventDefault();
2611
+ const searchNow = () => {
2527
2612
  if (!props.disabled) {
2528
2613
  if (timer !== void 0) clearTimeout(timer);
2529
2614
  emitSearch(currentValue.value);
@@ -2532,14 +2617,13 @@ var SearchInput = vue.defineComponent({
2532
2617
  return () => {
2533
2618
  const id = props.id ?? `oods-search-${generatedId.replace(/:/g, "")}`;
2534
2619
  const ariaLabel = stringValue(attrs["aria-label"]) ?? props.label ?? props.placeholder;
2535
- return vue.h("form", {
2620
+ return vue.h("div", {
2536
2621
  ...attrs,
2537
2622
  class: mergedClass("oods-search-input", attrs.class),
2538
2623
  role: "search",
2539
2624
  "aria-label": ariaLabel,
2540
2625
  "data-oods-component": "SearchInput",
2541
- "data-behavioral": "search",
2542
- onSubmit: submit
2626
+ "data-behavioral": "search"
2543
2627
  }, [
2544
2628
  vue.h(Input, {
2545
2629
  id,
@@ -2548,19 +2632,25 @@ var SearchInput = vue.defineComponent({
2548
2632
  value: currentValue.value,
2549
2633
  placeholder: props.placeholder,
2550
2634
  disabled: props.disabled,
2635
+ inputClass: "oods-search-input__control",
2551
2636
  "aria-label": props.label ? void 0 : ariaLabel,
2552
2637
  onInput: (value) => updateValue(value),
2553
2638
  onKeydown: (event) => {
2554
2639
  if (event.key === "Escape") clear();
2640
+ if (event.key === "Enter") {
2641
+ event.preventDefault();
2642
+ searchNow();
2643
+ }
2555
2644
  }
2556
2645
  }),
2557
2646
  props.clearable && currentValue.value ? vue.h("button", {
2558
2647
  type: "button",
2648
+ class: "oods-search-input__clear",
2559
2649
  "data-search-clear": "true",
2560
2650
  "aria-label": "Clear search",
2561
2651
  disabled: props.disabled,
2562
2652
  onClick: clear
2563
- }, "\xD7") : null
2653
+ }, [statusIcon("x")]) : null
2564
2654
  ]);
2565
2655
  };
2566
2656
  }
@@ -2707,17 +2797,18 @@ var RelativeTimestamp = vue.defineComponent({
2707
2797
  props.createdAt
2708
2798
  ) ?? "";
2709
2799
  if (props.hideWhenEmpty && (!datetime || Number.isNaN(Date.parse(datetime)))) return null;
2800
+ const absolute = componentContracts.formatDateTime(datetime, { timeZone: props.timezone });
2710
2801
  const content = firstDefined(
2711
2802
  props.relative,
2712
2803
  props.label,
2713
2804
  props.text,
2714
- props.now === void 0 ? componentContracts.formatDateTime(datetime, { timeZone: props.timezone }) : relativeTimestampLabel(datetime, props.now)
2805
+ !absolute ? "Unknown time" : props.now === void 0 ? absolute : relativeTimestampLabel(datetime, props.now)
2715
2806
  ) ?? "";
2716
2807
  return vue.h("time", {
2717
2808
  ...attrs,
2718
2809
  class: mergedClass("oods-relative-timestamp", attrs.class),
2719
2810
  datetime: datetime || void 0,
2720
- title: stringValue(attrs.title) ?? componentContracts.formatDateTime(datetime, { timeZone: props.timezone }),
2811
+ title: stringValue(attrs.title) ?? absolute,
2721
2812
  "data-oods-component": "RelativeTimestamp"
2722
2813
  }, content);
2723
2814
  };
@@ -2965,7 +3056,7 @@ function summary(id) {
2965
3056
  } });
2966
3057
  }
2967
3058
  function preview(id, type) {
2968
- return vue.defineComponent({ name: id, props: { svg: String, title: String, description: String, width: Number, height: Number }, setup(props, { slots }) {
3059
+ return vue.defineComponent({ name: id, props: { svg: String, svgNarrow: String, svgWide: String, svgDark: String, svgDarkNarrow: String, svgDarkWide: String, svgHc: String, svgHcNarrow: String, svgHcWide: String, title: String, description: String, width: Number, height: Number }, setup(props, { slots }) {
2969
3060
  return () => vue.h(VizAreaPreview, { ...props, title: props.title ?? `${type[0].toUpperCase()}${type.slice(1)} chart`, "data-oods-component": id, "data-viz-preview-type": type }, { default: slots.default ?? (() => vue.h(Text, { content: "No rendered chart supplied" })) });
2970
3061
  } });
2971
3062
  }
@@ -3031,6 +3122,7 @@ exports.CommunicationDetailPanel = CommunicationDetailPanel;
3031
3122
  exports.CycleProgressCard = CycleProgressCard;
3032
3123
  exports.DatePicker = DatePicker;
3033
3124
  exports.DetailHeader = DetailHeader;
3125
+ exports.Dialog = Dialog;
3034
3126
  exports.FilterPanel = FilterPanel;
3035
3127
  exports.FormLabelGroup = FormLabelGroup;
3036
3128
  exports.GeoFieldMappingForm = GeoFieldMappingForm;
@@ -3069,6 +3161,7 @@ exports.StatusBadge = StatusBadge;
3069
3161
  exports.StatusColorLegend = StatusColorLegend;
3070
3162
  exports.StatusSelector = StatusSelector;
3071
3163
  exports.StatusTimeline = StatusTimeline;
3164
+ exports.Switch = Switch;
3072
3165
  exports.Table = Table;
3073
3166
  exports.TableBody = TableBody;
3074
3167
  exports.TableCaption = TableCaption;