@plumile/ui 0.1.114 → 0.1.115

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.
@@ -8,15 +8,17 @@ import { useTranslation as _ } from "react-i18next";
8
8
  import { createPortal as v } from "react-dom";
9
9
  //#region src/atomic/atoms/modal/Modal.tsx
10
10
  var y = (y) => {
11
- let { isOpen: b, onClose: x, title: S, children: C, footer: w, closeAriaLabel: T, initialFocus: E } = y, { t: D } = _("ui"), O = f(), k = p(null), A = p(null);
11
+ let { isOpen: b, onClose: x, title: S, children: C, footer: w, closeAriaLabel: T, initialFocus: E } = y, { t: D } = _("ui"), O = f(), k = p(null), A = p(null), j = p(E), M = p(x);
12
12
  d(() => {
13
- if (!b) return () => {};
13
+ j.current = E, M.current = x;
14
+ }), d(() => {
15
+ if (!b) return;
14
16
  document.activeElement instanceof HTMLElement && (A.current = document.activeElement);
15
17
  let r = k.current;
16
- r != null && e(n(r, E));
18
+ r != null && e(n(r, j.current));
17
19
  let i = (e) => {
18
20
  if (e.key === "Escape") {
19
- x();
21
+ M.current();
20
22
  return;
21
23
  }
22
24
  if (e.key !== "Tab") return;
@@ -34,18 +36,16 @@ var y = (y) => {
34
36
  !e.shiftKey && document.activeElement === a && (e.preventDefault(), i.focus());
35
37
  };
36
38
  return window.addEventListener("keydown", i), () => {
37
- window.removeEventListener("keydown", i), A.current?.focus(), A.current = null;
39
+ window.removeEventListener("keydown", i);
40
+ let e = A.current;
41
+ e != null && e.isConnected && document.contains(e) && e.focus(), A.current = null;
38
42
  };
39
- }, [
40
- E,
41
- b,
42
- x
43
- ]);
44
- let j = (e) => {
43
+ }, [b]);
44
+ let N = (e) => {
45
45
  e.stopPropagation();
46
46
  };
47
47
  if (!b) return null;
48
- let M = /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(i, {
48
+ let P = /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(i, {
49
49
  isVisible: b,
50
50
  onClick: x
51
51
  }), /* @__PURE__ */ h("div", {
@@ -53,7 +53,7 @@ var y = (y) => {
53
53
  children: /* @__PURE__ */ g("div", {
54
54
  className: o,
55
55
  ref: k,
56
- onClick: j,
56
+ onClick: N,
57
57
  role: "dialog",
58
58
  "aria-modal": "true",
59
59
  "aria-labelledby": O,
@@ -88,7 +88,7 @@ var y = (y) => {
88
88
  ]
89
89
  })
90
90
  })] });
91
- return typeof document > "u" ? M : v(M, document.body);
91
+ return typeof document > "u" ? P : v(P, document.body);
92
92
  };
93
93
  //#endregion
94
94
  export { y as Modal };
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.js","names":[],"sources":["../../../../../src/atomic/atoms/modal/Modal.tsx"],"sourcesContent":["import React, { type JSX, useEffect, useId, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useTranslation } from 'react-i18next';\n\nimport { ModalCloseSvg } from '../../../icons/ModalCloseSvg.js';\nimport { Overlay } from '../overlay/Overlay.js';\nimport {\n focusElement,\n getFocusableElements,\n resolveInitialFocusTarget,\n type InitialFocusTarget,\n} from '../../../focus/focusable.js';\nimport * as styles from './modal.css.js';\n\ntype Props = {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n children: React.ReactNode;\n footer?: React.ReactNode;\n closeAriaLabel?: string;\n initialFocus: InitialFocusTarget;\n};\n\nexport const Modal = (props: Props): JSX.Element | null => {\n const {\n isOpen,\n onClose,\n title,\n children,\n footer,\n closeAriaLabel,\n initialFocus,\n } = props;\n const { t } = useTranslation('ui');\n const titleId = useId();\n const modalRef = useRef<HTMLDivElement>(null);\n const restoreFocusRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n if (!isOpen) {\n return () => {};\n }\n\n if (document.activeElement instanceof HTMLElement) {\n restoreFocusRef.current = document.activeElement;\n }\n\n const modalElement = modalRef.current;\n if (modalElement != null) {\n focusElement(resolveInitialFocusTarget(modalElement, initialFocus));\n }\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n return;\n }\n\n if (e.key !== 'Tab') {\n return;\n }\n\n const modalElement = modalRef.current;\n if (modalElement == null) {\n return;\n }\n\n const focusableElements = getFocusableElements(modalElement);\n\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n if (firstElement == null || lastElement == null) {\n e.preventDefault();\n modalElement.focus();\n return;\n }\n\n if (e.shiftKey && document.activeElement === firstElement) {\n e.preventDefault();\n lastElement.focus();\n return;\n }\n\n if (!e.shiftKey && document.activeElement === lastElement) {\n e.preventDefault();\n firstElement.focus();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n\n return () => {\n window.removeEventListener('keydown', handleKeyDown);\n restoreFocusRef.current?.focus();\n restoreFocusRef.current = null;\n };\n }, [initialFocus, isOpen, onClose]);\n\n // Prevent click from bubbling to overlay\n const handleModalClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n };\n\n if (!isOpen) {\n return null;\n }\n\n const modalContent = (\n <>\n <Overlay isVisible={isOpen} onClick={onClose} />\n <div className={styles.modalContainer}>\n <div\n className={styles.modal}\n ref={modalRef}\n onClick={handleModalClick}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n tabIndex={-1}\n >\n <div className={styles.modalHeader}>\n <h2 id={titleId} className={styles.modalTitle}>\n {title}\n </h2>\n <button\n className={styles.closeButton}\n onClick={onClose}\n aria-label={closeAriaLabel ?? t('common.actions.close')}\n type=\"button\"\n >\n <ModalCloseSvg width={20} height={20} aria-hidden=\"true\" />\n </button>\n </div>\n <div className={styles.modalContent}>{children}</div>\n {footer != null && <div className={styles.modalFooter}>{footer}</div>}\n </div>\n </div>\n </>\n );\n\n if (typeof document === 'undefined') {\n return modalContent;\n }\n\n return createPortal(modalContent, document.body);\n};\n"],"mappings":";;;;;;;;;AAwBA,IAAa,KAAS,MAAqC;CACzD,IAAM,EACJ,WACA,YACA,UACA,aACA,WACA,mBACA,oBACE,GACE,EAAE,SAAM,EAAe,KAAK,EAC5B,IAAU,GAAO,EACjB,IAAW,EAAuB,KAAK,EACvC,IAAkB,EAA2B,KAAK;CAExD,QAAgB;EACd,IAAI,CAAC,GACH,aAAa;EAGf,AAAI,SAAS,yBAAyB,gBACpC,EAAgB,UAAU,SAAS;EAGrC,IAAM,IAAe,EAAS;EAC9B,AAAI,KAAgB,QAClB,EAAa,EAA0B,GAAc,EAAa,CAAC;EAGrE,IAAM,KAAiB,MAAqB;GAC1C,IAAI,EAAE,QAAQ,UAAU;IACtB,GAAS;IACT;;GAGF,IAAI,EAAE,QAAQ,OACZ;GAGF,IAAM,IAAe,EAAS;GAC9B,IAAI,KAAgB,MAClB;GAGF,IAAM,IAAoB,EAAqB,EAAa,EAEtD,IAAe,EAAkB,IACjC,IAAc,EAAkB,EAAkB,SAAS;GACjE,IAAI,KAAgB,QAAQ,KAAe,MAAM;IAE/C,AADA,EAAE,gBAAgB,EAClB,EAAa,OAAO;IACpB;;GAGF,IAAI,EAAE,YAAY,SAAS,kBAAkB,GAAc;IAEzD,AADA,EAAE,gBAAgB,EAClB,EAAY,OAAO;IACnB;;GAGF,AAAI,CAAC,EAAE,YAAY,SAAS,kBAAkB,MAC5C,EAAE,gBAAgB,EAClB,EAAa,OAAO;;EAMxB,OAFA,OAAO,iBAAiB,WAAW,EAAc,QAEpC;GAGX,AAFA,OAAO,oBAAoB,WAAW,EAAc,EACpD,EAAgB,SAAS,OAAO,EAChC,EAAgB,UAAU;;IAE3B;EAAC;EAAc;EAAQ;EAAQ,CAAC;CAGnC,IAAM,KAAoB,MAAwB;EAChD,EAAE,iBAAiB;;CAGrB,IAAI,CAAC,GACH,OAAO;CAGT,IAAM,IACJ,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EAAS,WAAW;EAAQ,SAAS;EAAW,CAAA,EAChD,kBAAC,OAAD;EAAK,WAAW;YACd,kBAAC,OAAD;GACE,WAAW;GACX,KAAK;GACL,SAAS;GACT,MAAK;GACL,cAAW;GACX,mBAAiB;GACjB,UAAU;aAPZ;IASE,kBAAC,OAAD;KAAK,WAAW;eAAhB,CACE,kBAAC,MAAD;MAAI,IAAI;MAAS,WAAW;gBACzB;MACE,CAAA,EACL,kBAAC,UAAD;MACE,WAAW;MACX,SAAS;MACT,cAAY,KAAkB,EAAE,uBAAuB;MACvD,MAAK;gBAEL,kBAAC,GAAD;OAAe,OAAO;OAAI,QAAQ;OAAI,eAAY;OAAS,CAAA;MACpD,CAAA,CACL;;IACN,kBAAC,OAAD;KAAK,WAAW;KAAsB;KAAe,CAAA;IACpD,KAAU,QAAQ,kBAAC,OAAD;KAAK,WAAW;eAAqB;KAAa,CAAA;IACjE;;EACF,CAAA,CACL,EAAA,CAAA;CAOL,OAJI,OAAO,WAAa,MACf,IAGF,EAAa,GAAc,SAAS,KAAK"}
1
+ {"version":3,"file":"Modal.js","names":[],"sources":["../../../../../src/atomic/atoms/modal/Modal.tsx"],"sourcesContent":["import React, { type JSX, useEffect, useId, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useTranslation } from 'react-i18next';\n\nimport { ModalCloseSvg } from '../../../icons/ModalCloseSvg.js';\nimport { Overlay } from '../overlay/Overlay.js';\nimport {\n focusElement,\n getFocusableElements,\n resolveInitialFocusTarget,\n type InitialFocusTarget,\n} from '../../../focus/focusable.js';\nimport * as styles from './modal.css.js';\n\ntype Props = {\n isOpen: boolean;\n onClose: () => void;\n title: string;\n children: React.ReactNode;\n footer?: React.ReactNode;\n closeAriaLabel?: string;\n initialFocus: InitialFocusTarget;\n};\n\nexport const Modal = (props: Props): JSX.Element | null => {\n const {\n isOpen,\n onClose,\n title,\n children,\n footer,\n closeAriaLabel,\n initialFocus,\n } = props;\n const { t } = useTranslation('ui');\n const titleId = useId();\n const modalRef = useRef<HTMLDivElement>(null);\n const restoreFocusRef = useRef<HTMLElement | null>(null);\n const initialFocusRef = useRef(initialFocus);\n const onCloseRef = useRef(onClose);\n\n useEffect(() => {\n initialFocusRef.current = initialFocus;\n onCloseRef.current = onClose;\n });\n\n useEffect(() => {\n if (!isOpen) {\n return undefined;\n }\n\n if (document.activeElement instanceof HTMLElement) {\n restoreFocusRef.current = document.activeElement;\n }\n\n const modalElement = modalRef.current;\n if (modalElement != null) {\n focusElement(\n resolveInitialFocusTarget(modalElement, initialFocusRef.current),\n );\n }\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onCloseRef.current();\n return;\n }\n\n if (e.key !== 'Tab') {\n return;\n }\n\n const modalElement = modalRef.current;\n if (modalElement == null) {\n return;\n }\n\n const focusableElements = getFocusableElements(modalElement);\n\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n if (firstElement == null || lastElement == null) {\n e.preventDefault();\n modalElement.focus();\n return;\n }\n\n if (e.shiftKey && document.activeElement === firstElement) {\n e.preventDefault();\n lastElement.focus();\n return;\n }\n\n if (!e.shiftKey && document.activeElement === lastElement) {\n e.preventDefault();\n firstElement.focus();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n\n return () => {\n window.removeEventListener('keydown', handleKeyDown);\n const restoreFocusElement = restoreFocusRef.current;\n if (\n restoreFocusElement != null &&\n restoreFocusElement.isConnected &&\n document.contains(restoreFocusElement)\n ) {\n restoreFocusElement.focus();\n }\n restoreFocusRef.current = null;\n };\n }, [isOpen]);\n\n // Prevent click from bubbling to overlay\n const handleModalClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n };\n\n if (!isOpen) {\n return null;\n }\n\n const modalContent = (\n <>\n <Overlay isVisible={isOpen} onClick={onClose} />\n <div className={styles.modalContainer}>\n <div\n className={styles.modal}\n ref={modalRef}\n onClick={handleModalClick}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n tabIndex={-1}\n >\n <div className={styles.modalHeader}>\n <h2 id={titleId} className={styles.modalTitle}>\n {title}\n </h2>\n <button\n className={styles.closeButton}\n onClick={onClose}\n aria-label={closeAriaLabel ?? t('common.actions.close')}\n type=\"button\"\n >\n <ModalCloseSvg width={20} height={20} aria-hidden=\"true\" />\n </button>\n </div>\n <div className={styles.modalContent}>{children}</div>\n {footer != null && <div className={styles.modalFooter}>{footer}</div>}\n </div>\n </div>\n </>\n );\n\n if (typeof document === 'undefined') {\n return modalContent;\n }\n\n return createPortal(modalContent, document.body);\n};\n"],"mappings":";;;;;;;;;AAwBA,IAAa,KAAS,MAAqC;CACzD,IAAM,EACJ,WACA,YACA,UACA,aACA,WACA,mBACA,oBACE,GACE,EAAE,SAAM,EAAe,KAAK,EAC5B,IAAU,GAAO,EACjB,IAAW,EAAuB,KAAK,EACvC,IAAkB,EAA2B,KAAK,EAClD,IAAkB,EAAO,EAAa,EACtC,IAAa,EAAO,EAAQ;CAOlC,AALA,QAAgB;EAEd,AADA,EAAgB,UAAU,GAC1B,EAAW,UAAU;GACrB,EAEF,QAAgB;EACd,IAAI,CAAC,GACH;EAGF,AAAI,SAAS,yBAAyB,gBACpC,EAAgB,UAAU,SAAS;EAGrC,IAAM,IAAe,EAAS;EAC9B,AAAI,KAAgB,QAClB,EACE,EAA0B,GAAc,EAAgB,QAAQ,CACjE;EAGH,IAAM,KAAiB,MAAqB;GAC1C,IAAI,EAAE,QAAQ,UAAU;IACtB,EAAW,SAAS;IACpB;;GAGF,IAAI,EAAE,QAAQ,OACZ;GAGF,IAAM,IAAe,EAAS;GAC9B,IAAI,KAAgB,MAClB;GAGF,IAAM,IAAoB,EAAqB,EAAa,EAEtD,IAAe,EAAkB,IACjC,IAAc,EAAkB,EAAkB,SAAS;GACjE,IAAI,KAAgB,QAAQ,KAAe,MAAM;IAE/C,AADA,EAAE,gBAAgB,EAClB,EAAa,OAAO;IACpB;;GAGF,IAAI,EAAE,YAAY,SAAS,kBAAkB,GAAc;IAEzD,AADA,EAAE,gBAAgB,EAClB,EAAY,OAAO;IACnB;;GAGF,AAAI,CAAC,EAAE,YAAY,SAAS,kBAAkB,MAC5C,EAAE,gBAAgB,EAClB,EAAa,OAAO;;EAMxB,OAFA,OAAO,iBAAiB,WAAW,EAAc,QAEpC;GACX,OAAO,oBAAoB,WAAW,EAAc;GACpD,IAAM,IAAsB,EAAgB;GAQ5C,AANE,KAAuB,QACvB,EAAoB,eACpB,SAAS,SAAS,EAAoB,IAEtC,EAAoB,OAAO,EAE7B,EAAgB,UAAU;;IAE3B,CAAC,EAAO,CAAC;CAGZ,IAAM,KAAoB,MAAwB;EAChD,EAAE,iBAAiB;;CAGrB,IAAI,CAAC,GACH,OAAO;CAGT,IAAM,IACJ,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EAAS,WAAW;EAAQ,SAAS;EAAW,CAAA,EAChD,kBAAC,OAAD;EAAK,WAAW;YACd,kBAAC,OAAD;GACE,WAAW;GACX,KAAK;GACL,SAAS;GACT,MAAK;GACL,cAAW;GACX,mBAAiB;GACjB,UAAU;aAPZ;IASE,kBAAC,OAAD;KAAK,WAAW;eAAhB,CACE,kBAAC,MAAD;MAAI,IAAI;MAAS,WAAW;gBACzB;MACE,CAAA,EACL,kBAAC,UAAD;MACE,WAAW;MACX,SAAS;MACT,cAAY,KAAkB,EAAE,uBAAuB;MACvD,MAAK;gBAEL,kBAAC,GAAD;OAAe,OAAO;OAAI,QAAQ;OAAI,eAAY;OAAS,CAAA;MACpD,CAAA,CACL;;IACN,kBAAC,OAAD;KAAK,WAAW;KAAsB;KAAe,CAAA;IACpD,KAAU,QAAQ,kBAAC,OAAD;KAAK,WAAW;eAAqB;KAAa,CAAA;IACjE;;EACF,CAAA,CACL,EAAA,CAAA;CAOL,OAJI,OAAO,WAAa,MACf,IAGF,EAAa,GAAc,SAAS,KAAK"}
@@ -1,4 +1,5 @@
1
1
  /* empty css */
2
+ /* empty css */
2
3
  /* empty css */
3
4
  //#region src/atomic/molecules/markdown/components/MarkdownArticleContainer.css.ts
4
5
  var e = "_7ez1431 _7ez1430 txvbqb9ip txvbqbai7 txvbqbaop";
@@ -1,5 +1,4 @@
1
1
  /* empty css */
2
- /* empty css */
3
2
  /* empty css */
4
3
  //#region src/atomic/molecules/markdown/components/MarkdownLink.css.ts
5
4
  var e = "xtwkbg1 xtwkbg0 txvbqb3d txvbqb6b txvbqb78 txvbqb6x txvbqb7m txvbqbuu7", t = "xtwkbg3 xtwkbg1 xtwkbg0 txvbqb3d txvbqb6b txvbqb78 txvbqb6x txvbqb7m txvbqbuu7 xtwkbg2 txvbqbcp txvbqb9jg txvbqbany", n = "xtwkbg5 xtwkbg4 txvbqb9jg", r = "xtwkbg7 xtwkbg6 txvbqbf txvbqb3b";
@@ -1,6 +1,6 @@
1
1
  //#region src/focus/focusable.ts
2
2
  var e = "[data-initial-focus], [autofocus]", t = [
3
- "input:not([type=\"hidden\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"]):not([type=\"file\"]):not([disabled])",
3
+ "input:not([type=\"hidden\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"]):not([type=\"file\"]):not([type=\"checkbox\"]):not([type=\"radio\"]):not([disabled])",
4
4
  "textarea:not([disabled])",
5
5
  "[contenteditable=\"true\"]"
6
6
  ].join(","), n = [
@@ -1 +1 @@
1
- {"version":3,"file":"focusable.js","names":[],"sources":["../../../src/focus/focusable.ts"],"sourcesContent":["import type { RefObject } from 'react';\n\nexport type InitialFocusMode =\n | 'first-form-control'\n | 'first-focusable'\n | 'dialog'\n | 'none';\n\nexport type InitialFocusTarget =\n | InitialFocusMode\n | {\n mode: 'ref';\n ref: RefObject<HTMLElement | null>;\n fallback?: InitialFocusMode;\n }\n | {\n mode: 'selector';\n selector: string;\n fallback?: InitialFocusMode;\n };\n\nexport type FormInitialFocus =\n | 'first-form-control'\n | 'none'\n | {\n mode: 'ref';\n ref: RefObject<HTMLElement | null>;\n fallback?: 'first-form-control' | 'none';\n };\n\nconst explicitInitialFocusSelector = '[data-initial-focus], [autofocus]';\n\nconst formEditingSelector = [\n 'input:not([type=\"hidden\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"]):not([type=\"file\"]):not([disabled])',\n 'textarea:not([disabled])',\n '[contenteditable=\"true\"]',\n].join(',');\n\nconst formControlSelector = [\n 'select:not([disabled])',\n 'button:not([disabled])',\n 'input[type=\"checkbox\"]:not([disabled])',\n 'input[type=\"radio\"]:not([disabled])',\n].join(',');\n\nconst focusableSelector = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]',\n].join(',');\n\nconst hasHiddenAncestor = (element: HTMLElement): boolean => {\n return element.closest('[hidden], [aria-hidden=\"true\"]') != null;\n};\n\nconst isDisabled = (element: HTMLElement): boolean => {\n if (element.getAttribute('aria-disabled') === 'true') {\n return true;\n }\n\n if ('disabled' in element && element.disabled === true) {\n return true;\n }\n\n return false;\n};\n\nconst isVisible = (element: HTMLElement): boolean => {\n if (element.hidden === true) {\n return false;\n }\n\n if (element.getClientRects().length > 0) {\n return true;\n }\n\n const style = globalThis.getComputedStyle(element);\n\n return style.display !== 'none' && style.visibility !== 'hidden';\n};\n\nexport const isFocusableElement = (\n element: Element | null | undefined,\n): element is HTMLElement => {\n if (!(element instanceof HTMLElement)) {\n return false;\n }\n\n if (!element.isConnected) {\n return false;\n }\n\n if (isDisabled(element)) {\n return false;\n }\n\n if (hasHiddenAncestor(element)) {\n return false;\n }\n\n return isVisible(element);\n};\n\nconst findFirstMatching = (\n container: HTMLElement,\n selector: string,\n): HTMLElement | null => {\n const elements = Array.from(container.querySelectorAll(selector));\n return elements.find(isFocusableElement) ?? null;\n};\n\nexport const findFirstFormControl = (\n container: HTMLElement,\n): HTMLElement | null => {\n return (\n findFirstMatching(container, explicitInitialFocusSelector) ??\n findFirstMatching(container, formEditingSelector) ??\n findFirstMatching(container, formControlSelector)\n );\n};\n\nexport const findFirstFocusable = (\n container: HTMLElement,\n): HTMLElement | null => {\n if (container.matches(focusableSelector) && isFocusableElement(container)) {\n return container;\n }\n\n return findFirstMatching(container, focusableSelector);\n};\n\nexport const getFocusableElements = (container: HTMLElement): HTMLElement[] => {\n const elements = Array.from(container.querySelectorAll(focusableSelector));\n const result = elements.filter(isFocusableElement);\n\n if (container.matches(focusableSelector) && isFocusableElement(container)) {\n return [container, ...result];\n }\n\n return result;\n};\n\nconst resolveByMode = (\n container: HTMLElement,\n mode: InitialFocusMode,\n): HTMLElement | null => {\n switch (mode) {\n case 'first-form-control':\n return findFirstFormControl(container);\n case 'first-focusable':\n return findFirstFocusable(container);\n case 'dialog':\n return container;\n case 'none':\n return null;\n default:\n return null;\n }\n};\n\nexport const resolveInitialFocusTarget = (\n container: HTMLElement,\n target: InitialFocusTarget,\n): HTMLElement | null => {\n if (typeof target === 'string') {\n return resolveByMode(container, target);\n }\n\n if (target.mode === 'ref') {\n if (isFocusableElement(target.ref.current)) {\n return target.ref.current;\n }\n return resolveByMode(container, target.fallback ?? 'dialog');\n }\n\n const selected = container.querySelector(target.selector);\n if (isFocusableElement(selected)) {\n return selected;\n }\n\n return resolveByMode(container, target.fallback ?? 'dialog');\n};\n\nexport const resolveFormInitialFocusTarget = (\n container: HTMLElement,\n target: FormInitialFocus,\n): HTMLElement | null => {\n if (target === 'none') {\n return null;\n }\n\n if (target === 'first-form-control') {\n return findFirstFormControl(container);\n }\n\n if (isFocusableElement(target.ref.current)) {\n return target.ref.current;\n }\n\n if (target.fallback === 'first-form-control') {\n return findFirstFormControl(container);\n }\n\n return null;\n};\n\nexport const focusElement = (element: HTMLElement | null): void => {\n element?.focus({ preventScroll: true });\n};\n"],"mappings":";AA8BA,IAAM,IAA+B,qCAE/B,IAAsB;CAC1B;CACA;CACA;CACD,CAAC,KAAK,IAAI,EAEL,IAAsB;CAC1B;CACA;CACA;CACA;CACD,CAAC,KAAK,IAAI,EAEL,IAAoB;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC,KAAK,IAAI,EAEL,KAAqB,MAClB,EAAQ,QAAQ,mCAAiC,IAAI,MAGxD,KAAc,MACd,EAAQ,aAAa,gBAAgB,KAAK,UAI1C,cAAc,KAAW,EAAQ,aAAa,IAO9C,KAAa,MAAkC;CACnD,IAAI,EAAQ,WAAW,IACrB,OAAO;CAGT,IAAI,EAAQ,gBAAgB,CAAC,SAAS,GACpC,OAAO;CAGT,IAAM,IAAQ,WAAW,iBAAiB,EAAQ;CAElD,OAAO,EAAM,YAAY,UAAU,EAAM,eAAe;GAG7C,KACX,MAEI,EAAE,aAAmB,gBAIrB,CAAC,EAAQ,eAIT,EAAW,EAAQ,IAInB,EAAkB,EAAQ,GACrB,KAGF,EAAU,EAAQ,EAGrB,KACJ,GACA,MAEiB,MAAM,KAAK,EAAU,iBAAiB,EAAS,CACzD,CAAS,KAAK,EAAmB,IAAI,MAGjC,KACX,MAGE,EAAkB,GAAW,EAA6B,IAC1D,EAAkB,GAAW,EAAoB,IACjD,EAAkB,GAAW,EAAoB,EAIxC,KACX,MAEI,EAAU,QAAQ,EAAkB,IAAI,EAAmB,EAAU,GAChE,IAGF,EAAkB,GAAW,EAAkB,EAG3C,KAAwB,MAA0C;CAE7E,IAAM,IADW,MAAM,KAAK,EAAU,iBAAiB,EAAkB,CAC1D,CAAS,OAAO,EAAmB;CAMlD,OAJI,EAAU,QAAQ,EAAkB,IAAI,EAAmB,EAAU,GAChE,CAAC,GAAW,GAAG,EAAO,GAGxB;GAGH,KACJ,GACA,MACuB;CACvB,QAAQ,GAAR;EACE,KAAK,sBACH,OAAO,EAAqB,EAAU;EACxC,KAAK,mBACH,OAAO,EAAmB,EAAU;EACtC,KAAK,UACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,SACE,OAAO;;GAIA,KACX,GACA,MACuB;CACvB,IAAI,OAAO,KAAW,UACpB,OAAO,EAAc,GAAW,EAAO;CAGzC,IAAI,EAAO,SAAS,OAIlB,OAHI,EAAmB,EAAO,IAAI,QAAQ,GACjC,EAAO,IAAI,UAEb,EAAc,GAAW,EAAO,YAAY,SAAS;CAG9D,IAAM,IAAW,EAAU,cAAc,EAAO,SAAS;CAKzD,OAJI,EAAmB,EAAS,GACvB,IAGF,EAAc,GAAW,EAAO,YAAY,SAAS;GAGjD,KACX,GACA,MAEI,MAAW,SACN,OAGL,MAAW,uBACN,EAAqB,EAAU,GAGpC,EAAmB,EAAO,IAAI,QAAQ,GACjC,EAAO,IAAI,UAGhB,EAAO,aAAa,uBACf,EAAqB,EAAU,GAGjC,MAGI,KAAgB,MAAsC;CACjE,GAAS,MAAM,EAAE,eAAe,IAAM,CAAC"}
1
+ {"version":3,"file":"focusable.js","names":[],"sources":["../../../src/focus/focusable.ts"],"sourcesContent":["import type { RefObject } from 'react';\n\nexport type InitialFocusMode =\n | 'first-form-control'\n | 'first-focusable'\n | 'dialog'\n | 'none';\n\nexport type InitialFocusTarget =\n | InitialFocusMode\n | {\n mode: 'ref';\n ref: RefObject<HTMLElement | null>;\n fallback?: InitialFocusMode;\n }\n | {\n mode: 'selector';\n selector: string;\n fallback?: InitialFocusMode;\n };\n\nexport type FormInitialFocus =\n | 'first-form-control'\n | 'none'\n | {\n mode: 'ref';\n ref: RefObject<HTMLElement | null>;\n fallback?: 'first-form-control' | 'none';\n };\n\nconst explicitInitialFocusSelector = '[data-initial-focus], [autofocus]';\n\nconst formEditingSelector = [\n 'input:not([type=\"hidden\"]):not([type=\"button\"]):not([type=\"submit\"]):not([type=\"reset\"]):not([type=\"file\"]):not([type=\"checkbox\"]):not([type=\"radio\"]):not([disabled])',\n 'textarea:not([disabled])',\n '[contenteditable=\"true\"]',\n].join(',');\n\nconst formControlSelector = [\n 'select:not([disabled])',\n 'button:not([disabled])',\n 'input[type=\"checkbox\"]:not([disabled])',\n 'input[type=\"radio\"]:not([disabled])',\n].join(',');\n\nconst focusableSelector = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]',\n].join(',');\n\nconst hasHiddenAncestor = (element: HTMLElement): boolean => {\n return element.closest('[hidden], [aria-hidden=\"true\"]') != null;\n};\n\nconst isDisabled = (element: HTMLElement): boolean => {\n if (element.getAttribute('aria-disabled') === 'true') {\n return true;\n }\n\n if ('disabled' in element && element.disabled === true) {\n return true;\n }\n\n return false;\n};\n\nconst isVisible = (element: HTMLElement): boolean => {\n if (element.hidden === true) {\n return false;\n }\n\n if (element.getClientRects().length > 0) {\n return true;\n }\n\n const style = globalThis.getComputedStyle(element);\n\n return style.display !== 'none' && style.visibility !== 'hidden';\n};\n\nexport const isFocusableElement = (\n element: Element | null | undefined,\n): element is HTMLElement => {\n if (!(element instanceof HTMLElement)) {\n return false;\n }\n\n if (!element.isConnected) {\n return false;\n }\n\n if (isDisabled(element)) {\n return false;\n }\n\n if (hasHiddenAncestor(element)) {\n return false;\n }\n\n return isVisible(element);\n};\n\nconst findFirstMatching = (\n container: HTMLElement,\n selector: string,\n): HTMLElement | null => {\n const elements = Array.from(container.querySelectorAll(selector));\n return elements.find(isFocusableElement) ?? null;\n};\n\nexport const findFirstFormControl = (\n container: HTMLElement,\n): HTMLElement | null => {\n return (\n findFirstMatching(container, explicitInitialFocusSelector) ??\n findFirstMatching(container, formEditingSelector) ??\n findFirstMatching(container, formControlSelector)\n );\n};\n\nexport const findFirstFocusable = (\n container: HTMLElement,\n): HTMLElement | null => {\n if (container.matches(focusableSelector) && isFocusableElement(container)) {\n return container;\n }\n\n return findFirstMatching(container, focusableSelector);\n};\n\nexport const getFocusableElements = (container: HTMLElement): HTMLElement[] => {\n const elements = Array.from(container.querySelectorAll(focusableSelector));\n const result = elements.filter(isFocusableElement);\n\n if (container.matches(focusableSelector) && isFocusableElement(container)) {\n return [container, ...result];\n }\n\n return result;\n};\n\nconst resolveByMode = (\n container: HTMLElement,\n mode: InitialFocusMode,\n): HTMLElement | null => {\n switch (mode) {\n case 'first-form-control':\n return findFirstFormControl(container);\n case 'first-focusable':\n return findFirstFocusable(container);\n case 'dialog':\n return container;\n case 'none':\n return null;\n default:\n return null;\n }\n};\n\nexport const resolveInitialFocusTarget = (\n container: HTMLElement,\n target: InitialFocusTarget,\n): HTMLElement | null => {\n if (typeof target === 'string') {\n return resolveByMode(container, target);\n }\n\n if (target.mode === 'ref') {\n if (isFocusableElement(target.ref.current)) {\n return target.ref.current;\n }\n return resolveByMode(container, target.fallback ?? 'dialog');\n }\n\n const selected = container.querySelector(target.selector);\n if (isFocusableElement(selected)) {\n return selected;\n }\n\n return resolveByMode(container, target.fallback ?? 'dialog');\n};\n\nexport const resolveFormInitialFocusTarget = (\n container: HTMLElement,\n target: FormInitialFocus,\n): HTMLElement | null => {\n if (target === 'none') {\n return null;\n }\n\n if (target === 'first-form-control') {\n return findFirstFormControl(container);\n }\n\n if (isFocusableElement(target.ref.current)) {\n return target.ref.current;\n }\n\n if (target.fallback === 'first-form-control') {\n return findFirstFormControl(container);\n }\n\n return null;\n};\n\nexport const focusElement = (element: HTMLElement | null): void => {\n element?.focus({ preventScroll: true });\n};\n"],"mappings":";AA8BA,IAAM,IAA+B,qCAE/B,IAAsB;CAC1B;CACA;CACA;CACD,CAAC,KAAK,IAAI,EAEL,IAAsB;CAC1B;CACA;CACA;CACA;CACD,CAAC,KAAK,IAAI,EAEL,IAAoB;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC,KAAK,IAAI,EAEL,KAAqB,MAClB,EAAQ,QAAQ,mCAAiC,IAAI,MAGxD,KAAc,MACd,EAAQ,aAAa,gBAAgB,KAAK,UAI1C,cAAc,KAAW,EAAQ,aAAa,IAO9C,KAAa,MAAkC;CACnD,IAAI,EAAQ,WAAW,IACrB,OAAO;CAGT,IAAI,EAAQ,gBAAgB,CAAC,SAAS,GACpC,OAAO;CAGT,IAAM,IAAQ,WAAW,iBAAiB,EAAQ;CAElD,OAAO,EAAM,YAAY,UAAU,EAAM,eAAe;GAG7C,KACX,MAEI,EAAE,aAAmB,gBAIrB,CAAC,EAAQ,eAIT,EAAW,EAAQ,IAInB,EAAkB,EAAQ,GACrB,KAGF,EAAU,EAAQ,EAGrB,KACJ,GACA,MAEiB,MAAM,KAAK,EAAU,iBAAiB,EAAS,CACzD,CAAS,KAAK,EAAmB,IAAI,MAGjC,KACX,MAGE,EAAkB,GAAW,EAA6B,IAC1D,EAAkB,GAAW,EAAoB,IACjD,EAAkB,GAAW,EAAoB,EAIxC,KACX,MAEI,EAAU,QAAQ,EAAkB,IAAI,EAAmB,EAAU,GAChE,IAGF,EAAkB,GAAW,EAAkB,EAG3C,KAAwB,MAA0C;CAE7E,IAAM,IADW,MAAM,KAAK,EAAU,iBAAiB,EAAkB,CAC1D,CAAS,OAAO,EAAmB;CAMlD,OAJI,EAAU,QAAQ,EAAkB,IAAI,EAAmB,EAAU,GAChE,CAAC,GAAW,GAAG,EAAO,GAGxB;GAGH,KACJ,GACA,MACuB;CACvB,QAAQ,GAAR;EACE,KAAK,sBACH,OAAO,EAAqB,EAAU;EACxC,KAAK,mBACH,OAAO,EAAmB,EAAU;EACtC,KAAK,UACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,SACE,OAAO;;GAIA,KACX,GACA,MACuB;CACvB,IAAI,OAAO,KAAW,UACpB,OAAO,EAAc,GAAW,EAAO;CAGzC,IAAI,EAAO,SAAS,OAIlB,OAHI,EAAmB,EAAO,IAAI,QAAQ,GACjC,EAAO,IAAI,UAEb,EAAc,GAAW,EAAO,YAAY,SAAS;CAG9D,IAAM,IAAW,EAAU,cAAc,EAAO,SAAS;CAKzD,OAJI,EAAmB,EAAS,GACvB,IAGF,EAAc,GAAW,EAAO,YAAY,SAAS;GAGjD,KACX,GACA,MAEI,MAAW,SACN,OAGL,MAAW,uBACN,EAAqB,EAAU,GAGpC,EAAmB,EAAO,IAAI,QAAQ,GACjC,EAAO,IAAI,UAGhB,EAAO,aAAa,uBACf,EAAqB,EAAU,GAGjC,MAGI,KAAgB,MAAsC;CACjE,GAAS,MAAM,EAAE,eAAe,IAAM,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../../../../src/atomic/atoms/modal/Modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,GAAG,EAA4B,MAAM,OAAO,CAAC;AAMlE,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,6BAA6B,CAAC;AAGrC,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,kBAAkB,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,OAAO,KAAK,KAAG,GAAG,CAAC,OAAO,GAAG,IA0HlD,CAAC"}
1
+ {"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../../../../src/atomic/atoms/modal/Modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,GAAG,EAA4B,MAAM,OAAO,CAAC;AAMlE,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,6BAA6B,CAAC;AAGrC,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,kBAAkB,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,OAAO,KAAK,KAAG,GAAG,CAAC,OAAO,GAAG,IA0IlD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumile/ui",
3
- "version": "0.1.114",
3
+ "version": "0.1.115",
4
4
  "description": "Shared React UI primitives and theme for Kronex applications",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -162,7 +162,7 @@
162
162
  "tslib": "^2.8.1"
163
163
  },
164
164
  "devDependencies": {
165
- "@plumile/router": "^0.1.114",
165
+ "@plumile/router": "^0.1.115",
166
166
  "@types/react": "19.2.14",
167
167
  "@types/react-dom": "19.2.3",
168
168
  "i18next": "26.1.0",