@goplusvn/core 0.1.4 → 0.1.5
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/package.json +1 -1
- package/src/crud/components/crud-dialog.tsx +16 -0
- package/src/crud/components/crud-sheet.tsx +16 -0
- package/src/ui/feedback/sheet.tsx +2 -0
- package/src/ui/forms/editor/index.tsx +4 -1
- package/src/ui/primitives/dialog.tsx +6 -2
- package/src/ui/primitives/use-release-stuck-body-lock.ts +29 -0
package/package.json
CHANGED
|
@@ -136,6 +136,22 @@ export function CrudDialog({
|
|
|
136
136
|
};
|
|
137
137
|
}, [open]);
|
|
138
138
|
|
|
139
|
+
// FIX (lỗi conflict event kinh điển): Radix Dialog + Select/Combobox/Popover
|
|
140
|
+
// lồng nhau đôi khi để sót `pointer-events: none` / scroll-lock trên <body> sau
|
|
141
|
+
// khi đóng, khiến TOÀN trang không click được. Reset thủ công SAU khi đóng, có
|
|
142
|
+
// guard `=== "none"` và clearTimeout khi mở lại để không gỡ khoá lúc đang mở.
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
if (open) return;
|
|
145
|
+
const timer = setTimeout(() => {
|
|
146
|
+
if (document.body.style.pointerEvents === "none") {
|
|
147
|
+
document.body.style.pointerEvents = "";
|
|
148
|
+
}
|
|
149
|
+
document.body.style.overflow = "";
|
|
150
|
+
document.body.removeAttribute("data-scroll-locked");
|
|
151
|
+
}, 300);
|
|
152
|
+
return () => clearTimeout(timer);
|
|
153
|
+
}, [open]);
|
|
154
|
+
|
|
139
155
|
// Keyboard shortcuts
|
|
140
156
|
useEffect(() => {
|
|
141
157
|
if (!open) return;
|
|
@@ -139,6 +139,22 @@ export function CrudSheet({
|
|
|
139
139
|
};
|
|
140
140
|
}, [open]);
|
|
141
141
|
|
|
142
|
+
// FIX (lỗi conflict event kinh điển): Radix Sheet + Select/Combobox/Popover lồng
|
|
143
|
+
// nhau đôi khi để sót `pointer-events: none` / scroll-lock trên <body> sau khi
|
|
144
|
+
// đóng, khiến TOÀN trang không click được. Reset thủ công SAU khi đóng, có guard
|
|
145
|
+
// `=== "none"` và clearTimeout khi mở lại để không gỡ khoá lúc đang mở.
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
if (open) return;
|
|
148
|
+
const timer = setTimeout(() => {
|
|
149
|
+
if (document.body.style.pointerEvents === "none") {
|
|
150
|
+
document.body.style.pointerEvents = "";
|
|
151
|
+
}
|
|
152
|
+
document.body.style.overflow = "";
|
|
153
|
+
document.body.removeAttribute("data-scroll-locked");
|
|
154
|
+
}, 300);
|
|
155
|
+
return () => clearTimeout(timer);
|
|
156
|
+
}, [open]);
|
|
157
|
+
|
|
142
158
|
// Keyboard shortcuts
|
|
143
159
|
useEffect(() => {
|
|
144
160
|
if (!open) return;
|
|
@@ -4,6 +4,7 @@ import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
5
|
import type { ComponentProps } from "react";
|
|
6
6
|
import { cn } from "../../utils";
|
|
7
|
+
import { useReleaseStuckBodyLock } from "../primitives/use-release-stuck-body-lock";
|
|
7
8
|
|
|
8
9
|
export function Sheet({
|
|
9
10
|
...props
|
|
@@ -84,6 +85,7 @@ export function SheetContent({
|
|
|
84
85
|
side = "right",
|
|
85
86
|
...props
|
|
86
87
|
}: SheetContentProps) {
|
|
88
|
+
useReleaseStuckBodyLock();
|
|
87
89
|
return (
|
|
88
90
|
<SheetPortal>
|
|
89
91
|
<SheetOverlay />
|
|
@@ -72,7 +72,10 @@ export function Editor({
|
|
|
72
72
|
showOnlyCurrent: true,
|
|
73
73
|
}),
|
|
74
74
|
Typography,
|
|
75
|
-
|
|
75
|
+
// Cast: các gói @tiptap/* có thể lệch version @tiptap/core trong monorepo,
|
|
76
|
+
// gây lỗi type (Extension không khớp AnyExtension) khi build dts. An toàn
|
|
77
|
+
// vì runtime giống nhau; cast về đúng kiểu options yêu cầu.
|
|
78
|
+
] as unknown as UseEditorOptions["extensions"],
|
|
76
79
|
content: value,
|
|
77
80
|
onUpdate: ({ editor }) => {
|
|
78
81
|
onValueChange?.(editor.getHTML());
|
|
@@ -4,6 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
5
5
|
import { X } from "lucide-react";
|
|
6
6
|
import { cn } from "../../utils";
|
|
7
|
+
import { useReleaseStuckBodyLock } from "./use-release-stuck-body-lock";
|
|
7
8
|
|
|
8
9
|
const Dialog = DialogPrimitive.Root;
|
|
9
10
|
|
|
@@ -31,7 +32,9 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
|
31
32
|
const DialogContent = React.forwardRef<
|
|
32
33
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
|
33
34
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
|
34
|
-
>(({ className, children, ...props }, ref) =>
|
|
35
|
+
>(({ className, children, ...props }, ref) => {
|
|
36
|
+
useReleaseStuckBodyLock();
|
|
37
|
+
return (
|
|
35
38
|
<DialogPortal>
|
|
36
39
|
<DialogOverlay />
|
|
37
40
|
<DialogPrimitive.Content
|
|
@@ -49,7 +52,8 @@ const DialogContent = React.forwardRef<
|
|
|
49
52
|
</DialogPrimitive.Close>
|
|
50
53
|
</DialogPrimitive.Content>
|
|
51
54
|
</DialogPortal>
|
|
52
|
-
)
|
|
55
|
+
);
|
|
56
|
+
});
|
|
53
57
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
54
58
|
|
|
55
59
|
const DialogHeader = ({
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Lưới an toàn cho "lỗi conflict event kinh điển": Radix (Dialog/AlertDialog/Sheet
|
|
7
|
+
* + Select/Combobox/Popover lồng bên trong) đôi khi để sót `pointer-events: none`
|
|
8
|
+
* / scroll-lock trên <body> sau khi đóng, khiến TOÀN trang không click được.
|
|
9
|
+
*
|
|
10
|
+
* Gọi hook này trong *Content của mỗi primitive overlay. Content chỉ mount khi
|
|
11
|
+
* overlay mở; khi nó unmount (đã đóng) ta gỡ khoá — nhưng CHỈ khi không còn lớp
|
|
12
|
+
* dialog/popover nào đang mở, để không phá modal khác đang chồng lên.
|
|
13
|
+
*/
|
|
14
|
+
export function useReleaseStuckBodyLock() {
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
return () => {
|
|
17
|
+
setTimeout(() => {
|
|
18
|
+
const hasOpenLayer = document.querySelector(
|
|
19
|
+
'[role="dialog"][data-state="open"], [role="alertdialog"][data-state="open"], [data-radix-popper-content-wrapper]',
|
|
20
|
+
);
|
|
21
|
+
if (!hasOpenLayer && document.body.style.pointerEvents === "none") {
|
|
22
|
+
document.body.style.pointerEvents = "";
|
|
23
|
+
document.body.style.overflow = "";
|
|
24
|
+
document.body.removeAttribute("data-scroll-locked");
|
|
25
|
+
}
|
|
26
|
+
}, 0);
|
|
27
|
+
};
|
|
28
|
+
}, []);
|
|
29
|
+
}
|