asma-ui-core 3.103.1 → 3.105.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.
Files changed (25) hide show
  1. package/dist/asma-ui-core.css +1 -1
  2. package/dist/components/custom/module/header-layout/ToolbarActionGroup.js +6 -6
  3. package/dist/components/data-display/chip/StyledChip.js +48 -47
  4. package/dist/components/data-display/tooltip/StyledTooltip.js +62 -60
  5. package/dist/components/feedback/dialog/StyledDialog.js +94 -79
  6. package/dist/components/feedback/dialog/dialog-footer/StyledDialogFooter.js +51 -51
  7. package/dist/components/inputs/button/StyledButton.module.js +13 -13
  8. package/dist/components/inputs/dynamic-select/components/DynamicSelectAutocomplete.js +91 -82
  9. package/dist/components/inputs/select-autocomplete/StyledSelectAutocomplete.js +152 -152
  10. package/dist/components/navigation/menu/StyledMenu.js +17 -16
  11. package/dist/components/navigation/menu/StyledMenu.module.js +5 -2
  12. package/dist/components/navigation/menu/StyledMenuList.js +50 -36
  13. package/dist/components/navigation/tabs/StyledTab.js +28 -19
  14. package/dist/components/navigation/tabs/StyledTabs.js +33 -33
  15. package/dist/helpers/focusable.js +3 -2
  16. package/dist/helpers/warnUnnamedDialog.js +6 -0
  17. package/dist/src/components/feedback/dialog/StyledDialog.d.ts +10 -2
  18. package/dist/src/components/feedback/dialog/dialog-footer/StyledDialogFooter.d.ts +5 -3
  19. package/dist/src/components/navigation/menu/StyledMenuList.d.ts +2 -1
  20. package/dist/src/components/navigation/tabs/StyledTab.d.ts +11 -1
  21. package/dist/src/helpers/focusable.d.ts +1 -0
  22. package/dist/src/helpers/warnUnnamedDialog.d.ts +5 -0
  23. package/dist/table/components/columns/action-column/components/RowActionMenu.js +60 -47
  24. package/dist/table/shared-components/button/StyledButton.module.js +11 -11
  25. package/package.json +1 -1
@@ -1,60 +1,74 @@
1
- import { cn as S } from "../../../helpers/cn.js";
2
- import { consumerOverrides as v } from "../../../helpers/classOverride.js";
3
- import L from "./StyledMenu.module.js";
4
- import { useEffect as I, useLayoutEffect as M, useRef as R } from "react";
5
- import { jsx as d } from "react/jsx-runtime";
6
- var p = '[role="menu"], [role="listbox"]', u = '[role="menuitem"]', b = (o) => Array.from(o.childNodes).flatMap((r) => r instanceof HTMLElement ? r.hidden ? [] : r.matches(p) ? [null] : r.matches(u) ? [r] : r.querySelector(u) ? b(r) : [null] : r.textContent?.trim() ? [null] : []), y = (o) => o ? Array.from(o.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')) : [], H = ({ children: o, id: r, role: h = "menu", className: a, autoFocus: f, disablePadding: E, onClick: A, onKeyDown: w }) => {
7
- const i = R(null), c = v(a, "padding");
8
- M(() => {
1
+ import { cn as R } from "../../../helpers/cn.js";
2
+ import { consumerOverrides as T } from "../../../helpers/classOverride.js";
3
+ import p from "./StyledMenu.module.js";
4
+ import { useEffect as M, useLayoutEffect as k, useRef as q } from "react";
5
+ import { jsx as A } from "react/jsx-runtime";
6
+ var d = '[role="menu"], [role="listbox"]', y = '[role="menuitem"]', E = (r) => Array.from(r.childNodes).flatMap((t) => t instanceof HTMLElement ? t.hidden ? [] : t.matches(d) ? [null] : t.matches(y) ? [t] : t.querySelector(y) ? E(t) : [null] : t.textContent?.trim() ? [null] : []), h = (r) => r ? Array.from(r.querySelectorAll('[role="menuitem"]')) : [], v = (r) => h(r).filter((t) => t.getAttribute("aria-disabled") !== "true"), x = (r, t) => {
7
+ const u = h(r).filter((o) => o.closest(d) === r), m = (t && u.includes(t) ? t : void 0) ?? u.find((o) => o.tabIndex === 0) ?? v(r).find((o) => o.closest(d) === r) ?? u[0];
8
+ u.forEach((o) => {
9
+ o.tabIndex = o === m ? 0 : -1;
10
+ });
11
+ }, _ = ({ children: r, id: t, role: u = "menu", className: m, autoFocus: o, disablePadding: w, onClick: I, onKeyDown: L }) => {
12
+ const i = q(null), b = T(m, "padding");
13
+ k(() => {
9
14
  const e = i.current;
10
15
  if (!e) return;
11
- const t = () => {
12
- const n = b(e);
13
- Array.from(e.querySelectorAll(u)).filter((l) => l.closest(p) === e).forEach((l) => l.removeAttribute("data-menu-separator")), n.forEach((l, g) => l?.toggleAttribute("data-menu-separator", !!n[g + 1]));
16
+ const n = () => {
17
+ const a = E(e);
18
+ if (Array.from(e.querySelectorAll(y)).filter((l) => l.closest(d) === e).forEach((l) => l.removeAttribute("data-menu-separator")), a.forEach((l, f) => l?.toggleAttribute("data-menu-separator", !!a[f + 1])), e.classList.contains(p.anchoredList)) {
19
+ const l = (a.every(Boolean) ? a[7] : null)?.getBoundingClientRect(), f = l && l.height > 0 ? l.top - e.getBoundingClientRect().top + e.scrollTop + l.height / 2 : null;
20
+ e.style.maxHeight = f === null ? "" : `${f}px`, e.toggleAttribute("data-menu-scroll", f !== null);
21
+ }
22
+ x(e);
14
23
  };
15
- t();
16
- const s = new MutationObserver(t);
24
+ n();
25
+ const c = requestAnimationFrame(n), s = new MutationObserver(n);
17
26
  return s.observe(e, {
18
27
  childList: !0,
19
28
  subtree: !0,
20
29
  attributes: !0,
21
30
  attributeFilter: ["hidden"]
22
- }), () => s.disconnect();
23
- }, []), I(() => {
24
- f && y(i.current)[0]?.focus();
25
- }, [f]);
26
- const x = (e) => {
27
- if (w?.(e), ![
31
+ }), () => {
32
+ cancelAnimationFrame(c), s.disconnect();
33
+ };
34
+ }, []), M(() => {
35
+ o && (v(i.current)[0] ?? h(i.current)[0])?.focus();
36
+ }, [o]);
37
+ const S = (e) => {
38
+ if (L?.(e), ![
28
39
  "ArrowDown",
29
40
  "ArrowUp",
30
41
  "Home",
31
42
  "End"
32
43
  ].includes(e.key)) return;
33
44
  e.preventDefault();
34
- const t = y(i.current);
35
- if (t.length === 0) return;
36
- const s = t.findIndex((l) => l === document.activeElement);
37
- let n = s;
38
- e.key === "ArrowDown" ? n = (s + 1) % t.length : e.key === "ArrowUp" ? n = (s - 1 + t.length) % t.length : e.key === "Home" ? n = 0 : e.key === "End" && (n = t.length - 1), t[n]?.focus();
39
- }, m = {
40
- id: r,
41
- className: S(L.list, "m-0 list-none outline-none", !c && "px-0", !c && (E ? "py-0" : "py-2"), a),
45
+ const n = h(i.current);
46
+ if (n.length === 0) return;
47
+ const c = n.findIndex((a) => a === document.activeElement);
48
+ let s = c;
49
+ e.key === "ArrowDown" ? s = (c + 1) % n.length : e.key === "ArrowUp" ? s = (c - 1 + n.length) % n.length : e.key === "Home" ? s = 0 : e.key === "End" && (s = n.length - 1), n[s]?.focus(), i.current?.hasAttribute("data-menu-scroll") && n[s]?.scrollIntoView({ block: "nearest" });
50
+ }, g = {
51
+ id: t,
52
+ className: R(p.list, "m-0 list-none outline-none", !b && "px-0", !b && (w ? "py-0" : "py-2"), m),
42
53
  style: { fontFamily: "Roboto, Helvetica, Arial, sans-serif" },
43
- onClick: A,
44
- onKeyDown: x
54
+ onClick: I,
55
+ onKeyDown: S,
56
+ onFocus: (e) => {
57
+ i.current && e.target instanceof HTMLElement && x(i.current, e.target);
58
+ }
45
59
  };
46
- return h === "listbox" ? /* @__PURE__ */ d("ul", {
60
+ return u === "listbox" ? /* @__PURE__ */ A("ul", {
47
61
  ref: i,
48
- ...m,
62
+ ...g,
49
63
  role: "listbox",
50
- children: o
51
- }) : /* @__PURE__ */ d("ul", {
64
+ children: r
65
+ }) : /* @__PURE__ */ A("ul", {
52
66
  ref: i,
53
- ...m,
67
+ ...g,
54
68
  role: "menu",
55
- children: o
69
+ children: r
56
70
  });
57
71
  };
58
72
  export {
59
- H as StyledMenuList
73
+ _ as StyledMenuList
60
74
  };
@@ -1,30 +1,39 @@
1
- import { cn as f } from "../../../helpers/cn.js";
2
- import { resolveSx as x } from "../../../helpers/sx.js";
3
- import { useTabsContext as u } from "./TabsContext.js";
4
- import { useCallback as h } from "react";
5
- import { jsx as d } from "react/jsx-runtime";
6
- var k = ({ value: a, label: i, disabled: e, className: s, sx: l, index: m }) => {
7
- const t = u(), o = a !== void 0 ? a : m, r = t ? t.value === o : !1, c = /\btext-(?:xs|sm|base|lg|xl|\[)/.test(s ?? ""), p = /\bfont-(?:thin|extralight|light|normal|medium|semibold|bold|extrabold|black)\b/.test(s ?? ""), b = /\b(?:uppercase|lowercase|capitalize|normal-case)\b/.test(s ?? "");
8
- return /* @__PURE__ */ d("button", {
9
- ref: h((n) => {
10
- t?.register(o, n);
11
- }, [t, o]),
1
+ import { cn as g } from "../../../helpers/cn.js";
2
+ import { resolveSx as v } from "../../../helpers/sx.js";
3
+ import { StyledTooltip as y } from "../../data-display/tooltip/StyledTooltip.js";
4
+ import { useTabsContext as _ } from "./TabsContext.js";
5
+ import { useCallback as w, useId as S } from "react";
6
+ import { Fragment as T, jsx as i, jsxs as k } from "react/jsx-runtime";
7
+ var A = ({ value: l, label: d, disabled: o, tooltip: s, className: n, sx: b, index: f }) => {
8
+ const e = _(), p = S(), c = s ? `${p}-reason` : void 0, t = l !== void 0 ? l : f, r = e ? e.value === t : !1, x = /\btext-(?:xs|sm|base|lg|xl|\[)/.test(n ?? ""), u = /\bfont-(?:thin|extralight|light|normal|medium|semibold|bold|extrabold|black)\b/.test(n ?? ""), h = /\b(?:uppercase|lowercase|capitalize|normal-case)\b/.test(n ?? ""), m = /* @__PURE__ */ i("button", {
9
+ ref: w((a) => {
10
+ e?.register(t, a);
11
+ }, [e, t]),
12
12
  type: "button",
13
13
  role: "tab",
14
14
  "aria-selected": r,
15
- "aria-disabled": e ? !0 : void 0,
16
- disabled: e,
15
+ "aria-disabled": o ? !0 : void 0,
16
+ "aria-describedby": c,
17
17
  tabIndex: r ? 0 : -1,
18
- "data-tab-value": typeof o == "string" || typeof o == "number" ? String(o) : void 0,
19
- onClick: (n) => !e && t?.onSelect(n, o),
20
- className: f("inline-flex min-h-12 min-w-[90px] shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-t-lg border-0 bg-transparent px-4 py-3 tracking-normal outline-none transition-colors", !c && (t?.size === "small" ? "text-base" : "text-lg"), !p && (t?.size === "small" || r || e ? "font-semibold" : "font-medium hover:font-semibold focus-visible:font-semibold"), !b && "normal-case", t?.size === "small" && "min-h-10 px-3 py-2", "asma-pressable", e ? "text-delta-300" : r ? "text-gama-500" : "text-delta-600", !e && "cursor-pointer", "focus-visible:shadow-[inset_0_0_0_3px_var(--colors-focus-ring)]", !e && !r && "hover:shadow-[inset_0_-3px_0_0_var(--colors-delta-300)]", s),
18
+ "data-tab-value": typeof t == "string" || typeof t == "number" ? String(t) : void 0,
19
+ onClick: (a) => !o && e?.onSelect(a, t),
20
+ className: g("inline-flex min-h-12 min-w-[90px] shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-t-lg border-0 bg-transparent px-4 py-3 tracking-normal outline-none transition-colors", !x && (e?.size === "small" ? "text-base" : "text-lg"), !u && (e?.size === "small" || r || o ? "font-semibold" : "font-medium hover:font-semibold focus-visible:font-semibold"), !h && "normal-case", e?.size === "small" && "min-h-10 px-3 py-2", "asma-pressable", o ? "text-delta-300" : r ? "text-gama-500" : "text-delta-600", o ? "cursor-not-allowed" : "cursor-pointer", "focus-visible:shadow-[inset_0_0_0_3px_var(--colors-focus-ring)]", !o && !r && "hover:shadow-[inset_0_-3px_0_0_var(--colors-delta-300)]", n),
21
21
  style: {
22
22
  fontFamily: "Roboto, Helvetica, Arial, sans-serif",
23
- ...x(l)
23
+ ...v(b)
24
24
  },
25
- children: i
25
+ children: d
26
26
  });
27
+ return s ? /* @__PURE__ */ i(y, {
28
+ title: s,
29
+ arrow: !0,
30
+ children: /* @__PURE__ */ k(T, { children: [m, /* @__PURE__ */ i("span", {
31
+ id: c,
32
+ hidden: !0,
33
+ children: s
34
+ })] })
35
+ }) : m;
27
36
  };
28
37
  export {
29
- k as StyledTab
38
+ A as StyledTab
30
39
  };
@@ -1,4 +1,4 @@
1
- import { cn as n } from "../../../helpers/cn.js";
1
+ import { cn as s } from "../../../helpers/cn.js";
2
2
  import { resolveSx as K } from "../../../helpers/sx.js";
3
3
  import { ChevronRightIcon as M } from "../../icons/chevron-right-icon/ChevronRightIcon.js";
4
4
  import { ChevronLeftIcon as V } from "../../icons/chevron-left-icon/ChevronLeftIcon.js";
@@ -6,39 +6,39 @@ import { consumerOverrides as q } from "../../../helpers/classOverride.js";
6
6
  import { TabsContext as z } from "./TabsContext.js";
7
7
  import { Children as F, cloneElement as G, isValidElement as J, useCallback as b, useLayoutEffect as Q, useMemo as U, useRef as E, useState as A } from "react";
8
8
  import { jsx as l, jsxs as B } from "react/jsx-runtime";
9
- var I = 120, le = ({ value: i, onChange: m, variant: g = "standard", scrollButtons: w = "auto", centered: j, size: h = "default", className: p, sx: N, children: x }) => {
10
- const a = E(null), c = E(/* @__PURE__ */ new Map()), [u, O] = A({
9
+ var I = 120, le = ({ value: n, onChange: m, variant: g = "standard", scrollButtons: w = "auto", centered: j, size: f = "default", className: p, sx: N, children: x }) => {
10
+ const i = E(null), a = E(/* @__PURE__ */ new Map()), [h, O] = A({
11
11
  left: 0,
12
12
  width: 0,
13
13
  disabled: !1
14
- }), [d, W] = A({
14
+ }), [c, W] = A({
15
15
  left: !1,
16
16
  right: !1
17
17
  }), y = g === "scrollable", v = b((e, t) => {
18
- t ? c.current.set(e, t) : c.current.delete(e);
19
- }, []), S = b((e, t) => m?.(e, t), [m]), f = b(() => {
20
- const e = c.current.get(i), t = a.current;
18
+ t ? a.current.set(e, t) : a.current.delete(e);
19
+ }, []), S = b((e, t) => m?.(e, t), [m]), d = b(() => {
20
+ const e = a.current.get(n), t = i.current;
21
21
  if (e && O({
22
22
  left: e.offsetLeft,
23
23
  width: e.offsetWidth,
24
24
  disabled: e.disabled || e.getAttribute("aria-disabled") === "true"
25
25
  }), t) {
26
- const { scrollLeft: o, scrollWidth: r, clientWidth: s } = t;
26
+ const { scrollLeft: o, scrollWidth: r, clientWidth: u } = t;
27
27
  W({
28
28
  left: o > 1,
29
- right: o + s < r - 1
29
+ right: o + u < r - 1
30
30
  });
31
31
  }
32
- }, [i]);
32
+ }, [n]);
33
33
  Q(() => {
34
- f();
35
- const e = a.current;
34
+ d();
35
+ const e = i.current;
36
36
  if (!e) return;
37
- const t = new ResizeObserver(f);
37
+ const t = new ResizeObserver(d);
38
38
  return t.observe(e), () => t.disconnect();
39
- }, [f, x]);
39
+ }, [d, x]);
40
40
  const k = (e) => {
41
- a.current?.scrollBy({
41
+ i.current?.scrollBy({
42
42
  left: e,
43
43
  behavior: "smooth"
44
44
  });
@@ -50,33 +50,33 @@ var I = 120, le = ({ value: i, onChange: m, variant: g = "standard", scrollButto
50
50
  "End"
51
51
  ].includes(e.key)) return;
52
52
  e.preventDefault();
53
- const t = Array.from(c.current.values()).filter((s) => !s.disabled);
53
+ const t = Array.from(a.current.values());
54
54
  if (t.length === 0) return;
55
- const o = t.findIndex((s) => s === document.activeElement);
55
+ const o = t.findIndex((u) => u === document.activeElement);
56
56
  let r = o;
57
57
  e.key === "ArrowRight" ? r = (o + 1) % t.length : e.key === "ArrowLeft" ? r = (o - 1 + t.length) % t.length : e.key === "Home" ? r = 0 : e.key === "End" && (r = t.length - 1), t[r]?.focus();
58
- }, L = y && w !== !1, R = w === !0, D = L && (R || d.left), P = L && (R || d.right), T = q(p, "padding-x"), H = U(() => ({
59
- value: i,
60
- size: h,
58
+ }, L = y && w !== !1, R = w === !0, D = L && (R || c.left), P = L && (R || c.right), T = q(p, "padding-x"), H = U(() => ({
59
+ value: n,
60
+ size: f,
61
61
  onSelect: S,
62
62
  register: v
63
63
  }), [
64
- i,
65
- h,
64
+ n,
65
+ f,
66
66
  S,
67
67
  v
68
68
  ]), C = "flex h-10 w-10 shrink-0 items-center justify-center self-center rounded-[10%] border border-solid border-delta-500 text-delta-700 transition-colors hover:bg-gama-50 disabled:invisible";
69
69
  return /* @__PURE__ */ l(z.Provider, {
70
70
  value: H,
71
71
  children: /* @__PURE__ */ B("div", {
72
- className: n("relative flex items-center rounded-t-lg bg-white", !T && "px-4", p),
72
+ className: s("relative flex items-center rounded-t-lg bg-white", !T && "px-4", p),
73
73
  style: K(N),
74
74
  children: [
75
75
  D && /* @__PURE__ */ l("button", {
76
76
  type: "button",
77
77
  "aria-label": "scroll tabs left",
78
- className: n(C, "mr-2"),
79
- disabled: !d.left,
78
+ className: s(C, "mr-2"),
79
+ disabled: !c.left,
80
80
  onClick: () => k(-I),
81
81
  children: /* @__PURE__ */ l(V, {
82
82
  width: 24,
@@ -84,26 +84,26 @@ var I = 120, le = ({ value: i, onChange: m, variant: g = "standard", scrollButto
84
84
  })
85
85
  }),
86
86
  /* @__PURE__ */ B("div", {
87
- ref: a,
87
+ ref: i,
88
88
  role: "tablist",
89
89
  "aria-orientation": "horizontal",
90
90
  onKeyDown: _,
91
- onScroll: f,
92
- className: n("relative flex bg-[linear-gradient(to_top,var(--colors-delta-200)_1px,transparent_1px)] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", y ? "flex-1 overflow-x-auto" : "w-full", g === "fullWidth" && "[&>*]:flex-1", j && "justify-center", h === "small" && "min-h-9"),
91
+ onScroll: d,
92
+ className: s("relative flex bg-[linear-gradient(to_top,var(--colors-delta-200)_1px,transparent_1px)] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", y ? "flex-1 overflow-x-auto" : "w-full", g === "fullWidth" && "[&>*]:flex-1", j && "justify-center", f === "small" && "min-h-9"),
93
93
  children: [F.map(x, (e, t) => J(e) ? G(e, { index: t }) : e), /* @__PURE__ */ l("span", {
94
94
  "aria-hidden": !0,
95
- className: n("absolute bottom-0 h-[3px] transition-all duration-300", u.disabled ? "bg-delta-300" : "bg-gama-500"),
95
+ className: s("absolute bottom-0 h-[3px] transition-all duration-300", h.disabled ? "bg-delta-300" : "bg-gama-500"),
96
96
  style: {
97
- left: u.left,
98
- width: u.width
97
+ left: h.left,
98
+ width: h.width
99
99
  }
100
100
  })]
101
101
  }),
102
102
  P && /* @__PURE__ */ l("button", {
103
103
  type: "button",
104
104
  "aria-label": "scroll tabs right",
105
- className: n(C, "ml-2"),
106
- disabled: !d.right,
105
+ className: s(C, "ml-2"),
106
+ disabled: !c.right,
107
107
  onClick: () => k(I),
108
108
  children: /* @__PURE__ */ l(M, {
109
109
  width: 24,
@@ -1,5 +1,6 @@
1
- var a = (r) => r.tabIndex >= 0 && !r.matches(":disabled") && !r.closest("[inert]") && (r.checkVisibility?.() ?? !0), b = (r) => Array.from(r.querySelectorAll("*")).filter(a), i = (r) => a(r) ? r : Array.from(r.querySelectorAll("*")).find(a) ?? null;
1
+ var a = (r) => r.tabIndex >= 0 && !r.matches(":disabled") && !r.closest("[inert]") && (r.checkVisibility?.() ?? !0), b = (r) => Array.from(r.querySelectorAll("*")).filter(a), l = (r) => a(r) ? r : Array.from(r.querySelectorAll("*")).find(a) ?? null, i = (r) => (r.tabIndex >= 0 || r.hasAttribute("tabindex")) && !r.matches(":disabled") && !r.closest("[inert]") && (r.checkVisibility?.() ?? !0), s = (r) => i(r) ? r : Array.from(r.querySelectorAll("*")).find(i) ?? null;
2
2
  export {
3
- i as firstTabbable,
3
+ s as firstFocusable,
4
+ l as firstTabbable,
4
5
  b as tabbableWithin
5
6
  };
@@ -0,0 +1,6 @@
1
+ function a(e) {
2
+ typeof process < "u" && process.env.NODE_ENV === "production" || console.warn(`[asma-ui-core/StyledDialog] "${e ?? "dialog"}" has no accessible name — pass dialogTitle, dialogLabel or ariaLabel, or render a heading in its content`);
3
+ }
4
+ export {
5
+ a as warnUnnamedDialog
6
+ };
@@ -55,9 +55,17 @@ export interface IStyledDialogProps {
55
55
  dialogLabel?: ReactNode;
56
56
  /** @figmaProp header Title (Page title 24 SemiBold, delta-800) */
57
57
  dialogTitle?: ReactNode;
58
- /** Accessible name when the dialog has no visible title. */
59
- ariaLabel?: string;
60
58
  dialogHeaderNode?: ReactNode;
59
+ /**
60
+ * @figmaProp none — accessibility
61
+ * The dialog's accessible name when it shows no visible title: neither `dialogTitle`, a
62
+ * `<StyledDialogTitle>` child nor `dialogLabel`. A visible title or label always wins: the dialog
63
+ * is `aria-labelledby` it. Without any of these, the dialog is named by the first heading
64
+ * (`h1`–`h6` or `role="heading"`) in its content; with no heading either it stays unnamed and a
65
+ * development-only warning names its `dataTest`. `dataTest` is never used as a name — it is a
66
+ * test hook, not text.
67
+ */
68
+ ariaLabel?: string;
61
69
  }
62
70
  /**
63
71
  * Modal dialog built on the native `<dialog>` element (replaces MUI `Dialog`) — backdrop, focus
@@ -6,6 +6,7 @@ import { ToolbarLocale } from '../../../custom/module/header-layout/useTranslati
6
6
  export interface StyledDialogFooterButton {
7
7
  label: string;
8
8
  onClick?: () => void;
9
+ /** Rendered as `aria-disabled`, not native `disabled`: the button stays focusable, so keyboard users reach its `tooltip`. A click does nothing. */
9
10
  disabled?: boolean;
10
11
  /** `submit` lets the footer drive the surrounding `<form>` without a click handler. */
11
12
  type?: 'button' | 'submit' | 'reset';
@@ -17,7 +18,8 @@ export interface StyledDialogFooterButton {
17
18
  /** Trailing icon. `loading` supplies its own and wins. */
18
19
  endIcon?: ReactNode;
19
20
  /**
20
- * Shows a spinner after the label and disables the button. Consumers previously swapped
21
+ * Shows a spinner after the label and makes the button busy (`aria-busy`, `aria-disabled`): it
22
+ * keeps focus and ignores further presses. Consumers previously swapped
21
23
  * the label *for* a spinner, which changes the button's width mid-submit — hence the
22
24
  * hard-coded `w-[98px]` workarounds in the footers this replaces. Keeping the label
23
25
  * makes the width stable on its own.
@@ -25,8 +27,8 @@ export interface StyledDialogFooterButton {
25
27
  loading?: boolean;
26
28
  /**
27
29
  * Wraps the button in a `StyledTooltip`. Falsy renders no tooltip, so the common
28
- * `tooltip={disabled && 'Locked for editing'}` reads naturally. A disabled button does
29
- * not emit pointer events, so the tooltip is anchored on a wrapper around it.
30
+ * `tooltip={disabled && 'Locked for editing'}` reads naturally. It opens on hover and on
31
+ * keyboard focus, since a disabled button stays focusable.
30
32
  */
31
33
  tooltip?: ReactNode;
32
34
  dataTest?: string;
@@ -13,6 +13,7 @@ export interface StyledMenuListProps {
13
13
  }
14
14
  /**
15
15
  * Keyboard-navigable `role="menu"` list (replaces MUI `MenuList`). Arrow-key / Home / End roving
16
- * focus over enabled `[role="menuitem"]` children. TASK-303.
16
+ * focus over every `[role="menuitem"]` child, disabled ones included; opening focuses the first
17
+ * enabled item. TASK-303.
17
18
  */
18
19
  export declare const StyledMenuList: ({ children, id, role, className, autoFocus, disablePadding, onClick, onKeyDown, }: StyledMenuListProps) => JSX.Element;
@@ -12,8 +12,18 @@ export interface StyledTabProps {
12
12
  value?: TabValue;
13
13
  /** @figmaProp Label (tab content; may include a leading icon) */
14
14
  label?: ReactNode;
15
- /** @figmaProp State = true→"Disabled" */
15
+ /**
16
+ * @figmaProp State = true→"Disabled". Rendered as `aria-disabled`, not native `disabled`: the tab
17
+ * stays in the arrow-key order so keyboard users can find it (disabled-states DIS-3); a click or
18
+ * Enter does not select it.
19
+ */
16
20
  disabled?: boolean;
21
+ /**
22
+ * @figmaProp none — a11y
23
+ * Tooltip on the tab, opened by hover and keyboard focus and read as the tab's description —
24
+ * typically why a `disabled` tab is unavailable (disabled-states DIS-1, DIS-2). Falsy renders none.
25
+ */
26
+ tooltip?: ReactNode;
17
27
  className?: string;
18
28
  sx?: unknown;
19
29
  /** @internal Injected by `StyledTabs` so a value-less tab selects by position (MUI parity). */
@@ -6,3 +6,4 @@ export declare const tabbableWithin: (root: ParentNode) => HTMLElement[];
6
6
  * disabled control, which the caller has to decide about.
7
7
  */
8
8
  export declare const firstTabbable: (root: HTMLElement) => HTMLElement | null;
9
+ export declare const firstFocusable: (root: HTMLElement) => HTMLElement | null;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Development-only: a `StyledDialog` with no `dialogTitle`, `dialogLabel`, `ariaLabel` or heading in its
3
+ * content has no accessible name (WCAG 4.1.2, axe `aria-dialog-name`). Silent in production.
4
+ */
5
+ export declare function warnUnnamedDialog(dataTest: string | undefined): void;
@@ -1,31 +1,37 @@
1
- import { DotsVerticalIcon as S } from "../../../../../components/icons/dots-vertical-icon/DotsVerticalIcon.js";
2
- import { CircleWarningOutlineIcon as A } from "../../../../../components/icons/warning-circle-icon/CircleWarningOutlineIcon.js";
3
- import { StyledPopover as D } from "../../../../../components/utils/popover/StyledPopover.js";
4
- import { StyledMenuList as O } from "../../../../../components/navigation/menu/StyledMenuList.js";
5
- import { isCustomAction as j } from "../../../../types.js";
6
- import { StyledTooltip as g } from "../../../../shared-components/tooltip/index.js";
7
- import { useToggleMenuVisibility as k } from "../../../../hooks/useToggleMenuVisibility.hook.js";
8
- import { StyledButton as I } from "../../../../shared-components/button/StyledButton.js";
9
- import { StyledMenuItem as R } from "../../../../shared-components/StyledMenuItem.js";
10
- import w, { useEffect as V, useMemo as z, useState as E } from "react";
11
- import { jsx as t, jsxs as b } from "react/jsx-runtime";
12
- function X({ tableData: l, actions: v, rowActionsState: x }) {
13
- const { anchorEl: C, open: a, handleClose: r, handleOpen: P } = k(), i = v(l.row), o = x?.(l.row) ?? { state: "enabled" }, d = l.table.options.meta?.locale, T = d === "no" ? "Ingen handlinger tilgjengelig" : "No actions available", y = d === "no" ? "Radhandlinger" : "Row actions", N = z(() => i.every((e) => "component" in e ? !1 : e.hide), [i]), u = i.length > 0 && !N, m = o.state === "enabled" && !u, M = o.state !== "hidden" && (u || m || o.state === "disabled"), [c, s] = E(!1);
14
- if (V(() => {
15
- if (!c) return;
16
- const e = window.setTimeout(() => s(!1), 1600);
1
+ import { DotsVerticalIcon as A } from "../../../../../components/icons/dots-vertical-icon/DotsVerticalIcon.js";
2
+ import { CircleWarningOutlineIcon as O } from "../../../../../components/icons/warning-circle-icon/CircleWarningOutlineIcon.js";
3
+ import { StyledPopover as j } from "../../../../../components/utils/popover/StyledPopover.js";
4
+ import { StyledMenuList as k } from "../../../../../components/navigation/menu/StyledMenuList.js";
5
+ import { isCustomAction as R } from "../../../../types.js";
6
+ import { StyledTooltip as b } from "../../../../shared-components/tooltip/index.js";
7
+ import { useToggleMenuVisibility as E } from "../../../../hooks/useToggleMenuVisibility.hook.js";
8
+ import { StyledButton as B } from "../../../../shared-components/button/StyledButton.js";
9
+ import { StyledMenuItem as I } from "../../../../shared-components/StyledMenuItem.js";
10
+ import v, { useEffect as L, useMemo as V, useRef as z, useState as F } from "react";
11
+ import { jsx as t, jsxs as x } from "react/jsx-runtime";
12
+ function _({ tableData: r, actions: y, rowActionsState: T }) {
13
+ const { anchorEl: C, open: c, handleClose: i, handleOpen: M } = E(), a = y(r.row), o = T?.(r.row) ?? { state: "enabled" }, u = r.table.options.meta?.locale, P = u === "no" ? "Ingen handlinger tilgjengelig" : "No actions available", N = u === "no" ? "Radhandlinger" : "Row actions", D = V(() => a.every((e) => "component" in e ? !1 : e.hide), [a]), m = a.length > 0 && !D, f = o.state === "enabled" && !m, S = o.state !== "hidden" && (m || f || o.state === "disabled"), [p, l] = F(!1), h = z(!1), s = (e) => {
14
+ h.current = e, l(!0);
15
+ };
16
+ if (L(() => {
17
+ if (!p || !h.current) return;
18
+ const e = window.setTimeout(() => l(!1), 1600);
17
19
  return () => window.clearTimeout(e);
18
- }, [c]), !M) return /* @__PURE__ */ t("div", { className: "flex w-[40px] items-center justify-center" });
19
- const p = o.state === "disabled", f = /* @__PURE__ */ t(I, {
20
+ }, [p]), !S) return /* @__PURE__ */ t("div", { className: "flex w-[40px] items-center justify-center" });
21
+ const d = o.state === "disabled", g = /* @__PURE__ */ t(B, {
20
22
  dataTest: "row-actions-button",
21
- "aria-label": y,
23
+ "aria-label": N,
22
24
  "aria-haspopup": "true",
23
- "aria-expanded": a,
25
+ "aria-expanded": c,
24
26
  variant: "text",
25
27
  size: "small",
26
- disabled: p,
28
+ "aria-disabled": d ? !0 : void 0,
27
29
  onClick: (e) => {
28
- e.stopPropagation(), e.preventDefault(), !p && (e.currentTarget.focus({ preventScroll: !0 }), a ? r() : P(e));
30
+ if (e.stopPropagation(), e.preventDefault(), d) {
31
+ s(!1);
32
+ return;
33
+ }
34
+ e.currentTarget.focus({ preventScroll: !0 }), c ? i() : M(e);
29
35
  },
30
36
  onMouseDown: (e) => {
31
37
  e.stopPropagation(), e.preventDefault();
@@ -33,38 +39,45 @@ function X({ tableData: l, actions: v, rowActionsState: x }) {
33
39
  onMouseUp: (e) => {
34
40
  e.stopPropagation(), e.preventDefault();
35
41
  },
36
- children: /* @__PURE__ */ t(S, {
37
- className: p ? "text-delta-300" : "text-delta-700",
42
+ children: /* @__PURE__ */ t(A, {
43
+ className: d ? "text-delta-300" : "text-delta-700",
38
44
  width: 20,
39
45
  height: 20
40
46
  })
41
47
  });
42
48
  return /* @__PURE__ */ t("div", {
43
49
  className: "flex w-[40px] items-center justify-center",
44
- children: /* @__PURE__ */ b("div", {
50
+ children: /* @__PURE__ */ x("div", {
45
51
  className: "flex items-center justify-center",
46
- children: [o.state === "disabled" ? /* @__PURE__ */ t(g, {
52
+ children: [o.state === "disabled" ? /* @__PURE__ */ t(b, {
47
53
  title: o.tooltipTitle,
48
54
  arrow: !0,
49
55
  placement: o.tooltipPlacement ?? "top",
50
- open: c,
51
- onOpen: () => s(!0),
52
- onClose: () => s(!1),
56
+ open: p,
57
+ onOpen: () => s(!1),
58
+ onClose: () => l(!1),
53
59
  children: /* @__PURE__ */ t("span", {
54
60
  className: "cursor-not-allowed",
61
+ onMouseEnter: () => s(!1),
62
+ onMouseLeave: () => l(!1),
63
+ onFocus: () => s(!1),
64
+ onBlur: () => l(!1),
65
+ onKeyDown: (e) => {
66
+ e.key === "Escape" && l(!1);
67
+ },
55
68
  onTouchStart: (e) => {
56
69
  e.stopPropagation(), e.preventDefault(), s(!0);
57
70
  },
58
71
  onClick: (e) => {
59
72
  e.stopPropagation(), e.preventDefault();
60
73
  },
61
- children: f
74
+ children: g
62
75
  })
63
- }) : f, o.state === "enabled" && /* @__PURE__ */ t(D, {
64
- open: a,
76
+ }) : g, o.state === "enabled" && /* @__PURE__ */ t(j, {
77
+ open: c,
65
78
  anchorEl: C,
66
- onClose: r,
67
- onClick: r,
79
+ onClose: i,
80
+ onClick: i,
68
81
  anchorOrigin: {
69
82
  horizontal: "right",
70
83
  vertical: "bottom"
@@ -73,28 +86,28 @@ function X({ tableData: l, actions: v, rowActionsState: x }) {
73
86
  horizontal: "right",
74
87
  vertical: "top"
75
88
  },
76
- children: m ? /* @__PURE__ */ b("div", {
89
+ children: f ? /* @__PURE__ */ x("div", {
77
90
  className: "flex items-center gap-2 p-3 text-base text-delta-700",
78
- children: [/* @__PURE__ */ t(A, {
91
+ children: [/* @__PURE__ */ t(O, {
79
92
  width: 20,
80
93
  height: 20
81
- }), /* @__PURE__ */ t("span", { children: T })]
82
- }) : /* @__PURE__ */ t(O, {
94
+ }), /* @__PURE__ */ t("span", { children: P })]
95
+ }) : /* @__PURE__ */ t(k, {
83
96
  disablePadding: !0,
84
- children: i.map((e, h) => {
85
- if (j(e)) {
86
- const n = e.component(l.row, r);
87
- return w.isValidElement(n) ? /* @__PURE__ */ t(w.Fragment, { children: n }, h) : null;
97
+ children: a.map((e, w) => {
98
+ if (R(e)) {
99
+ const n = e.component(r.row, i);
100
+ return v.isValidElement(n) ? /* @__PURE__ */ t(v.Fragment, { children: n }, w) : null;
88
101
  }
89
- return e.hide ? null : /* @__PURE__ */ t(g, {
102
+ return e.hide ? null : /* @__PURE__ */ t(b, {
90
103
  title: e?.tooltipTitle,
91
104
  arrow: !0,
92
105
  placement: e?.tooltipPlacement ?? "left",
93
- children: /* @__PURE__ */ t("span", { children: /* @__PURE__ */ t(R, {
106
+ children: /* @__PURE__ */ t("span", { children: /* @__PURE__ */ t(I, {
94
107
  className: e.className,
95
108
  disabled: e.disabled,
96
109
  onClick: () => {
97
- e.disabled || e.onClick?.(l.row);
110
+ e.disabled || e.onClick?.(r.row);
98
111
  },
99
112
  onMouseDown: (n) => {
100
113
  n.stopPropagation(), n.preventDefault();
@@ -104,7 +117,7 @@ function X({ tableData: l, actions: v, rowActionsState: x }) {
104
117
  },
105
118
  children: e.label
106
119
  }) })
107
- }, h);
120
+ }, w);
108
121
  })
109
122
  })
110
123
  })]
@@ -112,5 +125,5 @@ function X({ tableData: l, actions: v, rowActionsState: x }) {
112
125
  });
113
126
  }
114
127
  export {
115
- X as RowActionMenu
128
+ _ as RowActionMenu
116
129
  };