@gouno/ui 0.3.2

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 (231) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/LICENSE +21 -0
  3. package/README.md +144 -0
  4. package/dist/base.css +239 -0
  5. package/dist/bootstrap.js +22 -0
  6. package/dist/components/primitives/alert-dialog.d.ts +18 -0
  7. package/dist/components/primitives/alert-dialog.js +43 -0
  8. package/dist/components/primitives/alert.d.ts +9 -0
  9. package/dist/components/primitives/alert.js +25 -0
  10. package/dist/components/primitives/avatar.d.ts +14 -0
  11. package/dist/components/primitives/avatar.js +42 -0
  12. package/dist/components/primitives/badge.d.ts +9 -0
  13. package/dist/components/primitives/badge.js +25 -0
  14. package/dist/components/primitives/button.d.ts +10 -0
  15. package/dist/components/primitives/button.js +36 -0
  16. package/dist/components/primitives/checkbox.d.ts +4 -0
  17. package/dist/components/primitives/checkbox.js +10 -0
  18. package/dist/components/primitives/dialog.d.ts +20 -0
  19. package/dist/components/primitives/dialog.js +37 -0
  20. package/dist/components/primitives/dropdown-menu.d.ts +25 -0
  21. package/dist/components/primitives/dropdown-menu.js +51 -0
  22. package/dist/components/primitives/empty.d.ts +11 -0
  23. package/dist/components/primitives/empty.js +33 -0
  24. package/dist/components/primitives/field.d.ts +24 -0
  25. package/dist/components/primitives/field.js +75 -0
  26. package/dist/components/primitives/input.d.ts +3 -0
  27. package/dist/components/primitives/input.js +7 -0
  28. package/dist/components/primitives/label.d.ts +4 -0
  29. package/dist/components/primitives/label.js +8 -0
  30. package/dist/components/primitives/popover.d.ts +16 -0
  31. package/dist/components/primitives/popover.js +31 -0
  32. package/dist/components/primitives/radio-group.d.ts +5 -0
  33. package/dist/components/primitives/radio-group.js +13 -0
  34. package/dist/components/primitives/select.d.ts +15 -0
  35. package/dist/components/primitives/select.js +38 -0
  36. package/dist/components/primitives/separator.d.ts +4 -0
  37. package/dist/components/primitives/separator.js +8 -0
  38. package/dist/components/primitives/sheet.d.ts +17 -0
  39. package/dist/components/primitives/sheet.js +41 -0
  40. package/dist/components/primitives/skeleton.d.ts +2 -0
  41. package/dist/components/primitives/skeleton.js +6 -0
  42. package/dist/components/primitives/switch.d.ts +6 -0
  43. package/dist/components/primitives/switch.js +8 -0
  44. package/dist/components/primitives/table.d.ts +28 -0
  45. package/dist/components/primitives/table.js +44 -0
  46. package/dist/components/primitives/tabs.d.ts +11 -0
  47. package/dist/components/primitives/tabs.js +30 -0
  48. package/dist/components/primitives/textarea.d.ts +3 -0
  49. package/dist/components/primitives/textarea.js +7 -0
  50. package/dist/components/primitives/tooltip.d.ts +13 -0
  51. package/dist/components/primitives/tooltip.js +24 -0
  52. package/dist/core/affix.d.ts +14 -0
  53. package/dist/core/affix.js +29 -0
  54. package/dist/core/alert.d.ts +54 -0
  55. package/dist/core/alert.js +56 -0
  56. package/dist/core/anchor.d.ts +16 -0
  57. package/dist/core/anchor.js +31 -0
  58. package/dist/core/app.d.ts +5 -0
  59. package/dist/core/app.js +5 -0
  60. package/dist/core/aspect-ratio.d.ts +6 -0
  61. package/dist/core/aspect-ratio.js +6 -0
  62. package/dist/core/autocomplete.d.ts +24 -0
  63. package/dist/core/autocomplete.js +139 -0
  64. package/dist/core/avatar.d.ts +26 -0
  65. package/dist/core/avatar.js +20 -0
  66. package/dist/core/badge.d.ts +16 -0
  67. package/dist/core/badge.js +22 -0
  68. package/dist/core/breadcrumb.d.ts +55 -0
  69. package/dist/core/breadcrumb.js +69 -0
  70. package/dist/core/button.d.ts +49 -0
  71. package/dist/core/button.js +66 -0
  72. package/dist/core/calendar.d.ts +48 -0
  73. package/dist/core/calendar.js +179 -0
  74. package/dist/core/card.d.ts +30 -0
  75. package/dist/core/card.js +12 -0
  76. package/dist/core/carousel.d.ts +49 -0
  77. package/dist/core/carousel.js +166 -0
  78. package/dist/core/cascader.d.ts +19 -0
  79. package/dist/core/cascader.js +45 -0
  80. package/dist/core/code-block.d.ts +16 -0
  81. package/dist/core/code-block.js +47 -0
  82. package/dist/core/collapse.d.ts +49 -0
  83. package/dist/core/collapse.js +96 -0
  84. package/dist/core/color-picker.d.ts +9 -0
  85. package/dist/core/color-picker.js +8 -0
  86. package/dist/core/config-provider.d.ts +10 -0
  87. package/dist/core/config-provider.js +14 -0
  88. package/dist/core/control-types.d.ts +2 -0
  89. package/dist/core/control-types.js +7 -0
  90. package/dist/core/date-picker.d.ts +13 -0
  91. package/dist/core/date-picker.js +14 -0
  92. package/dist/core/date-range-picker.d.ts +26 -0
  93. package/dist/core/date-range-picker.js +10 -0
  94. package/dist/core/descriptions.d.ts +41 -0
  95. package/dist/core/descriptions.js +133 -0
  96. package/dist/core/drawer.d.ts +9 -0
  97. package/dist/core/drawer.js +58 -0
  98. package/dist/core/empty.d.ts +8 -0
  99. package/dist/core/empty.js +5 -0
  100. package/dist/core/feedback.d.ts +5 -0
  101. package/dist/core/feedback.js +5 -0
  102. package/dist/core/field.d.ts +15 -0
  103. package/dist/core/field.js +19 -0
  104. package/dist/core/float-button.d.ts +13 -0
  105. package/dist/core/float-button.js +22 -0
  106. package/dist/core/form.d.ts +19 -0
  107. package/dist/core/form.js +56 -0
  108. package/dist/core/icon-button.d.ts +7 -0
  109. package/dist/core/icon-button.js +4 -0
  110. package/dist/core/icon.d.ts +17 -0
  111. package/dist/core/icon.js +35 -0
  112. package/dist/core/image.d.ts +76 -0
  113. package/dist/core/image.js +189 -0
  114. package/dist/core/index.d.ts +79 -0
  115. package/dist/core/index.js +77 -0
  116. package/dist/core/input-number.d.ts +24 -0
  117. package/dist/core/input-number.js +70 -0
  118. package/dist/core/input-otp.d.ts +14 -0
  119. package/dist/core/input-otp.js +76 -0
  120. package/dist/core/input.d.ts +14 -0
  121. package/dist/core/input.js +51 -0
  122. package/dist/core/kbd.d.ts +8 -0
  123. package/dist/core/kbd.js +11 -0
  124. package/dist/core/layout-primitives.d.ts +11 -0
  125. package/dist/core/layout-primitives.js +8 -0
  126. package/dist/core/layout.d.ts +71 -0
  127. package/dist/core/layout.js +119 -0
  128. package/dist/core/list.d.ts +37 -0
  129. package/dist/core/list.js +35 -0
  130. package/dist/core/locale.d.ts +48 -0
  131. package/dist/core/locale.js +32 -0
  132. package/dist/core/mentions.d.ts +10 -0
  133. package/dist/core/mentions.js +112 -0
  134. package/dist/core/menu.d.ts +79 -0
  135. package/dist/core/menu.js +265 -0
  136. package/dist/core/message.d.ts +16 -0
  137. package/dist/core/message.js +36 -0
  138. package/dist/core/modal.d.ts +40 -0
  139. package/dist/core/modal.js +67 -0
  140. package/dist/core/notification.d.ts +15 -0
  141. package/dist/core/notification.js +39 -0
  142. package/dist/core/page-layout.d.ts +6 -0
  143. package/dist/core/page-layout.js +7 -0
  144. package/dist/core/pagination.d.ts +28 -0
  145. package/dist/core/pagination.js +69 -0
  146. package/dist/core/popconfirm.d.ts +13 -0
  147. package/dist/core/popconfirm.js +42 -0
  148. package/dist/core/progress.d.ts +6 -0
  149. package/dist/core/progress.js +8 -0
  150. package/dist/core/public-props.d.ts +82 -0
  151. package/dist/core/public-props.js +1 -0
  152. package/dist/core/qrcode.d.ts +14 -0
  153. package/dist/core/qrcode.js +17 -0
  154. package/dist/core/rate.d.ts +11 -0
  155. package/dist/core/rate.js +48 -0
  156. package/dist/core/result.d.ts +12 -0
  157. package/dist/core/result.js +19 -0
  158. package/dist/core/segmented.d.ts +29 -0
  159. package/dist/core/segmented.js +38 -0
  160. package/dist/core/select.d.ts +27 -0
  161. package/dist/core/select.js +143 -0
  162. package/dist/core/selection-controls.d.ts +12 -0
  163. package/dist/core/selection-controls.js +23 -0
  164. package/dist/core/separator.d.ts +24 -0
  165. package/dist/core/separator.js +17 -0
  166. package/dist/core/slider.d.ts +2 -0
  167. package/dist/core/slider.js +6 -0
  168. package/dist/core/spin.d.ts +7 -0
  169. package/dist/core/spin.js +7 -0
  170. package/dist/core/spinner.d.ts +3 -0
  171. package/dist/core/spinner.js +6 -0
  172. package/dist/core/splitter.d.ts +44 -0
  173. package/dist/core/splitter.js +208 -0
  174. package/dist/core/statistic.d.ts +12 -0
  175. package/dist/core/statistic.js +6 -0
  176. package/dist/core/steps.d.ts +54 -0
  177. package/dist/core/steps.js +106 -0
  178. package/dist/core/tabs.d.ts +40 -0
  179. package/dist/core/tabs.js +80 -0
  180. package/dist/core/tag.d.ts +19 -0
  181. package/dist/core/tag.js +29 -0
  182. package/dist/core/textarea.d.ts +8 -0
  183. package/dist/core/textarea.js +14 -0
  184. package/dist/core/time-picker.d.ts +9 -0
  185. package/dist/core/time-picker.js +8 -0
  186. package/dist/core/timeline.d.ts +37 -0
  187. package/dist/core/timeline.js +48 -0
  188. package/dist/core/tour.d.ts +18 -0
  189. package/dist/core/tour.js +51 -0
  190. package/dist/core/transfer.d.ts +16 -0
  191. package/dist/core/transfer.js +46 -0
  192. package/dist/core/tree-select.d.ts +19 -0
  193. package/dist/core/tree-select.js +19 -0
  194. package/dist/core/tree.d.ts +89 -0
  195. package/dist/core/tree.js +386 -0
  196. package/dist/core/typography.d.ts +20 -0
  197. package/dist/core/typography.js +12 -0
  198. package/dist/core/upload.d.ts +20 -0
  199. package/dist/core/upload.js +72 -0
  200. package/dist/core/watermark.d.ts +10 -0
  201. package/dist/core/watermark.js +21 -0
  202. package/dist/fonts/inter-LICENSE +93 -0
  203. package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
  204. package/dist/fonts/jetbrains-mono-LICENSE +93 -0
  205. package/dist/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  206. package/dist/gouno/app-shell.d.ts +22 -0
  207. package/dist/gouno/app-shell.js +27 -0
  208. package/dist/gouno/index.d.ts +4 -0
  209. package/dist/gouno/index.js +4 -0
  210. package/dist/gouno/page-container.d.ts +4 -0
  211. package/dist/gouno/page-container.js +6 -0
  212. package/dist/gouno/page-header.d.ts +8 -0
  213. package/dist/gouno/page-header.js +6 -0
  214. package/dist/hooks/use-overlay-body.d.ts +6 -0
  215. package/dist/hooks/use-overlay-body.js +18 -0
  216. package/dist/index.d.ts +5 -0
  217. package/dist/index.js +5 -0
  218. package/dist/lib/utils.d.ts +2 -0
  219. package/dist/lib/utils.js +5 -0
  220. package/dist/patterns/bulk-action-bar.d.ts +8 -0
  221. package/dist/patterns/bulk-action-bar.js +7 -0
  222. package/dist/patterns/index.d.ts +5 -0
  223. package/dist/patterns/index.js +5 -0
  224. package/dist/theme/index.d.ts +2 -0
  225. package/dist/theme/index.js +2 -0
  226. package/dist/theme/provider.d.ts +22 -0
  227. package/dist/theme/provider.js +76 -0
  228. package/dist/theme/theme-toggle.d.ts +6 -0
  229. package/dist/theme/theme-toggle.js +10 -0
  230. package/dist/tokens.css +164 -0
  231. package/package.json +111 -0
@@ -0,0 +1,10 @@
1
+ import { type TextareaProps } from "./textarea.js";
2
+ export interface MentionsProps extends Omit<TextareaProps, "value" | "defaultValue" | "onChange" | "onSelect" | "role" | "aria-autocomplete" | "aria-controls" | "aria-activedescendant" | "aria-haspopup" | "aria-expanded"> {
3
+ options: readonly string[];
4
+ prefix?: string;
5
+ value?: string;
6
+ defaultValue?: string;
7
+ onChange?: (value: string) => void;
8
+ onSelect?: (value: string) => void;
9
+ }
10
+ export declare const Mentions: import("react").ForwardRefExoticComponent<MentionsProps & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,112 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useId, useState, } from "react";
3
+ import { cn } from "../lib/utils.js";
4
+ import { Textarea } from "./textarea.js";
5
+ function escapeRegExp(value) {
6
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7
+ }
8
+ function findActiveMention(value, prefix) {
9
+ if (!prefix)
10
+ return null;
11
+ const match = value.match(new RegExp(`${escapeRegExp(prefix)}([^\\s]*)$`, "u"));
12
+ if (!match || match.index === undefined)
13
+ return null;
14
+ return { start: match.index, query: match[1] ?? "" };
15
+ }
16
+ export const Mentions = forwardRef(function Mentions({ options, prefix = "@", value, defaultValue = "", onChange, onSelect, className, disabled, readOnly, onFocus, onBlur, onKeyDown, ...props }, ref) {
17
+ const [inner, setInner] = useState(defaultValue);
18
+ const [focused, setFocused] = useState(false);
19
+ const [dismissed, setDismissed] = useState(false);
20
+ const [highlighted, setHighlighted] = useState(0);
21
+ const listboxId = useId();
22
+ const current = value ?? inner;
23
+ const activeMention = findActiveMention(current, prefix);
24
+ const query = activeMention?.query.toLocaleLowerCase() ?? "";
25
+ const matches = activeMention
26
+ ? options.filter((option) => option.toLocaleLowerCase().includes(query))
27
+ : [];
28
+ const activeIndex = matches.length === 0
29
+ ? -1
30
+ : Math.min(Math.max(highlighted, 0), matches.length - 1);
31
+ const popupOpen = focused &&
32
+ !dismissed &&
33
+ Boolean(activeMention) &&
34
+ matches.length > 0 &&
35
+ !disabled &&
36
+ !readOnly;
37
+ const update = (next) => {
38
+ if (value === undefined)
39
+ setInner(next);
40
+ onChange?.(next);
41
+ };
42
+ const choose = (option) => {
43
+ if (!activeMention || disabled || readOnly)
44
+ return;
45
+ const next = `${current.slice(0, activeMention.start)}${prefix}${option} `;
46
+ update(next);
47
+ onSelect?.(option);
48
+ setDismissed(true);
49
+ setHighlighted(0);
50
+ };
51
+ const handleKeyDown = (event) => {
52
+ onKeyDown?.(event);
53
+ if (event.defaultPrevented || disabled || readOnly)
54
+ return;
55
+ if (event.key === "ArrowDown" && activeMention && matches.length > 0) {
56
+ event.preventDefault();
57
+ if (!popupOpen) {
58
+ setDismissed(false);
59
+ setHighlighted(0);
60
+ }
61
+ else {
62
+ setHighlighted((activeIndex + 1) % matches.length);
63
+ }
64
+ }
65
+ else if (event.key === "ArrowUp" &&
66
+ focused &&
67
+ activeMention &&
68
+ matches.length > 0) {
69
+ event.preventDefault();
70
+ if (!popupOpen) {
71
+ setDismissed(false);
72
+ setHighlighted(matches.length - 1);
73
+ }
74
+ else {
75
+ setHighlighted((activeIndex - 1 + matches.length) % matches.length);
76
+ }
77
+ }
78
+ else if (event.key === "Enter" && popupOpen && activeIndex >= 0) {
79
+ event.preventDefault();
80
+ const option = matches[activeIndex];
81
+ if (option !== undefined)
82
+ choose(option);
83
+ }
84
+ else if (event.key === "Escape" && popupOpen) {
85
+ event.preventDefault();
86
+ setDismissed(true);
87
+ setHighlighted(0);
88
+ }
89
+ };
90
+ return (_jsxs("div", { "data-slot": "mentions", className: "relative min-w-0", children: [_jsx(Textarea, { ...props, ref: ref, "data-slot": "mentions-input", value: current, disabled: disabled, readOnly: readOnly, "aria-autocomplete": "list", "aria-haspopup": "listbox", "aria-controls": popupOpen ? listboxId : undefined, "aria-activedescendant": popupOpen && activeIndex >= 0
91
+ ? `${listboxId}-option-${activeIndex}`
92
+ : undefined, onFocus: (event) => {
93
+ onFocus?.(event);
94
+ if (!event.defaultPrevented && !disabled && !readOnly) {
95
+ setFocused(true);
96
+ setDismissed(false);
97
+ setHighlighted(0);
98
+ }
99
+ }, onBlur: (event) => {
100
+ onBlur?.(event);
101
+ setFocused(false);
102
+ setDismissed(false);
103
+ setHighlighted(0);
104
+ }, onKeyDown: handleKeyDown, onChange: (event) => {
105
+ update(event.target.value);
106
+ setDismissed(false);
107
+ setHighlighted(0);
108
+ }, className: cn("min-h-24", className) }), popupOpen ? (_jsx("ul", { id: listboxId, role: "listbox", "data-slot": "mentions-popup", className: "absolute z-50 mt-1 max-h-48 w-full overflow-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-overlay", children: matches.map((option, index) => (_jsxs("li", { id: `${listboxId}-option-${index}`, role: "option", "aria-selected": index === activeIndex, "data-slot": "mentions-option", "data-highlighted": index === activeIndex || undefined, className: cn("cursor-pointer rounded px-2 py-1.5 text-sm", index === activeIndex && "bg-accent text-accent-foreground", "hover:bg-accent hover:text-accent-foreground"), onMouseEnter: () => setHighlighted(index), onMouseDown: (event) => {
109
+ event.preventDefault();
110
+ choose(option);
111
+ }, children: [prefix, option] }, `${option}-${index}`))) })) : null] }));
112
+ });
@@ -0,0 +1,79 @@
1
+ import { type CSSProperties, type HTMLAttributes, type Key, type KeyboardEvent, type MouseEvent, type ReactNode, type Ref } from "react";
2
+ export type MenuMode = "vertical" | "horizontal" | "inline";
3
+ export type MenuTriggerSubMenuAction = "hover" | "click";
4
+ export interface MenuItem {
5
+ key: Key;
6
+ label: ReactNode;
7
+ type?: "item";
8
+ icon?: ReactNode;
9
+ disabled?: boolean;
10
+ title?: string;
11
+ }
12
+ export interface MenuSubMenuItem {
13
+ key: Key;
14
+ label: ReactNode;
15
+ type: "submenu";
16
+ children: readonly MenuNode[];
17
+ icon?: ReactNode;
18
+ disabled?: boolean;
19
+ title?: string;
20
+ }
21
+ export interface MenuItemGroup {
22
+ key: Key;
23
+ type: "group";
24
+ label?: ReactNode;
25
+ children: readonly MenuNode[];
26
+ }
27
+ export interface MenuDividerItem {
28
+ key: Key;
29
+ type: "divider";
30
+ }
31
+ export type MenuNode = MenuItem | MenuSubMenuItem | MenuItemGroup | MenuDividerItem;
32
+ export interface MenuClickInfo {
33
+ key: Key;
34
+ keyPath: Key[];
35
+ item: MenuItem;
36
+ nativeEvent: MouseEvent<HTMLElement> | KeyboardEvent<HTMLElement>;
37
+ }
38
+ export interface MenuSelectInfo extends MenuClickInfo {
39
+ selectedKeys: Key[];
40
+ }
41
+ export interface MenuExpandIconInfo {
42
+ item: MenuSubMenuItem;
43
+ open: boolean;
44
+ mode: MenuMode;
45
+ }
46
+ export type MenuSemantic = "root" | "list" | "item" | "icon" | "label" | "submenu" | "expandIcon" | "group" | "groupLabel" | "divider";
47
+ export interface MenuSemanticInfo {
48
+ props: Readonly<{
49
+ mode: MenuMode;
50
+ multiple: boolean;
51
+ selectable: boolean;
52
+ inlineCollapsed: boolean;
53
+ }>;
54
+ }
55
+ export type MenuClassNames = Partial<Record<MenuSemantic, string>> | ((info: MenuSemanticInfo) => Partial<Record<MenuSemantic, string>>);
56
+ export type MenuStyles = Partial<Record<MenuSemantic, CSSProperties>> | ((info: MenuSemanticInfo) => Partial<Record<MenuSemantic, CSSProperties>>);
57
+ export interface MenuProps extends Omit<HTMLAttributes<HTMLElement>, "children" | "onClick" | "onSelect"> {
58
+ items: readonly MenuNode[];
59
+ selectedKeys?: readonly Key[];
60
+ defaultSelectedKeys?: readonly Key[];
61
+ openKeys?: readonly Key[];
62
+ defaultOpenKeys?: readonly Key[];
63
+ mode?: MenuMode;
64
+ multiple?: boolean;
65
+ selectable?: boolean;
66
+ inlineCollapsed?: boolean;
67
+ inlineIndent?: number;
68
+ triggerSubMenuAction?: MenuTriggerSubMenuAction;
69
+ forceSubMenuRender?: boolean;
70
+ expandIcon?: ReactNode | ((info: MenuExpandIconInfo) => ReactNode);
71
+ onClick?: (info: MenuClickInfo) => void;
72
+ onSelect?: (info: MenuSelectInfo) => void;
73
+ onDeselect?: (info: MenuSelectInfo) => void;
74
+ onOpenChange?: (openKeys: Key[]) => void;
75
+ classNames?: MenuClassNames;
76
+ styles?: MenuStyles;
77
+ ref?: Ref<HTMLElement>;
78
+ }
79
+ export declare function Menu({ items, selectedKeys, defaultSelectedKeys, openKeys, defaultOpenKeys, mode, multiple, selectable, inlineCollapsed, inlineIndent, triggerSubMenuAction, forceSubMenuRender, expandIcon, onClick, onSelect, onDeselect, onOpenChange, classNames, styles, className, style, onKeyDown, "aria-label": ariaLabel, ref, ...props }: MenuProps): import("react").JSX.Element;
@@ -0,0 +1,265 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useRef, useState, } from "react";
3
+ import { ChevronRight } from "lucide-react";
4
+ import { cn } from "../lib/utils.js";
5
+ function isSubMenu(item) {
6
+ return item.type === "submenu";
7
+ }
8
+ function isGroup(item) {
9
+ return item.type === "group";
10
+ }
11
+ function isDivider(item) {
12
+ return item.type === "divider";
13
+ }
14
+ function keyToken(key) {
15
+ return `${typeof key === "number" ? "n" : "s"}:${String(key)}`;
16
+ }
17
+ function includesKey(keys, key) {
18
+ return keys.some((candidate) => candidate === key);
19
+ }
20
+ function uniqueKeys(keys) {
21
+ return Array.from(new Set(keys));
22
+ }
23
+ function collectVisibleFocusableKeys(items, openKeys) {
24
+ return items.flatMap((item) => {
25
+ if (isDivider(item))
26
+ return [];
27
+ if (isGroup(item))
28
+ return collectVisibleFocusableKeys(item.children, openKeys);
29
+ if (item.disabled)
30
+ return [];
31
+ return [
32
+ item.key,
33
+ ...(isSubMenu(item) && includesKey(openKeys, item.key)
34
+ ? collectVisibleFocusableKeys(item.children, openKeys)
35
+ : []),
36
+ ];
37
+ });
38
+ }
39
+ function collectKeyMap(items, map = new Map()) {
40
+ for (const item of items) {
41
+ map.set(keyToken(item.key), item.key);
42
+ if (isSubMenu(item) || isGroup(item))
43
+ collectKeyMap(item.children, map);
44
+ }
45
+ return map;
46
+ }
47
+ function assignRef(ref, value) {
48
+ if (!ref)
49
+ return;
50
+ if (typeof ref === "function") {
51
+ ref(value);
52
+ return;
53
+ }
54
+ ref.current = value;
55
+ }
56
+ function hasHiddenAncestor(element) {
57
+ let current = element;
58
+ while (current) {
59
+ if (current.hidden)
60
+ return true;
61
+ current = current.parentElement;
62
+ }
63
+ return false;
64
+ }
65
+ export function Menu({ items, selectedKeys, defaultSelectedKeys = [], openKeys, defaultOpenKeys = [], mode = "vertical", multiple = false, selectable = true, inlineCollapsed = false, inlineIndent = 24, triggerSubMenuAction = "click", forceSubMenuRender = false, expandIcon, onClick, onSelect, onDeselect, onOpenChange, classNames, styles, className, style, onKeyDown, "aria-label": ariaLabel, ref, ...props }) {
66
+ const rootRef = useRef(null);
67
+ const [innerSelectedKeys, setInnerSelectedKeys] = useState(() => uniqueKeys(defaultSelectedKeys));
68
+ const [innerOpenKeys, setInnerOpenKeys] = useState(() => uniqueKeys(defaultOpenKeys));
69
+ const actualSelectedKeys = selectedKeys ?? innerSelectedKeys;
70
+ const actualOpenKeys = openKeys ?? innerOpenKeys;
71
+ const visibleFocusableKeys = useMemo(() => collectVisibleFocusableKeys(items, actualOpenKeys), [items, actualOpenKeys]);
72
+ const keyMap = useMemo(() => collectKeyMap(items), [items]);
73
+ const [focusKey, setFocusKey] = useState(() => defaultSelectedKeys[0] ?? null);
74
+ const effectiveFocusKey = focusKey !== null && includesKey(visibleFocusableKeys, focusKey)
75
+ ? focusKey
76
+ : (visibleFocusableKeys[0] ?? null);
77
+ const normalizedInlineIndent = Number.isFinite(inlineIndent) ? Math.max(0, inlineIndent) : 24;
78
+ const collapsedInline = mode === "inline" && inlineCollapsed;
79
+ const semanticInfo = {
80
+ props: { mode, multiple, selectable, inlineCollapsed: collapsedInline },
81
+ };
82
+ const semanticClassNames = typeof classNames === "function" ? classNames(semanticInfo) : (classNames ?? {});
83
+ const semanticStyles = typeof styles === "function" ? styles(semanticInfo) : (styles ?? {});
84
+ const setSelected = (next) => {
85
+ const normalized = uniqueKeys(next);
86
+ if (selectedKeys === undefined)
87
+ setInnerSelectedKeys(normalized);
88
+ return normalized;
89
+ };
90
+ const setOpen = (next) => {
91
+ const normalized = uniqueKeys(next);
92
+ if (openKeys === undefined)
93
+ setInnerOpenKeys(normalized);
94
+ onOpenChange?.(normalized);
95
+ return normalized;
96
+ };
97
+ const toggleOpen = (key, nextOpen) => {
98
+ const currentlyOpen = includesKey(actualOpenKeys, key);
99
+ const shouldOpen = nextOpen ?? !currentlyOpen;
100
+ if (shouldOpen === currentlyOpen)
101
+ return;
102
+ setOpen(shouldOpen
103
+ ? [...actualOpenKeys, key]
104
+ : actualOpenKeys.filter((candidate) => candidate !== key));
105
+ };
106
+ const activateItem = (item, keyPath, nativeEvent) => {
107
+ const info = { key: item.key, keyPath, item, nativeEvent };
108
+ onClick?.(info);
109
+ if (!selectable || item.disabled)
110
+ return;
111
+ const selected = includesKey(actualSelectedKeys, item.key);
112
+ if (multiple && selected) {
113
+ const next = setSelected(actualSelectedKeys.filter((key) => key !== item.key));
114
+ onDeselect?.({ ...info, selectedKeys: next });
115
+ return;
116
+ }
117
+ const next = setSelected(multiple ? [...actualSelectedKeys, item.key] : [item.key]);
118
+ onSelect?.({ ...info, selectedKeys: next });
119
+ };
120
+ const focusByToken = (token) => {
121
+ if (!token)
122
+ return;
123
+ const nextKey = keyMap.get(token);
124
+ if (nextKey === undefined)
125
+ return;
126
+ setFocusKey(nextKey);
127
+ const nextElement = Array.from(rootRef.current?.querySelectorAll("[data-menu-key]") ?? []).find((element) => element.dataset.menuKey === token && !hasHiddenAncestor(element));
128
+ nextElement?.focus();
129
+ };
130
+ const visibleFocusableElements = () => Array.from(rootRef.current?.querySelectorAll("[data-menu-key]") ?? []).filter((element) => element.getAttribute("aria-disabled") !== "true" && !hasHiddenAncestor(element));
131
+ const moveFocus = (target, delta, sameDepth = false) => {
132
+ const targetDepth = target.dataset.menuDepth;
133
+ const elements = visibleFocusableElements().filter((element) => !sameDepth || element.dataset.menuDepth === targetDepth);
134
+ const index = elements.indexOf(target);
135
+ if (index < 0 || elements.length === 0)
136
+ return;
137
+ const next = elements[(index + delta + elements.length) % elements.length];
138
+ focusByToken(next.dataset.menuKey ?? null);
139
+ };
140
+ const focusBoundary = (toEnd) => {
141
+ const elements = visibleFocusableElements();
142
+ const next = toEnd ? elements[elements.length - 1] : elements[0];
143
+ focusByToken(next?.dataset.menuKey ?? null);
144
+ };
145
+ const handleRootKeyDown = (event) => {
146
+ onKeyDown?.(event);
147
+ if (event.defaultPrevented)
148
+ return;
149
+ const target = event.target instanceof HTMLElement ? event.target : null;
150
+ if (!target?.dataset.menuKey)
151
+ return;
152
+ const isHorizontalRoot = mode === "horizontal" && target.dataset.menuDepth === "0";
153
+ if (event.key === "Home" || event.key === "End") {
154
+ event.preventDefault();
155
+ focusBoundary(event.key === "End");
156
+ return;
157
+ }
158
+ if (event.key === "ArrowRight") {
159
+ if (isHorizontalRoot) {
160
+ event.preventDefault();
161
+ moveFocus(target, 1, true);
162
+ return;
163
+ }
164
+ if (target.dataset.menuSubmenu === "true") {
165
+ const key = keyMap.get(target.dataset.menuKey);
166
+ if (key !== undefined) {
167
+ event.preventDefault();
168
+ toggleOpen(key, true);
169
+ }
170
+ }
171
+ return;
172
+ }
173
+ if (event.key === "ArrowLeft") {
174
+ const parentToken = target.dataset.menuParentKey;
175
+ if (parentToken) {
176
+ const parentKey = keyMap.get(parentToken);
177
+ if (parentKey !== undefined) {
178
+ event.preventDefault();
179
+ toggleOpen(parentKey, false);
180
+ focusByToken(parentToken);
181
+ }
182
+ return;
183
+ }
184
+ if (isHorizontalRoot) {
185
+ event.preventDefault();
186
+ moveFocus(target, -1, true);
187
+ }
188
+ return;
189
+ }
190
+ if (event.key === "ArrowDown") {
191
+ if (isHorizontalRoot && target.dataset.menuSubmenu === "true") {
192
+ const key = keyMap.get(target.dataset.menuKey);
193
+ if (key !== undefined) {
194
+ event.preventDefault();
195
+ toggleOpen(key, true);
196
+ }
197
+ return;
198
+ }
199
+ event.preventDefault();
200
+ moveFocus(target, 1);
201
+ return;
202
+ }
203
+ if (event.key === "ArrowUp") {
204
+ event.preventDefault();
205
+ moveFocus(target, -1);
206
+ return;
207
+ }
208
+ if (event.key === "Escape") {
209
+ const parentToken = target.dataset.menuParentKey;
210
+ if (parentToken) {
211
+ const parentKey = keyMap.get(parentToken);
212
+ if (parentKey !== undefined) {
213
+ event.preventDefault();
214
+ toggleOpen(parentKey, false);
215
+ focusByToken(parentToken);
216
+ }
217
+ }
218
+ }
219
+ };
220
+ const renderNodes = (nodes, path = [], depth = 0, parentKey) => nodes.map((node) => {
221
+ if (isDivider(node)) {
222
+ return (_jsx("li", { role: "separator", "data-slot": "menu-divider", className: cn("my-1 h-px bg-border", semanticClassNames.divider), style: semanticStyles.divider }, node.key));
223
+ }
224
+ if (isGroup(node)) {
225
+ return (_jsxs("li", { role: "none", "data-slot": "menu-group", className: cn("min-w-0", semanticClassNames.group), style: semanticStyles.group, children: [node.label !== undefined ? (_jsx("div", { "data-slot": "menu-group-label", className: cn("px-3 py-1.5 text-xs font-medium text-muted-foreground", semanticClassNames.groupLabel), style: semanticStyles.groupLabel, children: node.label })) : null, _jsx("ul", { role: "group", className: "m-0 flex list-none flex-col gap-1 p-0", children: renderNodes(node.children, path, depth, parentKey) })] }, node.key));
226
+ }
227
+ const token = keyToken(node.key);
228
+ const parentToken = parentKey === undefined ? undefined : keyToken(parentKey);
229
+ const selected = includesKey(actualSelectedKeys, node.key);
230
+ const isFocused = effectiveFocusKey === node.key;
231
+ const itemPadding = mode === "inline" && !collapsedInline
232
+ ? { paddingInlineStart: `${12 + depth * normalizedInlineIndent}px` }
233
+ : undefined;
234
+ const label = (_jsx("span", { "data-slot": "menu-label", className: cn("min-w-0 flex-1 truncate", collapsedInline && "sr-only", semanticClassNames.label), style: semanticStyles.label, children: node.label }));
235
+ const icon = node.icon !== undefined ? (_jsx("span", { "aria-hidden": "true", "data-slot": "menu-icon", className: cn("flex size-4 shrink-0 items-center justify-center [&_svg]:size-4", semanticClassNames.icon), style: semanticStyles.icon, children: node.icon })) : null;
236
+ if (isSubMenu(node)) {
237
+ const open = includesKey(actualOpenKeys, node.key);
238
+ const popup = mode !== "inline" || collapsedInline;
239
+ const originExpandIcon = (_jsx(ChevronRight, { "aria-hidden": "true", className: cn("transition-transform", open && !popup && "rotate-90") }));
240
+ const resolvedExpandIcon = typeof expandIcon === "function"
241
+ ? expandIcon({ item: node, open, mode })
242
+ : (expandIcon ?? originExpandIcon);
243
+ const shouldRenderSubmenu = open || forceSubMenuRender;
244
+ return (_jsxs("li", { role: "none", "data-slot": "menu-submenu", className: cn("relative min-w-0", semanticClassNames.submenu), style: semanticStyles.submenu, onMouseEnter: triggerSubMenuAction === "hover" && !node.disabled
245
+ ? () => toggleOpen(node.key, true)
246
+ : undefined, onMouseLeave: triggerSubMenuAction === "hover" && !node.disabled
247
+ ? () => toggleOpen(node.key, false)
248
+ : undefined, children: [_jsxs("button", { type: "button", role: "menuitem", title: node.title, disabled: node.disabled, "aria-disabled": node.disabled || undefined, "aria-haspopup": "menu", "aria-expanded": open, "data-menu-key": token, "data-menu-parent-key": parentToken, "data-menu-submenu": "true", "data-menu-depth": depth, tabIndex: isFocused ? 0 : -1, onFocus: () => setFocusKey(node.key), onClick: () => {
249
+ if (triggerSubMenuAction === "click")
250
+ toggleOpen(node.key);
251
+ }, className: cn("flex min-h-9 w-full min-w-0 items-center gap-2 rounded-md px-3 py-2 text-left text-sm text-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50", open && "bg-accent/70 text-accent-foreground", collapsedInline && "justify-center px-2", semanticClassNames.item), style: { ...semanticStyles.item, ...itemPadding }, children: [icon, label, _jsx("span", { "aria-hidden": "true", "data-slot": "menu-expand-icon", className: cn("ml-auto flex size-4 shrink-0 items-center justify-center [&_svg]:size-4", collapsedInline && "sr-only", semanticClassNames.expandIcon), style: semanticStyles.expandIcon, children: resolvedExpandIcon })] }), shouldRenderSubmenu ? (_jsx("ul", { role: "menu", hidden: !open, "aria-label": typeof node.label === "string" ? node.label : undefined, "data-slot": "menu-list", className: cn("m-0 list-none p-0", popup
252
+ ? cn("absolute z-50 min-w-44 rounded-md border bg-popover p-1 text-popover-foreground shadow-overlay", mode === "horizontal" && depth === 0
253
+ ? "left-0 top-full mt-1"
254
+ : "left-full top-0 ml-1")
255
+ : "mt-1 flex flex-col gap-1", semanticClassNames.list), style: semanticStyles.list, children: renderNodes(node.children, [...path, node.key], depth + 1, node.key) })) : null] }, node.key));
256
+ }
257
+ const role = multiple && selectable ? "menuitemcheckbox" : "menuitem";
258
+ const keyPath = [...path, node.key];
259
+ return (_jsx("li", { role: "none", className: "min-w-0", children: _jsxs("button", { type: "button", role: role, title: node.title, disabled: node.disabled, "aria-disabled": node.disabled || undefined, "aria-current": !multiple && selectable && selected ? "page" : undefined, "aria-checked": multiple && selectable ? selected : undefined, "data-menu-key": token, "data-menu-parent-key": parentToken, "data-menu-depth": depth, tabIndex: isFocused ? 0 : -1, onFocus: () => setFocusKey(node.key), onClick: (event) => activateItem(node, keyPath, event), className: cn("flex min-h-9 w-full min-w-0 items-center gap-2 rounded-md px-3 py-2 text-left text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50", selected ? "bg-accent text-accent-foreground" : "text-foreground", collapsedInline && "justify-center px-2", semanticClassNames.item), style: { ...semanticStyles.item, ...itemPadding }, children: [icon, label] }) }, node.key));
260
+ });
261
+ return (_jsx("nav", { ...props, ref: (node) => {
262
+ rootRef.current = node;
263
+ assignRef(ref, node);
264
+ }, "aria-label": ariaLabel, "data-slot": "menu", "data-mode": mode, "data-inline-collapsed": collapsedInline || undefined, onKeyDown: handleRootKeyDown, className: cn("min-w-0", semanticClassNames.root, className), style: { ...semanticStyles.root, ...style }, children: _jsx("ul", { role: mode === "horizontal" ? "menubar" : "menu", "data-slot": "menu-list", className: cn("m-0 min-w-0 list-none p-0", mode === "horizontal" ? "flex items-center gap-1" : "flex flex-col gap-1", collapsedInline && "w-12", semanticClassNames.list), style: semanticStyles.list, children: renderNodes(items) }) }));
265
+ }
@@ -0,0 +1,16 @@
1
+ import { type ReactNode } from "react";
2
+ type MessageTone = "info" | "success" | "warning" | "error";
3
+ type MessageOpen = (content: ReactNode, tone?: MessageTone) => void;
4
+ export interface MessageProviderProps {
5
+ children: ReactNode;
6
+ duration?: number;
7
+ }
8
+ export declare function MessageProvider({ children, duration, }: MessageProviderProps): import("react").JSX.Element;
9
+ export declare function useMessage(): {
10
+ open: MessageOpen;
11
+ info: (content: ReactNode) => void;
12
+ success: (content: ReactNode) => void;
13
+ warning: (content: ReactNode) => void;
14
+ error: (content: ReactNode) => void;
15
+ };
16
+ export {};
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createContext, useCallback, useContext, useEffect, useRef, useState, } from "react";
3
+ const MessageContext = createContext(null);
4
+ export function MessageProvider({ children, duration = 2500, }) {
5
+ const [items, setItems] = useState([]);
6
+ const nextId = useRef(0);
7
+ const timers = useRef(new Map());
8
+ const show = useCallback((content, tone = "info") => {
9
+ nextId.current += 1;
10
+ const id = nextId.current;
11
+ setItems((current) => [...current, { id, content, tone }]);
12
+ const timer = setTimeout(() => {
13
+ timers.current.delete(id);
14
+ setItems((current) => current.filter((item) => item.id !== id));
15
+ }, Math.max(0, duration));
16
+ timers.current.set(id, timer);
17
+ }, [duration]);
18
+ useEffect(() => () => {
19
+ for (const timer of timers.current.values())
20
+ clearTimeout(timer);
21
+ timers.current.clear();
22
+ }, []);
23
+ return (_jsxs(MessageContext.Provider, { value: show, children: [children, _jsx("div", { "data-slot": "message-region", className: "pointer-events-none fixed inset-x-0 top-4 z-[100] flex flex-col items-center gap-2", children: items.map((item) => (_jsx("div", { "data-slot": "message", "data-tone": item.tone, role: item.tone === "error" ? "alert" : "status", "aria-atomic": "true", className: "rounded-md border bg-popover px-4 py-2 text-sm shadow-overlay", children: item.content }, item.id))) })] }));
24
+ }
25
+ export function useMessage() {
26
+ const open = useContext(MessageContext);
27
+ if (!open)
28
+ throw new Error("useMessage must be used inside MessageProvider");
29
+ return {
30
+ open,
31
+ info: (content) => open(content, "info"),
32
+ success: (content) => open(content, "success"),
33
+ warning: (content) => open(content, "warning"),
34
+ error: (content) => open(content, "error"),
35
+ };
36
+ }
@@ -0,0 +1,40 @@
1
+ import { type ReactNode, type CSSProperties } from "react";
2
+ import { type ButtonProps } from "./button.js";
3
+ export interface ModalProps {
4
+ open?: boolean;
5
+ defaultOpen?: boolean;
6
+ title?: ReactNode;
7
+ description?: ReactNode;
8
+ children?: ReactNode;
9
+ footer?: ReactNode;
10
+ onClose?: () => void;
11
+ onOpenChange?: (open: boolean) => void;
12
+ afterOpenChange?: (open: boolean) => void;
13
+ size?: "sm" | "md" | "lg" | "xl";
14
+ maxWidth?: string;
15
+ className?: string;
16
+ closeOnEsc?: boolean;
17
+ closeOnBackdrop?: boolean;
18
+ showCloseButton?: boolean;
19
+ "aria-label"?: string;
20
+ contentStyle?: CSSProperties;
21
+ loading?: boolean;
22
+ centered?: boolean;
23
+ mask?: boolean;
24
+ zIndex?: number;
25
+ destroyOnClose?: boolean;
26
+ onOk?: () => void | Promise<void>;
27
+ onCancel?: () => void;
28
+ okText?: ReactNode;
29
+ cancelText?: ReactNode;
30
+ confirmLoading?: boolean;
31
+ okButtonProps?: ButtonProps;
32
+ cancelButtonProps?: ButtonProps;
33
+ styles?: {
34
+ header?: CSSProperties;
35
+ body?: CSSProperties;
36
+ footer?: CSSProperties;
37
+ mask?: CSSProperties;
38
+ };
39
+ }
40
+ export declare function Modal({ open, defaultOpen, title, description, children, footer, onClose, onOpenChange, afterOpenChange, size, maxWidth, className, closeOnEsc, closeOnBackdrop, showCloseButton, "aria-label": ariaLabel, contentStyle, loading, centered, mask, zIndex, destroyOnClose, onOk, onCancel, okText, cancelText, confirmLoading, okButtonProps, cancelButtonProps, styles, }: ModalProps): import("react").JSX.Element;
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useEffectEvent, useRef, useState, } from "react";
3
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "../components/primitives/dialog.js";
4
+ import { Button } from "./button.js";
5
+ import { useOverlayBody } from "../hooks/use-overlay-body.js";
6
+ import { cn } from "../lib/utils.js";
7
+ const closeText = () => typeof document !== "undefined" &&
8
+ document.documentElement.lang.startsWith("en")
9
+ ? "Close"
10
+ : "关闭";
11
+ export function Modal({ open, defaultOpen = false, title, description, children, footer, onClose, onOpenChange, afterOpenChange, size = "md", maxWidth, className, closeOnEsc = true, closeOnBackdrop = false, showCloseButton = true, "aria-label": ariaLabel, contentStyle, loading = false, centered = true, mask = true, zIndex = 50, destroyOnClose = true, onOk, onCancel, okText = "确定", cancelText = "取消", confirmLoading = false, okButtonProps, cancelButtonProps, styles, }) {
12
+ const [internalOpen, setInternalOpen] = useState(defaultOpen);
13
+ const previousFocus = useRef(null);
14
+ const controlled = open !== undefined;
15
+ const visible = open ?? internalOpen;
16
+ const hasBody = loading || children != null;
17
+ const retained = useOverlayBody(children, visible, destroyOnClose);
18
+ const changeOpen = (next) => {
19
+ if (!controlled)
20
+ setInternalOpen(next);
21
+ onOpenChange?.(next);
22
+ if (!next) {
23
+ onCancel?.();
24
+ onClose?.();
25
+ }
26
+ };
27
+ useEffect(() => {
28
+ if (visible)
29
+ previousFocus.current =
30
+ document.activeElement instanceof HTMLElement
31
+ ? document.activeElement
32
+ : null;
33
+ return () => {
34
+ if (previousFocus.current?.isConnected)
35
+ previousFocus.current.focus();
36
+ };
37
+ }, [visible]);
38
+ const notifyOpenChange = useEffectEvent((next) => afterOpenChange?.(next));
39
+ useEffect(() => {
40
+ notifyOpenChange(visible);
41
+ }, [visible]);
42
+ return (_jsxs(_Fragment, { children: [retained.portal, _jsx(Dialog, { open: visible, onOpenChange: changeOpen, children: _jsxs(DialogContent, { className: cn({
43
+ sm: "sm:max-w-md",
44
+ md: "sm:max-w-xl",
45
+ lg: "sm:max-w-3xl",
46
+ xl: "sm:max-w-5xl",
47
+ }[size], !centered && "top-[10vh] translate-y-0", "max-h-[calc(100dvh-2rem)] overflow-y-auto", className), style: { maxWidth, zIndex, ...contentStyle }, mask: mask, zIndex: zIndex, maskStyle: styles?.mask, showCloseButton: showCloseButton, onEscapeKeyDown: (e) => {
48
+ if (!closeOnEsc)
49
+ e.preventDefault();
50
+ }, onPointerDownOutside: (e) => {
51
+ if (!closeOnBackdrop)
52
+ e.preventDefault();
53
+ }, onCloseAutoFocus: (e) => {
54
+ if (previousFocus.current?.isConnected) {
55
+ e.preventDefault();
56
+ previousFocus.current.focus();
57
+ }
58
+ }, children: [_jsxs(DialogHeader, { style: styles?.header, children: [_jsx(DialogTitle, { className: title ? undefined : "sr-only", children: title || ariaLabel || closeText() }), description ? (_jsx(DialogDescription, { children: description })) : null] }), hasBody ? (_jsxs("div", { "data-slot": "modal-body", className: "min-w-0 py-2", style: styles?.body, "aria-busy": loading || undefined, children: [loading && (_jsx("div", { role: "status", className: "py-8 text-center text-sm text-muted-foreground", children: "\u52A0\u8F7D\u4E2D\u2026" })), _jsx("div", { hidden: loading, children: retained.body })] })) : null, (footer !== undefined ? footer !== null : Boolean(onOk)) && (_jsx("div", { className: "flex flex-wrap justify-end gap-3 border-t pt-4", style: styles?.footer, children: footer !== undefined ? (footer) : (_jsxs(_Fragment, { children: [_jsx(Button, { ...cancelButtonProps, disabled: confirmLoading || cancelButtonProps?.disabled, onClick: (event) => {
59
+ cancelButtonProps?.onClick?.(event);
60
+ if (!event.defaultPrevented)
61
+ changeOpen(false);
62
+ }, children: cancelText }), _jsx(Button, { variant: "solid", color: "primary", ...okButtonProps, loading: confirmLoading || okButtonProps?.loading, onClick: (event) => {
63
+ okButtonProps?.onClick?.(event);
64
+ if (!event.defaultPrevented)
65
+ void onOk?.();
66
+ }, children: okText })] })) }))] }) })] }));
67
+ }
@@ -0,0 +1,15 @@
1
+ import { type ReactNode } from "react";
2
+ export interface NotificationNotice {
3
+ title: ReactNode;
4
+ description?: ReactNode;
5
+ duration?: number;
6
+ }
7
+ export interface NotificationProviderProps {
8
+ children: ReactNode;
9
+ }
10
+ type NotificationOpen = (notice: NotificationNotice) => void;
11
+ export declare function NotificationProvider({ children, }: NotificationProviderProps): import("react").JSX.Element;
12
+ export declare function useNotification(): {
13
+ open: NotificationOpen;
14
+ };
15
+ export {};