@goplusvn/core 0.1.97 → 0.1.99
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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
## 0.1.99 — Native Event Isolation ngăn chặn hoàn toàn việc Dialog/Sheet cha cướp focus của ô tìm kiếm
|
|
2
|
+
|
|
3
|
+
Khi người dùng click hoặc chạm vào ô tìm kiếm hoặc danh sách của Popover nằm trong Dialog/Sheet/Modal,
|
|
4
|
+
Radix Dialog trên document lắng nghe native pointerdown/touchstart và gọi preventDefault().
|
|
5
|
+
Bằng cách cô lập native event trên cả PopoverContent và SearchInputRef (pointerdown, mousedown, touchstart),
|
|
6
|
+
Dialog cha không bao giờ can thiệp vào các thao tác chạm/click/focus bên trong dropdown.
|
|
7
|
+
|
|
8
|
+
**Đổi**
|
|
9
|
+
|
|
10
|
+
- `ui/primitives/combobox.tsx` & `ui/forms/multi-select.tsx` — bổ sung native event listener `stopPropagation`
|
|
11
|
+
cho `searchInputRef` và `onPointerDownCapture` trên `PopoverContent` + `Input`.
|
|
12
|
+
|
|
13
|
+
## 0.1.98 — Chuẩn hóa Modal FocusScope cho Combobox/MultiSelect khi nằm trong Dialog/Sheet/Modal
|
|
14
|
+
|
|
15
|
+
Khi Combobox hoặc MultiSelect nằm trong Modal/Dialog/Sheet (như Modal thanh toán POS hay Sheet bộ lọc nâng cao),
|
|
16
|
+
cơ chế FocusScope Stack của Radix yêu cầu `modal={true}` kết hợp với auto-focus vào `searchInputRef`
|
|
17
|
+
và loại bỏ hoàn toàn các rào cản `stopPropagation` trên `onFocus`/`onClick` của Input.
|
|
18
|
+
|
|
19
|
+
**Đổi**
|
|
20
|
+
|
|
21
|
+
- `ui/primitives/combobox.tsx` & `ui/forms/multi-select.tsx` — kích hoạt `modal={true}` mặc định,
|
|
22
|
+
tự động focus vào `searchInputRef` khi mở dropdown, bổ sung `onPointerDown` stopPropagation trên Input
|
|
23
|
+
để người dùng click/chạm vào ô tìm kiếm lập tức nhận con trỏ nhập liệu và bật bàn phím.
|
|
24
|
+
|
|
1
25
|
## 0.1.97 — Sửa triệt để tương tác chạm và nhập liệu cho ô tìm kiếm Combobox/MultiSelect
|
|
2
26
|
|
|
3
27
|
Khi `modal={true}` được bật mặc định, Radix Popover kích hoạt FocusScope + ScrollLock
|
package/package.json
CHANGED
|
@@ -212,7 +212,7 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
|
|
|
212
212
|
loadingText = "Đang tải...",
|
|
213
213
|
className,
|
|
214
214
|
id,
|
|
215
|
-
modal =
|
|
215
|
+
modal = true,
|
|
216
216
|
},
|
|
217
217
|
ref,
|
|
218
218
|
) => {
|
|
@@ -414,12 +414,26 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
|
|
|
414
414
|
return { start, end };
|
|
415
415
|
}, [isVirtual, scrollTop, filteredOptions.length]);
|
|
416
416
|
|
|
417
|
-
// Reset search when dropdown closes
|
|
417
|
+
// Reset search when dropdown closes + Native event isolation cho ô search input
|
|
418
|
+
// Ngăn Radix Dialog's DismissableLayer bắt native pointerdown/touchstart trên document
|
|
419
|
+
// và gọi preventDefault() làm mất focus khi ô input nằm trong Dialog/Sheet/Modal.
|
|
418
420
|
useEffect(() => {
|
|
419
421
|
if (!open) {
|
|
420
422
|
setSearchValue("");
|
|
421
423
|
setScrollTop(0);
|
|
424
|
+
return;
|
|
422
425
|
}
|
|
426
|
+
const el = searchInputRef.current;
|
|
427
|
+
if (!el) return;
|
|
428
|
+
const stop = (e: Event) => e.stopPropagation();
|
|
429
|
+
el.addEventListener("pointerdown", stop);
|
|
430
|
+
el.addEventListener("mousedown", stop);
|
|
431
|
+
el.addEventListener("touchstart", stop);
|
|
432
|
+
return () => {
|
|
433
|
+
el.removeEventListener("pointerdown", stop);
|
|
434
|
+
el.removeEventListener("mousedown", stop);
|
|
435
|
+
el.removeEventListener("touchstart", stop);
|
|
436
|
+
};
|
|
423
437
|
}, [open]);
|
|
424
438
|
|
|
425
439
|
// Reset highlight khi mở/lọc thay đổi
|
|
@@ -732,6 +746,11 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
|
|
|
732
746
|
collisionPadding={8}
|
|
733
747
|
onOpenAutoFocus={(e) => {
|
|
734
748
|
e.preventDefault();
|
|
749
|
+
searchInputRef.current?.focus();
|
|
750
|
+
}}
|
|
751
|
+
onPointerDownCapture={(e) => {
|
|
752
|
+
// Native event isolation: ngăn Dialog/Sheet cha bắt pointerdown trên document và gọi preventDefault()
|
|
753
|
+
e.stopPropagation();
|
|
735
754
|
}}
|
|
736
755
|
className="z-[100] flex w-[var(--radix-popover-trigger-width)] min-w-[15rem] max-w-[calc(100vw-1rem)] flex-col overflow-hidden rounded-md border bg-popover/95 p-0 text-popover-foreground shadow-lg shadow-black/5 backdrop-blur-md"
|
|
737
756
|
style={{
|
|
@@ -754,7 +773,13 @@ export const MultiSelect = React.forwardRef<MultiSelectRef, MultiSelectProps>(
|
|
|
754
773
|
onChange={(e) => {
|
|
755
774
|
setSearchValue(e.target.value);
|
|
756
775
|
}}
|
|
757
|
-
|
|
776
|
+
onPointerDownCapture={(e) => {
|
|
777
|
+
e.stopPropagation();
|
|
778
|
+
}}
|
|
779
|
+
onMouseDownCapture={(e) => {
|
|
780
|
+
e.stopPropagation();
|
|
781
|
+
}}
|
|
782
|
+
onTouchStartCapture={(e) => {
|
|
758
783
|
e.stopPropagation();
|
|
759
784
|
}}
|
|
760
785
|
onKeyDown={(e) => {
|
|
@@ -25,8 +25,8 @@ interface ComboboxProps {
|
|
|
25
25
|
className?: string;
|
|
26
26
|
id?: string;
|
|
27
27
|
/**
|
|
28
|
-
* Chế độ modal cho Popover (mặc định
|
|
29
|
-
*
|
|
28
|
+
* Chế độ modal cho Popover (mặc định true). Bắt buộc true để kích hoạt
|
|
29
|
+
* FocusScope Stack của Radix khi nằm trong Dialog/Sheet/Modal.
|
|
30
30
|
*/
|
|
31
31
|
modal?: boolean;
|
|
32
32
|
/**
|
|
@@ -56,7 +56,7 @@ export function Combobox({
|
|
|
56
56
|
disabled = false,
|
|
57
57
|
className,
|
|
58
58
|
id,
|
|
59
|
-
modal =
|
|
59
|
+
modal = true,
|
|
60
60
|
maxHeight = "20rem",
|
|
61
61
|
}: ComboboxProps) {
|
|
62
62
|
const [open, setOpen] = useState(false);
|
|
@@ -80,11 +80,25 @@ export function Combobox({
|
|
|
80
80
|
});
|
|
81
81
|
}, [options, searchValue]);
|
|
82
82
|
|
|
83
|
-
// Reset search when dropdown closes
|
|
83
|
+
// Reset search when dropdown closes + Native event isolation cho ô search input
|
|
84
|
+
// Ngăn Radix Dialog's DismissableLayer bắt native pointerdown/touchstart trên document
|
|
85
|
+
// và gọi preventDefault() làm mất focus khi ô input nằm trong Dialog/Sheet/Modal.
|
|
84
86
|
useEffect(() => {
|
|
85
87
|
if (!open) {
|
|
86
88
|
setSearchValue("");
|
|
89
|
+
return;
|
|
87
90
|
}
|
|
91
|
+
const el = searchInputRef.current;
|
|
92
|
+
if (!el) return;
|
|
93
|
+
const stop = (e: Event) => e.stopPropagation();
|
|
94
|
+
el.addEventListener("pointerdown", stop);
|
|
95
|
+
el.addEventListener("mousedown", stop);
|
|
96
|
+
el.addEventListener("touchstart", stop);
|
|
97
|
+
return () => {
|
|
98
|
+
el.removeEventListener("pointerdown", stop);
|
|
99
|
+
el.removeEventListener("mousedown", stop);
|
|
100
|
+
el.removeEventListener("touchstart", stop);
|
|
101
|
+
};
|
|
88
102
|
}, [open]);
|
|
89
103
|
|
|
90
104
|
const handleSelect = useCallback(
|
|
@@ -178,6 +192,11 @@ export function Combobox({
|
|
|
178
192
|
collisionPadding={8}
|
|
179
193
|
onOpenAutoFocus={(e) => {
|
|
180
194
|
e.preventDefault();
|
|
195
|
+
searchInputRef.current?.focus();
|
|
196
|
+
}}
|
|
197
|
+
onPointerDownCapture={(e) => {
|
|
198
|
+
// Native event isolation: ngăn Dialog/Sheet cha bắt pointerdown trên document và gọi preventDefault()
|
|
199
|
+
e.stopPropagation();
|
|
181
200
|
}}
|
|
182
201
|
className="z-[100] w-[var(--radix-popover-trigger-width)] min-w-[12rem] max-w-[calc(100vw-1rem)] p-0 flex flex-col overflow-hidden"
|
|
183
202
|
style={{
|
|
@@ -194,7 +213,13 @@ export function Combobox({
|
|
|
194
213
|
onChange={(e) => {
|
|
195
214
|
setSearchValue(e.target.value);
|
|
196
215
|
}}
|
|
197
|
-
|
|
216
|
+
onPointerDownCapture={(e) => {
|
|
217
|
+
e.stopPropagation();
|
|
218
|
+
}}
|
|
219
|
+
onMouseDownCapture={(e) => {
|
|
220
|
+
e.stopPropagation();
|
|
221
|
+
}}
|
|
222
|
+
onTouchStartCapture={(e) => {
|
|
198
223
|
e.stopPropagation();
|
|
199
224
|
}}
|
|
200
225
|
onKeyDown={(e) => {
|