framepexls-ui-lib 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ActionIconButton.d.mts +11 -0
- package/dist/ActionIconButton.d.ts +11 -0
- package/dist/ActionIconButton.js +71 -0
- package/dist/ActionIconButton.mjs +41 -0
- package/dist/AppTopbar.d.mts +17 -0
- package/dist/AppTopbar.d.ts +17 -0
- package/dist/AppTopbar.js +51 -0
- package/dist/AppTopbar.mjs +31 -0
- package/dist/AvatarSquare.d.mts +16 -0
- package/dist/AvatarSquare.d.ts +16 -0
- package/dist/AvatarSquare.js +82 -0
- package/dist/AvatarSquare.mjs +52 -0
- package/dist/Badge.d.mts +13 -0
- package/dist/Badge.d.ts +13 -0
- package/dist/Badge.js +65 -0
- package/dist/Badge.mjs +45 -0
- package/dist/BadgeCluster.d.mts +17 -0
- package/dist/BadgeCluster.d.ts +17 -0
- package/dist/BadgeCluster.js +125 -0
- package/dist/BadgeCluster.mjs +95 -0
- package/dist/Breadcrumb.d.mts +11 -0
- package/dist/Breadcrumb.d.ts +11 -0
- package/dist/Breadcrumb.js +42 -0
- package/dist/Breadcrumb.mjs +12 -0
- package/dist/Button.d.mts +15 -0
- package/dist/Button.d.ts +15 -0
- package/dist/Button.js +72 -0
- package/dist/Button.mjs +52 -0
- package/dist/CalendarPanel.d.mts +13 -0
- package/dist/CalendarPanel.d.ts +13 -0
- package/dist/CalendarPanel.js +110 -0
- package/dist/CalendarPanel.mjs +90 -0
- package/dist/ChartCard.d.mts +15 -0
- package/dist/ChartCard.d.ts +15 -0
- package/dist/ChartCard.js +44 -0
- package/dist/ChartCard.mjs +24 -0
- package/dist/CheckboxPillsGroup.d.mts +28 -0
- package/dist/CheckboxPillsGroup.d.ts +28 -0
- package/dist/CheckboxPillsGroup.js +186 -0
- package/dist/CheckboxPillsGroup.mjs +156 -0
- package/dist/ColumnSelector.d.mts +17 -0
- package/dist/ColumnSelector.d.ts +17 -0
- package/dist/ColumnSelector.js +74 -0
- package/dist/ColumnSelector.mjs +54 -0
- package/dist/ComboSelect.d.mts +46 -0
- package/dist/ComboSelect.d.ts +46 -0
- package/dist/ComboSelect.js +442 -0
- package/dist/ComboSelect.mjs +412 -0
- package/dist/DateTimeField.d.mts +22 -0
- package/dist/DateTimeField.d.ts +22 -0
- package/dist/DateTimeField.js +409 -0
- package/dist/DateTimeField.mjs +379 -0
- package/dist/Dialog.d.mts +82 -0
- package/dist/Dialog.d.ts +82 -0
- package/dist/Dialog.js +408 -0
- package/dist/Dialog.mjs +368 -0
- package/dist/Dropdown.d.mts +52 -0
- package/dist/Dropdown.d.ts +52 -0
- package/dist/Dropdown.js +333 -0
- package/dist/Dropdown.mjs +313 -0
- package/dist/EmptyState.d.mts +8 -0
- package/dist/EmptyState.d.ts +8 -0
- package/dist/EmptyState.js +35 -0
- package/dist/EmptyState.mjs +15 -0
- package/dist/InfoGrid.d.mts +20 -0
- package/dist/InfoGrid.d.ts +20 -0
- package/dist/InfoGrid.js +67 -0
- package/dist/InfoGrid.mjs +47 -0
- package/dist/Input.d.mts +20 -0
- package/dist/Input.d.ts +20 -0
- package/dist/Input.js +85 -0
- package/dist/Input.mjs +55 -0
- package/dist/Money.d.mts +8 -0
- package/dist/Money.d.ts +8 -0
- package/dist/Money.js +30 -0
- package/dist/Money.mjs +10 -0
- package/dist/OrderButton.d.mts +11 -0
- package/dist/OrderButton.d.ts +11 -0
- package/dist/OrderButton.js +39 -0
- package/dist/OrderButton.mjs +19 -0
- package/dist/Pagination.d.mts +12 -0
- package/dist/Pagination.d.ts +12 -0
- package/dist/Pagination.js +71 -0
- package/dist/Pagination.mjs +51 -0
- package/dist/SearchInput.d.mts +17 -0
- package/dist/SearchInput.d.ts +17 -0
- package/dist/SearchInput.js +116 -0
- package/dist/SearchInput.mjs +86 -0
- package/dist/Select.d.mts +31 -0
- package/dist/Select.d.ts +31 -0
- package/dist/Select.js +293 -0
- package/dist/Select.mjs +263 -0
- package/dist/StatCard.d.mts +15 -0
- package/dist/StatCard.d.ts +15 -0
- package/dist/StatCard.js +47 -0
- package/dist/StatCard.mjs +27 -0
- package/dist/Steps.d.mts +31 -0
- package/dist/Steps.d.ts +31 -0
- package/dist/Steps.js +123 -0
- package/dist/Steps.mjs +99 -0
- package/dist/Table.d.mts +31 -0
- package/dist/Table.d.ts +31 -0
- package/dist/Table.js +153 -0
- package/dist/Table.mjs +117 -0
- package/dist/TimeAgo.d.mts +12 -0
- package/dist/TimeAgo.d.ts +12 -0
- package/dist/TimeAgo.js +104 -0
- package/dist/TimeAgo.mjs +74 -0
- package/dist/TimePanel.d.mts +14 -0
- package/dist/TimePanel.d.ts +14 -0
- package/dist/TimePanel.js +145 -0
- package/dist/TimePanel.mjs +125 -0
- package/dist/TimePopover.d.mts +33 -0
- package/dist/TimePopover.d.ts +33 -0
- package/dist/TimePopover.js +441 -0
- package/dist/TimePopover.mjs +406 -0
- package/dist/iconos/index.d.mts +60 -0
- package/dist/iconos/index.d.ts +60 -0
- package/dist/iconos/index.js +621 -0
- package/dist/iconos/index.mjs +548 -0
- package/dist/index.d.mts +32 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +141 -0
- package/dist/index.mjs +70 -0
- package/package.json +178 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var ColumnSelector_exports = {};
|
|
20
|
+
__export(ColumnSelector_exports, {
|
|
21
|
+
default: () => ColumnSelector
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(ColumnSelector_exports);
|
|
24
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
|
+
var import_framer_motion = require("framer-motion");
|
|
26
|
+
function ColumnSelector({
|
|
27
|
+
open,
|
|
28
|
+
onToggleOpen,
|
|
29
|
+
items,
|
|
30
|
+
visible,
|
|
31
|
+
setVisible
|
|
32
|
+
}) {
|
|
33
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative", children: [
|
|
34
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
35
|
+
"button",
|
|
36
|
+
{
|
|
37
|
+
onClick: (e) => {
|
|
38
|
+
e.stopPropagation();
|
|
39
|
+
onToggleOpen((v) => !v);
|
|
40
|
+
},
|
|
41
|
+
className: "rounded-2xl border border-slate-200 px-3 py-2 text-sm hover:bg-slate-50 dark:border-white/10 dark:hover:bg-white/5",
|
|
42
|
+
children: "Columnas"
|
|
43
|
+
}
|
|
44
|
+
),
|
|
45
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_framer_motion.AnimatePresence, { children: open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
46
|
+
import_framer_motion.motion.div,
|
|
47
|
+
{
|
|
48
|
+
initial: { opacity: 0, y: 6 },
|
|
49
|
+
animate: { opacity: 1, y: 0 },
|
|
50
|
+
exit: { opacity: 0, y: -6 },
|
|
51
|
+
className: "absolute right-0 z-20 mt-2 w-64 overflow-hidden rounded-2xl border border-slate-200 bg-white p-1 shadow-xl dark:border-white/10 dark:bg-[#0e0d0e]",
|
|
52
|
+
children: items.map(({ key, label }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
53
|
+
"label",
|
|
54
|
+
{
|
|
55
|
+
className: "flex cursor-pointer items-center justify-between gap-3 rounded-xl px-3 py-2 text-sm hover:bg-slate-50 dark:hover:bg-white/5",
|
|
56
|
+
children: [
|
|
57
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-medium text-slate-800 dark:text-slate-100", children: label }),
|
|
58
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
59
|
+
"input",
|
|
60
|
+
{
|
|
61
|
+
type: "checkbox",
|
|
62
|
+
checked: visible[key],
|
|
63
|
+
onChange: (e) => setVisible(key, e.target.checked),
|
|
64
|
+
className: "h-4 w-4 rounded border-slate-300"
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
key
|
|
70
|
+
))
|
|
71
|
+
}
|
|
72
|
+
) })
|
|
73
|
+
] });
|
|
74
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { AnimatePresence, motion } from "framer-motion";
|
|
3
|
+
function ColumnSelector({
|
|
4
|
+
open,
|
|
5
|
+
onToggleOpen,
|
|
6
|
+
items,
|
|
7
|
+
visible,
|
|
8
|
+
setVisible
|
|
9
|
+
}) {
|
|
10
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
11
|
+
/* @__PURE__ */ jsx(
|
|
12
|
+
"button",
|
|
13
|
+
{
|
|
14
|
+
onClick: (e) => {
|
|
15
|
+
e.stopPropagation();
|
|
16
|
+
onToggleOpen((v) => !v);
|
|
17
|
+
},
|
|
18
|
+
className: "rounded-2xl border border-slate-200 px-3 py-2 text-sm hover:bg-slate-50 dark:border-white/10 dark:hover:bg-white/5",
|
|
19
|
+
children: "Columnas"
|
|
20
|
+
}
|
|
21
|
+
),
|
|
22
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsx(
|
|
23
|
+
motion.div,
|
|
24
|
+
{
|
|
25
|
+
initial: { opacity: 0, y: 6 },
|
|
26
|
+
animate: { opacity: 1, y: 0 },
|
|
27
|
+
exit: { opacity: 0, y: -6 },
|
|
28
|
+
className: "absolute right-0 z-20 mt-2 w-64 overflow-hidden rounded-2xl border border-slate-200 bg-white p-1 shadow-xl dark:border-white/10 dark:bg-[#0e0d0e]",
|
|
29
|
+
children: items.map(({ key, label }) => /* @__PURE__ */ jsxs(
|
|
30
|
+
"label",
|
|
31
|
+
{
|
|
32
|
+
className: "flex cursor-pointer items-center justify-between gap-3 rounded-xl px-3 py-2 text-sm hover:bg-slate-50 dark:hover:bg-white/5",
|
|
33
|
+
children: [
|
|
34
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-slate-800 dark:text-slate-100", children: label }),
|
|
35
|
+
/* @__PURE__ */ jsx(
|
|
36
|
+
"input",
|
|
37
|
+
{
|
|
38
|
+
type: "checkbox",
|
|
39
|
+
checked: visible[key],
|
|
40
|
+
onChange: (e) => setVisible(key, e.target.checked),
|
|
41
|
+
className: "h-4 w-4 rounded border-slate-300"
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
key
|
|
47
|
+
))
|
|
48
|
+
}
|
|
49
|
+
) })
|
|
50
|
+
] });
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
ColumnSelector as default
|
|
54
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
|
|
4
|
+
type ComboOption = {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
hint?: string;
|
|
8
|
+
sublabel?: string;
|
|
9
|
+
image?: string | null;
|
|
10
|
+
right?: React__default.ReactNode;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
type ComboSection = {
|
|
14
|
+
key: string;
|
|
15
|
+
title: string;
|
|
16
|
+
options: ComboOption[];
|
|
17
|
+
rightHint?: React__default.ReactNode;
|
|
18
|
+
};
|
|
19
|
+
type ComboSelectProps = {
|
|
20
|
+
options?: ComboOption[];
|
|
21
|
+
sections?: ComboSection[];
|
|
22
|
+
value?: string | null;
|
|
23
|
+
onChange: (value: string | null, option?: ComboOption) => void;
|
|
24
|
+
placeholder?: string;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
loading?: boolean;
|
|
27
|
+
allowClear?: boolean;
|
|
28
|
+
searchable?: boolean;
|
|
29
|
+
maxItems?: number;
|
|
30
|
+
className?: string;
|
|
31
|
+
noResultsText?: string;
|
|
32
|
+
renderOption?: (opt: ComboOption, active: boolean, selected: boolean) => React__default.ReactNode;
|
|
33
|
+
renderSectionHeader?: (sec: ComboSection, sticky: boolean) => React__default.ReactNode;
|
|
34
|
+
portalTarget?: HTMLElement | null;
|
|
35
|
+
closeOnSelect?: boolean;
|
|
36
|
+
keepFocusOnSelect?: boolean;
|
|
37
|
+
clearQueryOnSelect?: boolean;
|
|
38
|
+
renderTags?: React__default.ReactNode;
|
|
39
|
+
/** Si true, las filas pueden tener inputs/botones y el click de fondo dispara onChange */
|
|
40
|
+
interactiveOptions?: boolean;
|
|
41
|
+
/** 🔹 Nuevo: notifica cambios en el texto de búsqueda */
|
|
42
|
+
onQueryChange?: (q: string) => void;
|
|
43
|
+
};
|
|
44
|
+
declare function ComboSelect({ options, sections, value, onChange, placeholder, disabled, loading, allowClear, searchable, maxItems, className, noResultsText, renderOption, renderSectionHeader, portalTarget, closeOnSelect, keepFocusOnSelect, clearQueryOnSelect, renderTags, interactiveOptions, onQueryChange, }: ComboSelectProps): react_jsx_runtime.JSX.Element;
|
|
45
|
+
|
|
46
|
+
export { type ComboOption, type ComboSection, type ComboSelectProps, ComboSelect as default };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
|
|
4
|
+
type ComboOption = {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
hint?: string;
|
|
8
|
+
sublabel?: string;
|
|
9
|
+
image?: string | null;
|
|
10
|
+
right?: React__default.ReactNode;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
type ComboSection = {
|
|
14
|
+
key: string;
|
|
15
|
+
title: string;
|
|
16
|
+
options: ComboOption[];
|
|
17
|
+
rightHint?: React__default.ReactNode;
|
|
18
|
+
};
|
|
19
|
+
type ComboSelectProps = {
|
|
20
|
+
options?: ComboOption[];
|
|
21
|
+
sections?: ComboSection[];
|
|
22
|
+
value?: string | null;
|
|
23
|
+
onChange: (value: string | null, option?: ComboOption) => void;
|
|
24
|
+
placeholder?: string;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
loading?: boolean;
|
|
27
|
+
allowClear?: boolean;
|
|
28
|
+
searchable?: boolean;
|
|
29
|
+
maxItems?: number;
|
|
30
|
+
className?: string;
|
|
31
|
+
noResultsText?: string;
|
|
32
|
+
renderOption?: (opt: ComboOption, active: boolean, selected: boolean) => React__default.ReactNode;
|
|
33
|
+
renderSectionHeader?: (sec: ComboSection, sticky: boolean) => React__default.ReactNode;
|
|
34
|
+
portalTarget?: HTMLElement | null;
|
|
35
|
+
closeOnSelect?: boolean;
|
|
36
|
+
keepFocusOnSelect?: boolean;
|
|
37
|
+
clearQueryOnSelect?: boolean;
|
|
38
|
+
renderTags?: React__default.ReactNode;
|
|
39
|
+
/** Si true, las filas pueden tener inputs/botones y el click de fondo dispara onChange */
|
|
40
|
+
interactiveOptions?: boolean;
|
|
41
|
+
/** 🔹 Nuevo: notifica cambios en el texto de búsqueda */
|
|
42
|
+
onQueryChange?: (q: string) => void;
|
|
43
|
+
};
|
|
44
|
+
declare function ComboSelect({ options, sections, value, onChange, placeholder, disabled, loading, allowClear, searchable, maxItems, className, noResultsText, renderOption, renderSectionHeader, portalTarget, closeOnSelect, keepFocusOnSelect, clearQueryOnSelect, renderTags, interactiveOptions, onQueryChange, }: ComboSelectProps): react_jsx_runtime.JSX.Element;
|
|
45
|
+
|
|
46
|
+
export { type ComboOption, type ComboSection, type ComboSelectProps, ComboSelect as default };
|
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var ComboSelect_exports = {};
|
|
31
|
+
__export(ComboSelect_exports, {
|
|
32
|
+
default: () => ComboSelect
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(ComboSelect_exports);
|
|
35
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
36
|
+
var import_react = __toESM(require("react"));
|
|
37
|
+
var import_react_dom = require("react-dom");
|
|
38
|
+
var import_AvatarSquare = __toESM(require("./AvatarSquare"));
|
|
39
|
+
const cx = (...a) => a.filter(Boolean).join(" ");
|
|
40
|
+
const controlShell = "relative w-full rounded-2xl border border-slate-200 bg-white text-sm text-slate-900 placeholder:text-slate-400 shadow-sm outline-none transition focus-within:ring-4 focus-within:ring-slate-900/5 focus-within:border-slate-300 disabled:opacity-60 disabled:cursor-not-allowed dark:border-white/10 dark:bg-white/10 dark:text-slate-100 dark:placeholder:text-slate-400 dark:focus-within:ring-white/10";
|
|
41
|
+
const isFocusableOrInteractive = (el) => {
|
|
42
|
+
if (!el) return false;
|
|
43
|
+
return !!el.closest(
|
|
44
|
+
'button, input, select, textarea, a[href], [role="button"], [contenteditable], [tabindex]:not([tabindex="-1"])'
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
function ComboSelect({
|
|
48
|
+
options = [],
|
|
49
|
+
sections,
|
|
50
|
+
value = null,
|
|
51
|
+
onChange,
|
|
52
|
+
placeholder = "Selecciona\u2026",
|
|
53
|
+
disabled,
|
|
54
|
+
loading,
|
|
55
|
+
allowClear = true,
|
|
56
|
+
searchable = true,
|
|
57
|
+
maxItems = 300,
|
|
58
|
+
className,
|
|
59
|
+
noResultsText = "Sin resultados",
|
|
60
|
+
renderOption,
|
|
61
|
+
renderSectionHeader,
|
|
62
|
+
portalTarget,
|
|
63
|
+
closeOnSelect = true,
|
|
64
|
+
keepFocusOnSelect = false,
|
|
65
|
+
clearQueryOnSelect = true,
|
|
66
|
+
renderTags,
|
|
67
|
+
interactiveOptions = false,
|
|
68
|
+
onQueryChange
|
|
69
|
+
// 🔹 nuevo
|
|
70
|
+
}) {
|
|
71
|
+
var _a;
|
|
72
|
+
const [query, _setQuery] = import_react.default.useState("");
|
|
73
|
+
const [open, setOpen] = import_react.default.useState(false);
|
|
74
|
+
const [activeIdx, setActiveIdx] = import_react.default.useState(0);
|
|
75
|
+
const setQ = import_react.default.useCallback(
|
|
76
|
+
(q) => {
|
|
77
|
+
_setQuery(q);
|
|
78
|
+
onQueryChange == null ? void 0 : onQueryChange(q);
|
|
79
|
+
},
|
|
80
|
+
[onQueryChange]
|
|
81
|
+
);
|
|
82
|
+
const rootRef = import_react.default.useRef(null);
|
|
83
|
+
const inputRef = import_react.default.useRef(null);
|
|
84
|
+
const dropRef = import_react.default.useRef(null);
|
|
85
|
+
const listId = import_react.default.useId();
|
|
86
|
+
const selected = import_react.default.useMemo(() => {
|
|
87
|
+
const flat = sections ? sections.flatMap((s) => s.options) : options;
|
|
88
|
+
return flat.find((o) => o.value === value) || null;
|
|
89
|
+
}, [options, value, sections]);
|
|
90
|
+
import_react.default.useEffect(() => {
|
|
91
|
+
if (!open) return;
|
|
92
|
+
const onFocusIn = (e) => {
|
|
93
|
+
var _a2, _b;
|
|
94
|
+
const t = e.target;
|
|
95
|
+
const insideRoot = !!((_a2 = rootRef.current) == null ? void 0 : _a2.contains(t));
|
|
96
|
+
const insideDrop = !!((_b = dropRef.current) == null ? void 0 : _b.contains(t));
|
|
97
|
+
if (!insideRoot && !insideDrop) setOpen(false);
|
|
98
|
+
};
|
|
99
|
+
document.addEventListener("focusin", onFocusIn);
|
|
100
|
+
return () => document.removeEventListener("focusin", onFocusIn);
|
|
101
|
+
}, [open]);
|
|
102
|
+
const isOutside = import_react.default.useCallback((e) => {
|
|
103
|
+
var _a2;
|
|
104
|
+
const path = (_a2 = e.composedPath) == null ? void 0 : _a2.call(e);
|
|
105
|
+
const t = e.target;
|
|
106
|
+
const inRoot = !!rootRef.current && (rootRef.current.contains(t) || (path == null ? void 0 : path.includes(rootRef.current)));
|
|
107
|
+
const inDrop = !!dropRef.current && (dropRef.current.contains(t) || (path == null ? void 0 : path.includes(dropRef.current)));
|
|
108
|
+
return !(inRoot || inDrop);
|
|
109
|
+
}, []);
|
|
110
|
+
import_react.default.useEffect(() => {
|
|
111
|
+
if (!open) return;
|
|
112
|
+
const onPointerDownCapture = (e) => {
|
|
113
|
+
if (isOutside(e)) setOpen(false);
|
|
114
|
+
};
|
|
115
|
+
window.addEventListener("pointerdown", onPointerDownCapture, true);
|
|
116
|
+
return () => window.removeEventListener("pointerdown", onPointerDownCapture, true);
|
|
117
|
+
}, [open, isOutside]);
|
|
118
|
+
const flatAll = import_react.default.useMemo(() => {
|
|
119
|
+
if (!sections)
|
|
120
|
+
return options.map((opt) => ({ kind: "option", secKey: "__", opt }));
|
|
121
|
+
const rows = [];
|
|
122
|
+
for (const s of sections) {
|
|
123
|
+
rows.push({ kind: "section", sec: s });
|
|
124
|
+
for (const o of s.options) rows.push({ kind: "option", secKey: s.key, opt: o });
|
|
125
|
+
}
|
|
126
|
+
return rows;
|
|
127
|
+
}, [options, sections]);
|
|
128
|
+
const filteredRows = import_react.default.useMemo(() => {
|
|
129
|
+
const q = query.trim().toLowerCase();
|
|
130
|
+
if (!q) return flatAll.slice(0, 2e3);
|
|
131
|
+
const match = (o) => {
|
|
132
|
+
var _a2, _b, _c, _d;
|
|
133
|
+
return o.label.toLowerCase().includes(q) || o.value.toLowerCase().includes(q) || ((_b = (_a2 = o.hint) == null ? void 0 : _a2.toLowerCase().includes(q)) != null ? _b : false) || ((_d = (_c = o.sublabel) == null ? void 0 : _c.toLowerCase().includes(q)) != null ? _d : false);
|
|
134
|
+
};
|
|
135
|
+
if (!sections || sections.length === 0) {
|
|
136
|
+
const opts = flatAll.filter((r) => r.kind === "option" && match(r.opt));
|
|
137
|
+
return opts.slice(0, maxItems);
|
|
138
|
+
}
|
|
139
|
+
const out = [];
|
|
140
|
+
let taken = 0;
|
|
141
|
+
for (const sec of sections) {
|
|
142
|
+
if (taken >= maxItems) break;
|
|
143
|
+
const matches = sec.options.filter(match);
|
|
144
|
+
if (matches.length === 0) continue;
|
|
145
|
+
out.push({ kind: "section", sec });
|
|
146
|
+
for (const opt of matches) {
|
|
147
|
+
if (taken >= maxItems) break;
|
|
148
|
+
out.push({ kind: "option", secKey: sec.key, opt });
|
|
149
|
+
taken++;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return out.length ? out : [];
|
|
153
|
+
}, [query, flatAll, maxItems, sections]);
|
|
154
|
+
import_react.default.useEffect(() => {
|
|
155
|
+
if (!open) setActiveIdx(0);
|
|
156
|
+
}, [open]);
|
|
157
|
+
const afterSelect = () => {
|
|
158
|
+
if (clearQueryOnSelect) setQ("");
|
|
159
|
+
if (closeOnSelect) {
|
|
160
|
+
setOpen(false);
|
|
161
|
+
requestAnimationFrame(() => {
|
|
162
|
+
var _a2;
|
|
163
|
+
return (_a2 = inputRef.current) == null ? void 0 : _a2.blur();
|
|
164
|
+
});
|
|
165
|
+
} else {
|
|
166
|
+
setOpen(true);
|
|
167
|
+
if (keepFocusOnSelect) requestAnimationFrame(() => {
|
|
168
|
+
var _a2;
|
|
169
|
+
return (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
170
|
+
});
|
|
171
|
+
setActiveIdx(0);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
const selectRowAt = (idx) => {
|
|
175
|
+
const row = filteredRows[idx];
|
|
176
|
+
if (!row || row.kind !== "option") return;
|
|
177
|
+
const opt = row.opt;
|
|
178
|
+
if (!opt || opt.disabled) return;
|
|
179
|
+
onChange(opt.value, opt);
|
|
180
|
+
afterSelect();
|
|
181
|
+
};
|
|
182
|
+
const onKeyDown = (e) => {
|
|
183
|
+
if (disabled) return;
|
|
184
|
+
if (!open && (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ")) {
|
|
185
|
+
e.preventDefault();
|
|
186
|
+
setOpen(true);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (!open) return;
|
|
190
|
+
if (e.key === "ArrowDown") {
|
|
191
|
+
e.preventDefault();
|
|
192
|
+
setActiveIdx((i) => Math.min(i + 1, Math.max(filteredRows.length - 1, 0)));
|
|
193
|
+
} else if (e.key === "ArrowUp") {
|
|
194
|
+
e.preventDefault();
|
|
195
|
+
setActiveIdx((i) => Math.max(i - 1, 0));
|
|
196
|
+
} else if (e.key === "Enter") {
|
|
197
|
+
e.preventDefault();
|
|
198
|
+
selectRowAt(activeIdx);
|
|
199
|
+
} else if (e.key === "Escape") setOpen(false);
|
|
200
|
+
};
|
|
201
|
+
const [dropStyle, setDropStyle] = import_react.default.useState(null);
|
|
202
|
+
const portalEl = typeof window !== "undefined" ? portalTarget != null ? portalTarget : document.body : null;
|
|
203
|
+
const updatePosition = import_react.default.useCallback(() => {
|
|
204
|
+
const el = rootRef.current;
|
|
205
|
+
if (!el) return;
|
|
206
|
+
const r = el.getBoundingClientRect();
|
|
207
|
+
const spaceBelow = window.innerHeight - r.bottom - 8;
|
|
208
|
+
const maxH = Math.max(200, Math.min(360, spaceBelow));
|
|
209
|
+
setDropStyle({
|
|
210
|
+
position: "fixed",
|
|
211
|
+
top: r.bottom + 6,
|
|
212
|
+
left: r.left,
|
|
213
|
+
width: r.width,
|
|
214
|
+
maxHeight: maxH,
|
|
215
|
+
zIndex: 1200
|
|
216
|
+
});
|
|
217
|
+
}, []);
|
|
218
|
+
import_react.default.useLayoutEffect(() => {
|
|
219
|
+
if (!open) return;
|
|
220
|
+
updatePosition();
|
|
221
|
+
const onScroll = () => updatePosition();
|
|
222
|
+
const onResize = () => updatePosition();
|
|
223
|
+
window.addEventListener("scroll", onScroll, true);
|
|
224
|
+
window.addEventListener("resize", onResize);
|
|
225
|
+
return () => {
|
|
226
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
227
|
+
window.removeEventListener("resize", onResize);
|
|
228
|
+
};
|
|
229
|
+
}, [open, updatePosition]);
|
|
230
|
+
const DefaultRow = (opt, isActive, isSel) => {
|
|
231
|
+
var _a2;
|
|
232
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
233
|
+
"div",
|
|
234
|
+
{
|
|
235
|
+
className: cx(
|
|
236
|
+
"flex items-center justify-between gap-3",
|
|
237
|
+
isActive ? "bg-slate-50 dark:bg-white/10" : "hover:bg-slate-50 dark:hover:bg-white/5"
|
|
238
|
+
),
|
|
239
|
+
children: [
|
|
240
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex items-center gap-3", children: [
|
|
241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
242
|
+
import_AvatarSquare.default,
|
|
243
|
+
{
|
|
244
|
+
size: 40,
|
|
245
|
+
src: (_a2 = opt.image) != null ? _a2 : void 0,
|
|
246
|
+
alt: opt.label,
|
|
247
|
+
className: "ring-1 ring-black/5",
|
|
248
|
+
radiusClass: "rounded-lg"
|
|
249
|
+
}
|
|
250
|
+
),
|
|
251
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0", children: [
|
|
252
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "truncate font-medium", children: opt.label }),
|
|
253
|
+
opt.sublabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "truncate text-xs text-slate-500", children: opt.sublabel }) : opt.hint ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "truncate text-xs text-slate-500", children: opt.hint }) : null
|
|
254
|
+
] })
|
|
255
|
+
] }),
|
|
256
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex shrink-0 items-center gap-3", children: [
|
|
257
|
+
opt.right != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-xs text-slate-600", children: opt.right }) : null,
|
|
258
|
+
isSel && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m5 12 4 4L19 6" }) })
|
|
259
|
+
] })
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
};
|
|
264
|
+
const DefaultSectionHeader = (sec, sticky) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
265
|
+
"div",
|
|
266
|
+
{
|
|
267
|
+
className: cx(
|
|
268
|
+
"px-3 py-1.5 text-[11px] font-semibold text-slate-700 flex items-center justify-between",
|
|
269
|
+
sticky ? "bg-white/80 backdrop-blur supports-[backdrop-filter]:backdrop-blur sticky top-0 z-10 border-b border-slate-100" : "bg-slate-50 dark:bg-white/5"
|
|
270
|
+
),
|
|
271
|
+
children: [
|
|
272
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: sec.title }),
|
|
273
|
+
sec.rightHint ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-2 shrink-0 text-[10px] text-slate-600", children: sec.rightHint }) : null
|
|
274
|
+
]
|
|
275
|
+
}
|
|
276
|
+
);
|
|
277
|
+
const dropdown = open && dropStyle ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
278
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
279
|
+
"div",
|
|
280
|
+
{
|
|
281
|
+
className: "fixed inset-0",
|
|
282
|
+
style: { zIndex: 1199 },
|
|
283
|
+
onMouseDown: () => {
|
|
284
|
+
setOpen(false);
|
|
285
|
+
setQ("");
|
|
286
|
+
},
|
|
287
|
+
onContextMenu: () => {
|
|
288
|
+
setOpen(false);
|
|
289
|
+
setQ("");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
),
|
|
293
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
294
|
+
"div",
|
|
295
|
+
{
|
|
296
|
+
ref: dropRef,
|
|
297
|
+
role: "listbox",
|
|
298
|
+
id: listId,
|
|
299
|
+
style: dropStyle,
|
|
300
|
+
className: "overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-xl dark:border-white/10 dark:bg-[#0f0d0e]",
|
|
301
|
+
children: filteredRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "px-3 py-2 text-sm text-slate-500", children: noResultsText }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "max-h-[inherit] overflow-auto py-1 text-sm", children: filteredRows.map((row, i) => {
|
|
302
|
+
if (row.kind === "section") {
|
|
303
|
+
const Header = renderSectionHeader != null ? renderSectionHeader : DefaultSectionHeader;
|
|
304
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { "aria-hidden": true, className: "sticky top-0 z-10", children: Header(row.sec, true) }, `sec-${row.sec.key}`);
|
|
305
|
+
}
|
|
306
|
+
const opt = row.opt;
|
|
307
|
+
const isSel = opt.value === value;
|
|
308
|
+
const isActive = i === activeIdx;
|
|
309
|
+
const handleRowClick = (e) => {
|
|
310
|
+
if (opt.disabled) return;
|
|
311
|
+
if (isFocusableOrInteractive(e.target)) return;
|
|
312
|
+
if (interactiveOptions) {
|
|
313
|
+
onChange(opt.value, opt);
|
|
314
|
+
if (clearQueryOnSelect) setQ("");
|
|
315
|
+
if (closeOnSelect) {
|
|
316
|
+
setOpen(false);
|
|
317
|
+
requestAnimationFrame(() => {
|
|
318
|
+
var _a2;
|
|
319
|
+
return (_a2 = inputRef.current) == null ? void 0 : _a2.blur();
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
setActiveIdx(0);
|
|
323
|
+
} else {
|
|
324
|
+
selectRowAt(i);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
const commonProps = {
|
|
328
|
+
id: `${listId}-opt-${i}`,
|
|
329
|
+
role: "option",
|
|
330
|
+
"aria-selected": isSel,
|
|
331
|
+
onMouseDown: (e) => {
|
|
332
|
+
if (!isFocusableOrInteractive(e.target)) e.preventDefault();
|
|
333
|
+
},
|
|
334
|
+
onMouseEnter: () => setActiveIdx(i),
|
|
335
|
+
className: cx(
|
|
336
|
+
"px-3 py-2",
|
|
337
|
+
!interactiveOptions && "cursor-pointer",
|
|
338
|
+
isActive ? "bg-slate-50 dark:bg-white/10" : "hover:bg-slate-50 dark:hover:bg-white/5",
|
|
339
|
+
opt.disabled && "opacity-50 cursor-not-allowed"
|
|
340
|
+
),
|
|
341
|
+
onClick: handleRowClick
|
|
342
|
+
};
|
|
343
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { ...commonProps, children: renderOption ? renderOption(opt, isActive, isSel) : DefaultRow(opt, isActive, isSel) }, `${row.secKey}-${opt.value}`);
|
|
344
|
+
}) })
|
|
345
|
+
}
|
|
346
|
+
)
|
|
347
|
+
] }) : null;
|
|
348
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
349
|
+
"div",
|
|
350
|
+
{
|
|
351
|
+
className: cx("relative", className),
|
|
352
|
+
ref: rootRef,
|
|
353
|
+
onMouseDown: () => {
|
|
354
|
+
if (!disabled) requestAnimationFrame(() => {
|
|
355
|
+
var _a2;
|
|
356
|
+
return (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
357
|
+
});
|
|
358
|
+
},
|
|
359
|
+
children: [
|
|
360
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx(controlShell, "pr-20 pl-3 py-2 min-h-[44px] flex flex-wrap items-center gap-2"), children: [
|
|
361
|
+
renderTags,
|
|
362
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
363
|
+
"input",
|
|
364
|
+
{
|
|
365
|
+
ref: inputRef,
|
|
366
|
+
role: "combobox",
|
|
367
|
+
"aria-haspopup": "listbox",
|
|
368
|
+
"aria-expanded": open,
|
|
369
|
+
"aria-controls": listId,
|
|
370
|
+
"aria-autocomplete": "list",
|
|
371
|
+
"aria-activedescendant": open ? `${listId}-opt-${activeIdx}` : void 0,
|
|
372
|
+
value: open ? query : (_a = selected == null ? void 0 : selected.label) != null ? _a : "",
|
|
373
|
+
onChange: (e) => {
|
|
374
|
+
if (!searchable) return;
|
|
375
|
+
setQ(e.target.value);
|
|
376
|
+
if (!open) setOpen(true);
|
|
377
|
+
},
|
|
378
|
+
onFocus: () => setOpen(true),
|
|
379
|
+
onKeyDown,
|
|
380
|
+
placeholder,
|
|
381
|
+
readOnly: !searchable,
|
|
382
|
+
disabled,
|
|
383
|
+
autoComplete: "off",
|
|
384
|
+
spellCheck: false,
|
|
385
|
+
className: cx("flex-1 min-w-[160px] bg-transparent outline-none border-0 p-0 py-1 text-sm", open && "ring-0")
|
|
386
|
+
}
|
|
387
|
+
)
|
|
388
|
+
] }),
|
|
389
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-1.5 pointer-events-none", children: [
|
|
390
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pointer-events-none text-xs text-slate-400", children: "cargando\u2026" }),
|
|
391
|
+
allowClear && value != null && !disabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
392
|
+
"button",
|
|
393
|
+
{
|
|
394
|
+
type: "button",
|
|
395
|
+
title: "Limpiar",
|
|
396
|
+
className: "pointer-events-auto inline-flex h-7 w-7 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-600 hover:bg-slate-50 active:scale-95 dark:border-white/10 dark:bg-white/5",
|
|
397
|
+
onMouseDown: (e) => {
|
|
398
|
+
e.preventDefault();
|
|
399
|
+
e.stopPropagation();
|
|
400
|
+
},
|
|
401
|
+
onClick: (e) => {
|
|
402
|
+
e.preventDefault();
|
|
403
|
+
e.stopPropagation();
|
|
404
|
+
onChange(null, void 0);
|
|
405
|
+
setQ("");
|
|
406
|
+
setActiveIdx(0);
|
|
407
|
+
setOpen(false);
|
|
408
|
+
requestAnimationFrame(() => {
|
|
409
|
+
var _a2;
|
|
410
|
+
return (_a2 = inputRef.current) == null ? void 0 : _a2.blur();
|
|
411
|
+
});
|
|
412
|
+
},
|
|
413
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18 6L6 18M6 6l12 12" }) })
|
|
414
|
+
}
|
|
415
|
+
),
|
|
416
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
417
|
+
"button",
|
|
418
|
+
{
|
|
419
|
+
type: "button",
|
|
420
|
+
title: open ? "Cerrar" : "Abrir",
|
|
421
|
+
className: "pointer-events-auto inline-flex h-7 w-7 items-center justify-center rounded-lg border border-slate-200 bg-white text-slate-600 hover:bg-slate-50 active:scale-95 dark:border-white/10 dark:bg-white/5",
|
|
422
|
+
onMouseDown: (e) => {
|
|
423
|
+
e.preventDefault();
|
|
424
|
+
e.stopPropagation();
|
|
425
|
+
},
|
|
426
|
+
onClick: () => {
|
|
427
|
+
setOpen((o) => !o);
|
|
428
|
+
if (!open) requestAnimationFrame(() => {
|
|
429
|
+
var _a2;
|
|
430
|
+
return (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
|
|
431
|
+
});
|
|
432
|
+
},
|
|
433
|
+
tabIndex: -1,
|
|
434
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", className: cx("h-4 w-4 transition", open && "rotate-180"), fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6 9 6 6 6-6" }) })
|
|
435
|
+
}
|
|
436
|
+
)
|
|
437
|
+
] }),
|
|
438
|
+
portalEl ? (0, import_react_dom.createPortal)(dropdown, portalEl) : dropdown
|
|
439
|
+
]
|
|
440
|
+
}
|
|
441
|
+
);
|
|
442
|
+
}
|