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.
Files changed (125) hide show
  1. package/dist/ActionIconButton.d.mts +11 -0
  2. package/dist/ActionIconButton.d.ts +11 -0
  3. package/dist/ActionIconButton.js +71 -0
  4. package/dist/ActionIconButton.mjs +41 -0
  5. package/dist/AppTopbar.d.mts +17 -0
  6. package/dist/AppTopbar.d.ts +17 -0
  7. package/dist/AppTopbar.js +51 -0
  8. package/dist/AppTopbar.mjs +31 -0
  9. package/dist/AvatarSquare.d.mts +16 -0
  10. package/dist/AvatarSquare.d.ts +16 -0
  11. package/dist/AvatarSquare.js +82 -0
  12. package/dist/AvatarSquare.mjs +52 -0
  13. package/dist/Badge.d.mts +13 -0
  14. package/dist/Badge.d.ts +13 -0
  15. package/dist/Badge.js +65 -0
  16. package/dist/Badge.mjs +45 -0
  17. package/dist/BadgeCluster.d.mts +17 -0
  18. package/dist/BadgeCluster.d.ts +17 -0
  19. package/dist/BadgeCluster.js +125 -0
  20. package/dist/BadgeCluster.mjs +95 -0
  21. package/dist/Breadcrumb.d.mts +11 -0
  22. package/dist/Breadcrumb.d.ts +11 -0
  23. package/dist/Breadcrumb.js +42 -0
  24. package/dist/Breadcrumb.mjs +12 -0
  25. package/dist/Button.d.mts +15 -0
  26. package/dist/Button.d.ts +15 -0
  27. package/dist/Button.js +72 -0
  28. package/dist/Button.mjs +52 -0
  29. package/dist/CalendarPanel.d.mts +13 -0
  30. package/dist/CalendarPanel.d.ts +13 -0
  31. package/dist/CalendarPanel.js +110 -0
  32. package/dist/CalendarPanel.mjs +90 -0
  33. package/dist/ChartCard.d.mts +15 -0
  34. package/dist/ChartCard.d.ts +15 -0
  35. package/dist/ChartCard.js +44 -0
  36. package/dist/ChartCard.mjs +24 -0
  37. package/dist/CheckboxPillsGroup.d.mts +28 -0
  38. package/dist/CheckboxPillsGroup.d.ts +28 -0
  39. package/dist/CheckboxPillsGroup.js +186 -0
  40. package/dist/CheckboxPillsGroup.mjs +156 -0
  41. package/dist/ColumnSelector.d.mts +17 -0
  42. package/dist/ColumnSelector.d.ts +17 -0
  43. package/dist/ColumnSelector.js +74 -0
  44. package/dist/ColumnSelector.mjs +54 -0
  45. package/dist/ComboSelect.d.mts +46 -0
  46. package/dist/ComboSelect.d.ts +46 -0
  47. package/dist/ComboSelect.js +442 -0
  48. package/dist/ComboSelect.mjs +412 -0
  49. package/dist/DateTimeField.d.mts +22 -0
  50. package/dist/DateTimeField.d.ts +22 -0
  51. package/dist/DateTimeField.js +409 -0
  52. package/dist/DateTimeField.mjs +379 -0
  53. package/dist/Dialog.d.mts +82 -0
  54. package/dist/Dialog.d.ts +82 -0
  55. package/dist/Dialog.js +408 -0
  56. package/dist/Dialog.mjs +368 -0
  57. package/dist/Dropdown.d.mts +52 -0
  58. package/dist/Dropdown.d.ts +52 -0
  59. package/dist/Dropdown.js +333 -0
  60. package/dist/Dropdown.mjs +313 -0
  61. package/dist/EmptyState.d.mts +8 -0
  62. package/dist/EmptyState.d.ts +8 -0
  63. package/dist/EmptyState.js +35 -0
  64. package/dist/EmptyState.mjs +15 -0
  65. package/dist/InfoGrid.d.mts +20 -0
  66. package/dist/InfoGrid.d.ts +20 -0
  67. package/dist/InfoGrid.js +67 -0
  68. package/dist/InfoGrid.mjs +47 -0
  69. package/dist/Input.d.mts +20 -0
  70. package/dist/Input.d.ts +20 -0
  71. package/dist/Input.js +85 -0
  72. package/dist/Input.mjs +55 -0
  73. package/dist/Money.d.mts +8 -0
  74. package/dist/Money.d.ts +8 -0
  75. package/dist/Money.js +30 -0
  76. package/dist/Money.mjs +10 -0
  77. package/dist/OrderButton.d.mts +11 -0
  78. package/dist/OrderButton.d.ts +11 -0
  79. package/dist/OrderButton.js +39 -0
  80. package/dist/OrderButton.mjs +19 -0
  81. package/dist/Pagination.d.mts +12 -0
  82. package/dist/Pagination.d.ts +12 -0
  83. package/dist/Pagination.js +71 -0
  84. package/dist/Pagination.mjs +51 -0
  85. package/dist/SearchInput.d.mts +17 -0
  86. package/dist/SearchInput.d.ts +17 -0
  87. package/dist/SearchInput.js +116 -0
  88. package/dist/SearchInput.mjs +86 -0
  89. package/dist/Select.d.mts +31 -0
  90. package/dist/Select.d.ts +31 -0
  91. package/dist/Select.js +293 -0
  92. package/dist/Select.mjs +263 -0
  93. package/dist/StatCard.d.mts +15 -0
  94. package/dist/StatCard.d.ts +15 -0
  95. package/dist/StatCard.js +47 -0
  96. package/dist/StatCard.mjs +27 -0
  97. package/dist/Steps.d.mts +31 -0
  98. package/dist/Steps.d.ts +31 -0
  99. package/dist/Steps.js +123 -0
  100. package/dist/Steps.mjs +99 -0
  101. package/dist/Table.d.mts +31 -0
  102. package/dist/Table.d.ts +31 -0
  103. package/dist/Table.js +153 -0
  104. package/dist/Table.mjs +117 -0
  105. package/dist/TimeAgo.d.mts +12 -0
  106. package/dist/TimeAgo.d.ts +12 -0
  107. package/dist/TimeAgo.js +104 -0
  108. package/dist/TimeAgo.mjs +74 -0
  109. package/dist/TimePanel.d.mts +14 -0
  110. package/dist/TimePanel.d.ts +14 -0
  111. package/dist/TimePanel.js +145 -0
  112. package/dist/TimePanel.mjs +125 -0
  113. package/dist/TimePopover.d.mts +33 -0
  114. package/dist/TimePopover.d.ts +33 -0
  115. package/dist/TimePopover.js +441 -0
  116. package/dist/TimePopover.mjs +406 -0
  117. package/dist/iconos/index.d.mts +60 -0
  118. package/dist/iconos/index.d.ts +60 -0
  119. package/dist/iconos/index.js +621 -0
  120. package/dist/iconos/index.mjs +548 -0
  121. package/dist/index.d.mts +32 -0
  122. package/dist/index.d.ts +32 -0
  123. package/dist/index.js +141 -0
  124. package/dist/index.mjs +70 -0
  125. package/package.json +178 -0
@@ -0,0 +1,412 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import { createPortal } from "react-dom";
5
+ import AvatarSquare from "./AvatarSquare";
6
+ const cx = (...a) => a.filter(Boolean).join(" ");
7
+ 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";
8
+ const isFocusableOrInteractive = (el) => {
9
+ if (!el) return false;
10
+ return !!el.closest(
11
+ 'button, input, select, textarea, a[href], [role="button"], [contenteditable], [tabindex]:not([tabindex="-1"])'
12
+ );
13
+ };
14
+ function ComboSelect({
15
+ options = [],
16
+ sections,
17
+ value = null,
18
+ onChange,
19
+ placeholder = "Selecciona\u2026",
20
+ disabled,
21
+ loading,
22
+ allowClear = true,
23
+ searchable = true,
24
+ maxItems = 300,
25
+ className,
26
+ noResultsText = "Sin resultados",
27
+ renderOption,
28
+ renderSectionHeader,
29
+ portalTarget,
30
+ closeOnSelect = true,
31
+ keepFocusOnSelect = false,
32
+ clearQueryOnSelect = true,
33
+ renderTags,
34
+ interactiveOptions = false,
35
+ onQueryChange
36
+ // 🔹 nuevo
37
+ }) {
38
+ var _a;
39
+ const [query, _setQuery] = React.useState("");
40
+ const [open, setOpen] = React.useState(false);
41
+ const [activeIdx, setActiveIdx] = React.useState(0);
42
+ const setQ = React.useCallback(
43
+ (q) => {
44
+ _setQuery(q);
45
+ onQueryChange == null ? void 0 : onQueryChange(q);
46
+ },
47
+ [onQueryChange]
48
+ );
49
+ const rootRef = React.useRef(null);
50
+ const inputRef = React.useRef(null);
51
+ const dropRef = React.useRef(null);
52
+ const listId = React.useId();
53
+ const selected = React.useMemo(() => {
54
+ const flat = sections ? sections.flatMap((s) => s.options) : options;
55
+ return flat.find((o) => o.value === value) || null;
56
+ }, [options, value, sections]);
57
+ React.useEffect(() => {
58
+ if (!open) return;
59
+ const onFocusIn = (e) => {
60
+ var _a2, _b;
61
+ const t = e.target;
62
+ const insideRoot = !!((_a2 = rootRef.current) == null ? void 0 : _a2.contains(t));
63
+ const insideDrop = !!((_b = dropRef.current) == null ? void 0 : _b.contains(t));
64
+ if (!insideRoot && !insideDrop) setOpen(false);
65
+ };
66
+ document.addEventListener("focusin", onFocusIn);
67
+ return () => document.removeEventListener("focusin", onFocusIn);
68
+ }, [open]);
69
+ const isOutside = React.useCallback((e) => {
70
+ var _a2;
71
+ const path = (_a2 = e.composedPath) == null ? void 0 : _a2.call(e);
72
+ const t = e.target;
73
+ const inRoot = !!rootRef.current && (rootRef.current.contains(t) || (path == null ? void 0 : path.includes(rootRef.current)));
74
+ const inDrop = !!dropRef.current && (dropRef.current.contains(t) || (path == null ? void 0 : path.includes(dropRef.current)));
75
+ return !(inRoot || inDrop);
76
+ }, []);
77
+ React.useEffect(() => {
78
+ if (!open) return;
79
+ const onPointerDownCapture = (e) => {
80
+ if (isOutside(e)) setOpen(false);
81
+ };
82
+ window.addEventListener("pointerdown", onPointerDownCapture, true);
83
+ return () => window.removeEventListener("pointerdown", onPointerDownCapture, true);
84
+ }, [open, isOutside]);
85
+ const flatAll = React.useMemo(() => {
86
+ if (!sections)
87
+ return options.map((opt) => ({ kind: "option", secKey: "__", opt }));
88
+ const rows = [];
89
+ for (const s of sections) {
90
+ rows.push({ kind: "section", sec: s });
91
+ for (const o of s.options) rows.push({ kind: "option", secKey: s.key, opt: o });
92
+ }
93
+ return rows;
94
+ }, [options, sections]);
95
+ const filteredRows = React.useMemo(() => {
96
+ const q = query.trim().toLowerCase();
97
+ if (!q) return flatAll.slice(0, 2e3);
98
+ const match = (o) => {
99
+ var _a2, _b, _c, _d;
100
+ 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);
101
+ };
102
+ if (!sections || sections.length === 0) {
103
+ const opts = flatAll.filter((r) => r.kind === "option" && match(r.opt));
104
+ return opts.slice(0, maxItems);
105
+ }
106
+ const out = [];
107
+ let taken = 0;
108
+ for (const sec of sections) {
109
+ if (taken >= maxItems) break;
110
+ const matches = sec.options.filter(match);
111
+ if (matches.length === 0) continue;
112
+ out.push({ kind: "section", sec });
113
+ for (const opt of matches) {
114
+ if (taken >= maxItems) break;
115
+ out.push({ kind: "option", secKey: sec.key, opt });
116
+ taken++;
117
+ }
118
+ }
119
+ return out.length ? out : [];
120
+ }, [query, flatAll, maxItems, sections]);
121
+ React.useEffect(() => {
122
+ if (!open) setActiveIdx(0);
123
+ }, [open]);
124
+ const afterSelect = () => {
125
+ if (clearQueryOnSelect) setQ("");
126
+ if (closeOnSelect) {
127
+ setOpen(false);
128
+ requestAnimationFrame(() => {
129
+ var _a2;
130
+ return (_a2 = inputRef.current) == null ? void 0 : _a2.blur();
131
+ });
132
+ } else {
133
+ setOpen(true);
134
+ if (keepFocusOnSelect) requestAnimationFrame(() => {
135
+ var _a2;
136
+ return (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
137
+ });
138
+ setActiveIdx(0);
139
+ }
140
+ };
141
+ const selectRowAt = (idx) => {
142
+ const row = filteredRows[idx];
143
+ if (!row || row.kind !== "option") return;
144
+ const opt = row.opt;
145
+ if (!opt || opt.disabled) return;
146
+ onChange(opt.value, opt);
147
+ afterSelect();
148
+ };
149
+ const onKeyDown = (e) => {
150
+ if (disabled) return;
151
+ if (!open && (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ")) {
152
+ e.preventDefault();
153
+ setOpen(true);
154
+ return;
155
+ }
156
+ if (!open) return;
157
+ if (e.key === "ArrowDown") {
158
+ e.preventDefault();
159
+ setActiveIdx((i) => Math.min(i + 1, Math.max(filteredRows.length - 1, 0)));
160
+ } else if (e.key === "ArrowUp") {
161
+ e.preventDefault();
162
+ setActiveIdx((i) => Math.max(i - 1, 0));
163
+ } else if (e.key === "Enter") {
164
+ e.preventDefault();
165
+ selectRowAt(activeIdx);
166
+ } else if (e.key === "Escape") setOpen(false);
167
+ };
168
+ const [dropStyle, setDropStyle] = React.useState(null);
169
+ const portalEl = typeof window !== "undefined" ? portalTarget != null ? portalTarget : document.body : null;
170
+ const updatePosition = React.useCallback(() => {
171
+ const el = rootRef.current;
172
+ if (!el) return;
173
+ const r = el.getBoundingClientRect();
174
+ const spaceBelow = window.innerHeight - r.bottom - 8;
175
+ const maxH = Math.max(200, Math.min(360, spaceBelow));
176
+ setDropStyle({
177
+ position: "fixed",
178
+ top: r.bottom + 6,
179
+ left: r.left,
180
+ width: r.width,
181
+ maxHeight: maxH,
182
+ zIndex: 1200
183
+ });
184
+ }, []);
185
+ React.useLayoutEffect(() => {
186
+ if (!open) return;
187
+ updatePosition();
188
+ const onScroll = () => updatePosition();
189
+ const onResize = () => updatePosition();
190
+ window.addEventListener("scroll", onScroll, true);
191
+ window.addEventListener("resize", onResize);
192
+ return () => {
193
+ window.removeEventListener("scroll", onScroll, true);
194
+ window.removeEventListener("resize", onResize);
195
+ };
196
+ }, [open, updatePosition]);
197
+ const DefaultRow = (opt, isActive, isSel) => {
198
+ var _a2;
199
+ return /* @__PURE__ */ jsxs(
200
+ "div",
201
+ {
202
+ className: cx(
203
+ "flex items-center justify-between gap-3",
204
+ isActive ? "bg-slate-50 dark:bg-white/10" : "hover:bg-slate-50 dark:hover:bg-white/5"
205
+ ),
206
+ children: [
207
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex items-center gap-3", children: [
208
+ /* @__PURE__ */ jsx(
209
+ AvatarSquare,
210
+ {
211
+ size: 40,
212
+ src: (_a2 = opt.image) != null ? _a2 : void 0,
213
+ alt: opt.label,
214
+ className: "ring-1 ring-black/5",
215
+ radiusClass: "rounded-lg"
216
+ }
217
+ ),
218
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
219
+ /* @__PURE__ */ jsx("div", { className: "truncate font-medium", children: opt.label }),
220
+ opt.sublabel ? /* @__PURE__ */ jsx("div", { className: "truncate text-xs text-slate-500", children: opt.sublabel }) : opt.hint ? /* @__PURE__ */ jsx("div", { className: "truncate text-xs text-slate-500", children: opt.hint }) : null
221
+ ] })
222
+ ] }),
223
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-3", children: [
224
+ opt.right != null ? /* @__PURE__ */ jsx("div", { className: "text-xs text-slate-600", children: opt.right }) : null,
225
+ isSel && /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { d: "m5 12 4 4L19 6" }) })
226
+ ] })
227
+ ]
228
+ }
229
+ );
230
+ };
231
+ const DefaultSectionHeader = (sec, sticky) => /* @__PURE__ */ jsxs(
232
+ "div",
233
+ {
234
+ className: cx(
235
+ "px-3 py-1.5 text-[11px] font-semibold text-slate-700 flex items-center justify-between",
236
+ 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"
237
+ ),
238
+ children: [
239
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: sec.title }),
240
+ sec.rightHint ? /* @__PURE__ */ jsx("span", { className: "ml-2 shrink-0 text-[10px] text-slate-600", children: sec.rightHint }) : null
241
+ ]
242
+ }
243
+ );
244
+ const dropdown = open && dropStyle ? /* @__PURE__ */ jsxs(Fragment, { children: [
245
+ /* @__PURE__ */ jsx(
246
+ "div",
247
+ {
248
+ className: "fixed inset-0",
249
+ style: { zIndex: 1199 },
250
+ onMouseDown: () => {
251
+ setOpen(false);
252
+ setQ("");
253
+ },
254
+ onContextMenu: () => {
255
+ setOpen(false);
256
+ setQ("");
257
+ }
258
+ }
259
+ ),
260
+ /* @__PURE__ */ jsx(
261
+ "div",
262
+ {
263
+ ref: dropRef,
264
+ role: "listbox",
265
+ id: listId,
266
+ style: dropStyle,
267
+ className: "overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-xl dark:border-white/10 dark:bg-[#0f0d0e]",
268
+ children: filteredRows.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-sm text-slate-500", children: noResultsText }) : /* @__PURE__ */ jsx("ul", { className: "max-h-[inherit] overflow-auto py-1 text-sm", children: filteredRows.map((row, i) => {
269
+ if (row.kind === "section") {
270
+ const Header = renderSectionHeader != null ? renderSectionHeader : DefaultSectionHeader;
271
+ return /* @__PURE__ */ jsx("li", { "aria-hidden": true, className: "sticky top-0 z-10", children: Header(row.sec, true) }, `sec-${row.sec.key}`);
272
+ }
273
+ const opt = row.opt;
274
+ const isSel = opt.value === value;
275
+ const isActive = i === activeIdx;
276
+ const handleRowClick = (e) => {
277
+ if (opt.disabled) return;
278
+ if (isFocusableOrInteractive(e.target)) return;
279
+ if (interactiveOptions) {
280
+ onChange(opt.value, opt);
281
+ if (clearQueryOnSelect) setQ("");
282
+ if (closeOnSelect) {
283
+ setOpen(false);
284
+ requestAnimationFrame(() => {
285
+ var _a2;
286
+ return (_a2 = inputRef.current) == null ? void 0 : _a2.blur();
287
+ });
288
+ }
289
+ setActiveIdx(0);
290
+ } else {
291
+ selectRowAt(i);
292
+ }
293
+ };
294
+ const commonProps = {
295
+ id: `${listId}-opt-${i}`,
296
+ role: "option",
297
+ "aria-selected": isSel,
298
+ onMouseDown: (e) => {
299
+ if (!isFocusableOrInteractive(e.target)) e.preventDefault();
300
+ },
301
+ onMouseEnter: () => setActiveIdx(i),
302
+ className: cx(
303
+ "px-3 py-2",
304
+ !interactiveOptions && "cursor-pointer",
305
+ isActive ? "bg-slate-50 dark:bg-white/10" : "hover:bg-slate-50 dark:hover:bg-white/5",
306
+ opt.disabled && "opacity-50 cursor-not-allowed"
307
+ ),
308
+ onClick: handleRowClick
309
+ };
310
+ return /* @__PURE__ */ jsx("li", { ...commonProps, children: renderOption ? renderOption(opt, isActive, isSel) : DefaultRow(opt, isActive, isSel) }, `${row.secKey}-${opt.value}`);
311
+ }) })
312
+ }
313
+ )
314
+ ] }) : null;
315
+ return /* @__PURE__ */ jsxs(
316
+ "div",
317
+ {
318
+ className: cx("relative", className),
319
+ ref: rootRef,
320
+ onMouseDown: () => {
321
+ if (!disabled) requestAnimationFrame(() => {
322
+ var _a2;
323
+ return (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
324
+ });
325
+ },
326
+ children: [
327
+ /* @__PURE__ */ jsxs("div", { className: cx(controlShell, "pr-20 pl-3 py-2 min-h-[44px] flex flex-wrap items-center gap-2"), children: [
328
+ renderTags,
329
+ /* @__PURE__ */ jsx(
330
+ "input",
331
+ {
332
+ ref: inputRef,
333
+ role: "combobox",
334
+ "aria-haspopup": "listbox",
335
+ "aria-expanded": open,
336
+ "aria-controls": listId,
337
+ "aria-autocomplete": "list",
338
+ "aria-activedescendant": open ? `${listId}-opt-${activeIdx}` : void 0,
339
+ value: open ? query : (_a = selected == null ? void 0 : selected.label) != null ? _a : "",
340
+ onChange: (e) => {
341
+ if (!searchable) return;
342
+ setQ(e.target.value);
343
+ if (!open) setOpen(true);
344
+ },
345
+ onFocus: () => setOpen(true),
346
+ onKeyDown,
347
+ placeholder,
348
+ readOnly: !searchable,
349
+ disabled,
350
+ autoComplete: "off",
351
+ spellCheck: false,
352
+ className: cx("flex-1 min-w-[160px] bg-transparent outline-none border-0 p-0 py-1 text-sm", open && "ring-0")
353
+ }
354
+ )
355
+ ] }),
356
+ /* @__PURE__ */ jsxs("div", { className: "absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-1.5 pointer-events-none", children: [
357
+ loading && /* @__PURE__ */ jsx("span", { className: "pointer-events-none text-xs text-slate-400", children: "cargando\u2026" }),
358
+ allowClear && value != null && !disabled && /* @__PURE__ */ jsx(
359
+ "button",
360
+ {
361
+ type: "button",
362
+ title: "Limpiar",
363
+ 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",
364
+ onMouseDown: (e) => {
365
+ e.preventDefault();
366
+ e.stopPropagation();
367
+ },
368
+ onClick: (e) => {
369
+ e.preventDefault();
370
+ e.stopPropagation();
371
+ onChange(null, void 0);
372
+ setQ("");
373
+ setActiveIdx(0);
374
+ setOpen(false);
375
+ requestAnimationFrame(() => {
376
+ var _a2;
377
+ return (_a2 = inputRef.current) == null ? void 0 : _a2.blur();
378
+ });
379
+ },
380
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" }) })
381
+ }
382
+ ),
383
+ /* @__PURE__ */ jsx(
384
+ "button",
385
+ {
386
+ type: "button",
387
+ title: open ? "Cerrar" : "Abrir",
388
+ 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",
389
+ onMouseDown: (e) => {
390
+ e.preventDefault();
391
+ e.stopPropagation();
392
+ },
393
+ onClick: () => {
394
+ setOpen((o) => !o);
395
+ if (!open) requestAnimationFrame(() => {
396
+ var _a2;
397
+ return (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
398
+ });
399
+ },
400
+ tabIndex: -1,
401
+ children: /* @__PURE__ */ 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__ */ jsx("path", { d: "m6 9 6 6 6-6" }) })
402
+ }
403
+ )
404
+ ] }),
405
+ portalEl ? createPortal(dropdown, portalEl) : dropdown
406
+ ]
407
+ }
408
+ );
409
+ }
410
+ export {
411
+ ComboSelect as default
412
+ };
@@ -0,0 +1,22 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React__default from 'react';
3
+
4
+ type PickerMode = "date" | "datetime-local" | "time";
5
+ type DateTimeFieldProps = Omit<React__default.InputHTMLAttributes<HTMLInputElement>, "type" | "value" | "onChange"> & {
6
+ type?: PickerMode;
7
+ /** ISO para date/datetime-local, HH:mm para time; o null */
8
+ value?: string | null;
9
+ min?: string;
10
+ max?: string;
11
+ /** Cambio por valor (recomendado) */
12
+ onValueChange?: (next: string | null) => void;
13
+ /** Si true, usa portal (document.body o portalId) */
14
+ portal?: boolean;
15
+ /** id del contenedor de portal (opcional) */
16
+ portalId?: string;
17
+ /** muestra botón de limpiar en el Input */
18
+ clearable?: boolean;
19
+ };
20
+ declare function DateTimeField({ type, value, min, max, onValueChange, portal, portalId, clearable, ...inputProps }: DateTimeFieldProps): react_jsx_runtime.JSX.Element;
21
+
22
+ export { type DateTimeFieldProps, DateTimeField as default };
@@ -0,0 +1,22 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React__default from 'react';
3
+
4
+ type PickerMode = "date" | "datetime-local" | "time";
5
+ type DateTimeFieldProps = Omit<React__default.InputHTMLAttributes<HTMLInputElement>, "type" | "value" | "onChange"> & {
6
+ type?: PickerMode;
7
+ /** ISO para date/datetime-local, HH:mm para time; o null */
8
+ value?: string | null;
9
+ min?: string;
10
+ max?: string;
11
+ /** Cambio por valor (recomendado) */
12
+ onValueChange?: (next: string | null) => void;
13
+ /** Si true, usa portal (document.body o portalId) */
14
+ portal?: boolean;
15
+ /** id del contenedor de portal (opcional) */
16
+ portalId?: string;
17
+ /** muestra botón de limpiar en el Input */
18
+ clearable?: boolean;
19
+ };
20
+ declare function DateTimeField({ type, value, min, max, onValueChange, portal, portalId, clearable, ...inputProps }: DateTimeFieldProps): react_jsx_runtime.JSX.Element;
21
+
22
+ export { type DateTimeFieldProps, DateTimeField as default };