@arkyn/components 3.0.8 → 3.0.10
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/dist/components/calendar/_calendarProvider.d.ts.map +1 -1
- package/dist/components/calendar/calendarTableTd/index.d.ts.map +1 -1
- package/dist/components/currencyInput/index.d.ts +1 -1
- package/dist/components/datePicker/datePickerCalendarContainer/index.d.ts +1 -0
- package/dist/components/datePicker/datePickerCalendarContainer/index.d.ts.map +1 -1
- package/dist/components/datePicker/datePickerContainer/index.d.ts +5 -1
- package/dist/components/datePicker/datePickerContainer/index.d.ts.map +1 -1
- package/dist/components/datePicker/index.d.ts.map +1 -1
- package/dist/components/drawer/drawerContainer/index.d.ts.map +1 -1
- package/dist/components/googleAnalytics/snippets/generateGAElements.d.ts.map +1 -1
- package/dist/components/googleTagManager/snippets/appendToDataLayer.d.ts.map +1 -1
- package/dist/components/googleTagManager/snippets/generateGTMElements.d.ts.map +1 -1
- package/dist/components/imageUpload/index.d.ts +1 -1
- package/dist/components/input/index.d.ts +1 -1
- package/dist/components/modal/modalContainer/index.d.ts.map +1 -1
- package/dist/components/multiSelect/index.d.ts +1 -1
- package/dist/components/multiSelect/index.d.ts.map +1 -1
- package/dist/components/multiSelect/multiSelectContainer/index.d.ts +6 -1
- package/dist/components/multiSelect/multiSelectContainer/index.d.ts.map +1 -1
- package/dist/components/multiSelect/multiSelectOption/index.d.ts +2 -0
- package/dist/components/multiSelect/multiSelectOption/index.d.ts.map +1 -1
- package/dist/components/multiSelect/multiSelectOptionsContainer/index.d.ts +1 -0
- package/dist/components/multiSelect/multiSelectOptionsContainer/index.d.ts.map +1 -1
- package/dist/components/popover/index.d.ts.map +1 -1
- package/dist/components/richText/index.d.ts +1 -1
- package/dist/components/richText/index.d.ts.map +1 -1
- package/dist/components/select/index.d.ts +1 -1
- package/dist/components/select/index.d.ts.map +1 -1
- package/dist/components/select/selectContainer/index.d.ts +6 -1
- package/dist/components/select/selectContainer/index.d.ts.map +1 -1
- package/dist/components/select/selectOption/index.d.ts +2 -0
- package/dist/components/select/selectOption/index.d.ts.map +1 -1
- package/dist/components/select/selectOptionsContainer/index.d.ts +1 -0
- package/dist/components/select/selectOptionsContainer/index.d.ts.map +1 -1
- package/dist/hooks/useEscapeKey.d.ts +24 -0
- package/dist/hooks/useEscapeKey.d.ts.map +1 -0
- package/dist/hooks/useFlipPosition.d.ts +38 -0
- package/dist/hooks/useFlipPosition.d.ts.map +1 -0
- package/dist/hooks/useFocusTrap.d.ts +28 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -0
- package/dist/index.js +1120 -881
- package/dist/index.js.map +1 -1
- package/dist/modules/components/calendar/_calendarProvider.js +47 -34
- package/dist/modules/components/calendar/_calendarProvider.js.map +1 -1
- package/dist/modules/components/calendar/calendarTableTd/index.js +7 -2
- package/dist/modules/components/calendar/calendarTableTd/index.js.map +1 -1
- package/dist/modules/components/calendar/calendarTableTd/styles.css +1 -1
- package/dist/modules/components/calendar/styles.css +2 -2
- package/dist/modules/components/currencyInput/index.js.map +1 -1
- package/dist/modules/components/datePicker/datePickerCalendarContainer/index.js +12 -16
- package/dist/modules/components/datePicker/datePickerCalendarContainer/index.js.map +1 -1
- package/dist/modules/components/datePicker/datePickerContainer/index.js +9 -2
- package/dist/modules/components/datePicker/datePickerContainer/index.js.map +1 -1
- package/dist/modules/components/datePicker/index.js +63 -44
- package/dist/modules/components/datePicker/index.js.map +1 -1
- package/dist/modules/components/datePicker/styles.css +4 -4
- package/dist/modules/components/drawer/drawerContainer/index.js +31 -23
- package/dist/modules/components/drawer/drawerContainer/index.js.map +1 -1
- package/dist/modules/components/facebookPixel/pixel.js +1 -1
- package/dist/modules/components/facebookPixel/pixel.js.map +1 -1
- package/dist/modules/components/googleAnalytics/snippets/generateGAElements.js +7 -6
- package/dist/modules/components/googleAnalytics/snippets/generateGAElements.js.map +1 -1
- package/dist/modules/components/googleTagManager/snippets/appendToDataLayer.js +7 -6
- package/dist/modules/components/googleTagManager/snippets/appendToDataLayer.js.map +1 -1
- package/dist/modules/components/googleTagManager/snippets/generateGTMElements.js +20 -14
- package/dist/modules/components/googleTagManager/snippets/generateGTMElements.js.map +1 -1
- package/dist/modules/components/imageUpload/index.js.map +1 -1
- package/dist/modules/components/input/index.js.map +1 -1
- package/dist/modules/components/modal/modalContainer/index.js +30 -22
- package/dist/modules/components/modal/modalContainer/index.js.map +1 -1
- package/dist/modules/components/multiSelect/index.js +119 -79
- package/dist/modules/components/multiSelect/index.js.map +1 -1
- package/dist/modules/components/multiSelect/multiSelectContainer/index.js +10 -2
- package/dist/modules/components/multiSelect/multiSelectContainer/index.js.map +1 -1
- package/dist/modules/components/multiSelect/multiSelectOption/index.js +7 -3
- package/dist/modules/components/multiSelect/multiSelectOption/index.js.map +1 -1
- package/dist/modules/components/multiSelect/multiSelectOption/styles.css +1 -1
- package/dist/modules/components/multiSelect/multiSelectOptionsContainer/index.js +19 -23
- package/dist/modules/components/multiSelect/multiSelectOptionsContainer/index.js.map +1 -1
- package/dist/modules/components/multiSelect/styles.css +1 -1
- package/dist/modules/components/popover/index.js +23 -17
- package/dist/modules/components/popover/index.js.map +1 -1
- package/dist/modules/components/richText/index.js +1 -1
- package/dist/modules/components/richText/index.js.map +1 -1
- package/dist/modules/components/searchPlaces.js +1 -1
- package/dist/modules/components/searchPlaces.js.map +1 -1
- package/dist/modules/components/select/index.js +120 -80
- package/dist/modules/components/select/index.js.map +1 -1
- package/dist/modules/components/select/selectContainer/index.js +10 -2
- package/dist/modules/components/select/selectContainer/index.js.map +1 -1
- package/dist/modules/components/select/selectOption/index.js +5 -2
- package/dist/modules/components/select/selectOption/index.js.map +1 -1
- package/dist/modules/components/select/selectOption/styles.css +1 -1
- package/dist/modules/components/select/selectOptionsContainer/index.js +18 -23
- package/dist/modules/components/select/selectOptionsContainer/index.js.map +1 -1
- package/dist/modules/components/select/styles.css +1 -1
- package/dist/modules/hooks/useEscapeKey.js +18 -0
- package/dist/modules/hooks/useEscapeKey.js.map +1 -0
- package/dist/modules/hooks/useFlipPosition.js +26 -0
- package/dist/modules/hooks/useFlipPosition.js.map +1 -0
- package/dist/modules/hooks/useFocusTrap.js +44 -0
- package/dist/modules/hooks/useFocusTrap.js.map +1 -0
- package/dist/modules/utils/escapeForInlineScript.js +14 -0
- package/dist/modules/utils/escapeForInlineScript.js.map +1 -0
- package/dist/style.css +1 -1
- package/dist/utils/escapeForInlineScript.d.ts +23 -0
- package/dist/utils/escapeForInlineScript.d.ts.map +1 -0
- package/package.json +16 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/components/modal/modalContainer/index.tsx"],"sourcesContent":["import {\n\ttype AnimationEvent,\n\ttype HTMLAttributes,\n\tuseEffect,\n\tuseState,\n} from \"react\";\n\nimport { useScrollLock } from \"../../../hooks/useScrollLock\";\nimport { ModalProvider } from \"../modalContext\";\nimport \"./styles.css\";\n\ntype ModalContainerProps = HTMLAttributes<HTMLElement> & {\n\t/** Controls whether the modal is visible. */\n\tisVisible: boolean;\n\t/** Callback invoked when the backdrop overlay is clicked. */\n\tmakeInvisible: () => void;\n};\n\n/**\n * ModalContainer, animated centered modal rendered over a backdrop overlay.\n *\n * Locks body scroll while open. Closes when the overlay is clicked.\n * Provides context consumed by `ModalHeader` (close button).\n *\n * @param props.isVisible - Whether the modal is open. Required.\n * @param props.makeInvisible - Called when the overlay is clicked. Required.\n *\n * **...Other valid HTML `<aside>` properties**\n *\n * @returns ModalContainer JSX element.\n *\n * @example\n * ```tsx\n * const [isOpen, setIsOpen] = useState(false);\n *\n * <ModalContainer isVisible={isOpen} makeInvisible={() => setIsOpen(false)}>\n * <ModalHeader><h2>Confirm deletion</h2></ModalHeader>\n * <main><p>This action cannot be undone.</p></main>\n * <ModalFooter>\n * <Button onClick={() => setIsOpen(false)}>Cancel</Button>\n * <Button scheme=\"danger\" onClick={handleDelete}>Delete</Button>\n * </ModalFooter>\n * </ModalContainer>\n * ```\n */\n\nfunction ModalContainer(args: ModalContainerProps) {\n\tconst {\n\t\tisVisible,\n\t\tmakeInvisible,\n\t\tchildren,\n\t\tclassName: baseClassName = \"\",\n\t\t...rest\n\t} = args;\n\n\tconst [mounted, setMounted] = useState(isVisible);\n\tconst [isExiting, setIsExiting] = useState(false);\n\n\tuseEffect(() => {\n\t\tif (isVisible) {\n\t\t\tsetMounted(true);\n\t\t\tsetIsExiting(false);\n\t\t} else if (mounted) {\n\t\t\tsetIsExiting(true);\n\t\t}\n\t}, [isVisible, mounted]);\n\n\tuseScrollLock(isVisible);\n\n\tfunction handleOverlayAnimationEnd(e: AnimationEvent<HTMLDivElement>) {\n\t\tif (e.target === e.currentTarget && isExiting) {\n\t\t\tsetIsExiting(false);\n\t\t\tsetMounted(false);\n\t\t\tmakeInvisible();\n\t\t}\n\t}\n\n\tif (!mounted) return null;\n\n\tconst className = [\n\t\t\"arkynModalContainer\",\n\t\tisExiting ? \"exiting\" : \"\",\n\t\tbaseClassName,\n\t]\n\t\t.filter(Boolean)\n\t\t.join(\" \");\n\n\treturn (\n\t\t<ModalProvider makeInvisible={() => setIsExiting(true)}>\n\t\t\t<aside className={className.trim()} {...rest}>\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"arkynModalContainerOverlay\"\n\t\t\t\t\tonClick={() => setIsExiting(true)}\n\t\t\t\t\tonAnimationEnd={handleOverlayAnimationEnd}\n\t\t\t\t/>\n\t\t\t\t<div
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/components/modal/modalContainer/index.tsx"],"sourcesContent":["import {\n\ttype AnimationEvent,\n\ttype HTMLAttributes,\n\tuseEffect,\n\tuseRef,\n\tuseState,\n} from \"react\";\n\nimport { useEscapeKey } from \"../../../hooks/useEscapeKey\";\nimport { useFocusTrap } from \"../../../hooks/useFocusTrap\";\nimport { useScrollLock } from \"../../../hooks/useScrollLock\";\nimport { ModalProvider } from \"../modalContext\";\nimport \"./styles.css\";\n\ntype ModalContainerProps = HTMLAttributes<HTMLElement> & {\n\t/** Controls whether the modal is visible. */\n\tisVisible: boolean;\n\t/** Callback invoked when the backdrop overlay is clicked. */\n\tmakeInvisible: () => void;\n};\n\n/**\n * ModalContainer, animated centered modal rendered over a backdrop overlay.\n *\n * Locks body scroll while open. Closes when the overlay is clicked.\n * Provides context consumed by `ModalHeader` (close button).\n *\n * @param props.isVisible - Whether the modal is open. Required.\n * @param props.makeInvisible - Called when the overlay is clicked. Required.\n *\n * **...Other valid HTML `<aside>` properties**\n *\n * @returns ModalContainer JSX element.\n *\n * @example\n * ```tsx\n * const [isOpen, setIsOpen] = useState(false);\n *\n * <ModalContainer isVisible={isOpen} makeInvisible={() => setIsOpen(false)}>\n * <ModalHeader><h2>Confirm deletion</h2></ModalHeader>\n * <main><p>This action cannot be undone.</p></main>\n * <ModalFooter>\n * <Button onClick={() => setIsOpen(false)}>Cancel</Button>\n * <Button scheme=\"danger\" onClick={handleDelete}>Delete</Button>\n * </ModalFooter>\n * </ModalContainer>\n * ```\n */\n\nfunction ModalContainer(args: ModalContainerProps) {\n\tconst {\n\t\tisVisible,\n\t\tmakeInvisible,\n\t\tchildren,\n\t\tclassName: baseClassName = \"\",\n\t\t...rest\n\t} = args;\n\n\tconst [mounted, setMounted] = useState(isVisible);\n\tconst [isExiting, setIsExiting] = useState(false);\n\tconst contentRef = useRef<HTMLDivElement>(null);\n\n\tuseEffect(() => {\n\t\tif (isVisible) {\n\t\t\tsetMounted(true);\n\t\t\tsetIsExiting(false);\n\t\t} else if (mounted) {\n\t\t\tsetIsExiting(true);\n\t\t}\n\t}, [isVisible, mounted]);\n\n\tuseScrollLock(isVisible);\n\n\tconst isDialogActive = mounted && !isExiting;\n\tuseEscapeKey(isDialogActive, () => setIsExiting(true));\n\tuseFocusTrap(isDialogActive, contentRef);\n\n\tfunction handleOverlayAnimationEnd(e: AnimationEvent<HTMLDivElement>) {\n\t\tif (e.target === e.currentTarget && isExiting) {\n\t\t\tsetIsExiting(false);\n\t\t\tsetMounted(false);\n\t\t\tmakeInvisible();\n\t\t}\n\t}\n\n\tif (!mounted) return null;\n\n\tconst className = [\n\t\t\"arkynModalContainer\",\n\t\tisExiting ? \"exiting\" : \"\",\n\t\tbaseClassName,\n\t]\n\t\t.filter(Boolean)\n\t\t.join(\" \");\n\n\treturn (\n\t\t<ModalProvider makeInvisible={() => setIsExiting(true)}>\n\t\t\t<aside className={className.trim()} {...rest}>\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"arkynModalContainerOverlay\"\n\t\t\t\t\tonClick={() => setIsExiting(true)}\n\t\t\t\t\tonAnimationEnd={handleOverlayAnimationEnd}\n\t\t\t\t/>\n\t\t\t\t<div\n\t\t\t\t\tref={contentRef}\n\t\t\t\t\trole=\"dialog\"\n\t\t\t\t\taria-modal=\"true\"\n\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\tclassName=\"arkynModalContainerContent\"\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</aside>\n\t\t</ModalProvider>\n\t);\n}\n\nexport { ModalContainer };\n"],"mappings":";;;;;;;;AAiDA,SAAS,EAAe,GAA2B;CAClD,IAAM,EACL,cACA,kBACA,aACA,WAAW,IAAgB,IAC3B,GAAG,MACA,GAEE,CAAC,GAAS,KAAc,EAAS,CAAS,GAC1C,CAAC,GAAW,KAAgB,EAAS,EAAK,GAC1C,IAAa,EAAuB,IAAI;CAW9C,AATA,QAAgB;EACf,AAAI,KACH,EAAW,EAAI,GACf,EAAa,EAAK,KACR,KACV,EAAa,EAAI;CAEnB,GAAG,CAAC,GAAW,CAAO,CAAC,GAEvB,EAAc,CAAS;CAEvB,IAAM,IAAiB,KAAW,CAAC;CAEnC,AADA,EAAa,SAAsB,EAAa,EAAI,CAAC,GACrD,EAAa,GAAgB,CAAU;CAEvC,SAAS,EAA0B,GAAmC;EACrE,AAAI,EAAE,WAAW,EAAE,iBAAiB,MACnC,EAAa,EAAK,GAClB,EAAW,EAAK,GAChB,EAAc;CAEhB;CAYA,OAVK,IAWJ,kBAAC,GAAD;EAAe,qBAAqB,EAAa,EAAI;YACpD,kBAAC,SAAD;GAAO,WAVS;IACjB;IACA,IAAY,YAAY;IACxB;GACD,CAAC,CACC,OAAO,OAAO,CAAC,CACf,KAAK,GAIa,CAAA,CAAU,KAAK;GAAG,GAAI;aAAxC,CACC,kBAAC,OAAD;IACC,WAAU;IACV,eAAe,EAAa,EAAI;IAChC,gBAAgB;GAChB,CAAA,GACD,kBAAC,OAAD;IACC,KAAK;IACL,MAAK;IACL,cAAW;IACX,UAAU;IACV,WAAU;IAET;GACG,CAAA,CACC;;CACO,CAAA,IA5BK;AA8BtB"}
|
|
@@ -1,118 +1,158 @@
|
|
|
1
1
|
import { useForm as e } from "../../hooks/useForm.js";
|
|
2
2
|
import { IconRenderer as t } from "../../services/iconRenderer.js";
|
|
3
3
|
import { FieldTemplate as n } from "../../services/fieldTemplate.js";
|
|
4
|
-
import { MultiSelectChevron as
|
|
5
|
-
import { MultiSelectContainer as
|
|
6
|
-
import { MultiSelectContent as
|
|
7
|
-
import { MultiSelectMark as
|
|
8
|
-
import { MultiSelectOption as
|
|
9
|
-
import { MultiSelectOptionsContainer as
|
|
10
|
-
import { MultiSelectOverlay as
|
|
11
|
-
import { MultiSelectSpinner as
|
|
12
|
-
import { useId as
|
|
13
|
-
import { jsx as
|
|
4
|
+
import { MultiSelectChevron as ee } from "./multiSelectChevron/index.js";
|
|
5
|
+
import { MultiSelectContainer as te } from "./multiSelectContainer/index.js";
|
|
6
|
+
import { MultiSelectContent as ne } from "./multiSelectContent/index.js";
|
|
7
|
+
import { MultiSelectMark as re } from "./multiSelectMark/index.js";
|
|
8
|
+
import { MultiSelectOption as ie } from "./multiSelectOption/index.js";
|
|
9
|
+
import { MultiSelectOptionsContainer as r } from "./multiSelectOptionsContainer/index.js";
|
|
10
|
+
import { MultiSelectOverlay as i } from "./multiSelectOverlay/index.js";
|
|
11
|
+
import { MultiSelectSpinner as a } from "./multiSelectSpinner/index.js";
|
|
12
|
+
import { useId as o, useRef as s, useState as c } from "react";
|
|
13
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
14
14
|
//#region src/components/multiSelect/index.tsx
|
|
15
|
-
function
|
|
16
|
-
let { name:
|
|
15
|
+
function d(d) {
|
|
16
|
+
let { name: f, options: p, className: m = "", placeholder: h = "Selecione...", closeOnSelect: g = !1, defaultValue: _ = [], errorMessage: v, isLoading: y = !1, readOnly: b = !1, isSearchable: ae = !1, id: oe, label: se, showAsterisk: ce, leftIcon: x, onSearch: S, onChange: C, onBlur: le, notFoundText: ue = "Sem opções disponíveis", onFocus: de, disabled: fe = !1, prefix: w, size: T = "md", value: pe, variant: E = "solid", unShowFieldTemplate: D = !1, orientation: O = "vertical" } = d, { fieldErrors: k } = e(), A = s(null), j = s(null), M = o(), N = oe || M, P = `${N}-listbox`, F = v || k?.[f], I = !!F, L = fe || y || b, R = {
|
|
17
17
|
md: 20,
|
|
18
18
|
lg: 20
|
|
19
|
-
}[
|
|
20
|
-
function
|
|
21
|
-
return
|
|
19
|
+
}[T], [z, B] = c(""), [V, H] = c(!1), [U, W] = c(_), [G, K] = c(-1), q = pe || U;
|
|
20
|
+
function J(e) {
|
|
21
|
+
return q.includes(e);
|
|
22
22
|
}
|
|
23
|
-
function
|
|
24
|
-
return
|
|
23
|
+
function me(e) {
|
|
24
|
+
return p.find((t) => t.value === e)?.label || "";
|
|
25
25
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
26
|
+
function Y(e) {
|
|
27
|
+
return `${P}-option-${e.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
|
|
28
|
+
}
|
|
29
|
+
function X() {
|
|
30
|
+
L || !A?.current || V || (H(!0), K(-1), A.current.focus(), de?.());
|
|
28
31
|
}
|
|
29
32
|
function Z() {
|
|
30
|
-
|
|
33
|
+
H(!1), K(-1), le && A.current && A.current.blur();
|
|
31
34
|
}
|
|
32
|
-
function
|
|
33
|
-
|
|
35
|
+
function he(e) {
|
|
36
|
+
B(e), K(-1), S && S(e);
|
|
34
37
|
}
|
|
35
38
|
function Q(e) {
|
|
36
|
-
|
|
39
|
+
J(e) ? (W(U.filter((t) => t !== e)), C && C(U.filter((t) => t !== e))) : (W([...U, e]), C && C([...U, e])), g && Z();
|
|
40
|
+
}
|
|
41
|
+
let $ = p.filter((e) => !!(d.onSearch || !d.isSearchable || e.label.toLowerCase().includes(z.toLowerCase())));
|
|
42
|
+
function ge(e) {
|
|
43
|
+
if (L) return;
|
|
44
|
+
if (!V) {
|
|
45
|
+
(e.key === "Enter" || e.key === " " || e.key === "ArrowDown") && (e.preventDefault(), X(), e.key === "ArrowDown" && K(0));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
let t = e.target?.tagName === "INPUT", n = e.target?.tagName === "BUTTON";
|
|
49
|
+
switch (e.key) {
|
|
50
|
+
case "Escape":
|
|
51
|
+
e.preventDefault(), Z(), j.current?.focus();
|
|
52
|
+
break;
|
|
53
|
+
case "ArrowDown":
|
|
54
|
+
e.preventDefault(), K((e) => $.length === 0 ? -1 : e < 0 || e + 1 >= $.length ? 0 : e + 1);
|
|
55
|
+
break;
|
|
56
|
+
case "ArrowUp":
|
|
57
|
+
e.preventDefault(), K((e) => $.length === 0 ? -1 : e < 0 || e - 1 < 0 ? $.length - 1 : e - 1);
|
|
58
|
+
break;
|
|
59
|
+
case " ":
|
|
60
|
+
if (t || n) return;
|
|
61
|
+
e.preventDefault(), G >= 0 && G < $.length && Q($[G].value);
|
|
62
|
+
break;
|
|
63
|
+
case "Enter":
|
|
64
|
+
if (n) return;
|
|
65
|
+
e.preventDefault(), G >= 0 && G < $.length && Q($[G].value);
|
|
66
|
+
break;
|
|
67
|
+
default: break;
|
|
68
|
+
}
|
|
37
69
|
}
|
|
38
|
-
let
|
|
39
|
-
return /* @__PURE__ */
|
|
40
|
-
name:
|
|
41
|
-
label:
|
|
42
|
-
showAsterisk:
|
|
43
|
-
className:
|
|
44
|
-
errorMessage:
|
|
45
|
-
unShowFieldTemplate:
|
|
46
|
-
orientation:
|
|
47
|
-
children: /* @__PURE__ */
|
|
48
|
-
handleContainerFocus:
|
|
49
|
-
disabled:
|
|
50
|
-
isError:
|
|
51
|
-
isFocused:
|
|
52
|
-
isLoading:
|
|
53
|
-
readOnly:
|
|
54
|
-
size:
|
|
55
|
-
variant:
|
|
56
|
-
prefixExists: !!
|
|
57
|
-
id:
|
|
70
|
+
let _e = G >= 0 && G < $.length ? Y($[G].value) : void 0;
|
|
71
|
+
return /* @__PURE__ */ l(n, {
|
|
72
|
+
name: f,
|
|
73
|
+
label: se,
|
|
74
|
+
showAsterisk: ce,
|
|
75
|
+
className: m,
|
|
76
|
+
errorMessage: F,
|
|
77
|
+
unShowFieldTemplate: D,
|
|
78
|
+
orientation: O,
|
|
79
|
+
children: /* @__PURE__ */ u(te, {
|
|
80
|
+
handleContainerFocus: X,
|
|
81
|
+
disabled: L,
|
|
82
|
+
isError: I,
|
|
83
|
+
isFocused: V,
|
|
84
|
+
isLoading: y,
|
|
85
|
+
readOnly: b,
|
|
86
|
+
size: T,
|
|
87
|
+
variant: E,
|
|
88
|
+
prefixExists: !!w,
|
|
89
|
+
id: N,
|
|
90
|
+
containerRef: j,
|
|
91
|
+
onContainerKeyDown: ge,
|
|
92
|
+
tabIndex: L ? -1 : 0,
|
|
93
|
+
ariaControls: P,
|
|
94
|
+
ariaActiveDescendant: _e,
|
|
58
95
|
children: [
|
|
59
|
-
/* @__PURE__ */
|
|
60
|
-
ref:
|
|
61
|
-
name:
|
|
62
|
-
value: JSON.stringify(
|
|
96
|
+
/* @__PURE__ */ l("input", {
|
|
97
|
+
ref: A,
|
|
98
|
+
name: f,
|
|
99
|
+
value: JSON.stringify(q),
|
|
63
100
|
type: "hidden"
|
|
64
101
|
}),
|
|
65
|
-
/* @__PURE__ */
|
|
66
|
-
iconSize:
|
|
67
|
-
icon:
|
|
102
|
+
/* @__PURE__ */ l(t, {
|
|
103
|
+
iconSize: R,
|
|
104
|
+
icon: w,
|
|
68
105
|
className: "prefix"
|
|
69
106
|
}),
|
|
70
|
-
|
|
71
|
-
size:
|
|
107
|
+
x && /* @__PURE__ */ l(x, {
|
|
108
|
+
size: R,
|
|
72
109
|
strokeWidth: 2.5
|
|
73
110
|
}),
|
|
74
|
-
/* @__PURE__ */
|
|
75
|
-
size:
|
|
76
|
-
children: [
|
|
77
|
-
label:
|
|
111
|
+
/* @__PURE__ */ u(ne, {
|
|
112
|
+
size: T,
|
|
113
|
+
children: [q.map((e) => /* @__PURE__ */ l(re, {
|
|
114
|
+
label: me(e),
|
|
78
115
|
value: e,
|
|
79
116
|
handleChangeValue: Q,
|
|
80
|
-
disabled:
|
|
81
|
-
}, e)),
|
|
117
|
+
disabled: L
|
|
118
|
+
}, e)), q.length <= 0 && /* @__PURE__ */ l("p", { children: h })]
|
|
82
119
|
}),
|
|
83
|
-
/* @__PURE__ */
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
120
|
+
/* @__PURE__ */ u(r, {
|
|
121
|
+
id: P,
|
|
122
|
+
isFocused: V,
|
|
123
|
+
isSearchable: ae,
|
|
124
|
+
search: z,
|
|
125
|
+
onSearch: he,
|
|
126
|
+
children: [$.map(({ label: e, value: t }, n) => /* @__PURE__ */ l(ie, {
|
|
127
|
+
id: Y(t),
|
|
89
128
|
label: e,
|
|
90
129
|
value: t,
|
|
91
|
-
size:
|
|
130
|
+
size: T,
|
|
131
|
+
isHighlighted: n === G,
|
|
92
132
|
handleChangeValue: Q,
|
|
93
|
-
optionHasSelected:
|
|
94
|
-
}, t)), $.length <= 0 && /* @__PURE__ */
|
|
133
|
+
optionHasSelected: J
|
|
134
|
+
}, t)), $.length <= 0 && /* @__PURE__ */ l("p", { children: ue })]
|
|
95
135
|
}),
|
|
96
|
-
/* @__PURE__ */
|
|
97
|
-
disabled:
|
|
98
|
-
isFocused:
|
|
99
|
-
readOnly:
|
|
100
|
-
iconSize:
|
|
101
|
-
isLoading:
|
|
136
|
+
/* @__PURE__ */ l(ee, {
|
|
137
|
+
disabled: L,
|
|
138
|
+
isFocused: V,
|
|
139
|
+
readOnly: b,
|
|
140
|
+
iconSize: R,
|
|
141
|
+
isLoading: y
|
|
102
142
|
}),
|
|
103
|
-
/* @__PURE__ */
|
|
104
|
-
iconSize:
|
|
105
|
-
isLoading:
|
|
143
|
+
/* @__PURE__ */ l(a, {
|
|
144
|
+
iconSize: R,
|
|
145
|
+
isLoading: y
|
|
106
146
|
}),
|
|
107
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ l(i, {
|
|
108
148
|
handleBlur: Z,
|
|
109
|
-
isFocused:
|
|
149
|
+
isFocused: V
|
|
110
150
|
})
|
|
111
151
|
]
|
|
112
152
|
})
|
|
113
153
|
});
|
|
114
154
|
}
|
|
115
155
|
//#endregion
|
|
116
|
-
export {
|
|
156
|
+
export { d as MultiSelect };
|
|
117
157
|
|
|
118
158
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/multiSelect/index.tsx"],"sourcesContent":["import type { LucideIcon } from \"lucide-react\";\nimport { type FocusEvent, useId, useRef, useState } from \"react\";\n\nimport { useForm } from \"../../hooks/useForm\";\nimport { FieldTemplate } from \"../../services/fieldTemplate\";\nimport { IconRenderer } from \"../../services/iconRenderer\";\n\nimport { MultiSelectChevron } from \"./multiSelectChevron\";\nimport { MultiSelectContainer } from \"./multiSelectContainer\";\nimport { MultiSelectContent } from \"./multiSelectContent\";\nimport { MultiSelectMark } from \"./multiSelectMark\";\nimport { MultiSelectOption } from \"./multiSelectOption\";\nimport { MultiSelectOptionsContainer } from \"./multiSelectOptionsContainer\";\nimport { MultiSelectOverlay } from \"./multiSelectOverlay\";\nimport { MultiSelectSpinner } from \"./multiSelectSpinner\";\n\ntype MultiSelectProps = {\n\t/** Field name for form submission. Required. */\n\tname: string;\n\t/** Array of selectable options. Required. */\n\toptions: { label: string; value: string }[];\n\t/** Optional HTML id for the underlying hidden input. */\n\tid?: string;\n\t/** Controlled array of selected values. */\n\tvalue?: string[];\n\t/** Uncontrolled default array of selected values. @default [] */\n\tdefaultValue?: string[];\n\t/** Displays an asterisk on the label to signal a required field. */\n\tshowAsterisk?: boolean;\n\t/** Optional label text displayed above the multiselect. */\n\tlabel?: string;\n\t/** Validation error message displayed below the multiselect. */\n\terrorMessage?: string;\n\t/** Placeholder text shown when no options are selected. @default \"Selecione...\" */\n\tplaceholder?: string;\n\t/** Text shown when no options match the search query. @default \"Sem opções disponíveis\" */\n\tnotFoundText?: string;\n\t/** Additional CSS class applied to the wrapper element. */\n\tclassName?: string;\n\t/** Disables all interactions. @default false */\n\tdisabled?: boolean;\n\t/** Prevents value changes while keeping the current selection visible. @default false */\n\treadOnly?: boolean;\n\t/** Shows a loading spinner and disables interactions. @default false */\n\tisLoading?: boolean;\n\t/** Enables search/filter within the dropdown. @default false */\n\tisSearchable?: boolean;\n\t/** Closes the dropdown after an option is selected or deselected. @default false */\n\tcloseOnSelect?: boolean;\n\t/** Callback fired when the search query changes. Use for async option loading. */\n\tonSearch?: (value: string) => void;\n\t/** Callback fired when the selected values array changes. */\n\tonChange?: (value: string[]) => void;\n\t/** Callback fired when the multiselect gains focus. */\n\tonFocus?: () => void;\n\t/** Callback fired when the multiselect loses focus. */\n\tonBlur?: (e: FocusEvent<HTMLDivElement>) => void;\n\t/**\n\t * MultiSelect size.\n\t * @default \"md\"\n\t */\n\tsize?: \"md\" | \"lg\";\n\t/**\n\t * Visual style variant.\n\t * - `solid`: filled background.\n\t * - `outline`: bordered, transparent background.\n\t * - `underline`: bottom border only.\n\t * @default \"solid\"\n\t */\n\tvariant?: \"solid\" | \"outline\" | \"underline\";\n\t/** Text or icon rendered at the far left, outside the select area. */\n\tprefix?: string | LucideIcon;\n\t/** Lucide icon rendered inside the select on the left. */\n\tleftIcon?: LucideIcon;\n\t/** Maximum height (in px) of the options dropdown. */\n\toptionMaxHeight?: number;\n\t/** When true, skips `FieldTemplate` wrapper (label and error text). @default false */\n\tunShowFieldTemplate?: boolean;\n\t/**\n\t * Layout direction forwarded to `FieldTemplate`.\n\t * @default \"horizontal\"\n\t */\n\torientation?: \"horizontal\" | \"vertical\" | \"horizontalReverse\";\n};\n\n/**\n * MultiSelect, multi-option dropdown with optional search, label, validation, and form integration.\n *\n * Selected values are stored as a JSON array in a hidden `<input>` for form submission.\n * Integrates with `useForm` to display validation errors by field name.\n *\n * @param props.name - Field name for form submission. Required.\n * @param props.options - Array of selectable options (`{ label, value }`). Required.\n * @param props.value - Controlled array of selected values.\n * @param props.defaultValue - Uncontrolled default selection. Default: []\n * @param props.label - Label text displayed above the multiselect.\n * @param props.placeholder - Placeholder shown when nothing is selected. Default: \"Selecione...\"\n * @param props.errorMessage - Validation error message.\n * @param props.isSearchable - Enables search/filter within the dropdown. Default: false\n * @param props.isLoading - Shows a loading spinner and disables interactions. Default: false\n * @param props.closeOnSelect - Closes the dropdown after toggling an option. Default: false\n * @param props.onChange - Callback fired when the selection changes.\n * @param props.onSearch - Callback fired when the search query changes.\n * @param props.size - MultiSelect size (`md` | `lg`). Default: \"md\"\n * @param props.variant - Visual style variant. Default: \"solid\"\n * @param props.orientation - Layout direction. Default: \"horizontal\"\n * @param props.unShowFieldTemplate - Skips wrapper, label, and error rendering. Default: false\n *\n * @returns MultiSelect JSX element wrapped in `FieldTemplate`.\n *\n * @example\n * ```tsx\n * // Basic\n * <MultiSelect\n * name=\"categories\"\n * options={[\n * { label: \"Technology\", value: \"tech\" },\n * { label: \"Design\", value: \"design\" },\n * ]}\n * />\n *\n * // With label, validation, and searchable\n * <MultiSelect\n * name=\"skills\"\n * label=\"Skills\"\n * showAsterisk\n * isSearchable\n * options={skillOptions}\n * errorMessage={errors.skills}\n * />\n *\n * // Controlled with async search\n * <MultiSelect\n * name=\"tags\"\n * label=\"Tags\"\n * value={selectedTags}\n * onChange={setSelectedTags}\n * onSearch={fetchTagOptions}\n * isLoading={isLoadingTags}\n * options={tagOptions}\n * />\n * ```\n */\n\nfunction MultiSelect(props: MultiSelectProps) {\n\tconst {\n\t\tname,\n\t\toptions,\n\t\tclassName: wrapperClassName = \"\",\n\t\tplaceholder = \"Selecione...\",\n\t\tcloseOnSelect = false,\n\t\tdefaultValue = [],\n\t\terrorMessage: baseErrorMessage,\n\t\tisLoading = false,\n\t\treadOnly = false,\n\t\tisSearchable = false,\n\t\tid,\n\t\tlabel,\n\t\tshowAsterisk,\n\t\tleftIcon: LeftIcon,\n\t\tonSearch,\n\t\tonChange,\n\t\tonBlur,\n\t\tnotFoundText = \"Sem opções disponíveis\",\n\t\tonFocus,\n\t\tdisabled: baseDisabled = false,\n\t\tprefix,\n\t\tsize = \"md\",\n\t\tvalue,\n\t\tvariant = \"solid\",\n\t\tunShowFieldTemplate = false,\n\t\torientation = \"vertical\",\n\t} = props;\n\n\tconst { fieldErrors } = useForm();\n\n\tconst multiSelectRef = useRef<HTMLInputElement>(null);\n\tconst generatedId = useId();\n\tconst multiSelectId = id || generatedId;\n\n\tconst errorMessage = baseErrorMessage || fieldErrors?.[name];\n\tconst isError = !!errorMessage;\n\tconst disabled = baseDisabled || isLoading || readOnly;\n\n\tconst iconSizes = { md: 20, lg: 20 };\n\tconst iconSize = iconSizes[size];\n\n\tconst [search, setSearch] = useState(\"\");\n\tconst [isFocused, setIsFocused] = useState(false);\n\tconst [selectedOptions, setSelectedOptions] = useState(defaultValue);\n\n\tconst forceSelectedOptions = value || selectedOptions;\n\n\tfunction optionHasSelected(value: string) {\n\t\treturn forceSelectedOptions.includes(value);\n\t}\n\n\tfunction getOptionLabel(value: string) {\n\t\tconst option = options.find((option) => option.value === value);\n\t\treturn option?.label || \"\";\n\t}\n\n\tfunction handleContainerFocus() {\n\t\tif (disabled || !multiSelectRef?.current || isFocused) return;\n\t\tsetIsFocused(true);\n\t\tmultiSelectRef.current.focus();\n\t\tonFocus?.();\n\t}\n\n\tfunction handleBlur() {\n\t\tsetIsFocused(false);\n\t\tif (onBlur && multiSelectRef.current) multiSelectRef.current.blur();\n\t}\n\n\tfunction handleSearch(value: string) {\n\t\tsetSearch(value);\n\t\tif (onSearch) onSearch(value);\n\t}\n\n\tfunction handleChangeValue(value: string) {\n\t\tif (optionHasSelected(value)) {\n\t\t\tsetSelectedOptions(selectedOptions.filter((v) => v !== value));\n\t\t\tif (onChange) onChange(selectedOptions.filter((v) => v !== value));\n\t\t} else {\n\t\t\tsetSelectedOptions([...selectedOptions, value]);\n\t\t\tif (onChange) onChange([...selectedOptions, value]);\n\t\t}\n\n\t\tif (closeOnSelect) handleBlur();\n\t}\n\n\tconst mappedOptions = options.filter((option) => {\n\t\tif (props.onSearch) return true;\n\t\tif (!props.isSearchable) return true;\n\t\tif (option.label.toLowerCase().includes(search.toLowerCase())) return true;\n\t\treturn false;\n\t});\n\n\treturn (\n\t\t<FieldTemplate\n\t\t\tname={name}\n\t\t\tlabel={label}\n\t\t\tshowAsterisk={showAsterisk}\n\t\t\tclassName={wrapperClassName}\n\t\t\terrorMessage={errorMessage}\n\t\t\tunShowFieldTemplate={unShowFieldTemplate}\n\t\t\torientation={orientation}\n\t\t>\n\t\t\t<MultiSelectContainer\n\t\t\t\thandleContainerFocus={handleContainerFocus}\n\t\t\t\tdisabled={disabled}\n\t\t\t\tisError={isError}\n\t\t\t\tisFocused={isFocused}\n\t\t\t\tisLoading={isLoading}\n\t\t\t\treadOnly={readOnly}\n\t\t\t\tsize={size}\n\t\t\t\tvariant={variant}\n\t\t\t\tprefixExists={!!prefix}\n\t\t\t\tid={multiSelectId}\n\t\t\t>\n\t\t\t\t<input\n\t\t\t\t\tref={multiSelectRef}\n\t\t\t\t\tname={name}\n\t\t\t\t\tvalue={JSON.stringify(forceSelectedOptions)}\n\t\t\t\t\ttype=\"hidden\"\n\t\t\t\t/>\n\n\t\t\t\t<IconRenderer iconSize={iconSize} icon={prefix} className=\"prefix\" />\n\n\t\t\t\t{LeftIcon && <LeftIcon size={iconSize} strokeWidth={2.5} />}\n\n\t\t\t\t<MultiSelectContent size={size}>\n\t\t\t\t\t{forceSelectedOptions.map((value) => (\n\t\t\t\t\t\t<MultiSelectMark\n\t\t\t\t\t\t\tkey={value}\n\t\t\t\t\t\t\tlabel={getOptionLabel(value)}\n\t\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\t\thandleChangeValue={handleChangeValue}\n\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\n\t\t\t\t\t{forceSelectedOptions.length <= 0 && <p>{placeholder}</p>}\n\t\t\t\t</MultiSelectContent>\n\n\t\t\t\t<MultiSelectOptionsContainer\n\t\t\t\t\tisFocused={isFocused}\n\t\t\t\t\tisSearchable={isSearchable}\n\t\t\t\t\tsearch={search}\n\t\t\t\t\tonSearch={handleSearch}\n\t\t\t\t>\n\t\t\t\t\t{mappedOptions.map(({ label, value }) => (\n\t\t\t\t\t\t<MultiSelectOption\n\t\t\t\t\t\t\tkey={value}\n\t\t\t\t\t\t\tlabel={label}\n\t\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\t\tsize={size}\n\t\t\t\t\t\t\thandleChangeValue={handleChangeValue}\n\t\t\t\t\t\t\toptionHasSelected={optionHasSelected}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\n\t\t\t\t\t{mappedOptions.length <= 0 && <p>{notFoundText}</p>}\n\t\t\t\t</MultiSelectOptionsContainer>\n\n\t\t\t\t<MultiSelectChevron\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tisFocused={isFocused}\n\t\t\t\t\treadOnly={readOnly}\n\t\t\t\t\ticonSize={iconSize}\n\t\t\t\t\tisLoading={isLoading}\n\t\t\t\t/>\n\n\t\t\t\t<MultiSelectSpinner iconSize={iconSize} isLoading={isLoading} />\n\t\t\t\t<MultiSelectOverlay handleBlur={handleBlur} isFocused={isFocused} />\n\t\t\t</MultiSelectContainer>\n\t\t</FieldTemplate>\n\t);\n}\n\nexport { MultiSelect };\n"],"mappings":";;;;;;;;;;;;;;AAgJA,SAAS,EAAY,GAAyB;CAC7C,IAAM,EACL,SACA,YACA,WAAW,IAAmB,IAC9B,iBAAc,gBACd,mBAAgB,IAChB,kBAAe,CAAC,GAChB,cAAc,IACd,eAAY,IACZ,cAAW,IACX,mBAAe,IACf,QACA,WACA,kBACA,UAAU,GACV,aACA,aACA,WACA,kBAAe,0BACf,YACA,UAAU,IAAe,IACzB,WACA,UAAO,MACP,UACA,aAAU,SACV,yBAAsB,IACtB,iBAAc,eACX,GAEE,EAAE,mBAAgB,EAAQ,GAE1B,IAAiB,EAAyB,IAAI,GAC9C,IAAc,EAAM,GACpB,KAAgB,MAAM,GAEtB,IAAe,MAAoB,IAAc,IACjD,IAAU,CAAC,CAAC,GACZ,IAAW,KAAgB,KAAa,GAGxC,IAAW;EADG,IAAI;EAAI,IAAI;CACf,EAAU,IAErB,CAAC,GAAQ,KAAa,EAAS,EAAE,GACjC,CAAC,GAAW,KAAgB,EAAS,EAAK,GAC1C,CAAC,GAAiB,KAAsB,EAAS,CAAY,GAE7D,IAAuB,KAAS;CAEtC,SAAS,EAAkB,GAAe;EACzC,OAAO,EAAqB,SAAS,CAAK;CAC3C;CAEA,SAAS,GAAe,GAAe;EAEtC,OADe,EAAQ,MAAM,MAAW,EAAO,UAAU,CAClD,CAAA,EAAQ,SAAS;CACzB;CAEA,SAAS,KAAuB;EAC3B,KAAY,CAAC,GAAgB,WAAW,MAC5C,EAAa,EAAI,GACjB,EAAe,QAAQ,MAAM,GAC7B,IAAU;CACX;CAEA,SAAS,IAAa;EAErB,AADA,EAAa,EAAK,GACd,KAAU,EAAe,WAAS,EAAe,QAAQ,KAAK;CACnE;CAEA,SAAS,GAAa,GAAe;EAEpC,AADA,EAAU,CAAK,GACX,KAAU,EAAS,CAAK;CAC7B;CAEA,SAAS,EAAkB,GAAe;EASzC,AARI,EAAkB,CAAK,KAC1B,EAAmB,EAAgB,QAAQ,MAAM,MAAM,CAAK,CAAC,GACzD,KAAU,EAAS,EAAgB,QAAQ,MAAM,MAAM,CAAK,CAAC,MAEjE,EAAmB,CAAC,GAAG,GAAiB,CAAK,CAAC,GAC1C,KAAU,EAAS,CAAC,GAAG,GAAiB,CAAK,CAAC,IAG/C,KAAe,EAAW;CAC/B;CAEA,IAAM,IAAgB,EAAQ,QAAQ,MAGrC,GAFI,EAAM,YACN,CAAC,EAAM,gBACP,EAAO,MAAM,YAAY,CAAC,CAAC,SAAS,EAAO,YAAY,CAAC,EAE5D;CAED,OACC,kBAAC,GAAD;EACO;EACC;EACO;EACd,WAAW;EACG;EACO;EACR;YAEb,kBAAC,GAAD;GACuB;GACZ;GACD;GACE;GACA;GACD;GACJ;GACG;GACT,cAAc,CAAC,CAAC;GAChB,IAAI;aAVL;IAYC,kBAAC,SAAD;KACC,KAAK;KACC;KACN,OAAO,KAAK,UAAU,CAAoB;KAC1C,MAAK;IACL,CAAA;IAED,kBAAC,GAAD;KAAwB;KAAU,MAAM;KAAQ,WAAU;IAAU,CAAA;IAEnE,KAAY,kBAAC,GAAD;KAAU,MAAM;KAAU,aAAa;IAAM,CAAA;IAE1D,kBAAC,GAAD;KAA0B;eAA1B,CACE,EAAqB,KAAK,MAC1B,kBAAC,GAAD;MAEC,OAAO,GAAe,CAAK;MACpB;MACY;MACT;KACV,GALK,CAKL,CACD,GAEA,EAAqB,UAAU,KAAK,kBAAC,KAAD,EAAA,UAAI,EAAe,CAAA,CACrC;;IAEpB,kBAAC,IAAD;KACY;KACG;KACN;KACR,UAAU;eAJX,CAME,EAAc,KAAK,EAAE,UAAO,eAC5B,kBAAC,GAAD;MAEQ;MACA;MACD;MACa;MACA;KACnB,GANK,CAML,CACD,GAEA,EAAc,UAAU,KAAK,kBAAC,KAAD,EAAA,UAAI,EAAgB,CAAA,CACtB;;IAE7B,kBAAC,GAAD;KACW;KACC;KACD;KACA;KACC;IACX,CAAA;IAED,kBAAC,GAAD;KAA8B;KAAqB;IAAY,CAAA;IAC/D,kBAAC,IAAD;KAAgC;KAAuB;IAAY,CAAA;GAC9C;;CACR,CAAA;AAEjB"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/multiSelect/index.tsx"],"sourcesContent":["import type { LucideIcon } from \"lucide-react\";\nimport {\n\ttype FocusEvent,\n\ttype KeyboardEvent,\n\tuseId,\n\tuseRef,\n\tuseState,\n} from \"react\";\n\nimport { useForm } from \"../../hooks/useForm\";\nimport { FieldTemplate } from \"../../services/fieldTemplate\";\nimport { IconRenderer } from \"../../services/iconRenderer\";\n\nimport { MultiSelectChevron } from \"./multiSelectChevron\";\nimport { MultiSelectContainer } from \"./multiSelectContainer\";\nimport { MultiSelectContent } from \"./multiSelectContent\";\nimport { MultiSelectMark } from \"./multiSelectMark\";\nimport { MultiSelectOption } from \"./multiSelectOption\";\nimport { MultiSelectOptionsContainer } from \"./multiSelectOptionsContainer\";\nimport { MultiSelectOverlay } from \"./multiSelectOverlay\";\nimport { MultiSelectSpinner } from \"./multiSelectSpinner\";\n\ntype MultiSelectProps = {\n\t/** Field name for form submission. Required. */\n\tname: string;\n\t/** Array of selectable options. Required. */\n\toptions: { label: string; value: string }[];\n\t/** Optional HTML id for the underlying hidden input. */\n\tid?: string;\n\t/** Controlled array of selected values. */\n\tvalue?: string[];\n\t/** Uncontrolled default array of selected values. @default [] */\n\tdefaultValue?: string[];\n\t/** Displays an asterisk on the label to signal a required field. */\n\tshowAsterisk?: boolean;\n\t/** Optional label text displayed above the multiselect. */\n\tlabel?: string;\n\t/** Validation error message displayed below the multiselect. */\n\terrorMessage?: string;\n\t/** Placeholder text shown when no options are selected. @default \"Selecione...\" */\n\tplaceholder?: string;\n\t/** Text shown when no options match the search query. @default \"Sem opções disponíveis\" */\n\tnotFoundText?: string;\n\t/** Additional CSS class applied to the wrapper element. */\n\tclassName?: string;\n\t/** Disables all interactions. @default false */\n\tdisabled?: boolean;\n\t/** Prevents value changes while keeping the current selection visible. @default false */\n\treadOnly?: boolean;\n\t/** Shows a loading spinner and disables interactions. @default false */\n\tisLoading?: boolean;\n\t/** Enables search/filter within the dropdown. @default false */\n\tisSearchable?: boolean;\n\t/** Closes the dropdown after an option is selected or deselected. @default false */\n\tcloseOnSelect?: boolean;\n\t/** Callback fired when the search query changes. Use for async option loading. */\n\tonSearch?: (value: string) => void;\n\t/** Callback fired when the selected values array changes. */\n\tonChange?: (value: string[]) => void;\n\t/** Callback fired when the multiselect gains focus. */\n\tonFocus?: () => void;\n\t/** Callback fired when the multiselect loses focus. */\n\tonBlur?: (e: FocusEvent<HTMLDivElement>) => void;\n\t/**\n\t * MultiSelect size.\n\t * @default \"md\"\n\t */\n\tsize?: \"md\" | \"lg\";\n\t/**\n\t * Visual style variant.\n\t * - `solid`: filled background.\n\t * - `outline`: bordered, transparent background.\n\t * - `underline`: bottom border only.\n\t * @default \"solid\"\n\t */\n\tvariant?: \"solid\" | \"outline\" | \"underline\";\n\t/** Text or icon rendered at the far left, outside the select area. */\n\tprefix?: string | LucideIcon;\n\t/** Lucide icon rendered inside the select on the left. */\n\tleftIcon?: LucideIcon;\n\t/** Maximum height (in px) of the options dropdown. */\n\toptionMaxHeight?: number;\n\t/** When true, skips `FieldTemplate` wrapper (label and error text). @default false */\n\tunShowFieldTemplate?: boolean;\n\t/**\n\t * Layout direction forwarded to `FieldTemplate`.\n\t * @default \"horizontal\"\n\t */\n\torientation?: \"horizontal\" | \"vertical\" | \"horizontalReverse\";\n};\n\n/**\n * MultiSelect, multi-option dropdown with optional search, label, validation, and form integration.\n *\n * Selected values are stored as a JSON array in a hidden `<input>` for form submission.\n * Integrates with `useForm` to display validation errors by field name.\n *\n * @param props.name - Field name for form submission. Required.\n * @param props.options - Array of selectable options (`{ label, value }`). Required.\n * @param props.value - Controlled array of selected values.\n * @param props.defaultValue - Uncontrolled default selection. Default: []\n * @param props.label - Label text displayed above the multiselect.\n * @param props.placeholder - Placeholder shown when nothing is selected. Default: \"Selecione...\"\n * @param props.errorMessage - Validation error message.\n * @param props.isSearchable - Enables search/filter within the dropdown. Default: false\n * @param props.isLoading - Shows a loading spinner and disables interactions. Default: false\n * @param props.closeOnSelect - Closes the dropdown after toggling an option. Default: false\n * @param props.onChange - Callback fired when the selection changes.\n * @param props.onSearch - Callback fired when the search query changes.\n * @param props.size - MultiSelect size (`md` | `lg`). Default: \"md\"\n * @param props.variant - Visual style variant. Default: \"solid\"\n * @param props.orientation - Layout direction. Default: \"vertical\"\n * @param props.unShowFieldTemplate - Skips wrapper, label, and error rendering. Default: false\n *\n * @returns MultiSelect JSX element wrapped in `FieldTemplate`.\n *\n * @example\n * ```tsx\n * // Basic\n * <MultiSelect\n * name=\"categories\"\n * options={[\n * { label: \"Technology\", value: \"tech\" },\n * { label: \"Design\", value: \"design\" },\n * ]}\n * />\n *\n * // With label, validation, and searchable\n * <MultiSelect\n * name=\"skills\"\n * label=\"Skills\"\n * showAsterisk\n * isSearchable\n * options={skillOptions}\n * errorMessage={errors.skills}\n * />\n *\n * // Controlled with async search\n * <MultiSelect\n * name=\"tags\"\n * label=\"Tags\"\n * value={selectedTags}\n * onChange={setSelectedTags}\n * onSearch={fetchTagOptions}\n * isLoading={isLoadingTags}\n * options={tagOptions}\n * />\n * ```\n */\n\nfunction MultiSelect(props: MultiSelectProps) {\n\tconst {\n\t\tname,\n\t\toptions,\n\t\tclassName: wrapperClassName = \"\",\n\t\tplaceholder = \"Selecione...\",\n\t\tcloseOnSelect = false,\n\t\tdefaultValue = [],\n\t\terrorMessage: baseErrorMessage,\n\t\tisLoading = false,\n\t\treadOnly = false,\n\t\tisSearchable = false,\n\t\tid,\n\t\tlabel,\n\t\tshowAsterisk,\n\t\tleftIcon: LeftIcon,\n\t\tonSearch,\n\t\tonChange,\n\t\tonBlur,\n\t\tnotFoundText = \"Sem opções disponíveis\",\n\t\tonFocus,\n\t\tdisabled: baseDisabled = false,\n\t\tprefix,\n\t\tsize = \"md\",\n\t\tvalue,\n\t\tvariant = \"solid\",\n\t\tunShowFieldTemplate = false,\n\t\torientation = \"vertical\",\n\t} = props;\n\n\tconst { fieldErrors } = useForm();\n\n\tconst multiSelectRef = useRef<HTMLInputElement>(null);\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\tconst generatedId = useId();\n\tconst multiSelectId = id || generatedId;\n\tconst listboxId = `${multiSelectId}-listbox`;\n\n\tconst errorMessage = baseErrorMessage || fieldErrors?.[name];\n\tconst isError = !!errorMessage;\n\tconst disabled = baseDisabled || isLoading || readOnly;\n\n\tconst iconSizes = { md: 20, lg: 20 };\n\tconst iconSize = iconSizes[size];\n\n\tconst [search, setSearch] = useState(\"\");\n\tconst [isFocused, setIsFocused] = useState(false);\n\tconst [selectedOptions, setSelectedOptions] = useState(defaultValue);\n\tconst [highlightedIndex, setHighlightedIndex] = useState(-1);\n\n\tconst forceSelectedOptions = value || selectedOptions;\n\n\tfunction optionHasSelected(value: string) {\n\t\treturn forceSelectedOptions.includes(value);\n\t}\n\n\tfunction getOptionLabel(value: string) {\n\t\tconst option = options.find((option) => option.value === value);\n\t\treturn option?.label || \"\";\n\t}\n\n\tfunction getOptionId(value: string) {\n\t\treturn `${listboxId}-option-${value.replace(/[^a-zA-Z0-9_-]/g, \"-\")}`;\n\t}\n\n\tfunction handleContainerFocus() {\n\t\tif (disabled || !multiSelectRef?.current || isFocused) return;\n\t\tsetIsFocused(true);\n\t\tsetHighlightedIndex(-1);\n\t\tmultiSelectRef.current.focus();\n\t\tonFocus?.();\n\t}\n\n\tfunction handleBlur() {\n\t\tsetIsFocused(false);\n\t\tsetHighlightedIndex(-1);\n\t\tif (onBlur && multiSelectRef.current) multiSelectRef.current.blur();\n\t}\n\n\tfunction handleSearch(value: string) {\n\t\tsetSearch(value);\n\t\t// The visible option list is about to change, so drop the current\n\t\t// highlight instead of letting it point at a filtered-out option.\n\t\tsetHighlightedIndex(-1);\n\t\tif (onSearch) onSearch(value);\n\t}\n\n\tfunction handleChangeValue(value: string) {\n\t\tif (optionHasSelected(value)) {\n\t\t\tsetSelectedOptions(selectedOptions.filter((v) => v !== value));\n\t\t\tif (onChange) onChange(selectedOptions.filter((v) => v !== value));\n\t\t} else {\n\t\t\tsetSelectedOptions([...selectedOptions, value]);\n\t\t\tif (onChange) onChange([...selectedOptions, value]);\n\t\t}\n\n\t\tif (closeOnSelect) handleBlur();\n\t}\n\n\tconst mappedOptions = options.filter((option) => {\n\t\tif (props.onSearch) return true;\n\t\tif (!props.isSearchable) return true;\n\t\tif (option.label.toLowerCase().includes(search.toLowerCase())) return true;\n\t\treturn false;\n\t});\n\n\tfunction handleContainerKeyDown(e: KeyboardEvent<HTMLDivElement>) {\n\t\tif (disabled) return;\n\n\t\tif (!isFocused) {\n\t\t\tif (e.key === \"Enter\" || e.key === \" \" || e.key === \"ArrowDown\") {\n\t\t\t\te.preventDefault();\n\t\t\t\thandleContainerFocus();\n\t\t\t\tif (e.key === \"ArrowDown\") setHighlightedIndex(0);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst isTypingTarget = (e.target as HTMLElement)?.tagName === \"INPUT\";\n\t\t// When focus has moved onto an option/button directly (e.g. via Tab),\n\t\t// let that element handle its own native Enter/Space activation instead\n\t\t// of double-handling it here through the highlighted-index shortcut.\n\t\tconst isButtonTarget = (e.target as HTMLElement)?.tagName === \"BUTTON\";\n\n\t\tswitch (e.key) {\n\t\t\tcase \"Escape\":\n\t\t\t\te.preventDefault();\n\t\t\t\thandleBlur();\n\t\t\t\tcontainerRef.current?.focus();\n\t\t\t\tbreak;\n\t\t\tcase \"ArrowDown\":\n\t\t\t\te.preventDefault();\n\t\t\t\tsetHighlightedIndex((prev) => {\n\t\t\t\t\tif (mappedOptions.length === 0) return -1;\n\t\t\t\t\tif (prev < 0) return 0;\n\t\t\t\t\treturn prev + 1 >= mappedOptions.length ? 0 : prev + 1;\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"ArrowUp\":\n\t\t\t\te.preventDefault();\n\t\t\t\tsetHighlightedIndex((prev) => {\n\t\t\t\t\tif (mappedOptions.length === 0) return -1;\n\t\t\t\t\tif (prev < 0) return mappedOptions.length - 1;\n\t\t\t\t\treturn prev - 1 < 0 ? mappedOptions.length - 1 : prev - 1;\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \" \":\n\t\t\t\tif (isTypingTarget || isButtonTarget) return;\n\t\t\t\te.preventDefault();\n\t\t\t\tif (highlightedIndex >= 0 && highlightedIndex < mappedOptions.length) {\n\t\t\t\t\thandleChangeValue(mappedOptions[highlightedIndex].value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"Enter\":\n\t\t\t\tif (isButtonTarget) return;\n\t\t\t\te.preventDefault();\n\t\t\t\tif (highlightedIndex >= 0 && highlightedIndex < mappedOptions.length) {\n\t\t\t\t\thandleChangeValue(mappedOptions[highlightedIndex].value);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst activeDescendantId =\n\t\thighlightedIndex >= 0 && highlightedIndex < mappedOptions.length\n\t\t\t? getOptionId(mappedOptions[highlightedIndex].value)\n\t\t\t: undefined;\n\n\treturn (\n\t\t<FieldTemplate\n\t\t\tname={name}\n\t\t\tlabel={label}\n\t\t\tshowAsterisk={showAsterisk}\n\t\t\tclassName={wrapperClassName}\n\t\t\terrorMessage={errorMessage}\n\t\t\tunShowFieldTemplate={unShowFieldTemplate}\n\t\t\torientation={orientation}\n\t\t>\n\t\t\t<MultiSelectContainer\n\t\t\t\thandleContainerFocus={handleContainerFocus}\n\t\t\t\tdisabled={disabled}\n\t\t\t\tisError={isError}\n\t\t\t\tisFocused={isFocused}\n\t\t\t\tisLoading={isLoading}\n\t\t\t\treadOnly={readOnly}\n\t\t\t\tsize={size}\n\t\t\t\tvariant={variant}\n\t\t\t\tprefixExists={!!prefix}\n\t\t\t\tid={multiSelectId}\n\t\t\t\tcontainerRef={containerRef}\n\t\t\t\tonContainerKeyDown={handleContainerKeyDown}\n\t\t\t\ttabIndex={disabled ? -1 : 0}\n\t\t\t\tariaControls={listboxId}\n\t\t\t\tariaActiveDescendant={activeDescendantId}\n\t\t\t>\n\t\t\t\t<input\n\t\t\t\t\tref={multiSelectRef}\n\t\t\t\t\tname={name}\n\t\t\t\t\tvalue={JSON.stringify(forceSelectedOptions)}\n\t\t\t\t\ttype=\"hidden\"\n\t\t\t\t/>\n\n\t\t\t\t<IconRenderer iconSize={iconSize} icon={prefix} className=\"prefix\" />\n\n\t\t\t\t{LeftIcon && <LeftIcon size={iconSize} strokeWidth={2.5} />}\n\n\t\t\t\t<MultiSelectContent size={size}>\n\t\t\t\t\t{forceSelectedOptions.map((value) => (\n\t\t\t\t\t\t<MultiSelectMark\n\t\t\t\t\t\t\tkey={value}\n\t\t\t\t\t\t\tlabel={getOptionLabel(value)}\n\t\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\t\thandleChangeValue={handleChangeValue}\n\t\t\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\n\t\t\t\t\t{forceSelectedOptions.length <= 0 && <p>{placeholder}</p>}\n\t\t\t\t</MultiSelectContent>\n\n\t\t\t\t<MultiSelectOptionsContainer\n\t\t\t\t\tid={listboxId}\n\t\t\t\t\tisFocused={isFocused}\n\t\t\t\t\tisSearchable={isSearchable}\n\t\t\t\t\tsearch={search}\n\t\t\t\t\tonSearch={handleSearch}\n\t\t\t\t>\n\t\t\t\t\t{mappedOptions.map(({ label, value }, index) => (\n\t\t\t\t\t\t<MultiSelectOption\n\t\t\t\t\t\t\tkey={value}\n\t\t\t\t\t\t\tid={getOptionId(value)}\n\t\t\t\t\t\t\tlabel={label}\n\t\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\t\tsize={size}\n\t\t\t\t\t\t\tisHighlighted={index === highlightedIndex}\n\t\t\t\t\t\t\thandleChangeValue={handleChangeValue}\n\t\t\t\t\t\t\toptionHasSelected={optionHasSelected}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\n\t\t\t\t\t{mappedOptions.length <= 0 && <p>{notFoundText}</p>}\n\t\t\t\t</MultiSelectOptionsContainer>\n\n\t\t\t\t<MultiSelectChevron\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tisFocused={isFocused}\n\t\t\t\t\treadOnly={readOnly}\n\t\t\t\t\ticonSize={iconSize}\n\t\t\t\t\tisLoading={isLoading}\n\t\t\t\t/>\n\n\t\t\t\t<MultiSelectSpinner iconSize={iconSize} isLoading={isLoading} />\n\t\t\t\t<MultiSelectOverlay handleBlur={handleBlur} isFocused={isFocused} />\n\t\t\t</MultiSelectContainer>\n\t\t</FieldTemplate>\n\t);\n}\n\nexport { MultiSelect };\n"],"mappings":"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"}
|
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
import { jsx as e } from "react/jsx-runtime";
|
|
3
3
|
//#region src/components/multiSelect/multiSelectContainer/index.tsx
|
|
4
4
|
function t(t) {
|
|
5
|
-
let { children: n, handleContainerFocus: r, disabled: i, isError: a, isLoading: o, isFocused: s, className: c, readOnly: l, variant: u, size: d, id: f, prefixExists: p } = t;
|
|
6
|
-
return /* @__PURE__ */ e("
|
|
5
|
+
let { children: n, handleContainerFocus: r, disabled: i, isError: a, isLoading: o, isFocused: s, className: c, readOnly: l, variant: u, size: d, id: f, prefixExists: p, containerRef: m, onContainerKeyDown: h, tabIndex: g, ariaControls: _, ariaActiveDescendant: v } = t;
|
|
6
|
+
return /* @__PURE__ */ e("div", {
|
|
7
|
+
ref: m,
|
|
7
8
|
id: f,
|
|
9
|
+
tabIndex: g,
|
|
10
|
+
role: "combobox",
|
|
11
|
+
"aria-haspopup": "listbox",
|
|
12
|
+
"aria-expanded": s,
|
|
13
|
+
"aria-controls": _,
|
|
14
|
+
"aria-activedescendant": v,
|
|
8
15
|
className: `arkynMultiSelectContainer ${p ? "hasPrefix" : ""} ${u} ${d} ${i || l || o ? "opacity" : ""} ${a ? "errored" : ""} ${s ? "focused" : ""} ${c}`,
|
|
9
16
|
onClick: r,
|
|
17
|
+
onKeyDown: h,
|
|
10
18
|
children: n
|
|
11
19
|
});
|
|
12
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/components/multiSelect/multiSelectContainer/index.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport \"./styles.css\";\n\ntype MultiSelectContainerProps = {\n\tchildren: ReactNode;\n\thandleContainerFocus: () => void;\n\tprefixExists: boolean;\n\tisError: boolean;\n\tdisabled: boolean;\n\treadOnly: boolean;\n\tisLoading: boolean;\n\tisFocused: boolean;\n\tclassName?: string;\n\tid: string;\n\tvariant: \"solid\" | \"outline\" | \"underline\";\n\tsize: \"md\" | \"lg\";\n};\n\nfunction MultiSelectContainer(props: MultiSelectContainerProps) {\n\tconst {\n\t\tchildren,\n\t\thandleContainerFocus,\n\t\tdisabled,\n\t\tisError,\n\t\tisLoading,\n\t\tisFocused,\n\t\tclassName,\n\t\treadOnly,\n\t\tvariant,\n\t\tsize,\n\t\tid,\n\t\tprefixExists,\n\t} = props;\n\n\tconst hasPrefix = prefixExists ? \"hasPrefix\" : \"\";\n\tconst errored = isError ? \"errored\" : \"\";\n\tconst opacity = disabled || readOnly || isLoading ? \"opacity\" : \"\";\n\tconst focused = isFocused ? \"focused\" : \"\";\n\n\treturn (\n\t\t<
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/components/multiSelect/multiSelectContainer/index.tsx"],"sourcesContent":["import type { KeyboardEvent, ReactNode, RefObject } from \"react\";\nimport \"./styles.css\";\n\ntype MultiSelectContainerProps = {\n\tchildren: ReactNode;\n\thandleContainerFocus: () => void;\n\tprefixExists: boolean;\n\tisError: boolean;\n\tdisabled: boolean;\n\treadOnly: boolean;\n\tisLoading: boolean;\n\tisFocused: boolean;\n\tclassName?: string;\n\tid: string;\n\tvariant: \"solid\" | \"outline\" | \"underline\";\n\tsize: \"md\" | \"lg\";\n\tcontainerRef?: RefObject<HTMLDivElement | null>;\n\tonContainerKeyDown?: (e: KeyboardEvent<HTMLDivElement>) => void;\n\ttabIndex?: number;\n\tariaControls?: string;\n\tariaActiveDescendant?: string;\n};\n\nfunction MultiSelectContainer(props: MultiSelectContainerProps) {\n\tconst {\n\t\tchildren,\n\t\thandleContainerFocus,\n\t\tdisabled,\n\t\tisError,\n\t\tisLoading,\n\t\tisFocused,\n\t\tclassName,\n\t\treadOnly,\n\t\tvariant,\n\t\tsize,\n\t\tid,\n\t\tprefixExists,\n\t\tcontainerRef,\n\t\tonContainerKeyDown,\n\t\ttabIndex,\n\t\tariaControls,\n\t\tariaActiveDescendant,\n\t} = props;\n\n\tconst hasPrefix = prefixExists ? \"hasPrefix\" : \"\";\n\tconst errored = isError ? \"errored\" : \"\";\n\tconst opacity = disabled || readOnly || isLoading ? \"opacity\" : \"\";\n\tconst focused = isFocused ? \"focused\" : \"\";\n\n\treturn (\n\t\t<div\n\t\t\tref={containerRef}\n\t\t\tid={id}\n\t\t\ttabIndex={tabIndex}\n\t\t\trole=\"combobox\"\n\t\t\taria-haspopup=\"listbox\"\n\t\t\taria-expanded={isFocused}\n\t\t\taria-controls={ariaControls}\n\t\t\taria-activedescendant={ariaActiveDescendant}\n\t\t\tclassName={`arkynMultiSelectContainer ${hasPrefix} ${variant} ${size} ${opacity} ${errored} ${focused} ${className}`}\n\t\t\tonClick={handleContainerFocus}\n\t\t\tonKeyDown={onContainerKeyDown}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport { MultiSelectContainer };\n"],"mappings":";;;AAuBA,SAAS,EAAqB,GAAkC;CAC/D,IAAM,EACL,aACA,yBACA,aACA,YACA,cACA,cACA,cACA,aACA,YACA,SACA,OACA,iBACA,iBACA,uBACA,aACA,iBACA,4BACG;CAOJ,OACC,kBAAC,OAAD;EACC,KAAK;EACD;EACM;EACV,MAAK;EACL,iBAAc;EACd,iBAAe;EACf,iBAAe;EACf,yBAAuB;EACvB,WAAW,6BAfK,IAAe,cAAc,GAeK,GAAG,EAAQ,GAAG,EAAK,GAbvD,KAAY,KAAY,IAAY,YAAY,GAakB,GAdlE,IAAU,YAAY,GAcuD,GAZ7E,IAAY,YAAY,GAYgE,GAAG;EACzG,SAAS;EACT,WAAW;EAEV;CACG,CAAA;AAEP"}
|
|
@@ -3,10 +3,14 @@ import { jsx as e, jsxs as t } from "react/jsx-runtime";
|
|
|
3
3
|
import { Check as n } from "lucide-react";
|
|
4
4
|
//#region src/components/multiSelect/multiSelectOption/index.tsx
|
|
5
5
|
function r(r) {
|
|
6
|
-
let { label: i, optionHasSelected: a, handleChangeValue: o, value: s, size: c } = r;
|
|
7
|
-
return /* @__PURE__ */ t("
|
|
6
|
+
let { label: i, optionHasSelected: a, handleChangeValue: o, value: s, size: c, id: l, isHighlighted: u = !1 } = r, d = a(s);
|
|
7
|
+
return /* @__PURE__ */ t("button", {
|
|
8
|
+
type: "button",
|
|
9
|
+
id: l,
|
|
10
|
+
role: "option",
|
|
11
|
+
"aria-selected": d,
|
|
8
12
|
onClick: () => o(s),
|
|
9
|
-
className: `arkynMultiSelectOption ${c} ${
|
|
13
|
+
className: `arkynMultiSelectOption ${c} ${d ? "active" : ""} ${u ? "highlighted" : ""}`,
|
|
10
14
|
children: [
|
|
11
15
|
i,
|
|
12
16
|
" ",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/components/multiSelect/multiSelectOption/index.tsx"],"sourcesContent":["import { Check } from \"lucide-react\";\nimport \"./styles.css\";\n\ntype MultiSelectOptionProps = {\n\tvalue: string;\n\tlabel: string;\n\tsize: \"md\" | \"lg\";\n\toptionHasSelected: (value: string) => boolean;\n\thandleChangeValue: (value: string) => void;\n};\n\nfunction MultiSelectOption(props: MultiSelectOptionProps) {\n\tconst {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/components/multiSelect/multiSelectOption/index.tsx"],"sourcesContent":["import { Check } from \"lucide-react\";\nimport \"./styles.css\";\n\ntype MultiSelectOptionProps = {\n\tvalue: string;\n\tlabel: string;\n\tsize: \"md\" | \"lg\";\n\tid?: string;\n\tisHighlighted?: boolean;\n\toptionHasSelected: (value: string) => boolean;\n\thandleChangeValue: (value: string) => void;\n};\n\nfunction MultiSelectOption(props: MultiSelectOptionProps) {\n\tconst {\n\t\tlabel,\n\t\toptionHasSelected,\n\t\thandleChangeValue,\n\t\tvalue,\n\t\tsize,\n\t\tid,\n\t\tisHighlighted = false,\n\t} = props;\n\n\tconst isSelected = optionHasSelected(value);\n\tconst hasActive = isSelected ? \"active\" : \"\";\n\tconst highlighted = isHighlighted ? \"highlighted\" : \"\";\n\tconst className = `arkynMultiSelectOption ${size} ${hasActive} ${highlighted}`;\n\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tid={id}\n\t\t\trole=\"option\"\n\t\t\taria-selected={isSelected}\n\t\t\tonClick={() => handleChangeValue(value)}\n\t\t\tclassName={className}\n\t\t>\n\t\t\t{label} <Check />\n\t\t</button>\n\t);\n}\n\nexport { MultiSelectOption };\n"],"mappings":";;;;AAaA,SAAS,EAAkB,GAA+B;CACzD,IAAM,EACL,UACA,sBACA,sBACA,UACA,SACA,OACA,mBAAgB,OACb,GAEE,IAAa,EAAkB,CAAK;CAK1C,OACC,kBAAC,UAAD;EACC,MAAK;EACD;EACJ,MAAK;EACL,iBAAe;EACf,eAAe,EAAkB,CAAK;EAC3B,WAAA,0BAT+B,EAAK,GAF/B,IAAa,WAAW,GAEoB,GAD1C,IAAgB,gBAAgB;YAInD;GAQE;GAAM;GAAC,kBAAC,GAAD,CAAQ,CAAA;EACT;;AAEV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer arkyn{.arkynMultiSelectOption{color:var(--text-body,#52525b);-webkit-user-select:none;user-select:none;background-color:var(--background-foreground,#fff);justify-content:space-between;align-items:center;font-weight:400;line-height:21.79px;display:flex}.arkynMultiSelectOption.md{padding:8px 16px;font-size:14px}.arkynMultiSelectOption.lg{padding:8px 16px;font-size:16px}.arkynMultiSelectOption svg{width:20px;height:20px;color:rgb(var(--spotlight-primary,17, 109, 220));display:none}.arkynMultiSelectOption:hover{cursor:pointer;filter:brightness(.95)}.arkynMultiSelectOption.active{color:var(--text-heading,#09090b);filter:brightness(.95);font-weight:600}.arkynMultiSelectOption.active svg{display:unset}}
|
|
1
|
+
@layer arkyn{.arkynMultiSelectOption{text-align:left;width:100%;color:var(--text-body,#52525b);-webkit-user-select:none;user-select:none;background-color:var(--background-foreground,#fff);border:none;justify-content:space-between;align-items:center;margin:0;font-family:inherit;font-weight:400;line-height:21.79px;display:flex}.arkynMultiSelectOption.md{padding:8px 16px;font-size:14px}.arkynMultiSelectOption.lg{padding:8px 16px;font-size:16px}.arkynMultiSelectOption svg{width:20px;height:20px;color:rgb(var(--spotlight-primary,17, 109, 220));display:none}.arkynMultiSelectOption:hover{cursor:pointer;filter:brightness(.95)}.arkynMultiSelectOption.active{color:var(--text-heading,#09090b);filter:brightness(.95);font-weight:600}.arkynMultiSelectOption.active svg{display:unset}.arkynMultiSelectOption.highlighted{filter:brightness(.95)}}
|
|
@@ -1,38 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useFlipPosition as e } from "../../../hooks/useFlipPosition.js";
|
|
2
|
+
import { useScrollLock as t } from "../../../hooks/useScrollLock.js";
|
|
3
|
+
import { Input as n } from "../../input/index.js";
|
|
3
4
|
/* empty css */
|
|
4
|
-
import {
|
|
5
|
-
import { jsx as
|
|
6
|
-
import { Search as
|
|
5
|
+
import { useRef as r } from "react";
|
|
6
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
7
|
+
import { Search as o } from "lucide-react";
|
|
7
8
|
//#region src/components/multiSelect/multiSelectOptionsContainer/index.tsx
|
|
8
|
-
function
|
|
9
|
-
let { children: l, isFocused: u, isSearchable: d, search: f, onSearch: p } =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (!m.current) return;
|
|
13
|
-
let e = m.current.parentElement;
|
|
14
|
-
if (!e) return;
|
|
15
|
-
let t = e.getBoundingClientRect();
|
|
16
|
-
window.innerHeight - t.bottom < 300 && t.top > 300 ? g("top") : g("bottom");
|
|
17
|
-
})();
|
|
18
|
-
}, [u]);
|
|
19
|
-
function _(e) {
|
|
9
|
+
function s(s) {
|
|
10
|
+
let { children: c, id: l, isFocused: u, isSearchable: d, search: f, onSearch: p } = s, m = r(null), h = e(m, u, 300);
|
|
11
|
+
t(u);
|
|
12
|
+
function g(e) {
|
|
20
13
|
d && p(e.target.value);
|
|
21
14
|
}
|
|
22
|
-
return u ? /* @__PURE__ */
|
|
15
|
+
return u ? /* @__PURE__ */ a("div", {
|
|
23
16
|
ref: m,
|
|
17
|
+
id: l,
|
|
18
|
+
role: "listbox",
|
|
19
|
+
"aria-multiselectable": "true",
|
|
24
20
|
className: `arkynMultiSelectOptionsContainer ${h}`,
|
|
25
|
-
children: [d && /* @__PURE__ */
|
|
21
|
+
children: [d && /* @__PURE__ */ i(n, {
|
|
26
22
|
type: "search",
|
|
27
23
|
name: "search-select",
|
|
28
24
|
variant: "underline",
|
|
29
|
-
leftIcon:
|
|
25
|
+
leftIcon: o,
|
|
30
26
|
value: f,
|
|
31
|
-
onChange:
|
|
32
|
-
}),
|
|
27
|
+
onChange: g
|
|
28
|
+
}), c]
|
|
33
29
|
}) : null;
|
|
34
30
|
}
|
|
35
31
|
//#endregion
|
|
36
|
-
export {
|
|
32
|
+
export { s as MultiSelectOptionsContainer };
|
|
37
33
|
|
|
38
34
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/components/multiSelect/multiSelectOptionsContainer/index.tsx"],"sourcesContent":["import { Search } from \"lucide-react\";\nimport {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/components/multiSelect/multiSelectOptionsContainer/index.tsx"],"sourcesContent":["import { Search } from \"lucide-react\";\nimport { type ChangeEvent, type ReactNode, useRef } from \"react\";\n\nimport { useFlipPosition } from \"../../../hooks/useFlipPosition\";\nimport { useScrollLock } from \"../../../hooks/useScrollLock\";\nimport { Input } from \"../../input\";\n\nimport \"./styles.css\";\n\ntype MultiSelectOptionsContainerProps = {\n\tid?: string;\n\tisFocused: boolean;\n\tisSearchable: boolean;\n\tchildren: ReactNode;\n\tsearch: string;\n\tonSearch: (value: string) => void;\n};\n\nfunction MultiSelectOptionsContainer(props: MultiSelectOptionsContainerProps) {\n\tconst { children, id, isFocused, isSearchable, search, onSearch } = props;\n\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\tconst position = useFlipPosition(containerRef, isFocused, 300);\n\n\tuseScrollLock(isFocused);\n\n\tfunction handleSearch(e: ChangeEvent<HTMLInputElement>) {\n\t\tif (!isSearchable) return;\n\t\tonSearch(e.target.value);\n\t}\n\n\tif (!isFocused) return null;\n\n\treturn (\n\t\t<div\n\t\t\tref={containerRef}\n\t\t\tid={id}\n\t\t\trole=\"listbox\"\n\t\t\taria-multiselectable=\"true\"\n\t\t\tclassName={`arkynMultiSelectOptionsContainer ${position}`}\n\t\t>\n\t\t\t{isSearchable && (\n\t\t\t\t<Input\n\t\t\t\t\ttype=\"search\"\n\t\t\t\t\tname=\"search-select\"\n\t\t\t\t\tvariant=\"underline\"\n\t\t\t\t\tleftIcon={Search}\n\t\t\t\t\tvalue={search}\n\t\t\t\t\tonChange={handleSearch}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport { MultiSelectOptionsContainer };\n"],"mappings":";;;;;;;;AAkBA,SAAS,EAA4B,GAAyC;CAC7E,IAAM,EAAE,aAAU,OAAI,cAAW,iBAAc,WAAQ,gBAAa,GAE9D,IAAe,EAAuB,IAAI,GAC1C,IAAW,EAAgB,GAAc,GAAW,GAAG;CAE7D,EAAc,CAAS;CAEvB,SAAS,EAAa,GAAkC;EAClD,KACL,EAAS,EAAE,OAAO,KAAK;CACxB;CAIA,OAFK,IAGJ,kBAAC,OAAD;EACC,KAAK;EACD;EACJ,MAAK;EACL,wBAAqB;EACrB,WAAW,oCAAoC;YALhD,CAOE,KACA,kBAAC,GAAD;GACC,MAAK;GACL,MAAK;GACL,SAAQ;GACR,UAAU;GACV,OAAO;GACP,UAAU;EACV,CAAA,GAGD,CACG;MAtBiB;AAwBxB"}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
@layer arkyn{.arkynMultiSelectMark{background:var(--background,#f4f4f5);color:var(--text-body,#52525b);text-align:left;z-index:6;-webkit-user-select:none;user-select:none;border-radius:4px;align-items:center;gap:4px;padding:2px 6px;font-size:14px;font-weight:400;line-height:19.07px;display:flex}.arkynMultiSelectMark button{background:inherit;border:none;justify-content:center;align-items:center;width:15px;height:15px;display:flex}.arkynMultiSelectMark button:disabled{cursor:not-allowed}.arkynMultiSelectMark button:hover:not(:disabled){cursor:pointer;filter:brightness(.9)}.arkynMultiSelectMark button svg{min-width:10px;min-height:10px;color:var(--text-muted,#a1a1aa)}}
|
|
14
14
|
|
|
15
|
-
@layer arkyn{.arkynMultiSelectOption{color:var(--text-body,#52525b);-webkit-user-select:none;user-select:none;background-color:var(--background-foreground,#fff);justify-content:space-between;align-items:center;font-weight:400;line-height:21.79px;display:flex}.arkynMultiSelectOption.md{padding:8px 16px;font-size:14px}.arkynMultiSelectOption.lg{padding:8px 16px;font-size:16px}.arkynMultiSelectOption svg{width:20px;height:20px;color:rgb(var(--spotlight-primary,17, 109, 220));display:none}.arkynMultiSelectOption:hover{cursor:pointer;filter:brightness(.95)}.arkynMultiSelectOption.active{color:var(--text-heading,#09090b);filter:brightness(.95);font-weight:600}.arkynMultiSelectOption.active svg{display:unset}}
|
|
15
|
+
@layer arkyn{.arkynMultiSelectOption{text-align:left;width:100%;color:var(--text-body,#52525b);-webkit-user-select:none;user-select:none;background-color:var(--background-foreground,#fff);border:none;justify-content:space-between;align-items:center;margin:0;font-family:inherit;font-weight:400;line-height:21.79px;display:flex}.arkynMultiSelectOption.md{padding:8px 16px;font-size:14px}.arkynMultiSelectOption.lg{padding:8px 16px;font-size:16px}.arkynMultiSelectOption svg{width:20px;height:20px;color:rgb(var(--spotlight-primary,17, 109, 220));display:none}.arkynMultiSelectOption:hover{cursor:pointer;filter:brightness(.95)}.arkynMultiSelectOption.active{color:var(--text-heading,#09090b);filter:brightness(.95);font-weight:600}.arkynMultiSelectOption.active svg{display:unset}.arkynMultiSelectOption.highlighted{filter:brightness(.95)}}
|
|
16
16
|
|
|
17
17
|
@layer arkyn{.arkynMultiSelectOptionsContainer{z-index:7;border:1px solid var(--border,#e2e8f0);background-color:var(--background-foreground,#fff);border-radius:6px;flex-direction:column;flex:1;height:max-content;max-height:300px;list-style:none;display:flex;position:absolute;left:-2px;right:-2px;overflow:auto;box-shadow:0 4px 8px #0000001a}.arkynMultiSelectOptionsContainer.bottom{top:calc(100% + 5px)}.arkynMultiSelectOptionsContainer.top{bottom:calc(100% + 5px)}.arkynMultiSelectOptionsContainer>p{text-align:center;color:var(--text-body,#52525b);padding:16px;font-size:14px;font-weight:400;line-height:21.79px}}
|
|
18
18
|
|
|
@@ -1,32 +1,38 @@
|
|
|
1
1
|
import { useScrollLock as e } from "../../hooks/useScrollLock.js";
|
|
2
|
+
import { useEscapeKey as t } from "../../hooks/useEscapeKey.js";
|
|
3
|
+
import { useFocusTrap as n } from "../../hooks/useFocusTrap.js";
|
|
2
4
|
/* empty css */
|
|
3
|
-
import { useState as
|
|
4
|
-
import { jsx as
|
|
5
|
+
import { useRef as r, useState as i } from "react";
|
|
6
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
5
7
|
//#region src/components/popover/index.tsx
|
|
6
|
-
function
|
|
7
|
-
let { children:
|
|
8
|
-
function
|
|
9
|
-
|
|
8
|
+
function s(s) {
|
|
9
|
+
let { children: c, button: l, closeOnClick: u, className: d = "", orientation: f = "bottomLeft" } = s, [p, m] = i(!1), h = r(null), g = `arkynPopover ${f} ${p ? "visibleTrue" : "visibleFalse"} ${d}`;
|
|
10
|
+
function _() {
|
|
11
|
+
p || m(!0);
|
|
10
12
|
}
|
|
11
|
-
return e(
|
|
12
|
-
className:
|
|
13
|
-
onClick:
|
|
13
|
+
return e(p), t(p, () => m(!1)), n(p, h), /* @__PURE__ */ o("div", {
|
|
14
|
+
className: g,
|
|
15
|
+
onClick: _,
|
|
14
16
|
children: [
|
|
15
|
-
|
|
16
|
-
/* @__PURE__ */
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
l,
|
|
18
|
+
/* @__PURE__ */ a("div", {
|
|
19
|
+
ref: h,
|
|
20
|
+
role: "dialog",
|
|
21
|
+
"aria-modal": "true",
|
|
22
|
+
tabIndex: -1,
|
|
23
|
+
style: { visibility: p ? "visible" : "hidden" },
|
|
24
|
+
onClick: () => u && m(!1),
|
|
19
25
|
className: "arkynPopoverContent",
|
|
20
|
-
children:
|
|
26
|
+
children: c
|
|
21
27
|
}),
|
|
22
|
-
|
|
23
|
-
onClick: () =>
|
|
28
|
+
p && /* @__PURE__ */ a("div", {
|
|
29
|
+
onClick: () => m(!1),
|
|
24
30
|
className: "arkynPopoverOverlay"
|
|
25
31
|
})
|
|
26
32
|
]
|
|
27
33
|
});
|
|
28
34
|
}
|
|
29
35
|
//#endregion
|
|
30
|
-
export {
|
|
36
|
+
export { s as Popover };
|
|
31
37
|
|
|
32
38
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/popover/index.tsx"],"sourcesContent":["import { type ReactNode, useState } from \"react\";\n\nimport { useScrollLock } from \"../../hooks/useScrollLock\";\nimport \"./styles.css\";\n\ntype OrientationProps =\n\t| \"bottomLeft\"\n\t| \"bottomRight\"\n\t| \"topLeft\"\n\t| \"topRight\"\n\t| \"top\"\n\t| \"left\"\n\t| \"bottom\"\n\t| \"right\";\n\ntype PopoverProps = {\n\t/** Content rendered inside the floating panel. Required. */\n\tchildren: ReactNode;\n\t/** Trigger element, clicking it opens the popover. Required. */\n\tbutton: ReactNode;\n\t/** When true, clicking the popover content also closes it. @default false */\n\tcloseOnClick?: boolean;\n\t/**\n\t * Position of the floating panel relative to the trigger.\n\t * Options: `\"bottomLeft\"` | `\"bottomRight\"` | `\"topLeft\"` | `\"topRight\"` | `\"top\"` | `\"bottom\"` | `\"left\"` | `\"right\"`.\n\t * @default \"bottomLeft\"\n\t */\n\torientation?: OrientationProps;\n\t/** Additional CSS class applied to the popover root element. */\n\tclassName?: string;\n};\n\n/**\n * Popover, floating panel that appears relative to a trigger element.\n *\n * Clicking outside the popover (or clicking the content when `closeOnClick` is set)\n * dismisses it. Locks body scroll while open.\n *\n * @param props.children - Content to display inside the panel. Required.\n * @param props.button - Trigger element that opens the popover. Required.\n * @param props.closeOnClick - Clicking the content also closes the popover. Default: false\n * @param props.orientation - Panel position relative to the trigger. Default: \"bottomLeft\"\n * @param props.className - Additional CSS class for the root element.\n *\n * @returns Popover JSX element with trigger, animated panel, and outside-click overlay.\n *\n * @example\n * ```tsx\n * // Basic dropdown menu\n * <Popover button={<Button>Options</Button>} closeOnClick>\n * <ul>\n * <li onClick={handleEdit}>Edit</li>\n * <li onClick={handleDelete}>Delete</li>\n * </ul>\n * </Popover>\n *\n * // User profile menu (bottom-right)\n * <Popover\n * button={<IconButton icon={User} aria-label=\"Account\" />}\n * orientation=\"bottomRight\"\n * closeOnClick\n * >\n * <nav>\n * <a href=\"/profile\">Profile</a>\n * <a href=\"/settings\">Settings</a>\n * <a href=\"/logout\">Sign out</a>\n * </nav>\n * </Popover>\n *\n * // Filter panel (top-left)\n * <Popover button={<Badge>Filters</Badge>} orientation=\"topLeft\">\n * <Input name=\"search\" placeholder=\"Search...\" />\n * <Select name=\"status\" options={statusOptions} />\n * </Popover>\n * ```\n */\n\nfunction Popover(props: PopoverProps) {\n\tconst {\n\t\tchildren,\n\t\tbutton,\n\t\tcloseOnClick,\n\t\tclassName: baseClassName = \"\",\n\t\torientation = \"bottomLeft\",\n\t} = props;\n\tconst [isOpen, setIsOpen] = useState(false);\n\n\tconst visible = isOpen ? \"visibleTrue\" : \"visibleFalse\";\n\tconst className = `arkynPopover ${orientation} ${visible} ${baseClassName}`;\n\n\tfunction handleOpenPopover() {\n\t\tif (!isOpen) setIsOpen(true);\n\t}\n\n\tuseScrollLock(isOpen);\n\n\treturn (\n\t\t<div className={className} onClick={handleOpenPopover}>\n\t\t\t{button}\n\n\t\t\t<div\n\t\t\t\tstyle={{ visibility: isOpen ? \"visible\" : \"hidden\" }}\n\t\t\t\tonClick={() => closeOnClick && setIsOpen(false)}\n\t\t\t\tclassName=\"arkynPopoverContent\"\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\n\t\t\t{isOpen && (\n\t\t\t\t<div onClick={() => setIsOpen(false)} className=\"arkynPopoverOverlay\" />\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nexport { Popover };\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/popover/index.tsx"],"sourcesContent":["import { type ReactNode, useRef, useState } from \"react\";\n\nimport { useEscapeKey } from \"../../hooks/useEscapeKey\";\nimport { useFocusTrap } from \"../../hooks/useFocusTrap\";\nimport { useScrollLock } from \"../../hooks/useScrollLock\";\nimport \"./styles.css\";\n\ntype OrientationProps =\n\t| \"bottomLeft\"\n\t| \"bottomRight\"\n\t| \"topLeft\"\n\t| \"topRight\"\n\t| \"top\"\n\t| \"left\"\n\t| \"bottom\"\n\t| \"right\";\n\ntype PopoverProps = {\n\t/** Content rendered inside the floating panel. Required. */\n\tchildren: ReactNode;\n\t/** Trigger element, clicking it opens the popover. Required. */\n\tbutton: ReactNode;\n\t/** When true, clicking the popover content also closes it. @default false */\n\tcloseOnClick?: boolean;\n\t/**\n\t * Position of the floating panel relative to the trigger.\n\t * Options: `\"bottomLeft\"` | `\"bottomRight\"` | `\"topLeft\"` | `\"topRight\"` | `\"top\"` | `\"bottom\"` | `\"left\"` | `\"right\"`.\n\t * @default \"bottomLeft\"\n\t */\n\torientation?: OrientationProps;\n\t/** Additional CSS class applied to the popover root element. */\n\tclassName?: string;\n};\n\n/**\n * Popover, floating panel that appears relative to a trigger element.\n *\n * Clicking outside the popover (or clicking the content when `closeOnClick` is set)\n * dismisses it. Locks body scroll while open.\n *\n * @param props.children - Content to display inside the panel. Required.\n * @param props.button - Trigger element that opens the popover. Required.\n * @param props.closeOnClick - Clicking the content also closes the popover. Default: false\n * @param props.orientation - Panel position relative to the trigger. Default: \"bottomLeft\"\n * @param props.className - Additional CSS class for the root element.\n *\n * @returns Popover JSX element with trigger, animated panel, and outside-click overlay.\n *\n * @example\n * ```tsx\n * // Basic dropdown menu\n * <Popover button={<Button>Options</Button>} closeOnClick>\n * <ul>\n * <li onClick={handleEdit}>Edit</li>\n * <li onClick={handleDelete}>Delete</li>\n * </ul>\n * </Popover>\n *\n * // User profile menu (bottom-right)\n * <Popover\n * button={<IconButton icon={User} aria-label=\"Account\" />}\n * orientation=\"bottomRight\"\n * closeOnClick\n * >\n * <nav>\n * <a href=\"/profile\">Profile</a>\n * <a href=\"/settings\">Settings</a>\n * <a href=\"/logout\">Sign out</a>\n * </nav>\n * </Popover>\n *\n * // Filter panel (top-left)\n * <Popover button={<Badge>Filters</Badge>} orientation=\"topLeft\">\n * <Input name=\"search\" placeholder=\"Search...\" />\n * <Select name=\"status\" options={statusOptions} />\n * </Popover>\n * ```\n */\n\nfunction Popover(props: PopoverProps) {\n\tconst {\n\t\tchildren,\n\t\tbutton,\n\t\tcloseOnClick,\n\t\tclassName: baseClassName = \"\",\n\t\torientation = \"bottomLeft\",\n\t} = props;\n\tconst [isOpen, setIsOpen] = useState(false);\n\tconst contentRef = useRef<HTMLDivElement>(null);\n\n\tconst visible = isOpen ? \"visibleTrue\" : \"visibleFalse\";\n\tconst className = `arkynPopover ${orientation} ${visible} ${baseClassName}`;\n\n\tfunction handleOpenPopover() {\n\t\tif (!isOpen) setIsOpen(true);\n\t}\n\n\tuseScrollLock(isOpen);\n\tuseEscapeKey(isOpen, () => setIsOpen(false));\n\tuseFocusTrap(isOpen, contentRef);\n\n\treturn (\n\t\t<div className={className} onClick={handleOpenPopover}>\n\t\t\t{button}\n\n\t\t\t<div\n\t\t\t\tref={contentRef}\n\t\t\t\trole=\"dialog\"\n\t\t\t\taria-modal=\"true\"\n\t\t\t\ttabIndex={-1}\n\t\t\t\tstyle={{ visibility: isOpen ? \"visible\" : \"hidden\" }}\n\t\t\t\tonClick={() => closeOnClick && setIsOpen(false)}\n\t\t\t\tclassName=\"arkynPopoverContent\"\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\n\t\t\t{isOpen && (\n\t\t\t\t<div onClick={() => setIsOpen(false)} className=\"arkynPopoverOverlay\" />\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nexport { Popover };\n"],"mappings":";;;;;;;AA+EA,SAAS,EAAQ,GAAqB;CACrC,IAAM,EACL,aACA,WACA,iBACA,WAAW,IAAgB,IAC3B,iBAAc,iBACX,GACE,CAAC,GAAQ,KAAa,EAAS,EAAK,GACpC,IAAa,EAAuB,IAAI,GAGxC,IAAY,gBAAgB,EAAY,GAD9B,IAAS,gBAAgB,eACgB,GAAG;CAE5D,SAAS,IAAoB;EAC5B,AAAK,KAAQ,EAAU,EAAI;CAC5B;CAMA,OAJA,EAAc,CAAM,GACpB,EAAa,SAAc,EAAU,EAAK,CAAC,GAC3C,EAAa,GAAQ,CAAU,GAG9B,kBAAC,OAAD;EAAgB;EAAW,SAAS;YAApC;GACE;GAED,kBAAC,OAAD;IACC,KAAK;IACL,MAAK;IACL,cAAW;IACX,UAAU;IACV,OAAO,EAAE,YAAY,IAAS,YAAY,SAAS;IACnD,eAAe,KAAgB,EAAU,EAAK;IAC9C,WAAU;IAET;GACG,CAAA;GAEJ,KACA,kBAAC,OAAD;IAAK,eAAe,EAAU,EAAK;IAAG,WAAU;GAAuB,CAAA;EAEpE;;AAEP"}
|