@aloudata/aloudata-design 3.0.0-beta.9 → 3.0.1

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 (172) hide show
  1. package/dist/AProgress/index.d.ts +1 -1
  2. package/dist/AProgress/index.js +19 -5
  3. package/dist/AProgress/index.js.map +1 -1
  4. package/dist/Alert/index.d.ts +1 -1
  5. package/dist/Alert/index.js +22 -8
  6. package/dist/Alert/index.js.map +1 -1
  7. package/dist/Avatar/component/Avatar/index.d.ts +1 -1
  8. package/dist/Avatar/component/Avatar/index.js +4 -4
  9. package/dist/Avatar/component/Avatar/index.js.map +1 -1
  10. package/dist/Avatar/component/Avatar/type.d.ts +1 -1
  11. package/dist/Avatar/component/Avatar/type.js +6 -1
  12. package/dist/Avatar/component/Avatar/type.js.map +1 -1
  13. package/dist/Avatar/index.js +67 -8
  14. package/dist/Avatar/index.js.map +1 -1
  15. package/dist/Badge/index.d.ts +1 -0
  16. package/dist/Badge/index.js +32 -9
  17. package/dist/Badge/index.js.map +1 -1
  18. package/dist/Breadcrumb/index.js +21 -12
  19. package/dist/Breadcrumb/index.js.map +1 -1
  20. package/dist/Button/index.d.ts +2 -0
  21. package/dist/Button/index.js +39 -32
  22. package/dist/Button/index.js.map +1 -1
  23. package/dist/Card/index.js +5 -5
  24. package/dist/Card/index.js.map +1 -1
  25. package/dist/Checkbox/index.js +5 -12
  26. package/dist/Checkbox/index.js.map +1 -1
  27. package/dist/Checkbox/type.d.ts +3 -1
  28. package/dist/Collapse/index.js +40 -24
  29. package/dist/Collapse/index.js.map +1 -1
  30. package/dist/DataPreviewTable/components/Body/Cell.js +5 -4
  31. package/dist/DataPreviewTable/components/Body/Cell.js.map +1 -1
  32. package/dist/DataPreviewTable/components/Body/Error.js +1 -1
  33. package/dist/DataPreviewTable/components/Body/Error.js.map +1 -1
  34. package/dist/DataPreviewTable/components/Body/index.js +2 -1
  35. package/dist/DataPreviewTable/components/Body/index.js.map +1 -1
  36. package/dist/DataPreviewTable/components/DragBar/index.js +1 -1
  37. package/dist/DataPreviewTable/components/DragBar/index.js.map +1 -1
  38. package/dist/DataPreviewTable/components/Header/index.js +14 -12
  39. package/dist/DataPreviewTable/components/Header/index.js.map +1 -1
  40. package/dist/DataPreviewTable/index.js +5 -6
  41. package/dist/DataPreviewTable/index.js.map +1 -1
  42. package/dist/DatePicker/index.d.ts +4 -0
  43. package/dist/DatePicker/index.js +8 -6
  44. package/dist/DatePicker/index.js.map +1 -1
  45. package/dist/Drawer/index.d.ts +1 -0
  46. package/dist/Drawer/index.js +102 -47
  47. package/dist/Drawer/index.js.map +1 -1
  48. package/dist/Dropdown/index.d.ts +5 -0
  49. package/dist/Dropdown/index.js +155 -34
  50. package/dist/Dropdown/index.js.map +1 -1
  51. package/dist/Form/index.d.ts +45 -5
  52. package/dist/Form/index.js +59 -34
  53. package/dist/Form/index.js.map +1 -1
  54. package/dist/HighlightText/index.js +1 -1
  55. package/dist/HighlightText/index.js.map +1 -1
  56. package/dist/Input/components/Input/index.d.ts +5 -2
  57. package/dist/Input/components/Input/index.js +18 -6
  58. package/dist/Input/components/Input/index.js.map +1 -1
  59. package/dist/InputNumber/index.js +1 -0
  60. package/dist/InputNumber/index.js.map +1 -1
  61. package/dist/InputNumber/type.d.ts +2 -2
  62. package/dist/InputSearch/index.d.ts +3 -0
  63. package/dist/InputSearch/index.js +3 -2
  64. package/dist/InputSearch/index.js.map +1 -1
  65. package/dist/Layout/index.js +1 -1
  66. package/dist/Layout/index.js.map +1 -1
  67. package/dist/LogicTree/DisplayLogicTree.d.ts +1 -1
  68. package/dist/LogicTree/DisplayLogicTree.js.map +1 -1
  69. package/dist/LogicTree/components/DisplayLogicItem/index.d.ts +1 -1
  70. package/dist/LogicTree/components/DisplayLogicItem/index.js +1 -1
  71. package/dist/LogicTree/components/DisplayLogicItem/index.js.map +1 -1
  72. package/dist/LogicTree/components/LogicItem/index.js +2 -3
  73. package/dist/LogicTree/components/LogicItem/index.js.map +1 -1
  74. package/dist/LogicTree/index.d.ts +1 -1
  75. package/dist/LogicTree/index.js +26 -10
  76. package/dist/LogicTree/index.js.map +1 -1
  77. package/dist/MemberPicker/components/NickLabel.js +1 -1
  78. package/dist/MemberPicker/components/NickLabel.js.map +1 -1
  79. package/dist/MemberPicker/components/Panel.js +13 -14
  80. package/dist/MemberPicker/components/Panel.js.map +1 -1
  81. package/dist/MemberPicker/index.js +10 -5
  82. package/dist/MemberPicker/index.js.map +1 -1
  83. package/dist/Menu/index.d.ts +4 -0
  84. package/dist/Menu/index.js +35 -13
  85. package/dist/Menu/index.js.map +1 -1
  86. package/dist/Modal/index.d.ts +5 -2
  87. package/dist/Modal/index.js +119 -66
  88. package/dist/Modal/index.js.map +1 -1
  89. package/dist/Popconfirm/index.js +6 -1
  90. package/dist/Popconfirm/index.js.map +1 -1
  91. package/dist/Popover/index.js +5 -3
  92. package/dist/Popover/index.js.map +1 -1
  93. package/dist/Progress/index.d.ts +0 -3
  94. package/dist/Progress/index.js +0 -3
  95. package/dist/Progress/index.js.map +1 -1
  96. package/dist/Radio/components/Radio/index.js +14 -25
  97. package/dist/Radio/components/Radio/index.js.map +1 -1
  98. package/dist/RenameInput/index.js +0 -1
  99. package/dist/RenameInput/index.js.map +1 -1
  100. package/dist/Select/BaseSelect.js +12 -7
  101. package/dist/Select/BaseSelect.js.map +1 -1
  102. package/dist/Select/Selector/MultipleSelector.js +10 -6
  103. package/dist/Select/Selector/MultipleSelector.js.map +1 -1
  104. package/dist/Select/Selector/index.d.ts +2 -0
  105. package/dist/Select/Selector/index.js +1 -1
  106. package/dist/Select/Selector/index.js.map +1 -1
  107. package/dist/Select/components/Suffix.js +1 -1
  108. package/dist/Select/components/Suffix.js.map +1 -1
  109. package/dist/Select/interface.d.ts +4 -0
  110. package/dist/Select/utils/getWidthStyle.js.map +1 -1
  111. package/dist/Steps/index.js +6 -6
  112. package/dist/Steps/index.js.map +1 -1
  113. package/dist/Switch/index.js +21 -7
  114. package/dist/Switch/index.js.map +1 -1
  115. package/dist/Table/components/Footer/index.js +1 -1
  116. package/dist/Table/components/Footer/index.js.map +1 -1
  117. package/dist/Table/hooks/useRowDnd.js +2 -8
  118. package/dist/Table/hooks/useRowDnd.js.map +1 -1
  119. package/dist/Table/hooks/useRowSelection.d.ts +1 -1
  120. package/dist/Table/hooks/useRowSelection.js +7 -9
  121. package/dist/Table/hooks/useRowSelection.js.map +1 -1
  122. package/dist/Table/index.js +1 -1
  123. package/dist/Table/index.js.map +1 -1
  124. package/dist/Tabs/index.js +37 -30
  125. package/dist/Tabs/index.js.map +1 -1
  126. package/dist/Tooltip/index.js +5 -3
  127. package/dist/Tooltip/index.js.map +1 -1
  128. package/dist/Tour/index.js +48 -38
  129. package/dist/Tour/index.js.map +1 -1
  130. package/dist/Tree/DirectoryTree.d.ts +2 -2
  131. package/dist/Tree/DirectoryTree.js.map +1 -1
  132. package/dist/Tree/Tree.d.ts +13 -2
  133. package/dist/Tree/Tree2.js +86 -8
  134. package/dist/Tree/Tree2.js.map +1 -1
  135. package/dist/Tree/utils/composeAllowDrop.d.ts +14 -0
  136. package/dist/Tree/utils/composeAllowDrop.js +20 -0
  137. package/dist/Tree/utils/composeAllowDrop.js.map +1 -0
  138. package/dist/Upload/index.d.ts +15 -2
  139. package/dist/Upload/index.js +4 -2
  140. package/dist/Upload/index.js.map +1 -1
  141. package/dist/_utils/floatingLayer.d.ts +15 -0
  142. package/dist/_utils/floatingLayer.js +30 -0
  143. package/dist/_utils/floatingLayer.js.map +1 -0
  144. package/dist/_utils/storybookArgTypes.d.ts +11 -0
  145. package/dist/_utils/storybookArgTypes.js +2 -0
  146. package/dist/aloudata-design.css +1 -1
  147. package/dist/index.d.ts +15 -6
  148. package/dist/index.js +8 -3
  149. package/dist/theme/createTheme.d.ts +2 -0
  150. package/dist/theme/createTheme.js +46 -0
  151. package/dist/theme/createTheme.js.map +1 -0
  152. package/dist/theme/defaultTheme.d.ts +2 -0
  153. package/dist/theme/defaultTheme.js +19 -0
  154. package/dist/theme/defaultTheme.js.map +1 -0
  155. package/dist/theme/index.d.ts +5 -0
  156. package/dist/theme/index.js +4 -0
  157. package/dist/theme/initAldTheme.d.ts +2 -0
  158. package/dist/theme/initAldTheme.js +26 -0
  159. package/dist/theme/initAldTheme.js.map +1 -0
  160. package/dist/theme/themeToCssVars.d.ts +2 -0
  161. package/dist/theme/themeToCssVars.js +144 -0
  162. package/dist/theme/themeToCssVars.js.map +1 -0
  163. package/dist/theme/tokenMap.d.ts +5 -0
  164. package/dist/theme/tokenMap.js +12 -0
  165. package/dist/theme/tokenMap.js.map +1 -0
  166. package/dist/theme/types.d.ts +20 -0
  167. package/dist/theme/types.js +2 -0
  168. package/dist/theme.d.ts +2 -0
  169. package/package.json +9 -4
  170. package/dist/_utils/SimpleOverflow.d.ts +0 -14
  171. package/dist/_utils/SimpleOverflow.js +0 -61
  172. package/dist/_utils/SimpleOverflow.js.map +0 -1
@@ -1,8 +1,10 @@
1
1
  import { cn } from "../lib/utils.js";
2
2
  import Memo from "../Icon/components/CloseLightLine.js";
3
- import "react";
4
- import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { FloatingLayerProvider, useFloatingLayer } from "../_utils/floatingLayer.js";
4
+ import { useEffect, useRef } from "react";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
6
  import * as DialogPrimitive from "@radix-ui/react-dialog";
7
+ import { hideOthers } from "aria-hidden";
6
8
  //#region src/Drawer/index.tsx
7
9
  var sizePresets = {
8
10
  default: 378,
@@ -15,13 +17,48 @@ var placementStyles = {
15
17
  bottom: "tw-inset-x-0 tw-bottom-0 tw-w-full"
16
18
  };
17
19
  var slideAnimationStyles = {
18
- right: "tw-animate-in tw-slide-in-from-right tw-duration-300",
19
- left: "tw-animate-in tw-slide-in-from-left tw-duration-300",
20
- top: "tw-animate-in tw-slide-in-from-top tw-duration-300",
21
- bottom: "tw-animate-in tw-slide-in-from-bottom tw-duration-300"
20
+ right: "data-[state=open]:tw-animate-drawer-in-right data-[state=closed]:tw-animate-drawer-out-right",
21
+ left: "data-[state=open]:tw-animate-drawer-in-left data-[state=closed]:tw-animate-drawer-out-left",
22
+ top: "data-[state=open]:tw-animate-drawer-in-top data-[state=closed]:tw-animate-drawer-out-top",
23
+ bottom: "data-[state=open]:tw-animate-drawer-in-bottom data-[state=closed]:tw-animate-drawer-out-bottom"
22
24
  };
23
25
  function Drawer(props) {
24
- const { open = false, onClose, title, placement = "right", width, height, size = "default", closable = true, mask = true, maskClosable = true, className, style, contentWrapperStyle, bodyStyle, headerStyle, footer, footerStyle, extra, children, zIndex = 1e3 } = props;
26
+ const { open = false, onClose, title, description, placement = "right", width, height, size = "default", closable = true, mask = true, maskClosable = true, className, style, contentWrapperStyle, bodyStyle, headerStyle, footer, footerStyle, extra, children, zIndex = 1e3 } = props;
27
+ const contentRef = useRef(null);
28
+ useEffect(() => {
29
+ if (!open) return;
30
+ const prev = document.body.style.overflow;
31
+ document.body.style.overflow = "hidden";
32
+ return () => {
33
+ document.body.style.overflow = prev;
34
+ };
35
+ }, [open]);
36
+ useEffect(() => {
37
+ if (!open || !contentRef.current) return;
38
+ return hideOthers(contentRef.current);
39
+ }, [open]);
40
+ useEffect(() => {
41
+ if (!open || !contentRef.current) return;
42
+ const container = contentRef.current;
43
+ const handleKeyDown = (e) => {
44
+ if (e.key !== "Tab") return;
45
+ const focusable = container.querySelectorAll("a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]):not([disabled])");
46
+ if (focusable.length === 0) return;
47
+ const first = focusable[0];
48
+ const last = focusable[focusable.length - 1];
49
+ if (e.shiftKey) {
50
+ if (document.activeElement === first || !container.contains(document.activeElement)) {
51
+ e.preventDefault();
52
+ last.focus();
53
+ }
54
+ } else if (document.activeElement === last || !container.contains(document.activeElement)) {
55
+ e.preventDefault();
56
+ first.focus();
57
+ }
58
+ };
59
+ document.addEventListener("keydown", handleKeyDown);
60
+ return () => document.removeEventListener("keydown", handleKeyDown);
61
+ }, [open]);
25
62
  const isHorizontal = placement === "left" || placement === "right";
26
63
  const preset = sizePresets[size] || sizePresets.default;
27
64
  const sizeStyle = isHorizontal ? {
@@ -31,59 +68,77 @@ function Drawer(props) {
31
68
  height: height ?? preset,
32
69
  maxHeight: "100vh"
33
70
  };
71
+ const { maskZIndex, contentZIndex, nextLevel } = useFloatingLayer(zIndex);
34
72
  return /* @__PURE__ */ jsx(DialogPrimitive.Root, {
35
73
  open,
74
+ modal: false,
36
75
  onOpenChange: (val) => {
37
76
  if (!val) onClose?.();
38
77
  },
39
- children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [mask && /* @__PURE__ */ jsx(DialogPrimitive.Overlay, {
40
- className: "ald-drawer-mask tw-animate-in tw-fade-in-0 tw-fixed tw-inset-0 tw-bg-black/45",
41
- style: { zIndex },
78
+ children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [mask && /* @__PURE__ */ jsx("div", {
79
+ "data-state": open ? "open" : "closed",
80
+ className: "ald-drawer-mask tw-fixed tw-inset-0 tw-bg-black/45 data-[state=closed]:tw-animate-mask-out data-[state=open]:tw-animate-mask-in",
81
+ style: { zIndex: maskZIndex },
42
82
  onClick: maskClosable ? () => onClose?.() : void 0
43
- }), /* @__PURE__ */ jsxs(DialogPrimitive.Content, {
83
+ }), /* @__PURE__ */ jsx(DialogPrimitive.Content, {
84
+ ref: contentRef,
44
85
  className: cn("ald-drawer tw-fixed tw-flex tw-flex-col tw-bg-[var(--background-default)] tw-shadow-xl", placementStyles[placement], slideAnimationStyles[placement], className),
45
86
  style: {
46
- zIndex: zIndex + 1,
87
+ zIndex: contentZIndex,
47
88
  ...sizeStyle,
48
89
  ...contentWrapperStyle,
49
90
  ...style
50
91
  },
51
92
  onEscapeKeyDown: () => onClose?.(),
52
- onInteractOutside: maskClosable ? () => onClose?.() : void 0,
53
- children: [
54
- (title || closable || extra) && /* @__PURE__ */ jsxs("div", {
55
- className: "ald-drawer-header tw-flex tw-items-center tw-justify-between tw-border-b tw-border-solid tw-border-[var(--border-default)] tw-px-6 tw-py-4",
56
- style: headerStyle,
57
- children: [/* @__PURE__ */ jsx(DialogPrimitive.Title, {
58
- className: "ald-drawer-title tw-m-0 tw-text-base tw-font-semibold tw-text-[var(--content-primary)]",
59
- children: title
60
- }), /* @__PURE__ */ jsxs("div", {
61
- className: "tw-flex tw-items-center tw-gap-2",
62
- children: [extra, closable && /* @__PURE__ */ jsx(DialogPrimitive.Close, {
63
- asChild: true,
64
- children: /* @__PURE__ */ jsx("button", {
65
- type: "button",
66
- className: "ald-drawer-close tw-flex tw-size-8 tw-cursor-pointer tw-items-center tw-justify-center tw-rounded-r-50 tw-border-0 tw-bg-transparent hover:tw-bg-[var(--action-ghost-hover)]",
67
- onClick: () => onClose?.(),
68
- children: /* @__PURE__ */ jsx(Memo, {
69
- size: 20,
70
- color: "var(--content-secondary)"
71
- })
72
- })
73
- })]
74
- })]
75
- }),
76
- /* @__PURE__ */ jsx("div", {
77
- className: "ald-drawer-body tw-flex-1 tw-overflow-auto tw-px-6 tw-py-4",
78
- style: bodyStyle,
79
- children
80
- }),
81
- footer && /* @__PURE__ */ jsx("div", {
82
- className: "ald-drawer-footer tw-border-t tw-border-solid tw-border-[var(--border-default)] tw-px-6 tw-py-4",
83
- style: footerStyle,
84
- children: footer
85
- })
86
- ]
93
+ onInteractOutside: (event) => {
94
+ if (!maskClosable) event.preventDefault();
95
+ },
96
+ children: /* @__PURE__ */ jsxs(FloatingLayerProvider, {
97
+ value: nextLevel,
98
+ children: [
99
+ (title || description || closable || extra) && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("div", {
100
+ className: "ald-drawer-header ant-drawer-header tw-flex tw-flex-col tw-items-start tw-gap-[var(--component-gap-lg)] tw-self-stretch tw-bg-[var(--interaction-background-sidepanel)] tw-px-6 tw-pb-0 tw-pt-4",
101
+ style: headerStyle,
102
+ children: /* @__PURE__ */ jsxs("div", {
103
+ className: "tw-flex tw-w-full tw-flex-col tw-gap-[6px]",
104
+ children: [/* @__PURE__ */ jsxs("div", {
105
+ className: "tw-flex tw-w-full tw-items-start tw-justify-between tw-gap-[var(--component-gap-sm)]",
106
+ children: [/* @__PURE__ */ jsx(DialogPrimitive.Title, {
107
+ className: "ald-drawer-title ant-drawer-header-title tw-[font-feature-settings:\"liga\"_off,\"clig\"_off] tw-m-0 tw-flex-[1_0_0] tw-text-lg tw-font-semibold tw-leading-7 tw-text-[var(--content-primary)]",
108
+ children: title
109
+ }), extra || closable ? /* @__PURE__ */ jsxs("div", {
110
+ className: "ald-drawer-actions tw-flex tw-items-center tw-gap-[var(--component-gap-sm)]",
111
+ children: [extra, closable && /* @__PURE__ */ jsx(DialogPrimitive.Close, {
112
+ asChild: true,
113
+ children: /* @__PURE__ */ jsx("button", {
114
+ type: "button",
115
+ className: "ald-drawer-close tw-flex tw-size-8 tw-cursor-pointer tw-items-center tw-justify-center tw-rounded-r-50 tw-border-0 tw-bg-transparent hover:tw-bg-[var(--action-ghost-hover)]",
116
+ onClick: () => onClose?.(),
117
+ children: /* @__PURE__ */ jsx(Memo, {
118
+ size: 20,
119
+ color: "var(--content-secondary)"
120
+ })
121
+ })
122
+ })]
123
+ }) : null]
124
+ }), description ? /* @__PURE__ */ jsx("div", {
125
+ className: "ald-drawer-description tw-[font-feature-settings:\"liga\"_off,\"clig\"_off] tw-self-stretch tw-text-sm tw-font-normal tw-leading-5 tw-text-[var(--content-secondary)]",
126
+ children: description
127
+ }) : null]
128
+ })
129
+ }) }),
130
+ /* @__PURE__ */ jsx("div", {
131
+ className: "ald-drawer-body ant-drawer-body tw-min-w-0 tw-flex-[1_0_0] tw-self-stretch tw-overflow-auto tw-p-[var(--component-padding-2xl)]",
132
+ style: bodyStyle,
133
+ children
134
+ }),
135
+ footer && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", { className: "ald-drawer-footer-divider tw-h-px tw-bg-[var(--border-default)]" }), /* @__PURE__ */ jsx("div", {
136
+ className: "ald-drawer-footer ant-drawer-footer tw-flex tw-items-center tw-justify-end tw-gap-[var(--component-gap-lg)] tw-self-stretch tw-px-[var(--component-padding-2xl)] tw-py-[var(--component-padding-lg)]",
137
+ style: footerStyle,
138
+ children: footer
139
+ })] })
140
+ ]
141
+ })
87
142
  })] })
88
143
  });
89
144
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/Drawer/index.tsx"],"sourcesContent":["import * as DialogPrimitive from '@radix-ui/react-dialog';\nimport React from 'react';\nimport { CloseLightLine } from '../Icon';\nimport { cn } from '../lib/utils';\n\nexport interface DrawerProps {\n open?: boolean;\n onClose?: (e?: React.MouseEvent | React.KeyboardEvent) => void;\n title?: React.ReactNode;\n placement?: 'top' | 'right' | 'bottom' | 'left';\n width?: number | string;\n height?: number | string;\n size?: 'default' | 'large';\n closable?: boolean;\n mask?: boolean;\n maskClosable?: boolean;\n destroyOnClose?: boolean;\n className?: string;\n style?: React.CSSProperties;\n contentWrapperStyle?: React.CSSProperties;\n bodyStyle?: React.CSSProperties;\n headerStyle?: React.CSSProperties;\n maskStyle?: React.CSSProperties;\n footer?: React.ReactNode;\n footerStyle?: React.CSSProperties;\n extra?: React.ReactNode;\n children?: React.ReactNode;\n zIndex?: number;\n keyboard?: boolean;\n getContainer?: () => HTMLElement;\n}\n\nconst sizePresets: Record<string, number> = {\n default: 378,\n large: 736,\n};\n\nconst placementStyles: Record<string, string> = {\n right: 'tw-inset-y-0 tw-right-0 tw-h-full',\n left: 'tw-inset-y-0 tw-left-0 tw-h-full',\n top: 'tw-inset-x-0 tw-top-0 tw-w-full',\n bottom: 'tw-inset-x-0 tw-bottom-0 tw-w-full',\n};\n\nconst slideAnimationStyles: Record<string, string> = {\n right: 'tw-animate-in tw-slide-in-from-right tw-duration-300',\n left: 'tw-animate-in tw-slide-in-from-left tw-duration-300',\n top: 'tw-animate-in tw-slide-in-from-top tw-duration-300',\n bottom: 'tw-animate-in tw-slide-in-from-bottom tw-duration-300',\n};\n\nfunction Drawer(props: DrawerProps) {\n const {\n open = false,\n onClose,\n title,\n placement = 'right',\n width,\n height,\n size = 'default',\n closable = true,\n mask = true,\n maskClosable = true,\n className,\n style,\n contentWrapperStyle,\n bodyStyle,\n headerStyle,\n footer,\n footerStyle,\n extra,\n children,\n zIndex = 1000,\n } = props;\n\n const isHorizontal = placement === 'left' || placement === 'right';\n const preset = sizePresets[size] || sizePresets.default;\n const effectiveWidth = width ?? preset;\n const effectiveHeight = height ?? preset;\n const sizeStyle = isHorizontal\n ? { width: effectiveWidth, maxWidth: '100vw' }\n : { height: effectiveHeight, maxHeight: '100vh' };\n\n return (\n <DialogPrimitive.Root\n open={open}\n onOpenChange={(val) => {\n if (!val) onClose?.();\n }}\n >\n <DialogPrimitive.Portal>\n {mask && (\n <DialogPrimitive.Overlay\n className=\"ald-drawer-mask tw-animate-in tw-fade-in-0 tw-fixed tw-inset-0 tw-bg-black/45\"\n style={{ zIndex }}\n onClick={maskClosable ? () => onClose?.() : undefined}\n />\n )}\n <DialogPrimitive.Content\n className={cn(\n 'ald-drawer tw-fixed tw-flex tw-flex-col tw-bg-[var(--background-default)] tw-shadow-xl',\n placementStyles[placement],\n slideAnimationStyles[placement],\n className,\n )}\n style={{\n zIndex: zIndex + 1,\n ...sizeStyle,\n ...contentWrapperStyle,\n ...style,\n }}\n onEscapeKeyDown={() => onClose?.()}\n onInteractOutside={maskClosable ? () => onClose?.() : undefined}\n >\n {(title || closable || extra) && (\n <div\n className=\"ald-drawer-header tw-flex tw-items-center tw-justify-between tw-border-b tw-border-solid tw-border-[var(--border-default)] tw-px-6 tw-py-4\"\n style={headerStyle}\n >\n <DialogPrimitive.Title className=\"ald-drawer-title tw-m-0 tw-text-base tw-font-semibold tw-text-[var(--content-primary)]\">\n {title}\n </DialogPrimitive.Title>\n <div className=\"tw-flex tw-items-center tw-gap-2\">\n {extra}\n {closable && (\n <DialogPrimitive.Close asChild>\n <button\n type=\"button\"\n className=\"ald-drawer-close tw-flex tw-size-8 tw-cursor-pointer tw-items-center tw-justify-center tw-rounded-r-50 tw-border-0 tw-bg-transparent hover:tw-bg-[var(--action-ghost-hover)]\"\n onClick={() => onClose?.()}\n >\n <CloseLightLine\n size={20}\n color=\"var(--content-secondary)\"\n />\n </button>\n </DialogPrimitive.Close>\n )}\n </div>\n </div>\n )}\n <div\n className=\"ald-drawer-body tw-flex-1 tw-overflow-auto tw-px-6 tw-py-4\"\n style={bodyStyle}\n >\n {children}\n </div>\n {footer && (\n <div\n className=\"ald-drawer-footer tw-border-t tw-border-solid tw-border-[var(--border-default)] tw-px-6 tw-py-4\"\n style={footerStyle}\n >\n {footer}\n </div>\n )}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n}\n\nexport default Drawer;\n"],"mappings":";;;;;;AAgCA,IAAM,cAAsC;CAC1C,SAAS;CACT,OAAO;CACR;AAED,IAAM,kBAA0C;CAC9C,OAAO;CACP,MAAM;CACN,KAAK;CACL,QAAQ;CACT;AAED,IAAM,uBAA+C;CACnD,OAAO;CACP,MAAM;CACN,KAAK;CACL,QAAQ;CACT;AAED,SAAS,OAAO,OAAoB;CAClC,MAAM,EACJ,OAAO,OACP,SACA,OACA,YAAY,SACZ,OACA,QACA,OAAO,WACP,WAAW,MACX,OAAO,MACP,eAAe,MACf,WACA,OACA,qBACA,WACA,aACA,QACA,aACA,OACA,UACA,SAAS,QACP;CAEJ,MAAM,eAAe,cAAc,UAAU,cAAc;CAC3D,MAAM,SAAS,YAAY,SAAS,YAAY;CAGhD,MAAM,YAAY,eACd;EAAE,OAHiB,SAAS;EAGH,UAAU;EAAS,GAC5C;EAAE,QAHkB,UAAU;EAGH,WAAW;EAAS;AAEnD,QACE,oBAAC,gBAAgB,MAAjB;EACQ;EACN,eAAe,QAAQ;AACrB,OAAI,CAAC,IAAK,YAAW;;YAGvB,qBAAC,gBAAgB,QAAjB,EAAA,UAAA,CACG,QACC,oBAAC,gBAAgB,SAAjB;GACE,WAAU;GACV,OAAO,EAAE,QAAQ;GACjB,SAAS,qBAAqB,WAAW,GAAG;GAC5C,CAAA,EAEJ,qBAAC,gBAAgB,SAAjB;GACE,WAAW,GACT,0FACA,gBAAgB,YAChB,qBAAqB,YACrB,UACD;GACD,OAAO;IACL,QAAQ,SAAS;IACjB,GAAG;IACH,GAAG;IACH,GAAG;IACJ;GACD,uBAAuB,WAAW;GAClC,mBAAmB,qBAAqB,WAAW,GAAG;aAdxD;KAgBI,SAAS,YAAY,UACrB,qBAAC,OAAD;KACE,WAAU;KACV,OAAO;eAFT,CAIE,oBAAC,gBAAgB,OAAjB;MAAuB,WAAU;gBAC9B;MACqB,CAAA,EACxB,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,OACA,YACC,oBAAC,gBAAgB,OAAjB;OAAuB,SAAA;iBACrB,oBAAC,UAAD;QACE,MAAK;QACL,WAAU;QACV,eAAe,WAAW;kBAE1B,oBAAC,MAAD;SACE,MAAM;SACN,OAAM;SACN,CAAA;QACK,CAAA;OACa,CAAA,CAEtB;QACF;;IAER,oBAAC,OAAD;KACE,WAAU;KACV,OAAO;KAEN;KACG,CAAA;IACL,UACC,oBAAC,OAAD;KACE,WAAU;KACV,OAAO;eAEN;KACG,CAAA;IAEgB;KACH,EAAA,CAAA;EACJ,CAAA"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/Drawer/index.tsx"],"sourcesContent":["import * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { hideOthers } from 'aria-hidden';\nimport React, { useEffect, useRef } from 'react';\nimport { CloseLightLine } from '../Icon';\nimport {\n FloatingLayerProvider,\n useFloatingLayer,\n} from '../_utils/floatingLayer';\nimport { cn } from '../lib/utils';\n\nexport interface DrawerProps {\n open?: boolean;\n onClose?: (e?: React.MouseEvent | React.KeyboardEvent) => void;\n title?: React.ReactNode;\n description?: React.ReactNode;\n placement?: 'top' | 'right' | 'bottom' | 'left';\n width?: number | string;\n height?: number | string;\n size?: 'default' | 'large';\n closable?: boolean;\n mask?: boolean;\n maskClosable?: boolean;\n destroyOnClose?: boolean;\n className?: string;\n style?: React.CSSProperties;\n contentWrapperStyle?: React.CSSProperties;\n bodyStyle?: React.CSSProperties;\n headerStyle?: React.CSSProperties;\n maskStyle?: React.CSSProperties;\n footer?: React.ReactNode;\n footerStyle?: React.CSSProperties;\n extra?: React.ReactNode;\n children?: React.ReactNode;\n zIndex?: number;\n keyboard?: boolean;\n getContainer?: () => HTMLElement;\n}\n\nconst sizePresets: Record<string, number> = {\n default: 378,\n large: 736,\n};\n\nconst placementStyles: Record<string, string> = {\n right: 'tw-inset-y-0 tw-right-0 tw-h-full',\n left: 'tw-inset-y-0 tw-left-0 tw-h-full',\n top: 'tw-inset-x-0 tw-top-0 tw-w-full',\n bottom: 'tw-inset-x-0 tw-bottom-0 tw-w-full',\n};\n\nconst slideAnimationStyles: Record<string, string> = {\n right:\n 'data-[state=open]:tw-animate-drawer-in-right data-[state=closed]:tw-animate-drawer-out-right',\n left: 'data-[state=open]:tw-animate-drawer-in-left data-[state=closed]:tw-animate-drawer-out-left',\n top: 'data-[state=open]:tw-animate-drawer-in-top data-[state=closed]:tw-animate-drawer-out-top',\n bottom:\n 'data-[state=open]:tw-animate-drawer-in-bottom data-[state=closed]:tw-animate-drawer-out-bottom',\n};\n\nfunction Drawer(props: DrawerProps) {\n const {\n open = false,\n onClose,\n title,\n description,\n placement = 'right',\n width,\n height,\n size = 'default',\n closable = true,\n mask = true,\n maskClosable = true,\n className,\n style,\n contentWrapperStyle,\n bodyStyle,\n headerStyle,\n footer,\n footerStyle,\n extra,\n children,\n zIndex = 1000,\n } = props;\n\n const contentRef = useRef<HTMLDivElement>(null);\n\n // ---- modal={false} 补偿:锁定背景滚动 ----\n useEffect(() => {\n if (!open) return;\n const prev = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n return () => {\n document.body.style.overflow = prev;\n };\n }, [open]);\n\n // ---- modal={false} 补偿:aria-hidden(屏幕阅读器只感知抽屉) ----\n useEffect(() => {\n if (!open || !contentRef.current) return;\n return hideOthers(contentRef.current);\n }, [open]);\n\n // ---- modal={false} 补偿:Tab 焦点循环(不使用 MutationObserver,避免 FocusScope 劫持焦点)----\n useEffect(() => {\n if (!open || !contentRef.current) return;\n const container = contentRef.current;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Tab') return;\n const focusable = container.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]):not([disabled])',\n );\n if (focusable.length === 0) return;\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (e.shiftKey) {\n if (\n document.activeElement === first ||\n !container.contains(document.activeElement)\n ) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (\n document.activeElement === last ||\n !container.contains(document.activeElement)\n ) {\n e.preventDefault();\n first.focus();\n }\n }\n };\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [open]);\n\n const isHorizontal = placement === 'left' || placement === 'right';\n const preset = sizePresets[size] || sizePresets.default;\n const effectiveWidth = width ?? preset;\n const effectiveHeight = height ?? preset;\n const sizeStyle = isHorizontal\n ? { width: effectiveWidth, maxWidth: '100vw' }\n : { height: effectiveHeight, maxHeight: '100vh' };\n const { maskZIndex, contentZIndex, nextLevel } = useFloatingLayer(zIndex);\n\n // modal={false}:禁用 Radix FocusScope 的 MutationObserver,\n // 避免表单校验触发 DOM 变动时劫持焦点。手动补偿滚动锁定、aria-hidden、Tab 循环。\n return (\n <DialogPrimitive.Root\n open={open}\n modal={false}\n onOpenChange={(val) => {\n if (!val) onClose?.();\n }}\n >\n <DialogPrimitive.Portal>\n {/* modal={false} 时 DialogPrimitive.Overlay 不渲染,用普通 div 替代 */}\n {mask && (\n <div\n data-state={open ? 'open' : 'closed'}\n className=\"ald-drawer-mask tw-fixed tw-inset-0 tw-bg-black/45 data-[state=closed]:tw-animate-mask-out data-[state=open]:tw-animate-mask-in\"\n style={{ zIndex: maskZIndex }}\n onClick={maskClosable ? () => onClose?.() : undefined}\n />\n )}\n <DialogPrimitive.Content\n ref={contentRef}\n className={cn(\n 'ald-drawer tw-fixed tw-flex tw-flex-col tw-bg-[var(--background-default)] tw-shadow-xl',\n placementStyles[placement],\n slideAnimationStyles[placement],\n className,\n )}\n style={{\n zIndex: contentZIndex,\n ...sizeStyle,\n ...contentWrapperStyle,\n ...style,\n }}\n onEscapeKeyDown={() => onClose?.()}\n onInteractOutside={(event) => {\n if (!maskClosable) {\n event.preventDefault();\n }\n }}\n >\n <FloatingLayerProvider value={nextLevel}>\n {(title || description || closable || extra) && (\n <>\n {/* antd 兼容:保留 ant-drawer-header / ant-drawer-header-title class,消费方 CSS 可能依赖这些选择器 */}\n <div\n className=\"ald-drawer-header ant-drawer-header tw-flex tw-flex-col tw-items-start tw-gap-[var(--component-gap-lg)] tw-self-stretch tw-bg-[var(--interaction-background-sidepanel)] tw-px-6 tw-pb-0 tw-pt-4\"\n style={headerStyle}\n >\n <div className=\"tw-flex tw-w-full tw-flex-col tw-gap-[6px]\">\n <div className=\"tw-flex tw-w-full tw-items-start tw-justify-between tw-gap-[var(--component-gap-sm)]\">\n <DialogPrimitive.Title className='ald-drawer-title ant-drawer-header-title tw-[font-feature-settings:\"liga\"_off,\"clig\"_off] tw-m-0 tw-flex-[1_0_0] tw-text-lg tw-font-semibold tw-leading-7 tw-text-[var(--content-primary)]'>\n {title}\n </DialogPrimitive.Title>\n {extra || closable ? (\n <div className=\"ald-drawer-actions tw-flex tw-items-center tw-gap-[var(--component-gap-sm)]\">\n {extra}\n {closable && (\n <DialogPrimitive.Close asChild>\n <button\n type=\"button\"\n className=\"ald-drawer-close tw-flex tw-size-8 tw-cursor-pointer tw-items-center tw-justify-center tw-rounded-r-50 tw-border-0 tw-bg-transparent hover:tw-bg-[var(--action-ghost-hover)]\"\n onClick={() => onClose?.()}\n >\n <CloseLightLine\n size={20}\n color=\"var(--content-secondary)\"\n />\n </button>\n </DialogPrimitive.Close>\n )}\n </div>\n ) : null}\n </div>\n {description ? (\n <div className='ald-drawer-description tw-[font-feature-settings:\"liga\"_off,\"clig\"_off] tw-self-stretch tw-text-sm tw-font-normal tw-leading-5 tw-text-[var(--content-secondary)]'>\n {description}\n </div>\n ) : null}\n </div>\n </div>\n </>\n )}\n {/* antd 兼容:保留 ant-drawer-body class */}\n <div\n className=\"ald-drawer-body ant-drawer-body tw-min-w-0 tw-flex-[1_0_0] tw-self-stretch tw-overflow-auto tw-p-[var(--component-padding-2xl)]\"\n style={bodyStyle}\n >\n {children}\n </div>\n {footer && (\n <>\n <div className=\"ald-drawer-footer-divider tw-h-px tw-bg-[var(--border-default)]\" />\n {/* antd 兼容:antd .ant-drawer-footer 使用 text-align:right 让 inline 按钮右对齐,\n 此处加 tw-text-right 保持消费方传入 width:100% 子容器时 inline 元素仍右对齐。 */}\n <div\n className=\"ald-drawer-footer ant-drawer-footer tw-flex tw-items-center tw-justify-end tw-gap-[var(--component-gap-lg)] tw-self-stretch tw-px-[var(--component-padding-2xl)] tw-py-[var(--component-padding-lg)]\"\n style={footerStyle}\n >\n {footer}\n </div>\n </>\n )}\n </FloatingLayerProvider>\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n}\n\nexport default Drawer;\n"],"mappings":"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"}
@@ -85,5 +85,10 @@ export interface IDropdownProps {
85
85
  * @default false
86
86
  */
87
87
  popupMatchTriggerWidth?: boolean | number;
88
+ /**
89
+ * @description 空间不足时自动计算菜单最大高度并启用滚动,启用后 offset 固定为 0
90
+ * @default false
91
+ */
92
+ allowOverlap?: boolean;
88
93
  }
89
94
  export default function Dropdown(props: IDropdownProps): import("react/jsx-runtime").JSX.Element;
@@ -1,39 +1,125 @@
1
1
  import { cn } from "../lib/utils.js";
2
2
  /* empty css */
3
3
  import Menu from "../Menu/index.js";
4
- import { cloneElement, useCallback, useEffect, useMemo, useState } from "react";
4
+ import { useFloatingPopupZIndex } from "../_utils/floatingLayer.js";
5
+ import { cloneElement, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
5
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
7
  import { FloatingFocusManager, FloatingNode, FloatingTree, autoUpdate, flip, offset, safePolygon, shift, size, useClick, useDismiss, useFloating, useFloatingNodeId, useFloatingParentNodeId, useHover, useId as useId$1, useInteractions, useRole } from "@floating-ui/react";
7
8
  import { useMemoizedFn } from "ahooks";
8
9
  import ReactDOM from "react-dom";
9
10
  //#region src/Dropdown/index.tsx
11
+ var OVERLAY_EXIT_ANIMATION_MS = 200;
12
+ function resolvePlacementSide(currentPlacement) {
13
+ const [side] = currentPlacement.split("-");
14
+ if (side === "top" || side === "bottom" || side === "left" || side === "right") return side;
15
+ if (currentPlacement.startsWith("top")) return "top";
16
+ if (currentPlacement.startsWith("bottom")) return "bottom";
17
+ if (currentPlacement.startsWith("left")) return "left";
18
+ if (currentPlacement.startsWith("right")) return "right";
19
+ return "bottom";
20
+ }
10
21
  function Dropdown(props) {
11
- const { children, destroyPopupOnHide = true, getPopupContainer, menu, overlayClassName, placement = "bottom-start", trigger = "click", open, onOpenChange = () => {}, overlayStyle, dropdownRender, disabled, offset: offsetProps = 4, delay = 0, autoUpdatePos = false, initialFocus = -1, popupMatchTriggerWidth = false } = props;
22
+ const { children, destroyPopupOnHide = true, getPopupContainer, menu, overlayClassName, placement = "bottom-start", trigger = "click", open, onOpenChange = () => {}, overlayStyle, dropdownRender, disabled, offset: offsetProps = 4, delay = 0, autoUpdatePos = false, initialFocus = -1, popupMatchTriggerWidth = false, allowOverlap = false } = props;
12
23
  const [isOpen, setIsOpen] = useState(open || false);
24
+ const [isAnimatingOut, setIsAnimatingOut] = useState(false);
25
+ const closeAnimationTimerRef = useRef(null);
26
+ const lastResolvedFloatingStylesRef = useRef(null);
27
+ const lastResolvedSideRef = useRef(resolvePlacementSide(placement));
28
+ const currentFloatingStylesRef = useRef(null);
29
+ const currentFloatingSideRef = useRef(resolvePlacementSide(placement));
30
+ const popupZIndex = useFloatingPopupZIndex();
13
31
  const onOpenChangeFn = useMemoizedFn(onOpenChange);
14
32
  const isOpenControlled = open !== void 0;
33
+ const clearCloseAnimationTimer = useCallback(() => {
34
+ if (closeAnimationTimerRef.current) {
35
+ clearTimeout(closeAnimationTimerRef.current);
36
+ closeAnimationTimerRef.current = null;
37
+ }
38
+ }, []);
39
+ const stopCloseAnimation = useCallback(() => {
40
+ clearCloseAnimationTimer();
41
+ document.body.classList.remove("ald-dropdown-root-closing");
42
+ setIsAnimatingOut(false);
43
+ }, [clearCloseAnimationTimer]);
44
+ const markRootClosing = useCallback(() => {
45
+ document.body.classList.add("ald-dropdown-root-closing");
46
+ lastResolvedFloatingStylesRef.current = currentFloatingStylesRef.current ?? lastResolvedFloatingStylesRef.current;
47
+ lastResolvedSideRef.current = currentFloatingSideRef.current ?? lastResolvedSideRef.current;
48
+ }, []);
49
+ const startCloseAnimation = useCallback(() => {
50
+ clearCloseAnimationTimer();
51
+ markRootClosing();
52
+ setIsAnimatingOut(true);
53
+ closeAnimationTimerRef.current = setTimeout(() => {
54
+ document.body.classList.remove("ald-dropdown-root-closing");
55
+ setIsAnimatingOut(false);
56
+ closeAnimationTimerRef.current = null;
57
+ }, OVERLAY_EXIT_ANIMATION_MS);
58
+ }, [clearCloseAnimationTimer, markRootClosing]);
59
+ useLayoutEffect(() => {
60
+ if (!isOpenControlled) return;
61
+ if (open) {
62
+ stopCloseAnimation();
63
+ setIsOpen(true);
64
+ return;
65
+ }
66
+ if (isOpen) startCloseAnimation();
67
+ setIsOpen(false);
68
+ }, [
69
+ isOpen,
70
+ isOpenControlled,
71
+ open,
72
+ startCloseAnimation,
73
+ stopCloseAnimation
74
+ ]);
75
+ useEffect(() => {
76
+ return () => {
77
+ clearCloseAnimationTimer();
78
+ };
79
+ }, [clearCloseAnimationTimer]);
15
80
  useEffect(() => {
16
- if (isOpenControlled) setIsOpen(open);
17
- }, [open, isOpenControlled]);
81
+ return () => {
82
+ document.body.classList.remove("ald-dropdown-root-closing");
83
+ };
84
+ }, []);
18
85
  const onChangeOpen = useCallback((newOpen) => {
86
+ if (newOpen) stopCloseAnimation();
87
+ else startCloseAnimation();
19
88
  if (!isOpenControlled) setIsOpen(newOpen);
20
89
  onOpenChangeFn(newOpen);
21
- }, [isOpenControlled, onOpenChangeFn]);
90
+ }, [
91
+ isOpenControlled,
92
+ onOpenChangeFn,
93
+ startCloseAnimation,
94
+ stopCloseAnimation
95
+ ]);
22
96
  const nodeId = useFloatingNodeId();
23
- const { refs, floatingStyles, context } = useFloating({
97
+ const { refs, floatingStyles, context, placement: floatingPlacement, x, y } = useFloating({
24
98
  nodeId,
25
99
  placement,
26
100
  open: isOpen,
27
101
  onOpenChange: onChangeOpen,
28
102
  middleware: [
29
- offset(offsetProps),
30
- flip({ fallbackAxisSideDirection: "end" }),
31
- shift(),
32
- popupMatchTriggerWidth ? size({ apply({ rects, elements }) {
33
- Object.assign(elements.floating.style, { width: typeof popupMatchTriggerWidth === "number" ? `${popupMatchTriggerWidth}px` : `${rects.reference.width}px` });
34
- } }) : size({ apply({ elements }) {
35
- Object.assign(elements.floating.style, { minWidth: "144px" });
36
- } })
103
+ offset(allowOverlap ? 0 : offsetProps),
104
+ flip({
105
+ fallbackAxisSideDirection: "end",
106
+ ...allowOverlap && { fallbackStrategy: "bestFit" }
107
+ }),
108
+ shift(allowOverlap ? { mainAxis: true } : void 0),
109
+ size({
110
+ ...allowOverlap && { padding: 8 },
111
+ apply({ availableHeight, rects, elements }) {
112
+ const widthStyle = popupMatchTriggerWidth ? { width: typeof popupMatchTriggerWidth === "number" ? `${popupMatchTriggerWidth}px` : `${rects.reference.width}px` } : { minWidth: "144px" };
113
+ const heightStyle = allowOverlap ? {
114
+ maxHeight: `${Math.max(100, availableHeight)}px`,
115
+ overflowY: "auto"
116
+ } : {};
117
+ Object.assign(elements.floating.style, {
118
+ ...widthStyle,
119
+ ...heightStyle
120
+ });
121
+ }
122
+ })
37
123
  ],
38
124
  whileElementsMounted: autoUpdatePos ? autoUpdate : void 0
39
125
  });
@@ -78,41 +164,71 @@ function Dropdown(props) {
78
164
  });
79
165
  const onMenuItemClick = useCallback((info) => {
80
166
  if (menu?.onClick) menu.onClick(info);
81
- if (info.keepOpen) return;
82
- if (!isOpenControlled) setIsOpen(false);
83
- }, [isOpenControlled, menu]);
167
+ if (info.keepOpen) {
168
+ document.body.classList.remove("ald-dropdown-root-closing");
169
+ return;
170
+ }
171
+ onChangeOpen(false);
172
+ }, [menu, onChangeOpen]);
84
173
  const menuInstance = useMemo(() => {
85
174
  return /* @__PURE__ */ jsx(Menu, {
86
175
  ...menu,
87
176
  items: menu?.items || [],
88
- onClick: onMenuItemClick
177
+ onBeforeLeafItemClick: markRootClosing,
178
+ rootClosing: isAnimatingOut,
179
+ onClick: onMenuItemClick,
180
+ externalOverflow: allowOverlap
89
181
  });
90
- }, [menu, onMenuItemClick]);
182
+ }, [
183
+ allowOverlap,
184
+ isAnimatingOut,
185
+ markRootClosing,
186
+ menu,
187
+ onMenuItemClick
188
+ ]);
91
189
  const popupElement = useMemo(() => {
92
190
  return typeof dropdownRender === "function" ? dropdownRender(menuInstance) : menuInstance;
93
191
  }, [dropdownRender, menuInstance]);
192
+ const floatingSide = resolvePlacementSide(String(floatingPlacement));
193
+ const shouldKeepMounted = !destroyPopupOnHide || isOpen || isAnimatingOut;
194
+ const isPositionReady = x !== null && y !== null;
195
+ const overlayHidden = !isOpen && !isAnimatingOut || isOpen && !isPositionReady;
196
+ const resolvedFloatingStyles = isAnimatingOut ? lastResolvedFloatingStylesRef.current ?? floatingStyles : floatingStyles;
197
+ const resolvedFloatingSide = isAnimatingOut ? lastResolvedSideRef.current : floatingSide;
198
+ if (isOpen && isPositionReady) {
199
+ currentFloatingStylesRef.current = { ...floatingStyles };
200
+ currentFloatingSideRef.current = floatingSide;
201
+ lastResolvedFloatingStylesRef.current = { ...floatingStyles };
202
+ lastResolvedSideRef.current = floatingSide;
203
+ }
94
204
  const renderFloatingContent = useCallback(() => {
95
- const popupElem = /* @__PURE__ */ jsx(FloatingFocusManager, {
96
- context,
97
- modal: false,
98
- initialFocus,
205
+ const surface = /* @__PURE__ */ jsx("div", {
206
+ className: cn("ald-dropdown-overlay", "tw-pointer-events-auto tw-z-[1001] tw-max-w-none tw-outline-none", overlayClassName, { "ald-dropdown-overlay-hidden": overlayHidden }),
207
+ ref: refs.setFloating,
208
+ style: {
209
+ zIndex: popupZIndex,
210
+ ...resolvedFloatingStyles,
211
+ ...overlayStyle
212
+ },
213
+ "aria-labelledby": headingId,
214
+ ...isAnimatingOut ? {} : getFloatingProps(),
99
215
  children: /* @__PURE__ */ jsx("div", {
100
- className: cn("ald-dropdown-overlay", "tw-flex tw-flex-col tw-items-start tw-self-stretch", "tw-rounded-[var(--alias-radius-75,8px)]", "tw-border tw-border-solid tw-border-[var(--global-cool-gray-alpha-100,rgba(0,0,0,0.06))]", "tw-bg-[var(--interaction-background-modeless,#fff)]", "tw-shadow-[var(--elevation-bottom-bottom-lg,0_8px_24px_rgba(0,0,0,0.12))]", "tw-z-[1001] tw-max-w-none tw-px-0 tw-py-1 tw-text-sm", overlayClassName, { "ald-dropdown-overlay-hidden tw-invisible": !isOpen }),
101
- ref: refs.setFloating,
102
- style: {
103
- ...floatingStyles,
104
- ...overlayStyle
105
- },
106
- "aria-labelledby": headingId,
107
- ...getFloatingProps(),
216
+ className: cn("ald-dropdown-surface", "tw-flex tw-flex-col tw-items-start tw-text-sm"),
217
+ "data-state": isOpen ? "open" : "closed",
218
+ "data-side": resolvedFloatingSide,
108
219
  children: popupElement
109
220
  })
110
221
  });
222
+ const popupElem = isAnimatingOut && !isOpen ? surface : /* @__PURE__ */ jsx(FloatingFocusManager, {
223
+ context,
224
+ modal: false,
225
+ initialFocus,
226
+ children: surface
227
+ });
111
228
  const popupContainer = typeof getPopupContainer === "function" ? getPopupContainer() : document.body;
112
229
  return ReactDOM.createPortal(popupElem, popupContainer);
113
230
  }, [
114
231
  context,
115
- floatingStyles,
116
232
  getFloatingProps,
117
233
  getPopupContainer,
118
234
  headingId,
@@ -120,10 +236,15 @@ function Dropdown(props) {
120
236
  refs.setFloating,
121
237
  overlayClassName,
122
238
  overlayStyle,
239
+ popupZIndex,
240
+ overlayHidden,
241
+ isAnimatingOut,
123
242
  isOpen,
124
- initialFocus
243
+ initialFocus,
244
+ resolvedFloatingSide,
245
+ resolvedFloatingStyles
125
246
  ]);
126
- const popup = destroyPopupOnHide ? isOpen && renderFloatingContent() : renderFloatingContent();
247
+ const popup = shouldKeepMounted ? renderFloatingContent() : null;
127
248
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
128
249
  ref: useCallback((node) => {
129
250
  if (node) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/Dropdown/index.tsx"],"sourcesContent":["import './dropdown.css';\nimport {\n FloatingFocusManager,\n FloatingFocusManagerProps,\n FloatingNode,\n FloatingTree,\n OffsetOptions,\n UseHoverProps,\n autoUpdate,\n flip,\n offset,\n safePolygon,\n shift,\n size,\n useClick,\n useDismiss,\n useFloating,\n useFloatingNodeId,\n useFloatingParentNodeId,\n useHover,\n useId,\n useInteractions,\n useRole,\n} from '@floating-ui/react';\nimport { useMemoizedFn } from 'ahooks';\nimport { cn } from '../lib/utils';\nimport React, {\n cloneElement,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport ReactDOM from 'react-dom';\nimport Menu, { MenuInfo, MenuProps } from '../Menu';\n\nexport type ActionType = 'hover' | 'click';\nexport type PlacementType =\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-start'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-end'\n | 'left-start'\n | 'left-end'\n | 'right-start'\n | 'right-end'\n // Legacy antd-style placement names\n | 'topLeft'\n | 'topRight'\n | 'bottomLeft'\n | 'bottomRight';\nexport interface IDropdownProps {\n children: React.ReactNode;\n /**\n * @description 菜单弹出位置的偏移量\n */\n offset?: OffsetOptions;\n /**\n * @description 关闭后是否销毁 Dropdown\n * @default false\n */\n destroyPopupOnHide?: boolean;\n /**\n * @description 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位\n * @default () => document.body\n */\n getPopupContainer?: () => HTMLElement;\n /**\n * @description 菜单\n * @type Menu | () => Menu\n * @default -\n */\n menu?: MenuProps;\n // /**\n // * @description 菜单\n // * @type Menu | () => Menu\n // * @default -\n // */\n // menu?: ReactElement | (() => ReactElement);\n /**\n * @description 下拉根元素的类名称\n * @default -\n */\n overlayClassName?: string;\n /**\n * @description 菜单弹出位置\n * @default bottomLeft\n */\n placement?: PlacementType;\n /**\n * @description 触发下拉的行为\n * @type ActionType, 其中 ActionType 为 'hover' | 'click' | 'contextMenu';\n * @default click\n */\n trigger?: ActionType | ActionType[];\n /**\n * @description 菜单是否显示\n * @default -\n */\n open?: boolean;\n /**\n * @description 菜单显示状态改变时调用,参数为 open,点击菜单按钮导致的消失不会触发\n * @default -\n */\n onOpenChange?: (open: boolean) => void;\n /**\n * @description 下拉框的属性\n * @default -\n */\n overlayStyle?: React.CSSProperties;\n\n /**\n * @description 自定义下拉框内容\n * @default -\n */\n dropdownRender?: (menus: React.ReactNode) => React.ReactNode;\n /**\n * @description 是否禁用\n * @default false\n */\n // 透传给子元素,antd的dropdown用cloneElement生成dropdown的子元素,劫持了disabled属性,因此如果Dropdown上没有disabled属性,子元素不能获得该属性\n disabled?: boolean;\n /**\n * @description 鼠标移入后延迟显示下拉框的时间,单位为毫秒\n * @default 0\n */\n delay?: UseHoverProps['delay'];\n /**\n * @description 是否在下拉框变化的时候自动更新位置\n * @default false\n */\n autoUpdatePos?: boolean;\n /**\n * @description 初始化焦点,参照:https://floating-ui.com/docs/floatingfocusmanager#initialfocus\n */\n initialFocus?: FloatingFocusManagerProps['initialFocus'];\n\n /**\n * @description 菜单是否跟随触发元素宽度\n * @default false\n */\n popupMatchTriggerWidth?: boolean | number;\n}\n\nexport default function Dropdown(props: IDropdownProps) {\n const {\n children,\n destroyPopupOnHide = true,\n getPopupContainer,\n menu,\n overlayClassName,\n placement = 'bottom-start',\n trigger = 'click',\n open,\n onOpenChange = () => {},\n overlayStyle,\n dropdownRender,\n disabled,\n offset: offsetProps = 4,\n delay = 0,\n autoUpdatePos = false,\n // 默认不自动 focus\n initialFocus = -1,\n popupMatchTriggerWidth = false,\n } = props;\n const [isOpen, setIsOpen] = useState<boolean>(open || false);\n\n const onOpenChangeFn = useMemoizedFn(onOpenChange);\n const isOpenControlled = open !== undefined;\n\n useEffect(() => {\n if (isOpenControlled) {\n setIsOpen(open);\n }\n }, [open, isOpenControlled]);\n\n const onChangeOpen = useCallback(\n (newOpen: boolean) => {\n if (!isOpenControlled) {\n setIsOpen(newOpen);\n }\n onOpenChangeFn(newOpen);\n },\n [isOpenControlled, onOpenChangeFn],\n );\n\n const nodeId = useFloatingNodeId();\n const { refs, floatingStyles, context } = useFloating({\n nodeId,\n placement: placement as any,\n open: isOpen,\n onOpenChange: onChangeOpen,\n middleware: [\n offset(offsetProps),\n flip({ fallbackAxisSideDirection: 'end' }),\n shift(),\n popupMatchTriggerWidth\n ? size({\n apply({ rects, elements }) {\n Object.assign(elements.floating.style, {\n width:\n typeof popupMatchTriggerWidth === 'number'\n ? `${popupMatchTriggerWidth}px`\n : `${rects.reference.width}px`,\n });\n },\n })\n : size({\n apply({ elements }) {\n Object.assign(elements.floating.style, {\n minWidth: '144px',\n });\n },\n }),\n ],\n whileElementsMounted: autoUpdatePos ? autoUpdate : undefined,\n });\n\n const click = useClick(context);\n const hover = useHover(context, {\n enabled: trigger === 'hover',\n handleClose: safePolygon({}),\n delay: delay,\n });\n const dismiss = useDismiss(context, {});\n const role = useRole(context);\n\n const propsList = useMemo(() => {\n const res = [dismiss, role];\n\n let finalTrigger = trigger;\n if (Array.isArray(trigger)) {\n // 对于数组形式的 trigger,告警\n console.error(\n 'trigger should be a string, support \"hover\" or \"click\" now.',\n );\n finalTrigger = 'click';\n }\n\n if (finalTrigger === 'hover') {\n res.unshift(hover);\n } else if (finalTrigger === 'click') {\n res.unshift(click);\n }\n return res;\n }, [trigger, click, dismiss, role, hover]);\n\n const { getReferenceProps, getFloatingProps } = useInteractions(propsList);\n\n const headingId = useId();\n\n const child = children as React.ReactElement;\n const childProps = child.props || {};\n const referenceProps = getReferenceProps();\n const modifiedChild = cloneElement(child, {\n ...childProps,\n disabled,\n // ref: (node: HTMLDivElement) => refs.setReference(node),\n ...referenceProps,\n onClick: (event: React.MouseEvent<HTMLElement>) => {\n childProps.onClick?.(event);\n const { onClick: referenceOnClick } = referenceProps;\n if (typeof referenceOnClick === 'function') {\n referenceOnClick(event);\n }\n },\n });\n\n const onMenuItemClick = useCallback(\n (info: MenuInfo) => {\n if (menu?.onClick) {\n menu.onClick(info);\n }\n if (info.keepOpen) {\n return;\n }\n if (!isOpenControlled) {\n setIsOpen(false);\n }\n },\n [isOpenControlled, menu],\n );\n\n const menuInstance = useMemo(() => {\n const menuProps = {\n ...menu,\n items: menu?.items || [],\n };\n return <Menu {...menuProps} onClick={onMenuItemClick} />;\n }, [menu, onMenuItemClick]);\n\n const popupElement = useMemo(() => {\n return typeof dropdownRender === 'function'\n ? dropdownRender(menuInstance)\n : menuInstance;\n }, [dropdownRender, menuInstance]);\n\n // 渲染浮动内容到自定义容器\n const renderFloatingContent = useCallback(() => {\n const popupElem = (\n <FloatingFocusManager\n context={context}\n modal={false}\n initialFocus={initialFocus}\n >\n <div\n className={cn(\n 'ald-dropdown-overlay',\n 'tw-flex tw-flex-col tw-items-start tw-self-stretch',\n 'tw-rounded-[var(--alias-radius-75,8px)]',\n 'tw-border tw-border-solid tw-border-[var(--global-cool-gray-alpha-100,rgba(0,0,0,0.06))]',\n 'tw-bg-[var(--interaction-background-modeless,#fff)]',\n 'tw-shadow-[var(--elevation-bottom-bottom-lg,0_8px_24px_rgba(0,0,0,0.12))]',\n 'tw-z-[1001] tw-max-w-none tw-px-0 tw-py-1 tw-text-sm',\n overlayClassName,\n { 'ald-dropdown-overlay-hidden tw-invisible': !isOpen },\n )}\n ref={refs.setFloating}\n style={{ ...floatingStyles, ...overlayStyle }}\n aria-labelledby={headingId}\n {...getFloatingProps()}\n >\n {popupElement}\n </div>\n </FloatingFocusManager>\n );\n\n const popupContainer =\n typeof getPopupContainer === 'function'\n ? getPopupContainer()\n : document.body;\n return ReactDOM.createPortal(popupElem, popupContainer);\n }, [\n context,\n floatingStyles,\n getFloatingProps,\n getPopupContainer,\n headingId,\n popupElement,\n refs.setFloating,\n overlayClassName,\n overlayStyle,\n isOpen,\n initialFocus,\n ]);\n\n const popup = destroyPopupOnHide\n ? isOpen && renderFloatingContent()\n : renderFloatingContent();\n\n const setTargetRef = useCallback(\n (node: HTMLElement | null) => {\n if (node) {\n // display: contents 元素没有 box model,getBoundingClientRect() 返回零值\n // 需要获取实际的第一个子元素作为 floating-ui 的参考元素\n const target =\n node.style.display === 'contents'\n ? (node.firstElementChild as HTMLElement) || node\n : node;\n refs.setReference(target);\n } else {\n refs.setReference(null);\n }\n },\n [refs],\n );\n\n const content = (\n <>\n <span ref={setTargetRef} style={{ display: 'contents' }}>\n {modifiedChild}\n </span>\n <FloatingNode id={nodeId}>{popup}</FloatingNode>\n </>\n );\n\n const parentId = useFloatingParentNodeId();\n if (!parentId) {\n return <FloatingTree>{content}</FloatingTree>;\n }\n\n return content;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/Dropdown/index.tsx"],"sourcesContent":["import './dropdown.css';\nimport {\n FloatingFocusManager,\n FloatingFocusManagerProps,\n FloatingNode,\n FloatingTree,\n OffsetOptions,\n UseHoverProps,\n autoUpdate,\n flip,\n offset,\n safePolygon,\n shift,\n size,\n useClick,\n useDismiss,\n useFloating,\n useFloatingNodeId,\n useFloatingParentNodeId,\n useHover,\n useId,\n useInteractions,\n useRole,\n} from '@floating-ui/react';\nimport { useMemoizedFn } from 'ahooks';\nimport { cn } from '../lib/utils';\nimport React, {\n cloneElement,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport ReactDOM from 'react-dom';\nimport Menu, { MenuInfo, MenuProps } from '../Menu';\nimport { useFloatingPopupZIndex } from '../_utils/floatingLayer';\n\nconst OVERLAY_EXIT_ANIMATION_MS = 200;\n\nfunction resolvePlacementSide(\n currentPlacement: string,\n): 'top' | 'bottom' | 'left' | 'right' {\n const [side] = currentPlacement.split('-');\n if (\n side === 'top' ||\n side === 'bottom' ||\n side === 'left' ||\n side === 'right'\n ) {\n return side;\n }\n if (currentPlacement.startsWith('top')) {\n return 'top';\n }\n if (currentPlacement.startsWith('bottom')) {\n return 'bottom';\n }\n if (currentPlacement.startsWith('left')) {\n return 'left';\n }\n if (currentPlacement.startsWith('right')) {\n return 'right';\n }\n return 'bottom';\n}\n\nexport type ActionType = 'hover' | 'click';\nexport type PlacementType =\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-start'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-end'\n | 'left-start'\n | 'left-end'\n | 'right-start'\n | 'right-end'\n // Legacy antd-style placement names\n | 'topLeft'\n | 'topRight'\n | 'bottomLeft'\n | 'bottomRight';\nexport interface IDropdownProps {\n children: React.ReactNode;\n /**\n * @description 菜单弹出位置的偏移量\n */\n offset?: OffsetOptions;\n /**\n * @description 关闭后是否销毁 Dropdown\n * @default false\n */\n destroyPopupOnHide?: boolean;\n /**\n * @description 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位\n * @default () => document.body\n */\n getPopupContainer?: () => HTMLElement;\n /**\n * @description 菜单\n * @type Menu | () => Menu\n * @default -\n */\n menu?: MenuProps;\n // /**\n // * @description 菜单\n // * @type Menu | () => Menu\n // * @default -\n // */\n // menu?: ReactElement | (() => ReactElement);\n /**\n * @description 下拉根元素的类名称\n * @default -\n */\n overlayClassName?: string;\n /**\n * @description 菜单弹出位置\n * @default bottomLeft\n */\n placement?: PlacementType;\n /**\n * @description 触发下拉的行为\n * @type ActionType, 其中 ActionType 为 'hover' | 'click' | 'contextMenu';\n * @default click\n */\n trigger?: ActionType | ActionType[];\n /**\n * @description 菜单是否显示\n * @default -\n */\n open?: boolean;\n /**\n * @description 菜单显示状态改变时调用,参数为 open,点击菜单按钮导致的消失不会触发\n * @default -\n */\n onOpenChange?: (open: boolean) => void;\n /**\n * @description 下拉框的属性\n * @default -\n */\n overlayStyle?: React.CSSProperties;\n\n /**\n * @description 自定义下拉框内容\n * @default -\n */\n dropdownRender?: (menus: React.ReactNode) => React.ReactNode;\n /**\n * @description 是否禁用\n * @default false\n */\n // 透传给子元素,antd的dropdown用cloneElement生成dropdown的子元素,劫持了disabled属性,因此如果Dropdown上没有disabled属性,子元素不能获得该属性\n disabled?: boolean;\n /**\n * @description 鼠标移入后延迟显示下拉框的时间,单位为毫秒\n * @default 0\n */\n delay?: UseHoverProps['delay'];\n /**\n * @description 是否在下拉框变化的时候自动更新位置\n * @default false\n */\n autoUpdatePos?: boolean;\n /**\n * @description 初始化焦点,参照:https://floating-ui.com/docs/floatingfocusmanager#initialfocus\n */\n initialFocus?: FloatingFocusManagerProps['initialFocus'];\n\n /**\n * @description 菜单是否跟随触发元素宽度\n * @default false\n */\n popupMatchTriggerWidth?: boolean | number;\n /**\n * @description 空间不足时自动计算菜单最大高度并启用滚动,启用后 offset 固定为 0\n * @default false\n */\n allowOverlap?: boolean;\n}\n\nexport default function Dropdown(props: IDropdownProps) {\n const {\n children,\n destroyPopupOnHide = true,\n getPopupContainer,\n menu,\n overlayClassName,\n placement = 'bottom-start',\n trigger = 'click',\n open,\n onOpenChange = () => {},\n overlayStyle,\n dropdownRender,\n disabled,\n offset: offsetProps = 4,\n delay = 0,\n autoUpdatePos = false,\n // 默认不自动 focus\n initialFocus = -1,\n popupMatchTriggerWidth = false,\n allowOverlap = false,\n } = props;\n const [isOpen, setIsOpen] = useState<boolean>(open || false);\n const [isAnimatingOut, setIsAnimatingOut] = useState(false);\n const closeAnimationTimerRef = useRef<ReturnType<typeof setTimeout> | null>(\n null,\n );\n const lastResolvedFloatingStylesRef = useRef<React.CSSProperties | null>(\n null,\n );\n const lastResolvedSideRef = useRef<'top' | 'bottom' | 'left' | 'right'>(\n resolvePlacementSide(placement),\n );\n const currentFloatingStylesRef = useRef<React.CSSProperties | null>(null);\n const currentFloatingSideRef = useRef<'top' | 'bottom' | 'left' | 'right'>(\n resolvePlacementSide(placement),\n );\n const popupZIndex = useFloatingPopupZIndex();\n\n const onOpenChangeFn = useMemoizedFn(onOpenChange);\n const isOpenControlled = open !== undefined;\n\n const clearCloseAnimationTimer = useCallback(() => {\n if (closeAnimationTimerRef.current) {\n clearTimeout(closeAnimationTimerRef.current);\n closeAnimationTimerRef.current = null;\n }\n }, []);\n\n const stopCloseAnimation = useCallback(() => {\n clearCloseAnimationTimer();\n document.body.classList.remove('ald-dropdown-root-closing');\n setIsAnimatingOut(false);\n }, [clearCloseAnimationTimer]);\n\n const markRootClosing = useCallback(() => {\n document.body.classList.add('ald-dropdown-root-closing');\n lastResolvedFloatingStylesRef.current =\n currentFloatingStylesRef.current ?? lastResolvedFloatingStylesRef.current;\n lastResolvedSideRef.current =\n currentFloatingSideRef.current ?? lastResolvedSideRef.current;\n }, []);\n\n const startCloseAnimation = useCallback(() => {\n clearCloseAnimationTimer();\n markRootClosing();\n setIsAnimatingOut(true);\n closeAnimationTimerRef.current = setTimeout(() => {\n document.body.classList.remove('ald-dropdown-root-closing');\n setIsAnimatingOut(false);\n closeAnimationTimerRef.current = null;\n }, OVERLAY_EXIT_ANIMATION_MS);\n }, [clearCloseAnimationTimer, markRootClosing]);\n\n useLayoutEffect(() => {\n if (!isOpenControlled) {\n return;\n }\n\n if (open) {\n stopCloseAnimation();\n setIsOpen(true);\n return;\n }\n\n if (isOpen) {\n startCloseAnimation();\n }\n setIsOpen(false);\n }, [isOpen, isOpenControlled, open, startCloseAnimation, stopCloseAnimation]);\n\n useEffect(() => {\n return () => {\n clearCloseAnimationTimer();\n };\n }, [clearCloseAnimationTimer]);\n\n useEffect(() => {\n return () => {\n document.body.classList.remove('ald-dropdown-root-closing');\n };\n }, []);\n\n const onChangeOpen = useCallback(\n (newOpen: boolean) => {\n if (newOpen) {\n stopCloseAnimation();\n } else {\n startCloseAnimation();\n }\n\n if (!isOpenControlled) {\n setIsOpen(newOpen);\n }\n onOpenChangeFn(newOpen);\n },\n [isOpenControlled, onOpenChangeFn, startCloseAnimation, stopCloseAnimation],\n );\n\n const nodeId = useFloatingNodeId();\n const {\n refs,\n floatingStyles,\n context,\n placement: floatingPlacement,\n x,\n y,\n } = useFloating({\n nodeId,\n placement: placement as any,\n open: isOpen,\n onOpenChange: onChangeOpen,\n middleware: [\n offset(allowOverlap ? 0 : offsetProps),\n flip({\n fallbackAxisSideDirection: 'end',\n ...(allowOverlap && { fallbackStrategy: 'bestFit' }),\n }),\n shift(allowOverlap ? { mainAxis: true } : undefined),\n size({\n ...(allowOverlap && { padding: 8 }),\n apply({ availableHeight, rects, elements }) {\n const widthStyle = popupMatchTriggerWidth\n ? {\n width:\n typeof popupMatchTriggerWidth === 'number'\n ? `${popupMatchTriggerWidth}px`\n : `${rects.reference.width}px`,\n }\n : { minWidth: '144px' };\n const heightStyle = allowOverlap\n ? {\n maxHeight: `${Math.max(100, availableHeight)}px`,\n overflowY: 'auto',\n }\n : {};\n Object.assign(elements.floating.style, {\n ...widthStyle,\n ...heightStyle,\n });\n },\n }),\n ],\n whileElementsMounted: autoUpdatePos ? autoUpdate : undefined,\n });\n\n const click = useClick(context);\n const hover = useHover(context, {\n enabled: trigger === 'hover',\n handleClose: safePolygon({}),\n delay: delay,\n });\n const dismiss = useDismiss(context, {});\n const role = useRole(context);\n\n const propsList = useMemo(() => {\n const res = [dismiss, role];\n\n let finalTrigger = trigger;\n if (Array.isArray(trigger)) {\n // 对于数组形式的 trigger,告警\n console.error(\n 'trigger should be a string, support \"hover\" or \"click\" now.',\n );\n finalTrigger = 'click';\n }\n\n if (finalTrigger === 'hover') {\n res.unshift(hover);\n } else if (finalTrigger === 'click') {\n res.unshift(click);\n }\n return res;\n }, [trigger, click, dismiss, role, hover]);\n\n const { getReferenceProps, getFloatingProps } = useInteractions(propsList);\n\n const headingId = useId();\n\n const child = children as React.ReactElement;\n const childProps = child.props || {};\n const referenceProps = getReferenceProps();\n const modifiedChild = cloneElement(child, {\n ...childProps,\n disabled,\n // ref: (node: HTMLDivElement) => refs.setReference(node),\n ...referenceProps,\n onClick: (event: React.MouseEvent<HTMLElement>) => {\n childProps.onClick?.(event);\n const { onClick: referenceOnClick } = referenceProps;\n if (typeof referenceOnClick === 'function') {\n referenceOnClick(event);\n }\n },\n });\n\n const onMenuItemClick = useCallback(\n (info: MenuInfo) => {\n if (menu?.onClick) {\n menu.onClick(info);\n }\n if (info.keepOpen) {\n document.body.classList.remove('ald-dropdown-root-closing');\n return;\n }\n onChangeOpen(false);\n },\n [menu, onChangeOpen],\n );\n\n const menuInstance = useMemo(() => {\n const menuProps = {\n ...menu,\n items: menu?.items || [],\n onBeforeLeafItemClick: markRootClosing,\n rootClosing: isAnimatingOut,\n };\n return (\n <Menu\n {...menuProps}\n onClick={onMenuItemClick}\n externalOverflow={allowOverlap}\n />\n );\n }, [allowOverlap, isAnimatingOut, markRootClosing, menu, onMenuItemClick]);\n\n const popupElement = useMemo(() => {\n return typeof dropdownRender === 'function'\n ? dropdownRender(menuInstance)\n : menuInstance;\n }, [dropdownRender, menuInstance]);\n\n const floatingSide = resolvePlacementSide(String(floatingPlacement));\n const shouldKeepMounted = !destroyPopupOnHide || isOpen || isAnimatingOut;\n const isPositionReady = x !== null && y !== null;\n const overlayHidden =\n (!isOpen && !isAnimatingOut) || (isOpen && !isPositionReady);\n const resolvedFloatingStyles = isAnimatingOut\n ? lastResolvedFloatingStylesRef.current ?? floatingStyles\n : floatingStyles;\n const resolvedFloatingSide = isAnimatingOut\n ? lastResolvedSideRef.current\n : floatingSide;\n\n if (isOpen && isPositionReady) {\n currentFloatingStylesRef.current = { ...floatingStyles };\n currentFloatingSideRef.current = floatingSide;\n lastResolvedFloatingStylesRef.current = { ...floatingStyles };\n lastResolvedSideRef.current = floatingSide;\n }\n\n // 渲染浮动内容到自定义容器\n const renderFloatingContent = useCallback(() => {\n const surface = (\n <div\n className={cn(\n 'ald-dropdown-overlay',\n // tw-outline-none:FloatingFocusManager 打开时会聚焦浮层容器,不抑制 outline 会渲染出蓝色焦点框\n 'tw-pointer-events-auto tw-z-[1001] tw-max-w-none tw-outline-none',\n overlayClassName,\n { 'ald-dropdown-overlay-hidden': overlayHidden },\n )}\n ref={refs.setFloating}\n style={{\n zIndex: popupZIndex,\n ...resolvedFloatingStyles,\n ...overlayStyle,\n }}\n aria-labelledby={headingId}\n {...(isAnimatingOut ? {} : getFloatingProps())}\n >\n <div\n className={cn(\n 'ald-dropdown-surface',\n 'tw-flex tw-flex-col tw-items-start tw-text-sm',\n )}\n data-state={isOpen ? 'open' : 'closed'}\n data-side={resolvedFloatingSide}\n >\n {popupElement}\n </div>\n </div>\n );\n\n const popupElem =\n isAnimatingOut && !isOpen ? (\n surface\n ) : (\n <FloatingFocusManager\n context={context}\n modal={false}\n initialFocus={initialFocus}\n >\n {surface}\n </FloatingFocusManager>\n );\n\n const popupContainer =\n typeof getPopupContainer === 'function'\n ? getPopupContainer()\n : document.body;\n return ReactDOM.createPortal(popupElem, popupContainer);\n }, [\n context,\n getFloatingProps,\n getPopupContainer,\n headingId,\n popupElement,\n refs.setFloating,\n overlayClassName,\n overlayStyle,\n popupZIndex,\n overlayHidden,\n isAnimatingOut,\n isOpen,\n initialFocus,\n resolvedFloatingSide,\n resolvedFloatingStyles,\n ]);\n\n const popup = shouldKeepMounted ? renderFloatingContent() : null;\n\n const setTargetRef = useCallback(\n (node: HTMLElement | null) => {\n if (node) {\n // display: contents 元素没有 box model,getBoundingClientRect() 返回零值\n // 需要获取实际的第一个子元素作为 floating-ui 的参考元素\n const target =\n node.style.display === 'contents'\n ? (node.firstElementChild as HTMLElement) || node\n : node;\n refs.setReference(target);\n } else {\n refs.setReference(null);\n }\n },\n [refs],\n );\n\n const content = (\n <>\n <span ref={setTargetRef} style={{ display: 'contents' }}>\n {modifiedChild}\n </span>\n <FloatingNode id={nodeId}>{popup}</FloatingNode>\n </>\n );\n\n const parentId = useFloatingParentNodeId();\n if (!parentId) {\n return <FloatingTree>{content}</FloatingTree>;\n }\n\n return content;\n}\n"],"mappings":"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"}