framepexls-ui-lib 0.3.7 → 0.3.9

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.
@@ -74,6 +74,7 @@ function ComboSelect({
74
74
  var _a;
75
75
  const [query, _setQuery] = import_react.default.useState("");
76
76
  const [open, setOpen] = import_react.default.useState(false);
77
+ const closingUntil = import_react.default.useRef(0);
77
78
  const [activeIdx, setActiveIdx] = import_react.default.useState(0);
78
79
  const setQ = import_react.default.useCallback(
79
80
  (q) => {
@@ -91,6 +92,7 @@ function ComboSelect({
91
92
  return flat.find((o) => o.value === value) || null;
92
93
  }, [options, value, sections]);
93
94
  const closeDropdown = import_react.default.useCallback(() => {
95
+ closingUntil.current = (typeof performance !== "undefined" ? performance.now() : Date.now()) + 200;
94
96
  setOpen(false);
95
97
  if (clearQueryOnSelect) setQ("");
96
98
  requestAnimationFrame(() => {
@@ -126,14 +128,24 @@ function ComboSelect({
126
128
  const onPointerDownCapture = (e) => {
127
129
  if (isOutside(e)) closeDropdown();
128
130
  };
131
+ const onMouseDown = (e) => {
132
+ if (isOutside(e)) closeDropdown();
133
+ };
134
+ const onTouchStart = (e) => {
135
+ if (isOutside(e)) closeDropdown();
136
+ };
129
137
  const onKeyDown2 = (e) => {
130
138
  if (!open) return;
131
139
  if (e.key === "Escape") closeDropdown();
132
140
  };
133
141
  window.addEventListener("pointerdown", onPointerDownCapture, true);
142
+ window.addEventListener("mousedown", onMouseDown, true);
143
+ window.addEventListener("touchstart", onTouchStart, true);
134
144
  window.addEventListener("keydown", onKeyDown2, true);
135
145
  return () => {
136
146
  window.removeEventListener("pointerdown", onPointerDownCapture, true);
147
+ window.removeEventListener("mousedown", onMouseDown, true);
148
+ window.removeEventListener("touchstart", onTouchStart, true);
137
149
  window.removeEventListener("keydown", onKeyDown2, true);
138
150
  };
139
151
  }, [open, isOutside, closeDropdown]);
@@ -401,7 +413,11 @@ function ComboSelect({
401
413
  setQ(e.target.value);
402
414
  if (!open) setOpen(true);
403
415
  },
404
- onFocus: () => setOpen(true),
416
+ onFocus: () => {
417
+ const now = typeof performance !== "undefined" ? performance.now() : Date.now();
418
+ if (now < closingUntil.current) return;
419
+ setOpen(true);
420
+ },
405
421
  onKeyDown,
406
422
  placeholder,
407
423
  disabled,
@@ -41,6 +41,7 @@ function ComboSelect({
41
41
  var _a;
42
42
  const [query, _setQuery] = React.useState("");
43
43
  const [open, setOpen] = React.useState(false);
44
+ const closingUntil = React.useRef(0);
44
45
  const [activeIdx, setActiveIdx] = React.useState(0);
45
46
  const setQ = React.useCallback(
46
47
  (q) => {
@@ -58,6 +59,7 @@ function ComboSelect({
58
59
  return flat.find((o) => o.value === value) || null;
59
60
  }, [options, value, sections]);
60
61
  const closeDropdown = React.useCallback(() => {
62
+ closingUntil.current = (typeof performance !== "undefined" ? performance.now() : Date.now()) + 200;
61
63
  setOpen(false);
62
64
  if (clearQueryOnSelect) setQ("");
63
65
  requestAnimationFrame(() => {
@@ -93,14 +95,24 @@ function ComboSelect({
93
95
  const onPointerDownCapture = (e) => {
94
96
  if (isOutside(e)) closeDropdown();
95
97
  };
98
+ const onMouseDown = (e) => {
99
+ if (isOutside(e)) closeDropdown();
100
+ };
101
+ const onTouchStart = (e) => {
102
+ if (isOutside(e)) closeDropdown();
103
+ };
96
104
  const onKeyDown2 = (e) => {
97
105
  if (!open) return;
98
106
  if (e.key === "Escape") closeDropdown();
99
107
  };
100
108
  window.addEventListener("pointerdown", onPointerDownCapture, true);
109
+ window.addEventListener("mousedown", onMouseDown, true);
110
+ window.addEventListener("touchstart", onTouchStart, true);
101
111
  window.addEventListener("keydown", onKeyDown2, true);
102
112
  return () => {
103
113
  window.removeEventListener("pointerdown", onPointerDownCapture, true);
114
+ window.removeEventListener("mousedown", onMouseDown, true);
115
+ window.removeEventListener("touchstart", onTouchStart, true);
104
116
  window.removeEventListener("keydown", onKeyDown2, true);
105
117
  };
106
118
  }, [open, isOutside, closeDropdown]);
@@ -368,7 +380,11 @@ function ComboSelect({
368
380
  setQ(e.target.value);
369
381
  if (!open) setOpen(true);
370
382
  },
371
- onFocus: () => setOpen(true),
383
+ onFocus: () => {
384
+ const now = typeof performance !== "undefined" ? performance.now() : Date.now();
385
+ if (now < closingUntil.current) return;
386
+ setOpen(true);
387
+ },
372
388
  onKeyDown,
373
389
  placeholder,
374
390
  disabled,
package/dist/Dropdown.js CHANGED
@@ -153,7 +153,7 @@ function Trigger({
153
153
  className: [
154
154
  "inline-flex items-center gap-2 rounded-xl border border-slate-300/70 bg-white px-3 py-2",
155
155
  "text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50 active:scale-[0.98]",
156
- "dark:border-white/10 dark:bg-[var(--fx-surface)] dark:text-slate-200 dark:hover:bg-[var(--fx-surface)]",
156
+ "dark:border-white/10 dark:bg-[var(--fx-surface)] dark:text-slate-200 dark:hover:bg-white/10",
157
157
  className
158
158
  ].join(" "),
159
159
  ...safe,
package/dist/Dropdown.mjs CHANGED
@@ -123,7 +123,7 @@ function Trigger({
123
123
  className: [
124
124
  "inline-flex items-center gap-2 rounded-xl border border-slate-300/70 bg-white px-3 py-2",
125
125
  "text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50 active:scale-[0.98]",
126
- "dark:border-white/10 dark:bg-[var(--fx-surface)] dark:text-slate-200 dark:hover:bg-[var(--fx-surface)]",
126
+ "dark:border-white/10 dark:bg-[var(--fx-surface)] dark:text-slate-200 dark:hover:bg-white/10",
127
127
  className
128
128
  ].join(" "),
129
129
  ...safe,
@@ -53,6 +53,7 @@ function MultiComboSelect({
53
53
  enableDialog = true,
54
54
  dialogTitle = "Seleccionadas"
55
55
  }) {
56
+ const rootRef = import_react.default.useRef(null);
56
57
  const selectedSet = import_react.default.useMemo(() => new Set(value), [value]);
57
58
  const [dialogOpen, setDialogOpen] = import_react.default.useState(false);
58
59
  const toggle = import_react.default.useCallback(
@@ -65,7 +66,35 @@ function MultiComboSelect({
65
66
  },
66
67
  [selectedSet, onChange]
67
68
  );
68
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
69
+ import_react.default.useEffect(() => {
70
+ const closeIfOutside = (e) => {
71
+ var _a;
72
+ const t = e.target;
73
+ const inRoot = !!rootRef.current && rootRef.current.contains(t);
74
+ const inListbox = !!(t == null ? void 0 : t.closest('[role="listbox"]'));
75
+ if (!inRoot && !inListbox) {
76
+ const input = (_a = rootRef.current) == null ? void 0 : _a.querySelector('input[role="combobox"]');
77
+ if (input) {
78
+ try {
79
+ input.blur();
80
+ } catch {
81
+ }
82
+ }
83
+ }
84
+ };
85
+ const onPointerDownCapture = (e) => closeIfOutside(e);
86
+ const onMouseDown = (e) => closeIfOutside(e);
87
+ const onTouchStart = (e) => closeIfOutside(e);
88
+ window.addEventListener("pointerdown", onPointerDownCapture, true);
89
+ window.addEventListener("mousedown", onMouseDown, true);
90
+ window.addEventListener("touchstart", onTouchStart, true);
91
+ return () => {
92
+ window.removeEventListener("pointerdown", onPointerDownCapture, true);
93
+ window.removeEventListener("mousedown", onMouseDown, true);
94
+ window.removeEventListener("touchstart", onTouchStart, true);
95
+ };
96
+ }, []);
97
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: rootRef, children: [
69
98
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
70
99
  import_ComboSelect.default,
71
100
  {
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import React from "react";
4
4
  import ComboSelect from "./ComboSelect";
5
5
  import Dialog from "./Dialog";
@@ -20,6 +20,7 @@ function MultiComboSelect({
20
20
  enableDialog = true,
21
21
  dialogTitle = "Seleccionadas"
22
22
  }) {
23
+ const rootRef = React.useRef(null);
23
24
  const selectedSet = React.useMemo(() => new Set(value), [value]);
24
25
  const [dialogOpen, setDialogOpen] = React.useState(false);
25
26
  const toggle = React.useCallback(
@@ -32,7 +33,35 @@ function MultiComboSelect({
32
33
  },
33
34
  [selectedSet, onChange]
34
35
  );
35
- return /* @__PURE__ */ jsxs(Fragment, { children: [
36
+ React.useEffect(() => {
37
+ const closeIfOutside = (e) => {
38
+ var _a;
39
+ const t = e.target;
40
+ const inRoot = !!rootRef.current && rootRef.current.contains(t);
41
+ const inListbox = !!(t == null ? void 0 : t.closest('[role="listbox"]'));
42
+ if (!inRoot && !inListbox) {
43
+ const input = (_a = rootRef.current) == null ? void 0 : _a.querySelector('input[role="combobox"]');
44
+ if (input) {
45
+ try {
46
+ input.blur();
47
+ } catch {
48
+ }
49
+ }
50
+ }
51
+ };
52
+ const onPointerDownCapture = (e) => closeIfOutside(e);
53
+ const onMouseDown = (e) => closeIfOutside(e);
54
+ const onTouchStart = (e) => closeIfOutside(e);
55
+ window.addEventListener("pointerdown", onPointerDownCapture, true);
56
+ window.addEventListener("mousedown", onMouseDown, true);
57
+ window.addEventListener("touchstart", onTouchStart, true);
58
+ return () => {
59
+ window.removeEventListener("pointerdown", onPointerDownCapture, true);
60
+ window.removeEventListener("mousedown", onMouseDown, true);
61
+ window.removeEventListener("touchstart", onTouchStart, true);
62
+ };
63
+ }, []);
64
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, children: [
36
65
  /* @__PURE__ */ jsx(
37
66
  ComboSelect,
38
67
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "framepexls-ui-lib",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "description": "Componentes UI de Framepexls para React/Next.",