@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.
- package/lib/esm/atomic/atoms/modal/Modal.js +14 -14
- package/lib/esm/atomic/atoms/modal/Modal.js.map +1 -1
- package/lib/esm/atomic/molecules/markdown/components/MarkdownArticleContainer.css.js +1 -0
- package/lib/esm/atomic/molecules/markdown/components/MarkdownLink.css.js +0 -1
- package/lib/esm/focus/focusable.js +1 -1
- package/lib/esm/focus/focusable.js.map +1 -1
- package/lib/types/atomic/atoms/modal/Modal.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -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
|
-
|
|
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,
|
|
18
|
+
r != null && e(n(r, j.current));
|
|
17
19
|
let i = (e) => {
|
|
18
20
|
if (e.key === "Escape") {
|
|
19
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
|
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:
|
|
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" ?
|
|
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
|
|
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,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,
|
|
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.
|
|
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.
|
|
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",
|