dap-design-system 0.62.3 → 0.62.4

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.
@@ -82,3 +82,11 @@ export declare function getValidityStateObject(state: Partial<ValidityState>): {
82
82
  * @returns The kebab-cased string
83
83
  */
84
84
  export declare function kebabCase(str: string): string;
85
+ /**
86
+ * Returns `target.id` only when `target` lives in the given tree scope (document
87
+ * or shadow root). IDREF attributes such as aria-activedescendant resolve only
88
+ * within one scope, so a reference into another shadow root (e.g. an option the
89
+ * option list renders inside its own shadow root) is dropped by every browser's
90
+ * accessibility tree and reported by axe as aria-valid-attr-value.
91
+ */
92
+ export declare function idInScope(scope: Node | null | undefined, target: Element | null | undefined): string | undefined;
@@ -1,32 +1,32 @@
1
- var a = Object.defineProperty;
2
- var s = Object.getOwnPropertySymbols;
3
- var l = Object.prototype.hasOwnProperty, f = Object.prototype.propertyIsEnumerable;
4
- var i = (t, r, e) => r in t ? a(t, r, { enumerable: !0, configurable: !0, writable: !0, value: e }) : t[r] = e, c = (t, r) => {
5
- for (var e in r || (r = {}))
6
- l.call(r, e) && i(t, e, r[e]);
7
- if (s)
8
- for (var e of s(r))
9
- f.call(r, e) && i(t, e, r[e]);
1
+ var l = Object.defineProperty;
2
+ var i = Object.getOwnPropertySymbols;
3
+ var a = Object.prototype.hasOwnProperty, f = Object.prototype.propertyIsEnumerable;
4
+ var s = (t, e, r) => e in t ? l(t, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : t[e] = r, c = (t, e) => {
5
+ for (var r in e || (e = {}))
6
+ a.call(e, r) && s(t, r, e[r]);
7
+ if (i)
8
+ for (var r of i(e))
9
+ f.call(e, r) && s(t, r, e[r]);
10
10
  return t;
11
11
  };
12
12
  window.matchMedia(
13
13
  "(prefers-reduced-motion: reduce)"
14
14
  ).matches;
15
- function p(t) {
16
- var e;
17
- const r = (e = t.closest("dap-ds-card")) == null ? void 0 : e.getAttribute("size");
18
- t.setAttribute("size", r != null ? r : "sm");
15
+ function g(t) {
16
+ var r;
17
+ const e = (r = t.closest("dap-ds-card")) == null ? void 0 : r.getAttribute("size");
18
+ t.setAttribute("size", e != null ? e : "sm");
19
19
  }
20
20
  const m = (t) => {
21
- let r = {};
21
+ let e = {};
22
22
  try {
23
- r = JSON.parse(t != null ? t : "");
24
- } catch (e) {
23
+ e = JSON.parse(t != null ? t : "");
24
+ } catch (r) {
25
25
  console.error("Incorrect Json string data", {
26
26
  data: t
27
27
  });
28
28
  }
29
- return r;
29
+ return e;
30
30
  };
31
31
  function u(t) {
32
32
  return t == null || t === "null" || t === "undefined" ? "" : t;
@@ -35,28 +35,28 @@ const b = {
35
35
  fromAttribute: (t) => u(t),
36
36
  toAttribute: (t) => !t || t === "null" || t === "undefined" ? null : t
37
37
  };
38
- function g(t) {
39
- const r = (n) => {
38
+ function d(t) {
39
+ const e = (n) => {
40
40
  if (n instanceof Element && n.assignedSlot)
41
41
  return n.assignedSlot;
42
42
  const o = n.parentNode;
43
43
  return o instanceof ShadowRoot ? o.host : o;
44
44
  };
45
- let e = r(t);
46
- for (; e instanceof HTMLElement; ) {
47
- const { overflowY: n } = getComputedStyle(e);
48
- if (/(auto|scroll|overlay)/.test(n) && e.scrollHeight > e.clientHeight)
49
- return e;
50
- e = r(e);
45
+ let r = e(t);
46
+ for (; r instanceof HTMLElement; ) {
47
+ const { overflowY: n } = getComputedStyle(r);
48
+ if (/(auto|scroll|overlay)/.test(n) && r.scrollHeight > r.clientHeight)
49
+ return r;
50
+ r = e(r);
51
51
  }
52
52
  return null;
53
53
  }
54
54
  function h(t) {
55
- const r = g(t);
56
- if (!r)
55
+ const e = d(t);
56
+ if (!e)
57
57
  return;
58
- const e = r.getBoundingClientRect(), n = t.getBoundingClientRect();
59
- n.top < e.top ? r.scrollTop -= e.top - n.top : n.bottom > e.bottom && (r.scrollTop += n.bottom - e.bottom);
58
+ const r = e.getBoundingClientRect(), n = t.getBoundingClientRect();
59
+ n.top < r.top ? e.scrollTop -= r.top - n.top : n.bottom > r.bottom && (e.scrollTop += n.bottom - r.bottom);
60
60
  }
61
61
  function S(t) {
62
62
  return c({
@@ -76,14 +76,19 @@ function S(t) {
76
76
  function w(t) {
77
77
  return t.trim().toLowerCase().replace(/\./g, "-").replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/--+/g, "-").replace(/^-+|-+$/g, "");
78
78
  }
79
+ function y(t, e) {
80
+ if (!(!t || !(e != null && e.id)))
81
+ return e.getRootNode() === t ? e.id : void 0;
82
+ }
79
83
  export {
80
84
  m as JSONAttributeParser,
81
- g as getScrollParent,
85
+ d as getScrollParent,
82
86
  S as getValidityStateObject,
87
+ y as idInScope,
83
88
  w as kebabCase,
84
89
  u as normalizeStringProperty,
85
90
  h as scrollIntoContainer,
86
- p as setFromParentSize,
91
+ g as setFromParentSize,
87
92
  b as stringPropertyConverter
88
93
  };
89
94
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../src/common/utils.ts"],"sourcesContent":["export const isReducedMotion = window.matchMedia(\n '(prefers-reduced-motion: reduce)',\n).matches\n\nexport function isMobileView() {\n const mobileBreakpoint = getComputedStyle(document.documentElement)\n .getPropertyValue('--dds-breakpoints-small')\n .trim()\n\n const isMobileView = window.matchMedia(\n `(max-width: ${mobileBreakpoint})`,\n ).matches\n\n return isMobileView\n}\n\nexport function setFromParentSize(element: HTMLElement) {\n const size = element.closest('dap-ds-card')?.getAttribute('size')\n element.setAttribute('size', size ?? 'sm')\n}\n\nexport function numberRange(start: number, end: number): number[] {\n return Array.from({ length: end - start + 1 }, (_, i) => start + i)\n}\n\nexport const JSONAttributeParser = (value: string | null) => {\n let convertedValue = {}\n try {\n convertedValue = JSON.parse(value ?? '')\n } catch (error) {\n console.error('Incorrect Json string data', {\n data: value,\n })\n }\n\n return convertedValue\n}\n\n/**\n * Normalizes a string value that might be null, undefined, or the string \"null\"/\"undefined\".\n * This is useful for handling values from React/Next.js object spreads where null props\n * can be serialized as the string \"null\".\n *\n * @param value - The value to normalize\n * @returns An empty string if the value is null, undefined, or the string \"null\"/\"undefined\", otherwise the value\n *\n * @example\n * ```typescript\n * protected updated(changedProperties: Map<PropertyKey, unknown>): void {\n * super.updated(changedProperties)\n * if (changedProperties.has('title')) {\n * this.title = normalizeStringProperty(this.title)\n * }\n * }\n * ```\n */\nexport function normalizeStringProperty(\n value: string | null | undefined,\n): string {\n if (\n value === null ||\n value === undefined ||\n value === 'null' ||\n value === 'undefined'\n ) {\n return ''\n }\n return value\n}\n\n/**\n * Lit property converter that handles null/undefined values from React/Next.js object spreads.\n *\n * When React serializes null props (e.g., from object spreads like {...props} where props.title = null),\n * it can become the string \"null\" in HTML attributes. This converter normalizes these cases.\n *\n * @example\n * ```typescript\n * @property({\n * converter: stringPropertyConverter\n * })\n * title: string\n * ```\n *\n * This prevents the string \"null\" from appearing in the rendered output when:\n * - Props come from object spreads with null values\n * - React/Next.js serializes null as the string \"null\"\n * - Properties are set directly (bypassing attribute conversion)\n *\n * Note: For direct property assignments (e.g., `element.title = null`), also use\n * `normalizeStringProperty` in the `updated` lifecycle method.\n */\nexport const stringPropertyConverter = {\n fromAttribute: (value: string | null): string => {\n return normalizeStringProperty(value)\n },\n toAttribute: (value: string | null | undefined): string | null => {\n // Prevent reflecting null/undefined/empty values back to attributes\n // This avoids setting title=\"null\" or title=\"\" in the DOM\n if (!value || value === 'null' || value === 'undefined') {\n return null // null removes the attribute\n }\n return value\n },\n}\n\n/**\n * Finds the nearest scrollable ancestor of an element, crossing shadow DOM and\n * slot boundaries. Returns null if none is found before the document root.\n */\nexport function getScrollParent(element: Element): HTMLElement | null {\n const getParent = (node: Node): Node | null => {\n // Slotted content lives visually inside the slot, so continue up through it.\n if (node instanceof Element && node.assignedSlot) {\n return node.assignedSlot\n }\n const parent = node.parentNode\n // Cross a shadow root boundary via its host element.\n if (parent instanceof ShadowRoot) {\n return parent.host\n }\n return parent\n }\n\n let current = getParent(element)\n while (current instanceof HTMLElement) {\n const { overflowY } = getComputedStyle(current)\n if (\n /(auto|scroll|overlay)/.test(overflowY) &&\n current.scrollHeight > current.clientHeight\n ) {\n return current\n }\n current = getParent(current)\n }\n return null\n}\n\n/**\n * Reveals an element by scrolling only its nearest scrollable ancestor, without\n * bubbling the scroll to outer ancestors. Unlike `Element.scrollIntoView`, which\n * scrolls every scrollable ancestor up to the window, this keeps outer containers\n * (e.g. a modal body or the page) still. That matters for an option deep inside a\n * dropdown: revealing it must not scroll the trigger out of the viewport, which\n * would otherwise fire the popup's viewport auto-close and snap the dropdown shut.\n */\nexport function scrollIntoContainer(element: HTMLElement): void {\n const container = getScrollParent(element)\n if (!container) {\n return\n }\n\n const containerRect = container.getBoundingClientRect()\n const elementRect = element.getBoundingClientRect()\n\n if (elementRect.top < containerRect.top) {\n container.scrollTop -= containerRect.top - elementRect.top\n } else if (elementRect.bottom > containerRect.bottom) {\n container.scrollTop += elementRect.bottom - containerRect.bottom\n }\n}\n\nexport function getValidityStateObject(state: Partial<ValidityState>) {\n return {\n badInput: false,\n customError: false,\n patternMismatch: false,\n rangeOverflow: false,\n rangeUnderflow: false,\n stepMismatch: false,\n tooLong: false,\n tooShort: false,\n typeMismatch: false,\n valid: true,\n valueMissing: false,\n ...state,\n }\n}\n\n/**\n * Converts a string to kebab-case.\n *\n * @param str - The string to convert\n * @returns The kebab-cased string\n */\nexport function kebabCase(str: string): string {\n return str\n .trim()\n .toLowerCase()\n .replace(/\\./g, '-') // Convert dots to dashes first\n .replace(/\\s+/g, '-') // Convert spaces to dashes\n .replace(/[^a-z0-9-]/g, '') // Remove non-alphanumeric except dashes\n .replace(/--+/g, '-') // Collapse multiple dashes\n .replace(/^-+|-+$/g, '') // Remove leading/trailing dashes\n}\n"],"names":["setFromParentSize","element","_a","size","JSONAttributeParser","value","convertedValue","error","normalizeStringProperty","stringPropertyConverter","getScrollParent","getParent","node","parent","current","overflowY","scrollIntoContainer","container","containerRect","elementRect","getValidityStateObject","state","__spreadValues","kebabCase","str"],"mappings":";;;;;;;;;;;AAA+B,OAAO;AAAA,EACpC;AACF,EAAE;AAcK,SAASA,EAAkBC,GAAsB;AAhBzB,MAAAC;AAiB7B,QAAMC,KAAOD,IAAAD,EAAQ,QAAQ,aAAa,MAA7B,gBAAAC,EAAgC,aAAa;AAClD,EAAAD,EAAA,aAAa,QAAQE,KAAA,OAAAA,IAAQ,IAAI;AAC3C;AAMa,MAAAC,IAAsB,CAACC,MAAyB;AAC3D,MAAIC,IAAiB,CAAC;AAClB,MAAA;AACe,IAAAA,IAAA,KAAK,MAAMD,KAAA,OAAAA,IAAS,EAAE;AAAA,WAChCE,GAAO;AACd,YAAQ,MAAM,8BAA8B;AAAA,MAC1C,MAAMF;AAAA,IAAA,CACP;AAAA,EAAA;AAGI,SAAAC;AACT;AAoBO,SAASE,EACdH,GACQ;AACR,SACEA,KAAU,QAEVA,MAAU,UACVA,MAAU,cAEH,KAEFA;AACT;AAwBO,MAAMI,IAA0B;AAAA,EACrC,eAAe,CAACJ,MACPG,EAAwBH,CAAK;AAAA,EAEtC,aAAa,CAACA,MAGR,CAACA,KAASA,MAAU,UAAUA,MAAU,cACnC,OAEFA;AAEX;AAMO,SAASK,EAAgBT,GAAsC;AAC9D,QAAAU,IAAY,CAACC,MAA4B;AAEzC,QAAAA,aAAgB,WAAWA,EAAK;AAClC,aAAOA,EAAK;AAEd,UAAMC,IAASD,EAAK;AAEpB,WAAIC,aAAkB,aACbA,EAAO,OAETA;AAAA,EACT;AAEI,MAAAC,IAAUH,EAAUV,CAAO;AAC/B,SAAOa,aAAmB,eAAa;AACrC,UAAM,EAAE,WAAAC,EAAA,IAAc,iBAAiBD,CAAO;AAC9C,QACE,wBAAwB,KAAKC,CAAS,KACtCD,EAAQ,eAAeA,EAAQ;AAExB,aAAAA;AAET,IAAAA,IAAUH,EAAUG,CAAO;AAAA,EAAA;AAEtB,SAAA;AACT;AAUO,SAASE,EAAoBf,GAA4B;AACxD,QAAAgB,IAAYP,EAAgBT,CAAO;AACzC,MAAI,CAACgB;AACH;AAGI,QAAAC,IAAgBD,EAAU,sBAAsB,GAChDE,IAAclB,EAAQ,sBAAsB;AAE9C,EAAAkB,EAAY,MAAMD,EAAc,MACxBD,EAAA,aAAaC,EAAc,MAAMC,EAAY,MAC9CA,EAAY,SAASD,EAAc,WAClCD,EAAA,aAAaE,EAAY,SAASD,EAAc;AAE9D;AAEO,SAASE,EAAuBC,GAA+B;AAC7D,SAAAC,EAAA;AAAA,IACL,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,cAAc;AAAA,IACd,OAAO;AAAA,IACP,cAAc;AAAA,KACXD;AAEP;AAQO,SAASE,EAAUC,GAAqB;AACtC,SAAAA,EACJ,KACA,EAAA,cACA,QAAQ,OAAO,GAAG,EAClB,QAAQ,QAAQ,GAAG,EACnB,QAAQ,eAAe,EAAE,EACzB,QAAQ,QAAQ,GAAG,EACnB,QAAQ,YAAY,EAAE;AAC3B;"}
1
+ {"version":3,"file":"utils.js","sources":["../../src/common/utils.ts"],"sourcesContent":["export const isReducedMotion = window.matchMedia(\n '(prefers-reduced-motion: reduce)',\n).matches\n\nexport function isMobileView() {\n const mobileBreakpoint = getComputedStyle(document.documentElement)\n .getPropertyValue('--dds-breakpoints-small')\n .trim()\n\n const isMobileView = window.matchMedia(\n `(max-width: ${mobileBreakpoint})`,\n ).matches\n\n return isMobileView\n}\n\nexport function setFromParentSize(element: HTMLElement) {\n const size = element.closest('dap-ds-card')?.getAttribute('size')\n element.setAttribute('size', size ?? 'sm')\n}\n\nexport function numberRange(start: number, end: number): number[] {\n return Array.from({ length: end - start + 1 }, (_, i) => start + i)\n}\n\nexport const JSONAttributeParser = (value: string | null) => {\n let convertedValue = {}\n try {\n convertedValue = JSON.parse(value ?? '')\n } catch (error) {\n console.error('Incorrect Json string data', {\n data: value,\n })\n }\n\n return convertedValue\n}\n\n/**\n * Normalizes a string value that might be null, undefined, or the string \"null\"/\"undefined\".\n * This is useful for handling values from React/Next.js object spreads where null props\n * can be serialized as the string \"null\".\n *\n * @param value - The value to normalize\n * @returns An empty string if the value is null, undefined, or the string \"null\"/\"undefined\", otherwise the value\n *\n * @example\n * ```typescript\n * protected updated(changedProperties: Map<PropertyKey, unknown>): void {\n * super.updated(changedProperties)\n * if (changedProperties.has('title')) {\n * this.title = normalizeStringProperty(this.title)\n * }\n * }\n * ```\n */\nexport function normalizeStringProperty(\n value: string | null | undefined,\n): string {\n if (\n value === null ||\n value === undefined ||\n value === 'null' ||\n value === 'undefined'\n ) {\n return ''\n }\n return value\n}\n\n/**\n * Lit property converter that handles null/undefined values from React/Next.js object spreads.\n *\n * When React serializes null props (e.g., from object spreads like {...props} where props.title = null),\n * it can become the string \"null\" in HTML attributes. This converter normalizes these cases.\n *\n * @example\n * ```typescript\n * @property({\n * converter: stringPropertyConverter\n * })\n * title: string\n * ```\n *\n * This prevents the string \"null\" from appearing in the rendered output when:\n * - Props come from object spreads with null values\n * - React/Next.js serializes null as the string \"null\"\n * - Properties are set directly (bypassing attribute conversion)\n *\n * Note: For direct property assignments (e.g., `element.title = null`), also use\n * `normalizeStringProperty` in the `updated` lifecycle method.\n */\nexport const stringPropertyConverter = {\n fromAttribute: (value: string | null): string => {\n return normalizeStringProperty(value)\n },\n toAttribute: (value: string | null | undefined): string | null => {\n // Prevent reflecting null/undefined/empty values back to attributes\n // This avoids setting title=\"null\" or title=\"\" in the DOM\n if (!value || value === 'null' || value === 'undefined') {\n return null // null removes the attribute\n }\n return value\n },\n}\n\n/**\n * Finds the nearest scrollable ancestor of an element, crossing shadow DOM and\n * slot boundaries. Returns null if none is found before the document root.\n */\nexport function getScrollParent(element: Element): HTMLElement | null {\n const getParent = (node: Node): Node | null => {\n // Slotted content lives visually inside the slot, so continue up through it.\n if (node instanceof Element && node.assignedSlot) {\n return node.assignedSlot\n }\n const parent = node.parentNode\n // Cross a shadow root boundary via its host element.\n if (parent instanceof ShadowRoot) {\n return parent.host\n }\n return parent\n }\n\n let current = getParent(element)\n while (current instanceof HTMLElement) {\n const { overflowY } = getComputedStyle(current)\n if (\n /(auto|scroll|overlay)/.test(overflowY) &&\n current.scrollHeight > current.clientHeight\n ) {\n return current\n }\n current = getParent(current)\n }\n return null\n}\n\n/**\n * Reveals an element by scrolling only its nearest scrollable ancestor, without\n * bubbling the scroll to outer ancestors. Unlike `Element.scrollIntoView`, which\n * scrolls every scrollable ancestor up to the window, this keeps outer containers\n * (e.g. a modal body or the page) still. That matters for an option deep inside a\n * dropdown: revealing it must not scroll the trigger out of the viewport, which\n * would otherwise fire the popup's viewport auto-close and snap the dropdown shut.\n */\nexport function scrollIntoContainer(element: HTMLElement): void {\n const container = getScrollParent(element)\n if (!container) {\n return\n }\n\n const containerRect = container.getBoundingClientRect()\n const elementRect = element.getBoundingClientRect()\n\n if (elementRect.top < containerRect.top) {\n container.scrollTop -= containerRect.top - elementRect.top\n } else if (elementRect.bottom > containerRect.bottom) {\n container.scrollTop += elementRect.bottom - containerRect.bottom\n }\n}\n\nexport function getValidityStateObject(state: Partial<ValidityState>) {\n return {\n badInput: false,\n customError: false,\n patternMismatch: false,\n rangeOverflow: false,\n rangeUnderflow: false,\n stepMismatch: false,\n tooLong: false,\n tooShort: false,\n typeMismatch: false,\n valid: true,\n valueMissing: false,\n ...state,\n }\n}\n\n/**\n * Converts a string to kebab-case.\n *\n * @param str - The string to convert\n * @returns The kebab-cased string\n */\nexport function kebabCase(str: string): string {\n return str\n .trim()\n .toLowerCase()\n .replace(/\\./g, '-') // Convert dots to dashes first\n .replace(/\\s+/g, '-') // Convert spaces to dashes\n .replace(/[^a-z0-9-]/g, '') // Remove non-alphanumeric except dashes\n .replace(/--+/g, '-') // Collapse multiple dashes\n .replace(/^-+|-+$/g, '') // Remove leading/trailing dashes\n}\n\n/**\n * Returns `target.id` only when `target` lives in the given tree scope (document\n * or shadow root). IDREF attributes such as aria-activedescendant resolve only\n * within one scope, so a reference into another shadow root (e.g. an option the\n * option list renders inside its own shadow root) is dropped by every browser's\n * accessibility tree and reported by axe as aria-valid-attr-value.\n */\nexport function idInScope(\n scope: Node | null | undefined,\n target: Element | null | undefined,\n): string | undefined {\n if (!scope || !target?.id) {\n return undefined\n }\n return target.getRootNode() === scope ? target.id : undefined\n}\n"],"names":["setFromParentSize","element","_a","size","JSONAttributeParser","value","convertedValue","error","normalizeStringProperty","stringPropertyConverter","getScrollParent","getParent","node","parent","current","overflowY","scrollIntoContainer","container","containerRect","elementRect","getValidityStateObject","state","__spreadValues","kebabCase","str","idInScope","scope","target"],"mappings":";;;;;;;;;;;AAA+B,OAAO;AAAA,EACpC;AACF,EAAE;AAcK,SAASA,EAAkBC,GAAsB;AAhBzB,MAAAC;AAiB7B,QAAMC,KAAOD,IAAAD,EAAQ,QAAQ,aAAa,MAA7B,gBAAAC,EAAgC,aAAa;AAClD,EAAAD,EAAA,aAAa,QAAQE,KAAA,OAAAA,IAAQ,IAAI;AAC3C;AAMa,MAAAC,IAAsB,CAACC,MAAyB;AAC3D,MAAIC,IAAiB,CAAC;AAClB,MAAA;AACe,IAAAA,IAAA,KAAK,MAAMD,KAAA,OAAAA,IAAS,EAAE;AAAA,WAChCE,GAAO;AACd,YAAQ,MAAM,8BAA8B;AAAA,MAC1C,MAAMF;AAAA,IAAA,CACP;AAAA,EAAA;AAGI,SAAAC;AACT;AAoBO,SAASE,EACdH,GACQ;AACR,SACEA,KAAU,QAEVA,MAAU,UACVA,MAAU,cAEH,KAEFA;AACT;AAwBO,MAAMI,IAA0B;AAAA,EACrC,eAAe,CAACJ,MACPG,EAAwBH,CAAK;AAAA,EAEtC,aAAa,CAACA,MAGR,CAACA,KAASA,MAAU,UAAUA,MAAU,cACnC,OAEFA;AAEX;AAMO,SAASK,EAAgBT,GAAsC;AAC9D,QAAAU,IAAY,CAACC,MAA4B;AAEzC,QAAAA,aAAgB,WAAWA,EAAK;AAClC,aAAOA,EAAK;AAEd,UAAMC,IAASD,EAAK;AAEpB,WAAIC,aAAkB,aACbA,EAAO,OAETA;AAAA,EACT;AAEI,MAAAC,IAAUH,EAAUV,CAAO;AAC/B,SAAOa,aAAmB,eAAa;AACrC,UAAM,EAAE,WAAAC,EAAA,IAAc,iBAAiBD,CAAO;AAC9C,QACE,wBAAwB,KAAKC,CAAS,KACtCD,EAAQ,eAAeA,EAAQ;AAExB,aAAAA;AAET,IAAAA,IAAUH,EAAUG,CAAO;AAAA,EAAA;AAEtB,SAAA;AACT;AAUO,SAASE,EAAoBf,GAA4B;AACxD,QAAAgB,IAAYP,EAAgBT,CAAO;AACzC,MAAI,CAACgB;AACH;AAGI,QAAAC,IAAgBD,EAAU,sBAAsB,GAChDE,IAAclB,EAAQ,sBAAsB;AAE9C,EAAAkB,EAAY,MAAMD,EAAc,MACxBD,EAAA,aAAaC,EAAc,MAAMC,EAAY,MAC9CA,EAAY,SAASD,EAAc,WAClCD,EAAA,aAAaE,EAAY,SAASD,EAAc;AAE9D;AAEO,SAASE,EAAuBC,GAA+B;AAC7D,SAAAC,EAAA;AAAA,IACL,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,SAAS;AAAA,IACT,UAAU;AAAA,IACV,cAAc;AAAA,IACd,OAAO;AAAA,IACP,cAAc;AAAA,KACXD;AAEP;AAQO,SAASE,EAAUC,GAAqB;AACtC,SAAAA,EACJ,KACA,EAAA,cACA,QAAQ,OAAO,GAAG,EAClB,QAAQ,QAAQ,GAAG,EACnB,QAAQ,eAAe,EAAE,EACzB,QAAQ,QAAQ,GAAG,EACnB,QAAQ,YAAY,EAAE;AAC3B;AASgB,SAAAC,EACdC,GACAC,GACoB;AACpB,MAAI,GAACD,KAAS,EAACC,KAAA,QAAAA,EAAQ;AAGvB,WAAOA,EAAO,YAAkB,MAAAD,IAAQC,EAAO,KAAK;AACtD;"}
@@ -135,6 +135,14 @@ export default class ComboboxBaseElement extends GenericFormElement {
135
135
  reportValidity(): boolean;
136
136
  setValidity(): void;
137
137
  handleInvalid(event: Event): void;
138
+ /**
139
+ * Screen-reader status for the highlighted option while focus stays in the input.
140
+ * aria-activedescendant cannot reach options inside option-list's shadow root, so
141
+ * the highlight (e.g. the first match after typing) is announced through a polite
142
+ * live region instead. Once focus moves onto an option it is announced natively,
143
+ * so the status is cleared to avoid a double announcement.
144
+ */
145
+ get activeOptionStatus(): string;
138
146
  getActiveDescendant(): HTMLInputElement | import('../option-item/option-item.component').default | null | undefined;
139
147
  getSearchIconSize(size: string): "sm" | "md" | "lg";
140
148
  getInnerIconSize(size: string): 16 | 10;
@@ -1,6 +1,6 @@
1
- var w = Object.getPrototypeOf;
1
+ var C = Object.getPrototypeOf;
2
2
  var S = Reflect.get;
3
- var x = (m, e, t) => S(w(m), t, e);
3
+ var x = (m, e, t) => S(C(m), t, e);
4
4
  var h = (m, e, t) => new Promise((i, a) => {
5
5
  var n = (u) => {
6
6
  try {
@@ -19,25 +19,25 @@ var h = (m, e, t) => new Promise((i, a) => {
19
19
  });
20
20
  import { clsx as g } from "../../node_modules/clsx/dist/clsx.js";
21
21
  import "../../node_modules/@lit/reactive-element/reactive-element.js";
22
- import { nothing as I } from "../../node_modules/lit-html/lit-html.js";
22
+ import { nothing as y } from "../../node_modules/lit-html/lit-html.js";
23
23
  import "../../node_modules/lit-element/lit-element.js";
24
24
  import { property as r } from "../../node_modules/@lit/reactive-element/decorators/property.js";
25
25
  import { state as v } from "../../node_modules/@lit/reactive-element/decorators/state.js";
26
- import { query as C } from "../../node_modules/@lit/reactive-element/decorators/query.js";
26
+ import { query as w } from "../../node_modules/@lit/reactive-element/decorators/query.js";
27
27
  import { ifDefined as p } from "../../node_modules/lit-html/directives/if-defined.js";
28
28
  import { html as d } from "../../node_modules/lit-html/static.js";
29
- import { getValidityStateObject as D } from "../../common/utils.js";
30
- import { GenericFormElement as V } from "../../internal/mixin/genericFormElement.js";
29
+ import { getValidityStateObject as D, idInScope as O } from "../../common/utils.js";
30
+ import { GenericFormElement as $ } from "../../internal/mixin/genericFormElement.js";
31
31
  import "../../localization/localization.js";
32
- import $ from "./combobox.scss.js";
33
- import { t as y } from "../../node_modules/i18next/dist/esm/i18next.js";
34
- import { unsafeCSS as O } from "../../node_modules/@lit/reactive-element/css-tag.js";
35
- var T = Object.defineProperty, l = (m, e, t, i) => {
32
+ import V from "./combobox.scss.js";
33
+ import { t as f } from "../../node_modules/i18next/dist/esm/i18next.js";
34
+ import { unsafeCSS as T } from "../../node_modules/@lit/reactive-element/css-tag.js";
35
+ var A = Object.defineProperty, l = (m, e, t, i) => {
36
36
  for (var a = void 0, n = m.length - 1, o; n >= 0; n--)
37
37
  (o = m[n]) && (a = o(e, t, a) || a);
38
- return a && T(e, t, a), a;
38
+ return a && A(e, t, a), a;
39
39
  };
40
- const f = class f extends V {
40
+ const I = class I extends $ {
41
41
  constructor() {
42
42
  super(...arguments), this.placement = "bottom-start", this.opened = !1, this.searchMode = "autocomplete", this.search = !1, this.clearButton = "true", this.allowManualInput = !1, this.searchForText = !1, this.searchOnValueSet = "false", this.loading = !1, this.selectable = "true", this.noAnimation = !1, this.textComplete = !1, this.openOnEmpty = !1, this.disableViewportAutoClose = !1, this.multiselect = !1, this.clearButtonTestId = "combobox-clear-button", this.searchButtonTestId = "combobox-search-button", this.disableSearchWhenEmpty = !1, this.selectedItems = [], this.optionListObserver = null, this.isUserInteraction = !1, this.pendingInitialValues = [], this.handleClick = () => {
43
43
  !this.getComboboxOptions().length && !this.openOnEmpty ? this.hideDropDown() : this.opened ? this.hideDropDown() : this.showDropDown();
@@ -151,10 +151,10 @@ const f = class f extends V {
151
151
  firstUpdated(e) {
152
152
  return h(this, null, function* () {
153
153
  var a;
154
- x(f.prototype, this, "firstUpdated").call(this, e), yield this.optionList.updateComplete, yield new Promise((n) => requestAnimationFrame(n));
154
+ x(I.prototype, this, "firstUpdated").call(this, e), yield this.optionList.updateComplete, yield new Promise((n) => requestAnimationFrame(n));
155
155
  const t = this.getComboboxOptions();
156
156
  yield Promise.all(t.map((n) => n.updateComplete));
157
- const i = x(f.prototype, this, "value");
157
+ const i = x(I.prototype, this, "value");
158
158
  if (i)
159
159
  if (this.multiselect) {
160
160
  const n = i.split(",").map((o) => o.trim()).filter((o) => o);
@@ -288,12 +288,12 @@ const f = class f extends V {
288
288
  value: this.selectedItem.value,
289
289
  selectedItem: this.selectedItem,
290
290
  type: "select"
291
- }), yield this.updateComplete, this.value = this.selectedItem.value, this.selectedText = this.currentItem.text, this.triggerInput.value = this.currentItem.text, this.triggerInput.focus(), this.setValidity();
291
+ }), yield this.updateComplete, this.value = this.selectedItem.value, this.selectedText = this.currentItem.text, this.triggerInput.value = this.currentItem.text, this.triggerInput.focus(), this.setValidity(), this.multiselect || (yield this.hideDropDown());
292
292
  });
293
293
  }
294
294
  handleTextSearch(e) {
295
295
  return h(this, null, function* () {
296
- this.value = e, this.selectedText = e, this.triggerInput.value = e, this.triggerInput.focus(), this.emit("dds-search", { search: e }), this.setValidity();
296
+ this.value = e, this.selectedText = e, this.triggerInput.value = e, this.triggerInput.focus(), this.emit("dds-search", { search: e }), this.setValidity(), yield this.hideDropDown();
297
297
  });
298
298
  }
299
299
  handleArrowKeys(e) {
@@ -430,7 +430,7 @@ const f = class f extends V {
430
430
  });
431
431
  }
432
432
  get validationMessage() {
433
- return y("form.validationMessage.select");
433
+ return f("form.validationMessage.select");
434
434
  }
435
435
  checkValidity() {
436
436
  return this.required ? this.getValidity() : !0;
@@ -450,6 +450,26 @@ const f = class f extends V {
450
450
  handleInvalid(e) {
451
451
  e.preventDefault();
452
452
  }
453
+ /**
454
+ * Screen-reader status for the highlighted option while focus stays in the input.
455
+ * aria-activedescendant cannot reach options inside option-list's shadow root, so
456
+ * the highlight (e.g. the first match after typing) is announced through a polite
457
+ * live region instead. Once focus moves onto an option it is announced natively,
458
+ * so the status is cleared to avoid a double announcement.
459
+ */
460
+ get activeOptionStatus() {
461
+ var i, a, n;
462
+ if (!this.opened || !this.currentItem || ((i = this.shadowRoot) == null ? void 0 : i.activeElement) !== this.triggerInput)
463
+ return "";
464
+ const e = (n = (a = this.optionList) == null ? void 0 : a.getAllAvailabeOptions()) != null ? n : [], t = e.findIndex(
465
+ (o) => o.value === this.currentItem.value
466
+ );
467
+ return t < 0 ? "" : f("combobox.activeOption", {
468
+ option: this.currentItem.text,
469
+ position: t + 1,
470
+ count: e.length
471
+ });
472
+ }
453
473
  getActiveDescendant() {
454
474
  var t;
455
475
  return this.opened ? (t = this.optionList) == null ? void 0 : t.getActiveOption() : this.triggerInput;
@@ -491,14 +511,14 @@ const f = class f extends V {
491
511
  `;
492
512
  }
493
513
  renderChips() {
494
- return !this.multiselect || this.selectedItems.length === 0 ? I : d`
514
+ return !this.multiselect || this.selectedItems.length === 0 ? y : d`
495
515
  <div class="combobox__chips" part="chips">
496
516
  ${this.selectedItems.map((e) => this.renderChip(e))}
497
517
  </div>
498
518
  `;
499
519
  }
500
520
  renderInput() {
501
- var t, i;
521
+ var t;
502
522
  const e = this.multiselect ? this.selectedText : this.selectedText !== "" ? this.selectedText : this.selectedItemText;
503
523
  return d`<input
504
524
  id="input"
@@ -509,22 +529,25 @@ const f = class f extends V {
509
529
  "input--readonly": this.readonly,
510
530
  "input--multiselect": this.multiselect
511
531
  })}"
512
- aria-expanded=${this.opened}
532
+ aria-expanded=${this.opened ? "true" : "false"}
513
533
  aria-haspopup="listbox"
514
534
  aria-labelledby="label"
515
535
  aria-describedby="description ${this.feedback ? "feedback" : ""}"
516
536
  aria-disabled=${this.disabled}
517
537
  aria-autocomplete="both"
518
538
  aria-controls="option-list"
519
- aria-activedescendant=${p((t = this.getActiveDescendant()) == null ? void 0 : t.id)}
520
- aria-multiselectable=${this.multiselect ? "true" : "false"}
539
+ aria-activedescendant=${p(
540
+ // Options render in option-list's shadow root, out of this scope; a
541
+ // cross-scope IDREF is ignored by browsers, so only same-scope ids are set
542
+ O(this.shadowRoot, this.getActiveDescendant())
543
+ )}
521
544
  ?required=${this.required}
522
545
  ?readonly=${this.readonly}
523
546
  ?autofocus=${this.autofocus}
524
547
  autocomplete=${this.autocomplete}
525
548
  ?disabled=${this.disabled}
526
549
  value=${e}
527
- placeholder=${p((i = this.placeholder) != null ? i : "")}
550
+ placeholder=${p((t = this.placeholder) != null ? t : "")}
528
551
  type=${this.search ? "search" : "text"}
529
552
  @blur=${this.handleBlur}
530
553
  @focus=${this.handleFocus}
@@ -533,14 +556,14 @@ const f = class f extends V {
533
556
  @click=${this.handleClick} />`;
534
557
  }
535
558
  renderClearButton() {
536
- return this.clearButton !== "true" || this.readonly ? I : d`<div
559
+ return this.clearButton !== "true" || this.readonly ? y : d`<div
537
560
  class="${g("clear-icon", {
538
561
  "clear-icon--hidden": this.shouldHideClearIcon
539
562
  })}">
540
563
  <dap-ds-icon-button
541
564
  icon="close-line"
542
565
  data-testid=${this.clearButtonTestId}
543
- aria-label=${y("clear")}
566
+ aria-label=${f("clear")}
544
567
  ?disabled=${this.disabled}
545
568
  @click=${this.handleClearClick}></dap-ds-icon-button>
546
569
  </div>`;
@@ -571,10 +594,10 @@ const f = class f extends V {
571
594
  ?disabled=${this.disableSearchWhenEmpty && !this.hasSearchText}
572
595
  data-testid=${this.searchButtonTestId}
573
596
  iconSize=${this.getInnerIconSize(this.size)}
574
- aria-label=${(i = this.searchButtonAriaLabel) != null ? i : y("search")}
597
+ aria-label=${(i = this.searchButtonAriaLabel) != null ? i : f("search")}
575
598
  @click=${this.handleSearchClick}>
576
599
  </dap-ds-icon-button>`}
577
- </div>` : I;
600
+ </div>` : y;
578
601
  }
579
602
  renderSelectActions() {
580
603
  return d`<div
@@ -599,6 +622,7 @@ const f = class f extends V {
599
622
  size=${p(this.size)}
600
623
  value=${p(this.value)}
601
624
  selectable=${p(this.selectable)}
625
+ ?multiselectable=${this.multiselect}
602
626
  @dds-option-change=${this.handleSelectedChange}
603
627
  @dds-option-deselect=${this.handleOptionDeselect}
604
628
  @dds-keydown=${this.handleListKeyDown}
@@ -642,15 +666,22 @@ const f = class f extends V {
642
666
  </div>
643
667
  ${this.renderOptionList()}
644
668
  </dap-ds-popup>
669
+ <div
670
+ class="sr-only active-option-status"
671
+ role="status"
672
+ aria-live="polite"
673
+ aria-atomic="true">
674
+ ${this.activeOptionStatus}
675
+ </div>
645
676
  ${this.multiselect ? d`<div
646
677
  class="sr-only"
647
678
  role="status"
648
679
  aria-live="polite"
649
680
  aria-atomic="true">
650
- ${this.selectedItems.length > 0 ? y("combobox.multiselect.selected", {
681
+ ${this.selectedItems.length > 0 ? f("combobox.multiselect.selected", {
651
682
  count: this.selectedItems.length
652
683
  }) : ""}
653
- </div>` : I}
684
+ </div>` : y}
654
685
  ${this.feedback && d`<dap-ds-feedback
655
686
  part="feedback"
656
687
  feedbackType=${p(this.feedbackType)}
@@ -661,13 +692,13 @@ const f = class f extends V {
661
692
  </div>`;
662
693
  }
663
694
  };
664
- f.styles = O($);
665
- let s = f;
695
+ I.styles = T(V);
696
+ let s = I;
666
697
  l([
667
- C("input")
698
+ w("input")
668
699
  ], s.prototype, "triggerInput");
669
700
  l([
670
- C("dap-ds-option-list")
701
+ w("dap-ds-option-list")
671
702
  ], s.prototype, "optionList");
672
703
  l([
673
704
  r({ reflect: !0 })