@goplusvn/core 0.1.11 → 0.1.13
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 +61 -0
- package/package.json +1 -1
- package/src/crud/components/crud-card-view.tsx +44 -13
- package/src/crud/components/crud-detail-dialog.tsx +355 -0
- package/src/crud/components/crud-dialog.tsx +2 -2
- package/src/crud/components/crud-form.tsx +2 -2
- package/src/crud/components/crud-page.tsx +80 -0
- package/src/crud/components/crud-provider.tsx +3 -0
- package/src/crud/components/crud-sheet.tsx +2 -2
- package/src/crud/components/crud-table.tsx +12 -0
- package/src/crud/components/index.tsx +1 -0
- package/src/crud/lib/crud-utils.ts +81 -0
- package/src/providers/index.tsx +19 -0
- package/src/styles/base.css +41 -0
- package/src/types/index.ts +14 -0
- package/src/ui/data-display/data-table/data-table.tsx +18 -1
- package/src/ui/feedback/index.tsx +2 -0
- package/src/ui/layout/customizer.tsx +12 -42
- package/src/ui/layout/sidebar.tsx +7 -5
- package/src/ui/primitives/body-lock-guard.tsx +64 -0
- package/src/ui/primitives/body-lock.ts +68 -0
- package/src/ui/primitives/client.ts +2 -0
- package/src/ui/primitives/sidebar.tsx +25 -4
- package/src/ui/primitives/use-release-stuck-body-lock.ts +9 -16
|
@@ -21,6 +21,8 @@ export * from "./sticky-layout";
|
|
|
21
21
|
export * from "./prefetch-link";
|
|
22
22
|
export * from "./dynamic-icon";
|
|
23
23
|
export * from "./input-number";
|
|
24
|
+
export * from "./body-lock-guard";
|
|
25
|
+
export * from "./body-lock";
|
|
24
26
|
|
|
25
27
|
// Feedback Client Components
|
|
26
28
|
export * from "../feedback/sheet";
|
|
@@ -218,10 +218,16 @@ const Sidebar = React.forwardRef<
|
|
|
218
218
|
}, [hoverExpandEnabled, setHoverOpen]);
|
|
219
219
|
|
|
220
220
|
if (collapsible === "none") {
|
|
221
|
+
// A non-collapsing sidebar is permanently EXPANDED, so it must use the
|
|
222
|
+
// expanded surface (bg-background / text-foreground), NOT the deep
|
|
223
|
+
// `bg-sidebar` colour. On a coloured sidebar (e.g. the navy default) the
|
|
224
|
+
// old `bg-sidebar text-sidebar-foreground` left the group labels + active
|
|
225
|
+
// item — which are `text-primary` — at ~1.9:1 contrast (unreadable). This
|
|
226
|
+
// matches the expanded state of the collapsible sidebar (labels-on-light).
|
|
221
227
|
return (
|
|
222
228
|
<div
|
|
223
229
|
className={cn(
|
|
224
|
-
"flex h-full w-(--sidebar-width) flex-col bg-
|
|
230
|
+
"flex h-full w-(--sidebar-width) flex-col border-r bg-background text-foreground",
|
|
225
231
|
className,
|
|
226
232
|
)}
|
|
227
233
|
ref={ref}
|
|
@@ -294,7 +300,7 @@ const Sidebar = React.forwardRef<
|
|
|
294
300
|
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
|
295
301
|
// Adjustments for collapsible=icon
|
|
296
302
|
variant === "floating" || variant === "inset"
|
|
297
|
-
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_8px)] group-data-[collapsible=icon]:px-
|
|
303
|
+
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_8px)] group-data-[collapsible=icon]:px-1"
|
|
298
304
|
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[collapsible=icon]:border-r group-data-[collapsible=icon]:px-0",
|
|
299
305
|
// Hover expand - override icon width to full width on hover
|
|
300
306
|
"group-data-[hover-expanded=true]:!w-(--sidebar-width) group-data-[hover-expanded=true]:shadow-xl group-data-[hover-expanded=true]:z-[100]",
|
|
@@ -310,7 +316,12 @@ const Sidebar = React.forwardRef<
|
|
|
310
316
|
"group-data-[state=collapsed]:bg-sidebar group-data-[state=collapsed]:border-border/50",
|
|
311
317
|
"group-data-[state=expanded]:bg-background group-data-[state=expanded]:border-border/50",
|
|
312
318
|
"group-data-[hover-expanded=true]:!bg-background group-data-[hover-expanded=true]:!border-border/50",
|
|
313
|
-
|
|
319
|
+
// Floating & inset: the sidebar is a soft floating panel. Round
|
|
320
|
+
// ALL corners (rounded-xl) so the top-right corner where it meets
|
|
321
|
+
// the header reads as a soft curve, not a hard 90° junction. Inset
|
|
322
|
+
// previously had no radius (sharp navy block) — now matches.
|
|
323
|
+
"group-data-[variant=floating]:rounded-xl group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow",
|
|
324
|
+
"group-data-[variant=inset]:rounded-xl group-data-[variant=inset]:border group-data-[variant=inset]:border-sidebar-border group-data-[variant=inset]:shadow",
|
|
314
325
|
)}
|
|
315
326
|
>
|
|
316
327
|
{children}
|
|
@@ -386,7 +397,17 @@ const SidebarInset = React.forwardRef<
|
|
|
386
397
|
ref={ref}
|
|
387
398
|
className={cn(
|
|
388
399
|
"relative flex min-h-svh flex-1 flex-col bg-muted/40 transition-[margin] duration-200 ease-linear",
|
|
389
|
-
|
|
400
|
+
// Inset: content is a card floating with a uniform m-2 gap on ALL sides
|
|
401
|
+
// (no ml-0 override) so there's a small gap between the sidebar and the
|
|
402
|
+
// content/header instead of them touching.
|
|
403
|
+
"peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow",
|
|
404
|
+
// Floating: the content is full-bleed (no card), and its LEFT edge is
|
|
405
|
+
// the side that meets the floating sidebar. Give it a small left gap
|
|
406
|
+
// (ml-2) so it doesn't touch the sidebar, and round both left corners
|
|
407
|
+
// (top-left clips the sticky header, bottom-left clips the footer via
|
|
408
|
+
// overflow-hidden) so the content hugs the floating sidebar with soft
|
|
409
|
+
// curves instead of hard 90° corners. Right edge stays flush.
|
|
410
|
+
"md:peer-data-[variant=floating]:ml-2 md:peer-data-[variant=floating]:rounded-l-xl",
|
|
390
411
|
className,
|
|
391
412
|
)}
|
|
392
413
|
{...props}
|
|
@@ -2,28 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
|
|
5
|
+
import { releaseStuckBodyLock } from "./body-lock";
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
8
|
+
* Gọi trong *Content của mỗi primitive overlay (Dialog/Sheet/AlertDialog…). Content chỉ
|
|
9
|
+
* mount khi overlay mở; khi nó unmount (đã đóng) ta gỡ khoá body NẾU còn sót — nhưng chỉ
|
|
10
|
+
* khi không còn modal nào đang mở (xem {@link releaseStuckBodyLock}).
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* dialog/popover nào đang mở, để không phá modal khác đang chồng lên.
|
|
12
|
+
* Đây là lớp gỡ khoá TỨC THÌ tại thời điểm đóng; {@link BodyLockGuard} là lưới an toàn
|
|
13
|
+
* toàn cục bao quát các trường hợp còn lại.
|
|
13
14
|
*/
|
|
14
15
|
export function useReleaseStuckBodyLock() {
|
|
15
16
|
React.useEffect(() => {
|
|
16
17
|
return () => {
|
|
17
|
-
|
|
18
|
-
|
|
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);
|
|
18
|
+
// Đợi một nhịp để Radix chạy xong phần dọn dẹp đồng bộ của nó trước.
|
|
19
|
+
setTimeout(releaseStuckBodyLock, 0);
|
|
27
20
|
};
|
|
28
21
|
}, []);
|
|
29
22
|
}
|