@godxjp/ui 19.6.0 → 20.0.0

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 (137) hide show
  1. package/dist/components/data-display/card.d.ts +2 -2
  2. package/dist/components/data-display/collapsible.d.ts +23 -4
  3. package/dist/components/data-display/collapsible.js +119 -4
  4. package/dist/components/data-display/index.d.ts +3 -1
  5. package/dist/components/data-display/index.js +2 -0
  6. package/dist/components/data-display/legend.d.ts +15 -0
  7. package/dist/components/data-display/legend.js +11 -0
  8. package/dist/components/data-display/list-row.js +1 -1
  9. package/dist/components/data-display/popover.d.ts +58 -5
  10. package/dist/components/data-display/popover.js +206 -27
  11. package/dist/components/data-display/progress.d.ts +50 -2
  12. package/dist/components/data-display/progress.js +57 -9
  13. package/dist/components/data-entry/calendar.d.ts +1 -1
  14. package/dist/components/data-entry/calendar.js +67 -32
  15. package/dist/components/data-entry/checkbox.d.ts +19 -6
  16. package/dist/components/data-entry/checkbox.js +55 -16
  17. package/dist/components/data-entry/choice-option.d.ts +1 -1
  18. package/dist/components/data-entry/date-range-picker.d.ts +1 -1
  19. package/dist/components/data-entry/field.js +0 -1
  20. package/dist/components/data-entry/form.js +1 -1
  21. package/dist/components/data-entry/label.d.ts +3 -2
  22. package/dist/components/data-entry/label.js +23 -10
  23. package/dist/components/data-entry/month-picker.d.ts +1 -1
  24. package/dist/components/data-entry/month-range-picker.d.ts +1 -1
  25. package/dist/components/data-entry/transfer.js +16 -6
  26. package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
  27. package/dist/components/data-entry/tree-select.js +29 -12
  28. package/dist/components/data-entry/tree-utils.d.ts +1 -1
  29. package/dist/components/data-entry/upload.js +7 -2
  30. package/dist/components/feedback/dialog.d.ts +105 -38
  31. package/dist/components/feedback/dialog.js +272 -194
  32. package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
  33. package/dist/components/feedback/overlay-close-focus.js +31 -0
  34. package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
  35. package/dist/components/feedback/sheet.d.ts +53 -11
  36. package/dist/components/feedback/sheet.js +150 -81
  37. package/dist/components/feedback/tooltip.d.ts +51 -7
  38. package/dist/components/feedback/tooltip.js +107 -25
  39. package/dist/components/general/button.js +2 -2
  40. package/dist/components/general/logo.d.ts +17 -0
  41. package/dist/components/general/logo.js +22 -16
  42. package/dist/components/layout/app-shell.d.ts +1 -1
  43. package/dist/components/layout/app-shell.js +52 -8
  44. package/dist/components/layout/aspect-ratio.js +0 -1
  45. package/dist/components/layout/auth-divider.js +0 -1
  46. package/dist/components/layout/flex.d.ts +1 -1
  47. package/dist/components/layout/flex.js +19 -2
  48. package/dist/components/layout/nav-surface.d.ts +26 -0
  49. package/dist/components/layout/nav-surface.js +17 -0
  50. package/dist/components/layout/org-switcher.d.ts +5 -1
  51. package/dist/components/layout/org-switcher.js +5 -3
  52. package/dist/components/layout/separator.js +0 -1
  53. package/dist/components/layout/sidebar.js +4 -1
  54. package/dist/components/layout/split-pane.d.ts +14 -1
  55. package/dist/components/layout/split-pane.js +26 -13
  56. package/dist/components/layout/topbar-item.js +1 -2
  57. package/dist/components/navigation/app-setting-picker.js +21 -2
  58. package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
  59. package/dist/components/navigation/app-setting-toggle.js +96 -0
  60. package/dist/components/navigation/dropdown-menu.d.ts +199 -18
  61. package/dist/components/navigation/dropdown-menu.js +344 -117
  62. package/dist/components/navigation/index.d.ts +2 -0
  63. package/dist/components/navigation/index.js +2 -0
  64. package/dist/components/navigation/pagination-utils.d.ts +2 -1
  65. package/dist/components/navigation/tabs.d.ts +47 -6
  66. package/dist/components/navigation/tabs.js +152 -90
  67. package/dist/components/ui/accordion.d.ts +50 -5
  68. package/dist/components/ui/accordion.js +239 -33
  69. package/dist/components/ui/aspect-ratio.d.ts +23 -2
  70. package/dist/components/ui/aspect-ratio.js +15 -13
  71. package/dist/components/ui/avatar.d.ts +29 -4
  72. package/dist/components/ui/avatar.js +111 -25
  73. package/dist/components/ui/hover-card.d.ts +42 -4
  74. package/dist/components/ui/hover-card.js +183 -27
  75. package/dist/components/ui/label.js +0 -1
  76. package/dist/components/ui/segmented.d.ts +3 -3
  77. package/dist/components/ui/separator.d.ts +8 -2
  78. package/dist/components/ui/separator.js +17 -9
  79. package/dist/components/ui/toggle-group.d.ts +50 -5
  80. package/dist/components/ui/toggle-group.js +79 -20
  81. package/dist/components/ui/toggle.d.ts +31 -5
  82. package/dist/components/ui/toggle.js +42 -3
  83. package/dist/i18n/messages/en.json +8 -0
  84. package/dist/i18n/messages/ja.json +8 -0
  85. package/dist/i18n/messages/vi.json +8 -0
  86. package/dist/lib/control-styles.d.ts +1 -1
  87. package/dist/lib/control-styles.js +1 -1
  88. package/dist/lib/slot.d.ts +32 -0
  89. package/dist/lib/slot.js +22 -0
  90. package/dist/lib/variants.d.ts +22 -3
  91. package/dist/lib/variants.js +56 -1
  92. package/dist/props/components/app.prop.d.ts +25 -1
  93. package/dist/props/components/data-display.prop.d.ts +17 -0
  94. package/dist/props/components/data-entry.prop.d.ts +32 -4
  95. package/dist/props/components/index.d.ts +1 -1
  96. package/dist/props/components/layout.prop.d.ts +118 -5
  97. package/dist/props/components/navigation.prop.d.ts +1 -1
  98. package/dist/props/registry.d.ts +22 -2
  99. package/dist/props/registry.js +33 -2
  100. package/dist/props/vocabulary/content.prop.d.ts +1 -1
  101. package/dist/props/vocabulary/index.d.ts +2 -2
  102. package/dist/props/vocabulary/interaction.prop.d.ts +17 -1
  103. package/dist/props/vocabulary/layout.prop.d.ts +57 -1
  104. package/dist/styles/control.css +142 -1
  105. package/dist/styles/core.css +5 -2
  106. package/dist/styles/data-display-layout.css +72 -0
  107. package/dist/styles/focus-ring.css +4 -0
  108. package/dist/styles/index.css +5 -2
  109. package/dist/styles/layout.css +106 -0
  110. package/dist/styles/shell-layout.css +140 -8
  111. package/dist/styles/text-layout.css +5 -4
  112. package/dist/tokens/base.css +1 -1
  113. package/dist/tokens/components/data-display.css +11 -0
  114. package/dist/tokens/components/shell.css +3 -1
  115. package/dist/tokens/foundation.css +2 -0
  116. package/docs/COMPONENTS.md +9 -3
  117. package/docs/DESIGN-AUTHORITY.md +96 -71
  118. package/docs/FRAME-COVERAGE-REPORT.md +5 -3
  119. package/docs/README.md +14 -14
  120. package/docs/WHAT-BELONGS-HERE.md +179 -0
  121. package/docs/data-display/legend.tsx +145 -0
  122. package/docs/data-display/progress.tsx +32 -0
  123. package/docs/data-entry/segmented.tsx +1 -1
  124. package/docs/data-entry/select.tsx +2 -2
  125. package/docs/feedback/sheet.tsx +1 -1
  126. package/docs/layout/app-shell-arrangements.tsx +225 -0
  127. package/docs/layout/aspect-ratio.tsx +1 -1
  128. package/docs/navigation/app-setting-picker.tsx +26 -1
  129. package/docs/navigation/app-setting-toggle.tsx +111 -0
  130. package/package.json +11 -8
  131. package/scripts/_agent-setup.mjs +165 -3
  132. package/scripts/consumer-rule.md +98 -0
  133. package/scripts/guinea-pig-skill.md +322 -0
  134. package/scripts/init-guinea-pig.mjs +62 -0
  135. package/scripts/postinstall.mjs +13 -2
  136. package/scripts/ui-audit.mjs +115 -14
  137. /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
@@ -1,5 +1,4 @@
1
1
  import * as React from "react";
2
- import * as DialogPrimitive from "@radix-ui/react-dialog";
3
2
  import { type VariantProps } from "class-variance-authority";
4
3
  import type { SheetResponsiveProp } from "../../props/components/feedback.prop.js";
5
4
  import type { ToneProp, WidthProp } from "../../props/vocabulary/index.js";
@@ -12,18 +11,58 @@ export type SheetPresentation = "side" | "bottom";
12
11
  * viewport is at or below `--sheet-responsive-breakpoint-width`.
13
12
  */
14
13
  export declare function useSheetResponsiveMode(responsive?: SheetResponsiveProp): SheetPresentation;
15
- export declare function Sheet(props: React.ComponentProps<typeof DialogPrimitive.Root>): React.JSX.Element;
16
- export declare function SheetTrigger(props: React.ComponentProps<typeof DialogPrimitive.Trigger>): React.JSX.Element;
17
- export declare function SheetClose(props: React.ComponentProps<typeof DialogPrimitive.Close>): React.JSX.Element;
18
- export declare function SheetPortal(props: React.ComponentProps<typeof DialogPrimitive.Portal>): React.JSX.Element;
19
- export declare const SheetOverlay: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogOverlayProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
14
+ export interface SheetProps {
15
+ /** Trạng thái mở, kiểm soát. */
16
+ open?: boolean;
17
+ /** Trạng thái mở ban đầu khi không kiểm soát. */
18
+ defaultOpen?: boolean;
19
+ /** Gọi khi trạng thái mở đổi. */
20
+ onOpenChange?: (open: boolean) => void;
21
+ /**
22
+ * Giữ tên prop của Radix. RAC không có kiểu overlay không-modal: `Modal` LUÔN khoá cuộn và ẩn
23
+ * nền khỏi trình đọc màn hình, nên `modal={false}` không còn tắt được điều đó.
24
+ */
25
+ modal?: boolean;
26
+ children?: React.ReactNode;
27
+ }
28
+ export declare function Sheet({ open, defaultOpen, onOpenChange, modal: _modal, children }: SheetProps): React.JSX.Element;
29
+ export interface SheetTriggerProps extends React.ComponentPropsWithRef<"button"> {
30
+ /** Mượn thẻ của con thay vì dựng `<button>` riêng. */
31
+ asChild?: boolean;
32
+ }
33
+ export declare function SheetTrigger({ asChild, onClick, ...props }: SheetTriggerProps): React.JSX.Element;
34
+ export interface SheetCloseProps extends React.ComponentPropsWithRef<"button"> {
35
+ /** Mượn thẻ của con thay vì dựng `<button>` riêng. */
36
+ asChild?: boolean;
37
+ }
38
+ export declare function SheetClose({ asChild, onClick, ...props }: SheetCloseProps): React.JSX.Element;
39
+ export interface SheetPortalProps {
40
+ /** Giữ tên prop của Radix; RAC tự portal ra `document.body` từ `ModalOverlay`. */
41
+ forceMount?: true;
42
+ children?: React.ReactNode;
43
+ }
44
+ export declare function SheetPortal({ children }: SheetPortalProps): React.JSX.Element;
45
+ export interface SheetOverlayProps extends React.ComponentPropsWithRef<"div"> {
46
+ /** Giữ tên prop của Radix. */
47
+ forceMount?: true;
48
+ }
49
+ /**
50
+ * Không dựng gì — xem đầu tệp. Màn nền là `ModalOverlay` bên trong `SheetContent`, và nó vẫn mang
51
+ * `data-slot="sheet-overlay"` + `.ui-sheet-overlay` như trước.
52
+ */
53
+ export declare function SheetOverlay(_props: SheetOverlayProps): null;
54
+ export declare namespace SheetOverlay {
55
+ var displayName: string;
56
+ }
20
57
  declare const sheetVariants: (props?: ({
21
58
  side?: "bottom" | "left" | "right" | "top" | null | undefined;
22
59
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
23
- export interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>, VariantProps<typeof sheetVariants> {
60
+ export interface SheetContentProps extends React.ComponentPropsWithRef<"section">, VariantProps<typeof sheetVariants> {
24
61
  showCloseButton?: boolean;
25
62
  /** Optional semantic class for the owned backdrop (for a shell-specific overlay token). */
26
63
  overlayClassName?: string;
64
+ /** Giữ tên prop của Radix; RAC tự portal ra `document.body` từ `ModalOverlay`. */
65
+ forceMount?: true;
27
66
  /**
28
67
  * Desired panel size for side left/right (Ant Drawer `width`). Omit to keep the canonical drawer
29
68
  * default from `--sheet-width-default`.
@@ -35,9 +74,12 @@ export interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof
35
74
  */
36
75
  responsive?: SheetResponsiveProp;
37
76
  }
38
- export declare const SheetContent: React.ForwardRefExoticComponent<SheetContentProps & React.RefAttributes<HTMLDivElement>>;
77
+ export declare function SheetContent({ side, className, children, showCloseButton, overlayClassName, forceMount: _forceMount, width, responsive, style, ref, ...props }: SheetContentProps): React.JSX.Element;
78
+ export declare namespace SheetContent {
79
+ var displayName: string;
80
+ }
39
81
  export interface SheetHeaderProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
40
- /** Header title (Ant Drawer-style). Rendered as the Radix-bound SheetTitle (accessible name). */
82
+ /** Header title (Ant Drawer-style). Rendered as the bound SheetTitle (accessible name). */
41
83
  title?: React.ReactNode;
42
84
  /** Secondary line under the title (rendered as SheetDescription). */
43
85
  subtitle?: React.ReactNode;
@@ -49,5 +91,5 @@ export interface SheetHeaderProps extends Omit<React.HTMLAttributes<HTMLDivEleme
49
91
  export declare const SheetHeader: ({ className, title, subtitle, extra, tone, children, ...props }: SheetHeaderProps) => React.JSX.Element;
50
92
  export declare const SheetBody: ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
51
93
  export declare const SheetFooter: ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
52
- export declare const SheetTitle: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogTitleProps & React.RefAttributes<HTMLHeadingElement>, "ref"> & React.RefAttributes<HTMLHeadingElement>>;
53
- export declare const SheetDescription: React.ForwardRefExoticComponent<Omit<DialogPrimitive.DialogDescriptionProps & React.RefAttributes<HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
94
+ export declare const SheetTitle: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, "ref"> & React.RefAttributes<HTMLHeadingElement>>;
95
+ export declare const SheetDescription: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
@@ -1,12 +1,15 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import * as DialogPrimitive from "@radix-ui/react-dialog";
4
+ import { chain, mergeRefs } from "@react-aria/utils";
5
+ import { Dialog as RacDialog, Modal, ModalOverlay } from "react-aria-components";
5
6
  import { cva } from "class-variance-authority";
6
7
  import { X } from "lucide-react";
7
8
  import { useMediaQuery } from "../../lib/hooks.js";
8
9
  import { cn } from "../../lib/utils.js";
10
+ import { Slot } from "../../lib/slot.js";
9
11
  import { overlayHeaderToneClass } from "./overlay-header-tone.js";
12
+ import { useOverlayCloseFocus } from "./overlay-close-focus.js";
10
13
  import { useTranslation } from "../../i18n/use-translation.js";
11
14
  const toCssLength = (v) => typeof v === "number" ? `${v}px` : v;
12
15
  const SHEET_BREAKPOINT_TOKEN = "--sheet-responsive-breakpoint-width";
@@ -36,33 +39,74 @@ function useSheetResponsiveMode(responsive = "side") {
36
39
  if (responsive === "side" || responsive === "bottom") return responsive;
37
40
  return compact ? "bottom" : "side";
38
41
  }
39
- function Sheet(props) {
40
- return /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "sheet", ...props });
42
+ const SheetOpenContext = React.createContext(null);
43
+ function useSheetOpenState(component) {
44
+ const state = React.useContext(SheetOpenContext);
45
+ if (!state) {
46
+ throw new Error(`\`${component}\` ph\u1EA3i n\u1EB1m trong \`Sheet\`.`);
47
+ }
48
+ return state;
49
+ }
50
+ const SheetLabelContext = React.createContext(null);
51
+ function Sheet({ open, defaultOpen, onOpenChange, modal: _modal, children }) {
52
+ const [uncontrolled, setUncontrolled] = React.useState(defaultOpen ?? false);
53
+ const isOpen = open ?? uncontrolled;
54
+ const setOpen = React.useCallback(
55
+ (next) => {
56
+ if (next === isOpen) {
57
+ return;
58
+ }
59
+ if (open === void 0) {
60
+ setUncontrolled(next);
61
+ }
62
+ onOpenChange?.(next);
63
+ },
64
+ [isOpen, open, onOpenChange]
65
+ );
66
+ const state = React.useMemo(() => ({ isOpen, setOpen }), [isOpen, setOpen]);
67
+ return /* @__PURE__ */ jsx(SheetOpenContext.Provider, { value: state, children });
68
+ }
69
+ function SheetTrigger({ asChild, onClick, ...props }) {
70
+ const state = useSheetOpenState("SheetTrigger");
71
+ const Comp = asChild ? Slot : "button";
72
+ return /* @__PURE__ */ jsx(
73
+ Comp,
74
+ {
75
+ type: "button",
76
+ "data-slot": "sheet-trigger",
77
+ "aria-haspopup": "dialog",
78
+ "aria-expanded": state.isOpen,
79
+ "data-state": state.isOpen ? "open" : "closed",
80
+ ...props,
81
+ onClick: chain(onClick, () => {
82
+ state.setOpen(!state.isOpen);
83
+ })
84
+ }
85
+ );
41
86
  }
42
- function SheetTrigger(props) {
43
- return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { "data-slot": "sheet-trigger", ...props });
87
+ function SheetClose({ asChild, onClick, ...props }) {
88
+ const state = useSheetOpenState("SheetClose");
89
+ const Comp = asChild ? Slot : "button";
90
+ return /* @__PURE__ */ jsx(
91
+ Comp,
92
+ {
93
+ type: "button",
94
+ "data-slot": "sheet-close",
95
+ ...props,
96
+ onClick: chain(onClick, () => {
97
+ state.setOpen(false);
98
+ })
99
+ }
100
+ );
44
101
  }
45
- function SheetClose(props) {
46
- return /* @__PURE__ */ jsx(DialogPrimitive.Close, { "data-slot": "sheet-close", ...props });
102
+ function SheetPortal({ children }) {
103
+ return /* @__PURE__ */ jsx(Fragment, { children });
47
104
  }
48
- function SheetPortal(props) {
49
- return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { "data-slot": "sheet-portal", ...props });
105
+ function SheetOverlay(_props) {
106
+ return null;
50
107
  }
51
- const SheetOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
52
- DialogPrimitive.Overlay,
53
- {
54
- ref,
55
- "data-slot": "sheet-overlay",
56
- className: cn(
57
- // Scrim colour comes from the shared --overlay-background token (see dialog-layout.css),
58
- // so a service tints every overlay's backdrop from one knob instead of a baked bg-black/50.
59
- "ui-sheet-overlay data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 fixed",
60
- className
61
- ),
62
- ...props
63
- }
64
- ));
65
- SheetOverlay.displayName = DialogPrimitive.Overlay.displayName;
108
+ SheetOverlay.displayName = "SheetOverlay";
109
+ const SHEET_OVERLAY_CLASS = "ui-sheet-overlay data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 fixed";
66
110
  const sheetVariants = cva(
67
111
  "ui-sheet-panel fixed flex flex-col gap-[var(--space-chrome-gap)] bg-background px-[var(--sheet-pad-x)] py-[var(--sheet-pad-y)] transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
68
112
  {
@@ -82,35 +126,50 @@ const sheetVariants = cva(
82
126
  defaultVariants: { side: "right" }
83
127
  }
84
128
  );
85
- const SheetContent = React.forwardRef(
86
- ({
87
- side = "right",
88
- className,
89
- children,
90
- showCloseButton = true,
91
- overlayClassName,
92
- width,
93
- responsive = "side",
94
- style,
95
- ...props
96
- }, ref) => {
97
- const { t } = useTranslation();
98
- const presentation = useSheetResponsiveMode(responsive);
99
- const resolvedSide = presentation === "bottom" ? "bottom" : side;
100
- const bottomSheet = responsive !== "side" && presentation === "bottom";
101
- const horizontal = resolvedSide === "left" || resolvedSide === "right";
102
- const widthSet = width != null && horizontal;
103
- const mergedStyle = widthSet ? { ...style, ["--sheet-width"]: toCssLength(width) } : style;
104
- return /* @__PURE__ */ jsxs(SheetPortal, { children: [
105
- /* @__PURE__ */ jsx(SheetOverlay, { className: overlayClassName }),
106
- /* @__PURE__ */ jsxs(
107
- DialogPrimitive.Content,
129
+ function SheetContent({
130
+ side = "right",
131
+ className,
132
+ children,
133
+ showCloseButton = true,
134
+ overlayClassName,
135
+ forceMount: _forceMount,
136
+ width,
137
+ responsive = "side",
138
+ style,
139
+ ref,
140
+ ...props
141
+ }) {
142
+ const { t } = useTranslation();
143
+ const state = useSheetOpenState("SheetContent");
144
+ const presentation = useSheetResponsiveMode(responsive);
145
+ const titleId = React.useId();
146
+ const descriptionId = React.useId();
147
+ const labels = React.useMemo(() => ({ titleId, descriptionId }), [titleId, descriptionId]);
148
+ const resolvedSide = presentation === "bottom" ? "bottom" : side;
149
+ const bottomSheet = responsive !== "side" && presentation === "bottom";
150
+ const horizontal = resolvedSide === "left" || resolvedSide === "right";
151
+ const widthSet = width != null && horizontal;
152
+ const mergedStyle = widthSet ? { ...style, ["--sheet-width"]: toCssLength(width) } : style;
153
+ const dataState = state.isOpen ? "open" : "closed";
154
+ useOverlayCloseFocus(state.isOpen);
155
+ return /* @__PURE__ */ jsx(
156
+ ModalOverlay,
157
+ {
158
+ isOpen: state.isOpen,
159
+ onOpenChange: state.setOpen,
160
+ isDismissable: true,
161
+ "data-slot": "sheet-overlay",
162
+ "data-state": dataState,
163
+ className: cn(SHEET_OVERLAY_CLASS, overlayClassName),
164
+ children: /* @__PURE__ */ jsx(Modal, { className: "contents", children: /* @__PURE__ */ jsx(
165
+ RacDialog,
108
166
  {
109
- ref,
167
+ "aria-labelledby": props["aria-labelledby"] ?? titleId,
168
+ "aria-describedby": props["aria-describedby"] ?? descriptionId,
110
169
  "data-slot": "sheet-content",
170
+ "data-state": dataState,
111
171
  "data-responsive": responsive,
112
172
  "data-side": resolvedSide,
113
- style: mergedStyle,
114
173
  className: cn(
115
174
  sheetVariants({ side: resolvedSide }),
116
175
  // `width` caps at the viewport: full-width panel on a small screen, capped on a large one.
@@ -120,13 +179,15 @@ const SheetContent = React.forwardRef(
120
179
  bottomSheet && "max-h-[var(--sheet-bottom-max-height)]",
121
180
  className
122
181
  ),
123
- ...props,
124
- children: [
182
+ render: (racProps) => {
183
+ const { "data-rac": _rac, ref: racRef, ...rest } = racProps;
184
+ return /* @__PURE__ */ jsx("section", { ...rest, ...props, style: mergedStyle, ref: mergeRefs(ref, racRef) });
185
+ },
186
+ children: /* @__PURE__ */ jsxs(SheetLabelContext.Provider, { value: labels, children: [
125
187
  children,
126
188
  showCloseButton ? /* @__PURE__ */ jsxs(
127
- DialogPrimitive.Close,
189
+ SheetClose,
128
190
  {
129
- "data-slot": "sheet-close",
130
191
  className: "ui-sheet-close ui-focus-ring disabled:pointer-events-none",
131
192
  children: [
132
193
  /* @__PURE__ */ jsx(X, { className: "ui-sheet-close-icon", "aria-hidden": "true" }),
@@ -134,13 +195,13 @@ const SheetContent = React.forwardRef(
134
195
  ]
135
196
  }
136
197
  ) : null
137
- ]
198
+ ] })
138
199
  }
139
- )
140
- ] });
141
- }
142
- );
143
- SheetContent.displayName = DialogPrimitive.Content.displayName;
200
+ ) })
201
+ }
202
+ );
203
+ }
204
+ SheetContent.displayName = "SheetContent";
144
205
  const SheetHeader = ({
145
206
  className,
146
207
  title,
@@ -191,7 +252,7 @@ const SheetBody = ({ className, ...props }) => (
191
252
  )
192
253
  );
193
254
  const SheetFooter = ({ className, ...props }) => (
194
- // Pinned action bar (Ant Design Drawer footer): sticks to the bottom, full-bleed top border, actions
255
+ // Pinned action bar (the Drawer footer convention): sticks to the bottom, full-bleed top border, actions
195
256
  // RIGHT-aligned (primary rightmost). A destructive / clear / reset action goes far-LEFT — give it
196
257
  // `className="me-auto"`. See cardinal rule "Drawer & dialog footer layout".
197
258
  // Owns its full vertical padding (symmetric 16/16) via `py-4`; `-mb-6` cancels SheetContent's
@@ -208,26 +269,34 @@ const SheetFooter = ({ className, ...props }) => (
208
269
  }
209
270
  )
210
271
  );
211
- const SheetTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
212
- DialogPrimitive.Title,
213
- {
214
- ref,
215
- "data-slot": "sheet-title",
216
- className: cn("ui-sheet-title", className),
217
- ...props
218
- }
219
- ));
220
- SheetTitle.displayName = DialogPrimitive.Title.displayName;
221
- const SheetDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
222
- DialogPrimitive.Description,
223
- {
224
- ref,
225
- "data-slot": "sheet-description",
226
- className: cn("ui-sheet-description", className),
227
- ...props
228
- }
229
- ));
230
- SheetDescription.displayName = DialogPrimitive.Description.displayName;
272
+ const SheetTitle = React.forwardRef(({ className, ...props }, ref) => {
273
+ const labels = React.useContext(SheetLabelContext);
274
+ return /* @__PURE__ */ jsx(
275
+ "h2",
276
+ {
277
+ ref,
278
+ id: labels?.titleId,
279
+ "data-slot": "sheet-title",
280
+ className: cn("ui-sheet-title", className),
281
+ ...props
282
+ }
283
+ );
284
+ });
285
+ SheetTitle.displayName = "SheetTitle";
286
+ const SheetDescription = React.forwardRef(({ className, ...props }, ref) => {
287
+ const labels = React.useContext(SheetLabelContext);
288
+ return /* @__PURE__ */ jsx(
289
+ "p",
290
+ {
291
+ ref,
292
+ id: labels?.descriptionId,
293
+ "data-slot": "sheet-description",
294
+ className: cn("ui-sheet-description", className),
295
+ ...props
296
+ }
297
+ );
298
+ });
299
+ SheetDescription.displayName = "SheetDescription";
231
300
  export {
232
301
  Sheet,
233
302
  SheetBody,
@@ -1,10 +1,54 @@
1
1
  import * as React from "react";
2
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
2
+ type Side = "top" | "right" | "bottom" | "left";
3
+ type Align = "start" | "center" | "end";
4
+ interface TooltipProviderProps {
5
+ /** Delay mở dùng chung cho mọi `Tooltip` bên trong, tính bằng ms. */
6
+ delayDuration?: number;
7
+ /** Không còn tác dụng trên nền RAC — cửa sổ warm-up là biến toàn cục, cứng ở 500ms. */
8
+ skipDelayDuration?: number;
9
+ /** Không còn tác dụng trên nền RAC — tooltip của React Aria luôn giữ mở khi rê lên nội dung. */
10
+ disableHoverableContent?: boolean;
11
+ }
3
12
  /** Opt-in provider for tuning delay across a subtree. Each <Tooltip> already self-provides. */
4
- export declare function TooltipProvider({ delayDuration, ...props }: React.ComponentProps<typeof TooltipPrimitive.Provider>): React.JSX.Element;
5
- /** Self-contained tooltip — no app-level provider needed. Controllable via `open`/`onOpenChange`. */
6
- export declare function Tooltip({ delayDuration, ...props }: React.ComponentProps<typeof TooltipPrimitive.Root> & {
13
+ export declare function TooltipProvider({ delayDuration, skipDelayDuration: _skipDelayDuration, disableHoverableContent: _disableHoverableContent, children, }: React.PropsWithChildren<TooltipProviderProps>): React.JSX.Element;
14
+ interface TooltipProps {
15
+ /** Trạng thái mở, kiểm soát. */
16
+ open?: boolean;
17
+ /** Trạng thái mở ban đầu khi không kiểm soát. */
18
+ defaultOpen?: boolean;
19
+ /** Gọi khi trạng thái mở/đóng đổi. */
20
+ onOpenChange?: (open: boolean) => void;
21
+ /** Delay mở riêng cho tooltip này; thắng giá trị của `TooltipProvider`. */
7
22
  delayDuration?: number;
8
- }): React.JSX.Element;
9
- export declare const TooltipTrigger: React.ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>>;
10
- export declare const TooltipContent: React.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
23
+ /** Không còn tác dụng trên nền RAC — tooltip của React Aria luôn giữ mở khi rê lên nội dung. */
24
+ disableHoverableContent?: boolean;
25
+ }
26
+ /** Self-contained tooltip — no app-level provider needed. Controllable via `open`/`onOpenChange`. */
27
+ export declare function Tooltip({ open, defaultOpen, onOpenChange, delayDuration, disableHoverableContent: _disableHoverableContent, children, }: React.PropsWithChildren<TooltipProps>): React.JSX.Element;
28
+ interface TooltipTriggerProps extends React.ComponentPropsWithRef<"button"> {
29
+ /** Mượn thẻ của con thay vì dựng `<button>` riêng. */
30
+ asChild?: boolean;
31
+ }
32
+ export declare function TooltipTrigger({ asChild, children, ...props }: TooltipTriggerProps): React.JSX.Element;
33
+ interface TooltipContentProps extends React.ComponentPropsWithRef<"div"> {
34
+ /** Cạnh của trigger mà tooltip bám vào. */
35
+ side?: Side;
36
+ /** Canh tooltip theo cạnh của trigger. */
37
+ align?: Align;
38
+ /** Khoảng cách theo trục chính, tính bằng px. */
39
+ sideOffset?: number;
40
+ /** Khoảng cách theo trục phụ, tính bằng px. */
41
+ alignOffset?: number;
42
+ /** Lật tooltip sang cạnh đối diện khi hết chỗ. */
43
+ avoidCollisions?: boolean;
44
+ /** Khoảng chừa với mép khung nhìn. RAC chỉ nhận một số; object lấy cạnh lớn nhất. */
45
+ collisionPadding?: number | Partial<Record<Side, number>>;
46
+ /** Không còn tác dụng trên nền RAC — giữ trong kiểu vì là API công khai. */
47
+ sticky?: "partial" | "always";
48
+ /** Không còn tác dụng trên nền RAC — giữ trong kiểu vì là API công khai. */
49
+ hideWhenDetached?: boolean;
50
+ /** Không còn tác dụng trên nền RAC — giữ trong kiểu vì là API công khai. */
51
+ forceMount?: true;
52
+ }
53
+ export declare function TooltipContent({ className, style, children, ref, side, align, sideOffset, alignOffset, avoidCollisions, collisionPadding, sticky: _sticky, hideWhenDetached: _hideWhenDetached, forceMount: _forceMount, ...props }: TooltipContentProps): React.JSX.Element;
54
+ export {};
@@ -1,39 +1,121 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
4
+ import { mergeRefs } from "@react-aria/utils";
5
+ import {
6
+ Focusable,
7
+ Tooltip as AriaTooltip,
8
+ TooltipTrigger as AriaTooltipTrigger,
9
+ TooltipTriggerStateContext
10
+ } from "react-aria-components";
5
11
  import { cn } from "../../lib/utils.js";
12
+ import { Slot } from "../../lib/slot.js";
13
+ const DEFAULT_DELAY_DURATION = 200;
14
+ function toPlacement(side, align) {
15
+ if (align === "center") return side;
16
+ if (side === "top" || side === "bottom") return `${side} ${align}`;
17
+ return `${side} ${align === "start" ? "top" : "bottom"}`;
18
+ }
19
+ function toContainerPadding(padding) {
20
+ if (padding == null) return void 0;
21
+ if (typeof padding === "number") return padding;
22
+ const sides = Object.values(padding).filter(
23
+ (value) => typeof value === "number"
24
+ );
25
+ return sides.length ? Math.max(...sides) : void 0;
26
+ }
27
+ const TooltipDelayContext = React.createContext(void 0);
6
28
  function TooltipProvider({
7
- delayDuration = 200,
8
- ...props
29
+ delayDuration = DEFAULT_DELAY_DURATION,
30
+ skipDelayDuration: _skipDelayDuration,
31
+ disableHoverableContent: _disableHoverableContent,
32
+ children
9
33
  }) {
10
- return /* @__PURE__ */ jsx(TooltipPrimitive.Provider, { delayDuration, ...props });
34
+ return /* @__PURE__ */ jsx(TooltipDelayContext.Provider, { value: delayDuration, children });
11
35
  }
12
36
  function Tooltip({
13
- delayDuration = 200,
37
+ open,
38
+ defaultOpen,
39
+ onOpenChange,
40
+ delayDuration,
41
+ disableHoverableContent: _disableHoverableContent,
42
+ children
43
+ }) {
44
+ const providedDelay = React.useContext(TooltipDelayContext);
45
+ return /* @__PURE__ */ jsx(
46
+ AriaTooltipTrigger,
47
+ {
48
+ delay: delayDuration ?? providedDelay ?? DEFAULT_DELAY_DURATION,
49
+ isOpen: open,
50
+ defaultOpen,
51
+ onOpenChange,
52
+ children
53
+ }
54
+ );
55
+ }
56
+ function TooltipTrigger({ asChild, children, ...props }) {
57
+ const state = React.useContext(TooltipTriggerStateContext);
58
+ const Comp = asChild ? Slot : "button";
59
+ return /* @__PURE__ */ jsx(Focusable, { children: /* @__PURE__ */ jsx(Comp, { type: "button", "data-state": state?.isOpen ? "delayed-open" : "closed", ...props, children }) });
60
+ }
61
+ function TooltipContent({
62
+ className,
63
+ style,
64
+ children,
65
+ ref,
66
+ side = "top",
67
+ align = "center",
68
+ sideOffset = 6,
69
+ alignOffset,
70
+ avoidCollisions = true,
71
+ collisionPadding,
72
+ sticky: _sticky,
73
+ hideWhenDetached: _hideWhenDetached,
74
+ forceMount: _forceMount,
14
75
  ...props
15
76
  }) {
16
- return /* @__PURE__ */ jsx(TooltipPrimitive.Provider, { delayDuration, children: /* @__PURE__ */ jsx(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
77
+ return /* @__PURE__ */ jsx(
78
+ AriaTooltip,
79
+ {
80
+ placement: toPlacement(side, align),
81
+ offset: sideOffset,
82
+ crossOffset: alignOffset,
83
+ shouldFlip: avoidCollisions,
84
+ containerPadding: toContainerPadding(collisionPadding),
85
+ render: (racProps, { isExiting }) => {
86
+ const {
87
+ className: _racClassName,
88
+ "data-rac": _rac,
89
+ ref: racRef,
90
+ style: racStyle,
91
+ children: _racChildren,
92
+ ...rest
93
+ } = racProps;
94
+ return /* @__PURE__ */ jsx(
95
+ "div",
96
+ {
97
+ ...rest,
98
+ "data-slot": "tooltip-content",
99
+ "data-side": side,
100
+ "data-align": align,
101
+ "data-state": isExiting ? "closed" : "delayed-open",
102
+ ...props,
103
+ ref: mergeRefs(ref, racRef),
104
+ className: cn(
105
+ "ui-tooltip-content",
106
+ "data-[state=delayed-open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=delayed-open]:fade-in-0",
107
+ "data-[side=bottom]:slide-in-from-top-1 data-[side=top]:slide-in-from-bottom-1",
108
+ "data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1",
109
+ className
110
+ ),
111
+ style: { ...racStyle, ...style },
112
+ children
113
+ }
114
+ );
115
+ }
116
+ }
117
+ );
17
118
  }
18
- const TooltipTrigger = TooltipPrimitive.Trigger;
19
- const TooltipContent = React.forwardRef(({ className, sideOffset = 6, children, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
20
- TooltipPrimitive.Content,
21
- {
22
- ref,
23
- "data-slot": "tooltip-content",
24
- sideOffset,
25
- className: cn(
26
- "ui-tooltip-content",
27
- "data-[state=delayed-open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=delayed-open]:fade-in-0",
28
- "data-[side=bottom]:slide-in-from-top-1 data-[side=top]:slide-in-from-bottom-1",
29
- "data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1",
30
- className
31
- ),
32
- ...props,
33
- children
34
- }
35
- ) }));
36
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
37
119
  export {
38
120
  Tooltip,
39
121
  TooltipContent,
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { Slot } from "@radix-ui/react-slot";
4
+ import { Slot } from "../../lib/slot.js";
5
5
  import { cva } from "class-variance-authority";
6
6
  import { Loader2 } from "lucide-react";
7
7
  import { cn } from "../../lib/utils.js";
@@ -12,7 +12,7 @@ const buttonVariants = cva("ui-button", {
12
12
  // Colour is the TOKEN LAYER's (`.ui-button--default` in styles/control.css), not a utility's.
13
13
  // The three utilities that used to sit here — `bg-primary text-primary-foreground
14
14
  // hover:bg-primary/90` — restated the fill the components layer already declares and, being
15
- // utilities, out-ranked it: the hover step this library generates from antd's algorithm
15
+ // utilities, out-ranked it: the hover step this library takes from the derived tier
16
16
  // (`--primary-hover`) could never take effect while `hover:bg-primary/90` was emitted here.
17
17
  default: "ui-button--default",
18
18
  destructive: "ui-button--destructive bg-destructive text-destructive-foreground",
@@ -45,6 +45,23 @@ export interface LogoProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "
45
45
  * readable wordmark sits beside it.
46
46
  */
47
47
  label?: string;
48
+ /**
49
+ * Mượn thẻ của con làm GỐC của logo thay vì dựng `<span>` — cách để cả cái logo trở thành một
50
+ * LIÊN KẾT (`<a>`, hay `<Link>` của router).
51
+ *
52
+ * Vì sao cần một prop chứ không phải bọc ngoài: `.ui-logo-lockup` là `display: inline-flex`, nên
53
+ * bọc nó trong một `<a>` thường (`display: inline`) đặt lockup lên một line box và phần descender
54
+ * của strut đội thêm vài px vào ô mark — logo bị nhích lên trong thanh trên. Consumer chỉ còn
55
+ * cách viết `className="flex"` lên thẻ `<a>`, thứ `ui-audit` chặn đúng theo luật
56
+ * `no-utility-layout` (đo ở godx-chat, 08/09/2026). Với `asChild`, chính thẻ của consumer MANG
57
+ * `.ui-logo-lockup`, nên không còn phần tử trung gian nào để canh.
58
+ *
59
+ * Đúng MỘT con, và ruột của nó bị bỏ qua: nội dung của logo vẫn do `glyph`/`mark`/`wordmark`
60
+ * quyết định.
61
+ */
62
+ asChild?: boolean;
63
+ /** Chỉ dùng cùng `asChild`: đúng một phần tử để đi mượn. */
64
+ children?: React.ReactNode;
48
65
  }
49
66
  /**
50
67
  * The band the glyph's ink actually occupies, as the (top edge, bottom edge) of the UNION of every