@aloudata/aloudata-design 3.1.0 → 3.1.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.
- package/dist/AProgress/index.js +10 -0
- package/dist/AProgress/index.js.map +1 -1
- package/dist/Alert/index.js +3 -1
- package/dist/Alert/index.js.map +1 -1
- package/dist/Badge/index.js +37 -11
- package/dist/Badge/index.js.map +1 -1
- package/dist/Breadcrumb/index.js +12 -2
- package/dist/Breadcrumb/index.js.map +1 -1
- package/dist/Button/index.d.ts +1 -1
- package/dist/Button/index.js +20 -6
- package/dist/Button/index.js.map +1 -1
- package/dist/Card/index.js +1 -1
- package/dist/Card/index.js.map +1 -1
- package/dist/Carousel/index.js +9 -1
- package/dist/Carousel/index.js.map +1 -1
- package/dist/Checkbox/index.js +17 -2
- package/dist/Checkbox/index.js.map +1 -1
- package/dist/Checkbox/type.d.ts +10 -2
- package/dist/ColorPicker/index.js +112 -46
- package/dist/ColorPicker/index.js.map +1 -1
- package/dist/DataPreviewTable/components/Body/Cell.d.ts +2 -0
- package/dist/DataPreviewTable/components/Body/Cell.js +9 -1
- package/dist/DataPreviewTable/components/Body/Cell.js.map +1 -1
- package/dist/DataPreviewTable/components/Body/index.d.ts +1 -0
- package/dist/DataPreviewTable/components/Body/index.js +35 -23
- package/dist/DataPreviewTable/components/Body/index.js.map +1 -1
- package/dist/DataPreviewTable/components/Header/index.d.ts +1 -0
- package/dist/DataPreviewTable/components/Header/index.js +36 -28
- package/dist/DataPreviewTable/components/Header/index.js.map +1 -1
- package/dist/DataPreviewTable/index.js +19 -2
- package/dist/DataPreviewTable/index.js.map +1 -1
- package/dist/Drawer/index.d.ts +4 -0
- package/dist/Drawer/index.js +93 -79
- package/dist/Drawer/index.js.map +1 -1
- package/dist/Dropdown/index.d.ts +1 -1
- package/dist/Dropdown/index.js +64 -13
- package/dist/Dropdown/index.js.map +1 -1
- package/dist/Form/FormItemContext.d.ts +1 -1
- package/dist/Form/FormItemContext.js.map +1 -1
- package/dist/Form/index.js +50 -7
- package/dist/Form/index.js.map +1 -1
- package/dist/IconButton/index.d.ts +2 -2
- package/dist/IconButton/index.js +9 -3
- package/dist/IconButton/index.js.map +1 -1
- package/dist/Input/components/Input/index.js +18 -8
- package/dist/Input/components/Input/index.js.map +1 -1
- package/dist/Input/components/TextArea/index.js +18 -7
- package/dist/Input/components/TextArea/index.js.map +1 -1
- package/dist/Input/privateSemanticOwner.d.ts +2 -0
- package/dist/Input/privateSemanticOwner.js +1 -0
- package/dist/InputNumber/index.js +16 -9
- package/dist/InputNumber/index.js.map +1 -1
- package/dist/InputNumber/type.d.ts +2 -2
- package/dist/LogicTree/components/LogicItem/index.d.ts +2 -1
- package/dist/LogicTree/components/LogicItem/index.js +13 -2
- package/dist/LogicTree/components/LogicItem/index.js.map +1 -1
- package/dist/LogicTree/index.js +2 -0
- package/dist/LogicTree/index.js.map +1 -1
- package/dist/MemberPicker/components/MemberSelection.d.ts +2 -0
- package/dist/MemberPicker/components/MemberSelection.js +15 -13
- package/dist/MemberPicker/components/MemberSelection.js.map +1 -1
- package/dist/MemberPicker/components/MultipleOption.js +12 -0
- package/dist/MemberPicker/components/MultipleOption.js.map +1 -1
- package/dist/MemberPicker/components/Panel.d.ts +2 -0
- package/dist/MemberPicker/components/Panel.js +11 -1
- package/dist/MemberPicker/components/Panel.js.map +1 -1
- package/dist/MemberPicker/components/PanelWrapper.js +2 -0
- package/dist/MemberPicker/components/PanelWrapper.js.map +1 -1
- package/dist/MemberPicker/components/SelectedMemberTags.js +14 -6
- package/dist/MemberPicker/components/SelectedMemberTags.js.map +1 -1
- package/dist/MemberPicker/components/SingleOption.js +12 -0
- package/dist/MemberPicker/components/SingleOption.js.map +1 -1
- package/dist/MemberPicker/components/UserGroupSelection.d.ts +3 -1
- package/dist/MemberPicker/components/UserGroupSelection.js +65 -42
- package/dist/MemberPicker/components/UserGroupSelection.js.map +1 -1
- package/dist/MemberPicker/index.js +134 -108
- package/dist/MemberPicker/index.js.map +1 -1
- package/dist/Menu/index.d.ts +8 -0
- package/dist/Menu/index.js +33 -3
- package/dist/Menu/index.js.map +1 -1
- package/dist/Modal/index.d.ts +4 -0
- package/dist/Modal/index.js +55 -66
- package/dist/Modal/index.js.map +1 -1
- package/dist/OverflowCount/index.js +10 -0
- package/dist/OverflowCount/index.js.map +1 -1
- package/dist/Pagination/index.js +1 -0
- package/dist/Pagination/index.js.map +1 -1
- package/dist/Popconfirm/index.js +9 -1
- package/dist/Popconfirm/index.js.map +1 -1
- package/dist/Popover/index.js +52 -1
- package/dist/Popover/index.js.map +1 -1
- package/dist/Progress/index.js +4 -0
- package/dist/Progress/index.js.map +1 -1
- package/dist/Radio/components/Group/index.d.ts +5 -1
- package/dist/Radio/components/Group/index.js +7 -2
- package/dist/Radio/components/Group/index.js.map +1 -1
- package/dist/Radio/components/Radio/index.js +26 -0
- package/dist/Radio/components/Radio/index.js.map +1 -1
- package/dist/Radio/interface/radio.d.ts +7 -0
- package/dist/Radio/interface/radioGroup.d.ts +2 -0
- package/dist/RenameInput/index.js +11 -0
- package/dist/RenameInput/index.js.map +1 -1
- package/dist/Select/BaseSelect.d.ts +3 -0
- package/dist/Select/BaseSelect.js +229 -32
- package/dist/Select/BaseSelect.js.map +1 -1
- package/dist/Select/SelectTrigger.d.ts +2 -0
- package/dist/Select/SelectTrigger.js +13 -5
- package/dist/Select/SelectTrigger.js.map +1 -1
- package/dist/Select/components/OptionCollection.d.ts +41 -0
- package/dist/Select/components/OptionCollection.js +124 -0
- package/dist/Select/components/OptionCollection.js.map +1 -0
- package/dist/Select/index.js +45 -3
- package/dist/Select/index.js.map +1 -1
- package/dist/Select/interface.d.ts +1 -1
- package/dist/Skeleton/index.js +1 -1
- package/dist/Skeleton/index.js.map +1 -1
- package/dist/Spin/index.d.ts +1 -1
- package/dist/Spin/index.js +22 -7
- package/dist/Spin/index.js.map +1 -1
- package/dist/Switch/index.d.ts +5 -0
- package/dist/Switch/index.js +15 -5
- package/dist/Switch/index.js.map +1 -1
- package/dist/Table/components/Header.js +0 -1
- package/dist/Table/components/Header.js.map +1 -1
- package/dist/Table/index.js +42 -27
- package/dist/Table/index.js.map +1 -1
- package/dist/Tabs/index.js +1 -0
- package/dist/Tabs/index.js.map +1 -1
- package/dist/Tag/index.js +20 -1
- package/dist/Tag/index.js.map +1 -1
- package/dist/Tooltip/index.js +34 -5
- package/dist/Tooltip/index.js.map +1 -1
- package/dist/Tour/index.js +13 -1
- package/dist/Tour/index.js.map +1 -1
- package/dist/Tree/Tree2.js +2 -0
- package/dist/Tree/Tree2.js.map +1 -1
- package/dist/_utils/dialogAccessibility.d.ts +17 -0
- package/dist/_utils/dialogAccessibility.js +110 -0
- package/dist/_utils/dialogAccessibility.js.map +1 -0
- package/dist/_utils/formControlSemanticOwner.d.ts +3 -0
- package/dist/_utils/formControlSemanticOwner.js +17 -0
- package/dist/_utils/formControlSemanticOwner.js.map +1 -0
- package/dist/_utils/overlayCoordinator.js +1 -11
- package/dist/_utils/overlayCoordinator.js.map +1 -1
- package/dist/aloudata-design.css +1 -1
- package/dist/governance/semantic.d.ts +1 -0
- package/dist/governance/semantic.js +2 -0
- package/dist/governance/semantic.json +1737 -0
- package/dist/theme/contract/baselineResolvedTokenValueManifest.d.ts +1 -1
- package/dist/theme/contract/darkResolvedTokenValueManifest.d.ts +1 -1
- package/dist/theme/contract/tokenOutputContract.js +1 -0
- package/dist/theme/contract/tokenOutputContract.js.map +1 -1
- package/dist/theme/generator/acceptedColorValues.d.ts +2 -1
- package/dist/theme/generator/baselineTokenValueDelivery.d.ts +9 -1
- package/dist/theme/generator/minimalAcceptedColorValues.d.ts +2 -2
- package/dist/theme/generator/neutralSourceResolver.d.ts +28 -0
- package/dist/theme/generator/neutralSourceResolver.js +2 -0
- package/dist/theme/generator/neutralSourceValues.d.ts +28 -0
- package/dist/theme/generator/neutralSourceValues.js +2 -0
- package/dist/theme/governance/semanticGovernanceContract.d.ts +91 -0
- package/dist/theme/governance/semanticGovernanceContract.js +342 -0
- package/dist/theme/governance/semanticGovernanceContract.js.map +1 -0
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/index.js +1 -0
- package/dist/theme/neutralSourceContract.d.ts +3 -0
- package/dist/theme/neutralSourceContract.js +11 -0
- package/dist/theme/neutralSourceContract.js.map +1 -0
- package/dist/theme/runtime/colorValueMode/generated/darkBaselineDeclarations.d.ts +1 -1
- package/dist/theme/runtime/colorValueMode/generated/darkBaselineDeclarations.js +46 -45
- package/dist/theme/runtime/colorValueMode/generated/darkBaselineDeclarations.js.map +1 -1
- package/dist/theme/runtime/colorValueMode/generated/slateDarkDeclarations.d.ts +3 -0
- package/dist/theme/runtime/colorValueMode/generated/slateDarkDeclarations.js +2 -0
- package/dist/theme/runtime/colorValueMode/generated/slateLightDeclarations.d.ts +3 -0
- package/dist/theme/runtime/colorValueMode/generated/slateLightDeclarations.js +2 -0
- package/dist/theme/runtime/colorValueMode/generated/stoneDarkDeclarations.d.ts +3 -0
- package/dist/theme/runtime/colorValueMode/generated/stoneDarkDeclarations.js +2 -0
- package/dist/theme/runtime/colorValueMode/generated/stoneLightDeclarations.d.ts +3 -0
- package/dist/theme/runtime/colorValueMode/generated/stoneLightDeclarations.js +2 -0
- package/dist/theme/runtime/colorValueMode/generated/v3BaselineDeclarations.d.ts +1 -1
- package/dist/theme/runtime/colorValueMode/generated/v3BaselineDeclarations.js +42 -41
- package/dist/theme/runtime/colorValueMode/generated/v3BaselineDeclarations.js.map +1 -1
- package/dist/theme/runtime/colorValueMode/index.js +2 -12
- package/dist/theme/runtime/colorValueMode/index.js.map +1 -1
- package/dist/theme/runtime/colorValueMode/legacyNeutralCompatibility.d.ts +2 -0
- package/dist/theme/runtime/colorValueMode/legacyNeutralCompatibility.js +48 -0
- package/dist/theme/runtime/colorValueMode/legacyNeutralCompatibility.js.map +1 -0
- package/dist/theme/runtime/colorValueMode/registry.d.ts +1 -1
- package/dist/theme/runtime/colorValueMode/registry.js +2 -1
- package/dist/theme/runtime/colorValueMode/registry.js.map +1 -1
- package/dist/theme/runtime/initAldTheme.js +1 -3
- package/dist/theme/runtime/initAldTheme.js.map +1 -1
- package/dist/theme/runtime/neutralSource/index.d.ts +6 -0
- package/dist/theme/runtime/neutralSource/index.js +11 -0
- package/dist/theme/runtime/neutralSource/index.js.map +1 -0
- package/dist/theme/runtime/neutralSource.d.ts +2 -0
- package/package.json +12 -2
package/dist/Menu/index.js
CHANGED
|
@@ -2,14 +2,38 @@ import { cn } from "../lib/utils.js";
|
|
|
2
2
|
import Memo from "../Icon/components/CheckLightLine.js";
|
|
3
3
|
import Memo$1 from "../Icon/components/ChevronRightLine.js";
|
|
4
4
|
/* empty css */
|
|
5
|
-
import { useRef } from "react";
|
|
5
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import _ from "lodash";
|
|
8
8
|
import { ControlledMenu, MenuDivider, MenuHeader, MenuItem, SubMenu } from "@szhsin/react-menu";
|
|
9
9
|
//#region src/Menu/index.tsx
|
|
10
10
|
function Menu(props) {
|
|
11
|
-
const { className, items, onClick: onMenuClick, onBeforeLeafItemClick, selectedKeys, menuStyle, rootClosing = false, externalOverflow } = props;
|
|
11
|
+
const { className, items, onClick: onMenuClick, onBeforeLeafItemClick, selectedKeys, menuStyle, ariaLabel, initialFocus = "first", onRequestClose, rootClosing = false, externalOverflow } = props;
|
|
12
12
|
const selectedKeySet = new Set(selectedKeys || []);
|
|
13
|
+
const typeaheadRef = useRef({
|
|
14
|
+
query: "",
|
|
15
|
+
timestamp: 0
|
|
16
|
+
});
|
|
17
|
+
const menuItemFocus = useMemo(() => ({ position: initialFocus }), [initialFocus]);
|
|
18
|
+
const onMenuKeyDown = useCallback((event) => {
|
|
19
|
+
if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.key.length !== 1) return;
|
|
20
|
+
const now = Date.now();
|
|
21
|
+
const previous = typeaheadRef.current;
|
|
22
|
+
const query = `${now - previous.timestamp > 500 ? "" : previous.query}${event.key}`.toLocaleLowerCase();
|
|
23
|
+
typeaheadRef.current = {
|
|
24
|
+
query,
|
|
25
|
+
timestamp: now
|
|
26
|
+
};
|
|
27
|
+
const menuItems = Array.from(event.currentTarget.querySelectorAll("[role=\"menuitem\"]:not([aria-hidden=\"true\"]):not([aria-disabled=\"true\"])"));
|
|
28
|
+
const activeIndex = menuItems.indexOf(document.activeElement);
|
|
29
|
+
const match = [...menuItems.slice(activeIndex + 1), ...menuItems.slice(0, activeIndex + 1)].find((item) => {
|
|
30
|
+
return (item.getAttribute("aria-label") || item.textContent || "").trim().toLocaleLowerCase().startsWith(query);
|
|
31
|
+
});
|
|
32
|
+
if (match) {
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
match.focus();
|
|
35
|
+
}
|
|
36
|
+
}, []);
|
|
13
37
|
const hasDirectSelectedItem = (items) => items.some((item) => {
|
|
14
38
|
if (isSubMenuItem(item)) return selectedKeySet.has(item.key);
|
|
15
39
|
if (isHeaderMenuItem(item) || isDivideMenuItem(item)) return false;
|
|
@@ -46,6 +70,7 @@ function Menu(props) {
|
|
|
46
70
|
]
|
|
47
71
|
}),
|
|
48
72
|
disabled: item.disabled,
|
|
73
|
+
"aria-label": item.ariaLabel || titleStr || void 0,
|
|
49
74
|
itemProps: { className: isLeafSubMenu ? "ald-menu-submenu-leaf-trigger" : void 0 },
|
|
50
75
|
align: "start",
|
|
51
76
|
direction: "right",
|
|
@@ -64,6 +89,7 @@ function Menu(props) {
|
|
|
64
89
|
"ald-menu-item-selected": isSelected
|
|
65
90
|
}),
|
|
66
91
|
disabled: item.disabled,
|
|
92
|
+
"aria-label": item.ariaLabel || titleStr || void 0,
|
|
67
93
|
onClick: ({ syntheticEvent }) => {
|
|
68
94
|
onBeforeLeafItemClick?.();
|
|
69
95
|
const menuInfo = {
|
|
@@ -117,7 +143,11 @@ function Menu(props) {
|
|
|
117
143
|
anchorRef: ref,
|
|
118
144
|
className: cn(className, "ald-menu", isLeafRootMenu && !externalOverflow && "ald-menu-leaf", !isLeafRootMenu && menuStyle?.maxHeight !== void 0 && !externalOverflow && "ald-menu-scrollable"),
|
|
119
145
|
position: externalOverflow ? "initial" : "auto",
|
|
120
|
-
|
|
146
|
+
"aria-label": ariaLabel,
|
|
147
|
+
captureFocus: true,
|
|
148
|
+
menuItemFocus,
|
|
149
|
+
onKeyDown: onMenuKeyDown,
|
|
150
|
+
onClose: ({ reason }) => onRequestClose?.(reason),
|
|
121
151
|
viewScroll: externalOverflow ? "initial" : "auto",
|
|
122
152
|
overflow: externalOverflow ? "visible" : menuOverflow,
|
|
123
153
|
children: getMenuItems(items || [])
|
package/dist/Menu/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/Menu/index.tsx"],"sourcesContent":["import {\n ControlledMenu,\n MenuDivider,\n MenuHeader,\n MenuItem,\n SubMenu,\n} from '@szhsin/react-menu';\nimport { cn } from '../lib/utils';\nimport _ from 'lodash';\nimport React, { useRef } from 'react';\nimport { CheckLightLine, ChevronRightLine } from '../Icon';\nimport './menu.css';\n\nexport interface MenuProps {\n onClick?: (info: MenuInfo) => void;\n onBeforeLeafItemClick?: () => void;\n className?: string;\n items: MenuItemType[];\n selectedKeys?: string[];\n menuStyle?: React.CSSProperties;\n rootClosing?: boolean;\n /** @internal 由 Dropdown 注入,禁用内部定位/overflow 计算。不支持含 SubMenu 的菜单 */\n externalOverflow?: boolean;\n}\n\nexport default function Menu(props: MenuProps) {\n const {\n className,\n items,\n onClick: onMenuClick,\n onBeforeLeafItemClick,\n selectedKeys,\n menuStyle,\n rootClosing = false,\n externalOverflow,\n } = props;\n const selectedKeySet = new Set(selectedKeys || []);\n\n const hasDirectSelectedItem = (items: MenuItemType[]): boolean =>\n items.some((item) => {\n if (isSubMenuItem(item)) {\n return selectedKeySet.has(item.key);\n }\n if (isHeaderMenuItem(item) || isDivideMenuItem(item)) {\n return false;\n }\n return selectedKeySet.has(item.key);\n });\n\n const getMenuItems = (items: MenuItemType[], parentPath: string[] = []) => {\n const isSelectableGroup = hasDirectSelectedItem(items);\n\n return items.map((item, index) => {\n if (isDivideMenuItem(item)) {\n return <MenuDivider key={`divider_${index}`} />;\n }\n if (isHeaderMenuItem(item)) {\n return <MenuHeader key={`header_${index}`}>{item.label}</MenuHeader>;\n }\n const currPath = [...parentPath, item.key];\n const titleStr = _.isString(item.label) ? item.label : '';\n const isSelected = selectedKeys?.includes(item.key);\n\n if (isSubMenuItem(item)) {\n const isLeafSubMenu = isLeafMenu(item.children);\n const subMenuOverflow =\n isLeafSubMenu || menuStyle?.maxHeight !== undefined\n ? 'auto'\n : undefined;\n const subMenuItemLabel = (\n <div className=\"ald-menu-item-label\" title={titleStr}>\n {item.icon ? (\n <div className=\"ald-menu-item-label-icon\">{item.icon}</div>\n ) : null}\n <div className=\"ald-menu-item-label-text tw-text-typography-body-dense\">\n {item.label}\n </div>\n <div className=\"ald-menu-item-right\">\n {isSelectableGroup ? (\n <div className=\"ald-menu-item-selection-slot\" />\n ) : null}\n <ChevronRightLine size={16} />\n </div>\n </div>\n );\n\n return (\n <SubMenu\n key={item.key}\n label={subMenuItemLabel}\n disabled={item.disabled}\n itemProps={{\n className: isLeafSubMenu\n ? 'ald-menu-submenu-leaf-trigger'\n : undefined,\n }}\n align=\"start\"\n direction=\"right\"\n gap={-8}\n position=\"anchor\"\n shift={0}\n menuStyle={{\n ...menuStyle,\n }}\n menuClassName={cn(\n 'ald-menu-submenu-popup',\n isLeafSubMenu && 'ald-menu-submenu-popup-leaf',\n !isLeafSubMenu &&\n menuStyle?.maxHeight !== undefined &&\n 'ald-menu-submenu-popup-scrollable',\n item.popupClassName,\n rootClosing && 'ald-menu-submenu-popup-root-closing',\n )}\n overflow={subMenuOverflow}\n >\n {getMenuItems(item.children, currPath)}\n </SubMenu>\n );\n }\n\n return (\n <MenuItem\n key={item.key}\n className={cn(item.className, {\n 'ald-menu-item-danger': item.danger,\n 'ald-menu-item-selected': isSelected,\n })}\n disabled={item.disabled}\n onClick={({ syntheticEvent }) => {\n onBeforeLeafItemClick?.();\n const menuInfo = {\n key: item.key,\n keyPath: currPath,\n domEvent: syntheticEvent,\n };\n if (item.onClick) {\n item.onClick(menuInfo);\n }\n if (onMenuClick) {\n onMenuClick(menuInfo);\n }\n }}\n >\n <div className=\"ald-menu-item-label\" title={titleStr}>\n {item.icon ? (\n <div className=\"ald-menu-item-label-icon\">{item.icon}</div>\n ) : null}\n <div className=\"ald-menu-item-label-text tw-text-typography-body-dense\">\n {item.label}\n </div>\n {isSelectableGroup ? (\n <div className=\"ald-menu-item-right\">\n <div\n className={cn(\n 'ald-menu-item-selection-slot',\n isSelected &&\n 'ald-menu-item-selection-slot-selected ald-menu-item-selected-icon',\n )}\n >\n {isSelected ? <CheckLightLine /> : null}\n </div>\n </div>\n ) : null}\n </div>\n </MenuItem>\n );\n });\n };\n\n const ref = useRef(null);\n\n const isLeafRootMenu = isLeafMenu(items);\n const menuOverflow =\n isLeafRootMenu || menuStyle?.maxHeight !== undefined ? 'auto' : undefined;\n\n return (\n <>\n <div style={{ display: 'none' }} ref={ref} />\n <ControlledMenu\n state=\"open\"\n transition={{ open: true, close: true }}\n transitionTimeout={200}\n submenuOpenDelay={0}\n submenuCloseDelay={0}\n menuStyle={{\n ...menuStyle,\n }}\n anchorRef={ref}\n className={cn(\n className,\n 'ald-menu',\n isLeafRootMenu && !externalOverflow && 'ald-menu-leaf',\n !isLeafRootMenu &&\n menuStyle?.maxHeight !== undefined &&\n !externalOverflow &&\n 'ald-menu-scrollable',\n )}\n position={externalOverflow ? 'initial' : 'auto'}\n captureFocus={false}\n viewScroll={externalOverflow ? 'initial' : 'auto'}\n overflow={externalOverflow ? 'visible' : menuOverflow}\n >\n {getMenuItems(items || [])}\n </ControlledMenu>\n </>\n );\n}\n\nexport function isHeaderMenuItem(\n menuItem: MenuItemType,\n): menuItem is MenuHeaderType {\n return 'type' in menuItem && menuItem.type === 'header';\n}\n\nexport function isDivideMenuItem(\n menuItem: MenuItemType,\n): menuItem is MenuDividerType {\n return 'type' in menuItem && menuItem.type === 'divider';\n}\n\nexport function isSubMenuItem(menuItem: MenuItemType): menuItem is SubMenuType {\n return 'children' in menuItem && !!menuItem.children;\n}\n\nexport function isLeafMenu(menuItems: MenuItemType[]) {\n return !_.some(menuItems, (item) => isSubMenuItem(item));\n}\n\nexport type MenuItemType =\n | ItemType\n | MenuDividerType\n | SubMenuType\n | MenuHeaderType;\n\nexport interface ItemType {\n key: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n onClick?: (info: MenuInfo) => void;\n danger?: boolean;\n disabled?: boolean;\n className?: string;\n}\n\nexport interface MenuDividerType {\n key?: string;\n type: 'divider';\n}\n\nexport interface MenuHeaderType {\n key?: string;\n type: 'header';\n label: string;\n}\n\nexport interface SubMenuType {\n children: MenuItemType[];\n key: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n popupClassName?: string;\n disabled?: boolean;\n}\n\nexport interface MenuInfo {\n key: string;\n keyPath: string[];\n domEvent: MouseEvent | KeyboardEvent;\n // 阻止菜单关闭\n keepOpen?: boolean;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/Menu/index.tsx"],"sourcesContent":["import {\n ControlledMenu,\n MenuDivider,\n MenuHeader,\n MenuItem,\n SubMenu,\n} from '@szhsin/react-menu';\nimport { cn } from '../lib/utils';\nimport _ from 'lodash';\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { CheckLightLine, ChevronRightLine } from '../Icon';\nimport './menu.css';\n\nexport interface MenuProps {\n onClick?: (info: MenuInfo) => void;\n onBeforeLeafItemClick?: () => void;\n className?: string;\n items: MenuItemType[];\n selectedKeys?: string[];\n menuStyle?: React.CSSProperties;\n /** Accessible name for the command menu when its context is not otherwise clear. */\n ariaLabel?: string;\n /** @internal Requested initial keyboard position when the popup opens. */\n initialFocus?: 'first' | 'last';\n /** @internal Requests that the owning popup close, including on Escape. */\n onRequestClose?: (reason: 'click' | 'cancel' | 'blur' | 'scroll') => void;\n rootClosing?: boolean;\n /** @internal 由 Dropdown 注入,禁用内部定位/overflow 计算。不支持含 SubMenu 的菜单 */\n externalOverflow?: boolean;\n}\n\nexport default function Menu(props: MenuProps) {\n const {\n className,\n items,\n onClick: onMenuClick,\n onBeforeLeafItemClick,\n selectedKeys,\n menuStyle,\n ariaLabel,\n initialFocus = 'first',\n onRequestClose,\n rootClosing = false,\n externalOverflow,\n } = props;\n const selectedKeySet = new Set(selectedKeys || []);\n const typeaheadRef = useRef({ query: '', timestamp: 0 });\n const menuItemFocus = useMemo(\n () => ({ position: initialFocus }),\n [initialFocus],\n );\n const onMenuKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLUListElement>) => {\n if (\n event.defaultPrevented ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n event.key.length !== 1\n ) {\n return;\n }\n\n const now = Date.now();\n const previous = typeaheadRef.current;\n const query = `${now - previous.timestamp > 500 ? '' : previous.query}${\n event.key\n }`.toLocaleLowerCase();\n typeaheadRef.current = { query, timestamp: now };\n\n const menuItems = Array.from(\n event.currentTarget.querySelectorAll<HTMLElement>(\n '[role=\"menuitem\"]:not([aria-hidden=\"true\"]):not([aria-disabled=\"true\"])',\n ),\n );\n const activeIndex = menuItems.indexOf(\n document.activeElement as HTMLElement,\n );\n const orderedItems = [\n ...menuItems.slice(activeIndex + 1),\n ...menuItems.slice(0, activeIndex + 1),\n ];\n const match = orderedItems.find((item) => {\n const accessibleName =\n item.getAttribute('aria-label') || item.textContent || '';\n return accessibleName.trim().toLocaleLowerCase().startsWith(query);\n });\n\n if (match) {\n event.preventDefault();\n match.focus();\n }\n },\n [],\n );\n\n const hasDirectSelectedItem = (items: MenuItemType[]): boolean =>\n items.some((item) => {\n if (isSubMenuItem(item)) {\n return selectedKeySet.has(item.key);\n }\n if (isHeaderMenuItem(item) || isDivideMenuItem(item)) {\n return false;\n }\n return selectedKeySet.has(item.key);\n });\n\n const getMenuItems = (items: MenuItemType[], parentPath: string[] = []) => {\n const isSelectableGroup = hasDirectSelectedItem(items);\n\n return items.map((item, index) => {\n if (isDivideMenuItem(item)) {\n return <MenuDivider key={`divider_${index}`} />;\n }\n if (isHeaderMenuItem(item)) {\n return <MenuHeader key={`header_${index}`}>{item.label}</MenuHeader>;\n }\n const currPath = [...parentPath, item.key];\n const titleStr = _.isString(item.label) ? item.label : '';\n const isSelected = selectedKeys?.includes(item.key);\n\n if (isSubMenuItem(item)) {\n const isLeafSubMenu = isLeafMenu(item.children);\n const subMenuOverflow =\n isLeafSubMenu || menuStyle?.maxHeight !== undefined\n ? 'auto'\n : undefined;\n const subMenuItemLabel = (\n <div className=\"ald-menu-item-label\" title={titleStr}>\n {item.icon ? (\n <div className=\"ald-menu-item-label-icon\">{item.icon}</div>\n ) : null}\n <div className=\"ald-menu-item-label-text tw-text-typography-body-dense\">\n {item.label}\n </div>\n <div className=\"ald-menu-item-right\">\n {isSelectableGroup ? (\n <div className=\"ald-menu-item-selection-slot\" />\n ) : null}\n <ChevronRightLine size={16} />\n </div>\n </div>\n );\n\n return (\n <SubMenu\n key={item.key}\n label={subMenuItemLabel}\n disabled={item.disabled}\n aria-label={item.ariaLabel || titleStr || undefined}\n itemProps={{\n className: isLeafSubMenu\n ? 'ald-menu-submenu-leaf-trigger'\n : undefined,\n }}\n align=\"start\"\n direction=\"right\"\n gap={-8}\n position=\"anchor\"\n shift={0}\n menuStyle={{\n ...menuStyle,\n }}\n menuClassName={cn(\n 'ald-menu-submenu-popup',\n isLeafSubMenu && 'ald-menu-submenu-popup-leaf',\n !isLeafSubMenu &&\n menuStyle?.maxHeight !== undefined &&\n 'ald-menu-submenu-popup-scrollable',\n item.popupClassName,\n rootClosing && 'ald-menu-submenu-popup-root-closing',\n )}\n overflow={subMenuOverflow}\n >\n {getMenuItems(item.children, currPath)}\n </SubMenu>\n );\n }\n\n return (\n <MenuItem\n key={item.key}\n className={cn(item.className, {\n 'ald-menu-item-danger': item.danger,\n 'ald-menu-item-selected': isSelected,\n })}\n disabled={item.disabled}\n aria-label={item.ariaLabel || titleStr || undefined}\n onClick={({ syntheticEvent }) => {\n onBeforeLeafItemClick?.();\n const menuInfo = {\n key: item.key,\n keyPath: currPath,\n domEvent: syntheticEvent,\n };\n if (item.onClick) {\n item.onClick(menuInfo);\n }\n if (onMenuClick) {\n onMenuClick(menuInfo);\n }\n }}\n >\n <div className=\"ald-menu-item-label\" title={titleStr}>\n {item.icon ? (\n <div className=\"ald-menu-item-label-icon\">{item.icon}</div>\n ) : null}\n <div className=\"ald-menu-item-label-text tw-text-typography-body-dense\">\n {item.label}\n </div>\n {isSelectableGroup ? (\n <div className=\"ald-menu-item-right\">\n <div\n className={cn(\n 'ald-menu-item-selection-slot',\n isSelected &&\n 'ald-menu-item-selection-slot-selected ald-menu-item-selected-icon',\n )}\n >\n {isSelected ? <CheckLightLine /> : null}\n </div>\n </div>\n ) : null}\n </div>\n </MenuItem>\n );\n });\n };\n\n const ref = useRef(null);\n\n const isLeafRootMenu = isLeafMenu(items);\n const menuOverflow =\n isLeafRootMenu || menuStyle?.maxHeight !== undefined ? 'auto' : undefined;\n\n return (\n <>\n <div style={{ display: 'none' }} ref={ref} />\n <ControlledMenu\n state=\"open\"\n transition={{ open: true, close: true }}\n transitionTimeout={200}\n submenuOpenDelay={0}\n submenuCloseDelay={0}\n menuStyle={{\n ...menuStyle,\n }}\n anchorRef={ref}\n className={cn(\n className,\n 'ald-menu',\n isLeafRootMenu && !externalOverflow && 'ald-menu-leaf',\n !isLeafRootMenu &&\n menuStyle?.maxHeight !== undefined &&\n !externalOverflow &&\n 'ald-menu-scrollable',\n )}\n position={externalOverflow ? 'initial' : 'auto'}\n aria-label={ariaLabel}\n captureFocus\n menuItemFocus={menuItemFocus}\n onKeyDown={onMenuKeyDown}\n onClose={({ reason }) => onRequestClose?.(reason)}\n viewScroll={externalOverflow ? 'initial' : 'auto'}\n overflow={externalOverflow ? 'visible' : menuOverflow}\n >\n {getMenuItems(items || [])}\n </ControlledMenu>\n </>\n );\n}\n\nexport function isHeaderMenuItem(\n menuItem: MenuItemType,\n): menuItem is MenuHeaderType {\n return 'type' in menuItem && menuItem.type === 'header';\n}\n\nexport function isDivideMenuItem(\n menuItem: MenuItemType,\n): menuItem is MenuDividerType {\n return 'type' in menuItem && menuItem.type === 'divider';\n}\n\nexport function isSubMenuItem(menuItem: MenuItemType): menuItem is SubMenuType {\n return 'children' in menuItem && !!menuItem.children;\n}\n\nexport function isLeafMenu(menuItems: MenuItemType[]) {\n return !_.some(menuItems, (item) => isSubMenuItem(item));\n}\n\nexport type MenuItemType =\n | ItemType\n | MenuDividerType\n | SubMenuType\n | MenuHeaderType;\n\nexport interface ItemType {\n key: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n onClick?: (info: MenuInfo) => void;\n danger?: boolean;\n disabled?: boolean;\n className?: string;\n ariaLabel?: string;\n}\n\nexport interface MenuDividerType {\n key?: string;\n type: 'divider';\n}\n\nexport interface MenuHeaderType {\n key?: string;\n type: 'header';\n label: string;\n}\n\nexport interface SubMenuType {\n children: MenuItemType[];\n key: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n popupClassName?: string;\n disabled?: boolean;\n ariaLabel?: string;\n}\n\nexport interface MenuInfo {\n key: string;\n keyPath: string[];\n domEvent: MouseEvent | KeyboardEvent;\n // 阻止菜单关闭\n keepOpen?: boolean;\n}\n"],"mappings":"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"}
|
package/dist/Modal/index.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ export interface ModalProps {
|
|
|
27
27
|
'data-testid'?: string;
|
|
28
28
|
/** Pass through to the modal content root for accessibility and automated testing. */
|
|
29
29
|
'aria-label'?: string;
|
|
30
|
+
/** Dialog semantic role. Use alertdialog only for explicitly urgent confirmation flows. */
|
|
31
|
+
role?: 'dialog' | 'alertdialog';
|
|
30
32
|
/** Applied to the outer wrap layer (matches antd wrapClassName behavior) */
|
|
31
33
|
wrapClassName?: string;
|
|
32
34
|
style?: React.CSSProperties;
|
|
@@ -67,6 +69,8 @@ export interface ModalFuncProps {
|
|
|
67
69
|
type?: 'info' | 'success' | 'error' | 'warn' | 'warning' | 'confirm';
|
|
68
70
|
centered?: boolean;
|
|
69
71
|
maskClosable?: boolean;
|
|
72
|
+
/** Dialog semantic role. Use alertdialog only for explicitly urgent confirmation flows. */
|
|
73
|
+
role?: 'dialog' | 'alertdialog';
|
|
70
74
|
}
|
|
71
75
|
declare function OriginModal(props: OriginModalProps): import("react/jsx-runtime").JSX.Element;
|
|
72
76
|
type ModalFunc = (props: ModalFuncProps) => {
|
package/dist/Modal/index.js
CHANGED
|
@@ -7,9 +7,10 @@ import { FLOATING_LAYER_BASE_Z_INDEX, FloatingLayerProvider } from "../_utils/fl
|
|
|
7
7
|
import { ModalLayerProvider, useModalLayer } from "../_utils/overlayCoordinator.js";
|
|
8
8
|
import Button_default from "../Button/index.js";
|
|
9
9
|
import { LocaleContext, getTranslator } from "../locale/default.js";
|
|
10
|
-
|
|
10
|
+
/* empty css */
|
|
11
11
|
import ScrollArea_default from "../ScrollArea/index.js";
|
|
12
|
-
import {
|
|
12
|
+
import { focusInitialDialogTarget, markDialogEscapeEvent, restoreDialogFocus, useDialogAccessibility } from "../_utils/dialogAccessibility.js";
|
|
13
|
+
import React, { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
13
14
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
15
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
15
16
|
import { hideOthers } from "aria-hidden";
|
|
@@ -17,10 +18,6 @@ import { createRoot } from "react-dom/client";
|
|
|
17
18
|
//#region src/Modal/index.tsx
|
|
18
19
|
var destroyFns = [];
|
|
19
20
|
var DEFAULT_WIDTH = 552;
|
|
20
|
-
var modalEscapeEvents = /* @__PURE__ */ new WeakSet();
|
|
21
|
-
function shouldCancelTopModal(event) {
|
|
22
|
-
return !event.cancelBubble && (!event.defaultPrevented || modalEscapeEvents.has(event));
|
|
23
|
-
}
|
|
24
21
|
function ModalContentProviders({ layerId, floatingLevel, children }) {
|
|
25
22
|
return /* @__PURE__ */ jsx(ModalLayerProvider, {
|
|
26
23
|
id: layerId,
|
|
@@ -30,7 +27,7 @@ function ModalContentProviders({ layerId, floatingLevel, children }) {
|
|
|
30
27
|
})
|
|
31
28
|
});
|
|
32
29
|
}
|
|
33
|
-
var ModalTitle = ({ icon, title, subTitle }, type) => /* @__PURE__ */ jsxs("div", {
|
|
30
|
+
var ModalTitle = ({ icon, title, subTitle, titleId, descriptionId }, type) => /* @__PURE__ */ jsxs("div", {
|
|
34
31
|
className: "ald-modal-title-container tw-flex tw-items-center tw-gap-4",
|
|
35
32
|
children: [icon && /* @__PURE__ */ jsx("div", {
|
|
36
33
|
className: cn("ald-modal-icon-container tw-grid tw-size-10 tw-shrink-0 tw-place-items-center tw-rounded-[var(--global-grid-250)]", type === "info" && "ald-modal-cion-info-container tw-bg-[var(--background-informative-muted)]", type === "success" && "ald-modal-cion-success-container tw-bg-[var(--background-positive-muted)]", type === "warning" && "ald-modal-cion-warning-container tw-bg-[var(--background-warning-muted)]", type === "warn" && "ald-modal-cion-warning-container tw-bg-[var(--background-warning-muted)]", type === "error" && "ald-modal-cion-error-container tw-bg-[var(--background-negative-muted)]", type === "confirm" && "ald-modal-cion-confirm-container tw-bg-[var(--background-brand-muted)]"),
|
|
@@ -38,9 +35,11 @@ var ModalTitle = ({ icon, title, subTitle }, type) => /* @__PURE__ */ jsxs("div"
|
|
|
38
35
|
}), /* @__PURE__ */ jsxs("div", {
|
|
39
36
|
className: "ald-modal-text-container",
|
|
40
37
|
children: [title && /* @__PURE__ */ jsx("div", {
|
|
38
|
+
id: titleId,
|
|
41
39
|
className: cn("ald-modal-text-title tw-text-lg tw-font-semibold tw-leading-7 tw-text-[var(--content-primary)]", !subTitle && "ald-modal-text-title-only tw-text-xl"),
|
|
42
40
|
children: title
|
|
43
41
|
}), subTitle && /* @__PURE__ */ jsx("div", {
|
|
42
|
+
id: descriptionId,
|
|
44
43
|
className: "ald-modal-text-sub-title tw-mt-1 tw-text-xs tw-leading-4 tw-text-[var(--content-secondary)]",
|
|
45
44
|
children: subTitle
|
|
46
45
|
})]
|
|
@@ -69,12 +68,22 @@ function getIcon(type) {
|
|
|
69
68
|
function OriginModal(props) {
|
|
70
69
|
const { locale } = useContext(LocaleContext);
|
|
71
70
|
const t = getTranslator(locale);
|
|
72
|
-
const { className, "data-testid": dataTestId, "aria-label": ariaLabel, children, okType = "primary", width, closeIcon, subTitle, okButtonProps = {}, cancelButtonProps = {}, okText = t.Modal.sure, cancelText = t.Modal.cancel, icon, title, paddingLess, responsiveBounds, hideHeaderBottomBorder, virtualScrollBar, style, maskClosable = false, fullscreen, open = false, onOk, onCancel, footer, confirmLoading, closable = true, zIndex = 1e3, bodyStyle, keyboard = true, afterOpenChange, wrapClassName, _modalType, onTopChange } = props;
|
|
71
|
+
const { className, "data-testid": dataTestId, "aria-label": ariaLabel, role = "dialog", children, okType = "primary", width, closeIcon, subTitle, okButtonProps = {}, cancelButtonProps = {}, okText = t.Modal.sure, cancelText = t.Modal.cancel, icon, title, paddingLess, responsiveBounds, hideHeaderBottomBorder, virtualScrollBar, style, maskClosable = false, fullscreen, open = false, onOk, onCancel, footer, confirmLoading, closable = true, zIndex = 1e3, bodyStyle, keyboard = true, afterOpenChange, wrapClassName, _modalType, onTopChange } = props;
|
|
73
72
|
const prevOpenRef = useRef(open);
|
|
74
73
|
const contentRef = useRef(null);
|
|
75
74
|
const modalRef = useRef(null);
|
|
75
|
+
const generatedId = React.useId();
|
|
76
|
+
const titleId = `${generatedId}-title`;
|
|
77
|
+
const descriptionId = `${generatedId}-description`;
|
|
76
78
|
const { id: modalLayerId, maskZIndex, contentZIndex, isTop } = useModalLayer(open, zIndex);
|
|
77
79
|
const nextFloatingLevel = (maskZIndex - FLOATING_LAYER_BASE_Z_INDEX) / 10 + 1;
|
|
80
|
+
useDialogAccessibility({
|
|
81
|
+
open,
|
|
82
|
+
isTop,
|
|
83
|
+
keyboard,
|
|
84
|
+
containerRef: modalRef,
|
|
85
|
+
onEscape: () => onCancel?.({})
|
|
86
|
+
});
|
|
78
87
|
useLayoutEffect(() => {
|
|
79
88
|
onTopChange?.(isTop);
|
|
80
89
|
}, [isTop, onTopChange]);
|
|
@@ -88,44 +97,6 @@ function OriginModal(props) {
|
|
|
88
97
|
if (!open || !isTop || !contentRef.current) return;
|
|
89
98
|
return hideOthers(contentRef.current);
|
|
90
99
|
}, [isTop, open]);
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
if (!open || !isTop || !contentRef.current) return;
|
|
93
|
-
const container = contentRef.current;
|
|
94
|
-
const handleKeyDown = (e) => {
|
|
95
|
-
if (e.key !== "Tab") return;
|
|
96
|
-
const focusable = container.querySelectorAll("a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]):not([disabled])");
|
|
97
|
-
if (focusable.length === 0) return;
|
|
98
|
-
const first = focusable[0];
|
|
99
|
-
const last = focusable[focusable.length - 1];
|
|
100
|
-
if (e.shiftKey) {
|
|
101
|
-
if (document.activeElement === first || !container.contains(document.activeElement)) {
|
|
102
|
-
e.preventDefault();
|
|
103
|
-
last.focus();
|
|
104
|
-
}
|
|
105
|
-
} else if (document.activeElement === last || !container.contains(document.activeElement)) {
|
|
106
|
-
e.preventDefault();
|
|
107
|
-
first.focus();
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
111
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
112
|
-
}, [isTop, open]);
|
|
113
|
-
useEffect(() => {
|
|
114
|
-
if (!open || !isTop || !keyboard) return;
|
|
115
|
-
const handleEscape = (event) => {
|
|
116
|
-
if (event.key !== "Escape") return;
|
|
117
|
-
queueMicrotask(() => {
|
|
118
|
-
if (shouldCancelTopModal(event)) onCancel?.({});
|
|
119
|
-
});
|
|
120
|
-
};
|
|
121
|
-
window.addEventListener("keydown", handleEscape, true);
|
|
122
|
-
return () => window.removeEventListener("keydown", handleEscape, true);
|
|
123
|
-
}, [
|
|
124
|
-
isTop,
|
|
125
|
-
keyboard,
|
|
126
|
-
onCancel,
|
|
127
|
-
open
|
|
128
|
-
]);
|
|
129
100
|
const responsiveBoundsStyle = useMemo(() => {
|
|
130
101
|
if (!responsiveBounds) return {};
|
|
131
102
|
return {
|
|
@@ -141,14 +112,16 @@ function OriginModal(props) {
|
|
|
141
112
|
loading: confirmLoading,
|
|
142
113
|
...okButtonProps
|
|
143
114
|
};
|
|
115
|
+
const headerBorderClassName = hideHeaderBottomBorder ? "!tw-border-0" : "tw-border-b tw-border-solid tw-border-[var(--border-default)] !tw-border-x-0 !tw-border-t-0";
|
|
144
116
|
const renderFooter = () => {
|
|
145
117
|
if (footer === null) return null;
|
|
118
|
+
const footerBorderClassName = "tw-border-t tw-border-solid tw-border-[var(--border-default)] !tw-border-x-0 !tw-border-b-0";
|
|
146
119
|
if (footer) return /* @__PURE__ */ jsx("div", {
|
|
147
|
-
className: "ald-modal-footer ant-modal-footer tw-flex tw-items-center tw-justify-end tw-gap-2 tw-
|
|
120
|
+
className: cn("ald-modal-footer ant-modal-footer tw-flex tw-items-center tw-justify-end tw-gap-2 tw-bg-[var(--background-default)] tw-px-6 tw-py-3 tw-text-right", footerBorderClassName),
|
|
148
121
|
children: footer
|
|
149
122
|
});
|
|
150
123
|
return /* @__PURE__ */ jsxs("div", {
|
|
151
|
-
className: "ald-modal-footer ant-modal-footer tw-flex tw-justify-end tw-gap-2 tw-
|
|
124
|
+
className: cn("ald-modal-footer ant-modal-footer tw-flex tw-justify-end tw-gap-2 tw-px-6 tw-py-4", footerBorderClassName),
|
|
152
125
|
children: [/* @__PURE__ */ jsx(Button_default, {
|
|
153
126
|
type: "secondary",
|
|
154
127
|
size: "middle",
|
|
@@ -182,9 +155,13 @@ function OriginModal(props) {
|
|
|
182
155
|
children: /* @__PURE__ */ jsx(DialogPrimitive.Content, {
|
|
183
156
|
ref: modalRef,
|
|
184
157
|
tabIndex: -1,
|
|
158
|
+
role,
|
|
185
159
|
"data-testid": dataTestId,
|
|
160
|
+
"aria-modal": isTop || void 0,
|
|
161
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
162
|
+
"aria-describedby": subTitle ? descriptionId : void 0,
|
|
186
163
|
"aria-label": ariaLabel,
|
|
187
|
-
className: cn("ald-modal ant-modal tw-pointer-events-auto tw-box-border tw-flex tw-flex-col tw-overflow-hidden tw-bg-[var(--background-default)] tw-shadow-
|
|
164
|
+
className: cn("ald-modal ant-modal tw-pointer-events-auto tw-box-border tw-flex tw-flex-col tw-overflow-hidden tw-border-0 tw-bg-[var(--background-default)] tw-shadow-none tw-outline-none", fullscreen ? "ald-modal-fullscreen tw-fixed tw-inset-0 tw-size-full tw-rounded-none" : "tw-rounded-r-75", paddingLess && "ald-modal-padding-less", virtualScrollBar && "ald-modal-virtual-scroll-bar", hideHeaderBottomBorder && "ald-modal-hide-header-bottom-border", responsiveBounds && "ald-modal-responsive-bounds", className),
|
|
188
165
|
style: {
|
|
189
166
|
...fullscreen ? {} : {
|
|
190
167
|
width: responsiveBounds ? responsiveBoundsStyle.width : width || DEFAULT_WIDTH,
|
|
@@ -196,14 +173,11 @@ function OriginModal(props) {
|
|
|
196
173
|
event.preventDefault();
|
|
197
174
|
requestAnimationFrame(() => {
|
|
198
175
|
const modal = modalRef.current;
|
|
199
|
-
|
|
200
|
-
const activeOverlay = activeElement instanceof HTMLElement ? activeElement.closest("[role=\"dialog\"], [role=\"menu\"], [role=\"listbox\"]") : null;
|
|
201
|
-
if (!modal || activeOverlay && !activeOverlay.classList.contains("ald-modal") && activeOverlay !== modal && !modal.contains(activeOverlay)) return;
|
|
202
|
-
modal.focus({ preventScroll: true });
|
|
176
|
+
if (modal) focusInitialDialogTarget(modal);
|
|
203
177
|
});
|
|
204
178
|
},
|
|
205
179
|
onEscapeKeyDown: (event) => {
|
|
206
|
-
if (!event.defaultPrevented)
|
|
180
|
+
if (!event.defaultPrevented) markDialogEscapeEvent(event);
|
|
207
181
|
event.preventDefault();
|
|
208
182
|
},
|
|
209
183
|
onPointerDownOutside: (e) => {
|
|
@@ -214,13 +188,13 @@ function OriginModal(props) {
|
|
|
214
188
|
if (!maskClosable) e.preventDefault();
|
|
215
189
|
},
|
|
216
190
|
children: /* @__PURE__ */ jsx("div", {
|
|
217
|
-
className: "ant-modal-content tw-flex tw-h-full tw-flex-col",
|
|
191
|
+
className: "ant-modal-content tw-flex tw-h-full tw-flex-col !tw-rounded-none !tw-border-0 !tw-bg-transparent !tw-p-0 !tw-shadow-none",
|
|
218
192
|
children: /* @__PURE__ */ jsxs(ModalContentProviders, {
|
|
219
193
|
layerId: modalLayerId,
|
|
220
194
|
floatingLevel: nextFloatingLevel,
|
|
221
195
|
children: [
|
|
222
196
|
!fullscreen && /* @__PURE__ */ jsxs("div", {
|
|
223
|
-
className: cn("ald-modal-header ant-modal-header tw-flex tw-items-start tw-justify-between tw-bg-[var(--background-default)] tw-px-6 tw-py-4",
|
|
197
|
+
className: cn("ald-modal-header ant-modal-header tw-flex tw-items-start tw-justify-between tw-bg-[var(--background-default)] tw-px-6 tw-py-4", headerBorderClassName),
|
|
224
198
|
children: [/* @__PURE__ */ jsx(DialogPrimitive.Title, {
|
|
225
199
|
asChild: true,
|
|
226
200
|
children: /* @__PURE__ */ jsx("div", {
|
|
@@ -228,24 +202,39 @@ function OriginModal(props) {
|
|
|
228
202
|
children: ModalTitle({
|
|
229
203
|
icon,
|
|
230
204
|
title,
|
|
231
|
-
subTitle
|
|
205
|
+
subTitle,
|
|
206
|
+
titleId,
|
|
207
|
+
descriptionId
|
|
232
208
|
}, _modalType)
|
|
233
209
|
})
|
|
234
210
|
}), closable && /* @__PURE__ */ jsx(DialogPrimitive.Close, {
|
|
235
211
|
asChild: true,
|
|
236
|
-
children: /* @__PURE__ */ jsx("
|
|
237
|
-
|
|
212
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
213
|
+
type: "button",
|
|
214
|
+
className: "ant-modal-close ald-icon-button ald-icon-button-middle focus-visible:tw-outline focus-visible:tw-outline-2 focus-visible:tw-outline-offset-2 focus-visible:tw-outline-[var(--focus-ring)] forced-colors:focus-visible:tw-outline-[Highlight]",
|
|
215
|
+
"aria-label": "Close",
|
|
216
|
+
"data-overlay-close": "true",
|
|
238
217
|
onClick: onCancel,
|
|
239
|
-
children:
|
|
240
|
-
|
|
241
|
-
size:
|
|
218
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
219
|
+
className: "ald-icon-button-wrap",
|
|
220
|
+
children: closeIcon || /* @__PURE__ */ jsx(Memo$2, { size: 20 })
|
|
242
221
|
})
|
|
243
222
|
})
|
|
244
223
|
})]
|
|
245
224
|
}),
|
|
246
225
|
fullscreen && /* @__PURE__ */ jsx(DialogPrimitive.Title, {
|
|
226
|
+
asChild: true,
|
|
227
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
228
|
+
className: "tw-sr-only",
|
|
229
|
+
children: title && /* @__PURE__ */ jsx("span", {
|
|
230
|
+
id: titleId,
|
|
231
|
+
children: title
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
}),
|
|
235
|
+
subTitle && /* @__PURE__ */ jsx(DialogPrimitive.Description, {
|
|
247
236
|
className: "tw-sr-only",
|
|
248
|
-
children:
|
|
237
|
+
children: subTitle
|
|
249
238
|
}),
|
|
250
239
|
/* @__PURE__ */ jsx("div", {
|
|
251
240
|
className: cn("ald-modal-body ant-modal-body tw-flex-1 tw-text-sm tw-leading-5", fullscreen ? "tw-h-full tw-overflow-auto tw-p-0" : "tw-min-h-[130px]", !fullscreen && (virtualScrollBar ? "tw-overflow-hidden tw-p-0" : "tw-overflow-auto"), !fullscreen && !responsiveBounds && !virtualScrollBar && "tw-max-h-[68vh]", !fullscreen && !paddingLess && !virtualScrollBar && "tw-p-6"),
|
|
@@ -280,9 +269,7 @@ function createStaticModal(type, props) {
|
|
|
280
269
|
container.remove();
|
|
281
270
|
const idx = destroyFns.indexOf(destroy);
|
|
282
271
|
if (idx >= 0) destroyFns.splice(idx, 1);
|
|
283
|
-
|
|
284
|
-
if (shouldRestoreFocus && focusTarget?.isConnected) focusTarget.focus();
|
|
285
|
-
});
|
|
272
|
+
if (shouldRestoreFocus) restoreDialogFocus(focusTarget);
|
|
286
273
|
};
|
|
287
274
|
const update = (newProps) => {
|
|
288
275
|
currentProps = {
|
|
@@ -317,6 +304,7 @@ function createStaticModal(type, props) {
|
|
|
317
304
|
className: cn("ald-modal", p.className),
|
|
318
305
|
closable: p.closable,
|
|
319
306
|
maskClosable: p.maskClosable,
|
|
307
|
+
role: p.role,
|
|
320
308
|
_modalType: type,
|
|
321
309
|
onTopChange: (nextIsTop) => {
|
|
322
310
|
isTop = nextIsTop;
|
|
@@ -408,6 +396,7 @@ function useModal() {
|
|
|
408
396
|
className: cn("ald-modal", m.props.className),
|
|
409
397
|
closable: m.props.closable,
|
|
410
398
|
maskClosable: m.props.maskClosable,
|
|
399
|
+
role: m.props.role,
|
|
411
400
|
_modalType: m.type,
|
|
412
401
|
footer: isConfirmType ? void 0 : /* @__PURE__ */ jsx(Button_default, {
|
|
413
402
|
type: "primary",
|
package/dist/Modal/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/Modal/index.tsx"],"sourcesContent":["import * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { hideOthers } from 'aria-hidden';\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { createRoot } from 'react-dom/client';\nimport Button, { ButtonType, IButtonProps } from '../Button';\nimport {\n AttentionTriangleLightLine,\n CheckCircleLightLine,\n CloseLLine,\n InformationCircleLightLine,\n} from '../Icon';\nimport IconButton from '../IconButton';\nimport ScrollArea from '../ScrollArea';\nimport {\n FLOATING_LAYER_BASE_Z_INDEX,\n FLOATING_LAYER_STEP,\n FloatingLayerProvider,\n} from '../_utils/floatingLayer';\nimport {\n ModalLayerProvider,\n useModalLayer,\n} from '../_utils/overlayCoordinator';\nimport { LocaleContext, getTranslator } from '../locale/default';\nimport { cn } from '../lib/utils';\n\nexport const destroyFns: Array<() => void> = [];\n\nexport interface ModalProps {\n open?: boolean;\n onOk?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n onCancel?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n afterClose?: () => void;\n title?: React.ReactNode;\n subTitle?: React.ReactNode;\n icon?: React.ReactElement;\n width?: number | string;\n footer?: React.ReactNode | null;\n okText?: React.ReactNode;\n cancelText?: React.ReactNode;\n okButtonProps?: IButtonProps;\n cancelButtonProps?: IButtonProps;\n okType?: ButtonType;\n confirmLoading?: boolean;\n maskClosable?: boolean;\n closable?: boolean;\n closeIcon?: React.ReactNode;\n centered?: boolean;\n destroyOnClose?: boolean;\n className?: string;\n /** Pass through to the modal content root for automated testing. */\n 'data-testid'?: string;\n /** Pass through to the modal content root for accessibility and automated testing. */\n 'aria-label'?: string;\n /** Applied to the outer wrap layer (matches antd wrapClassName behavior) */\n wrapClassName?: string;\n style?: React.CSSProperties;\n bodyStyle?: React.CSSProperties;\n zIndex?: number;\n children?: React.ReactNode;\n paddingLess?: boolean;\n virtualScrollBar?: boolean;\n hideHeaderBottomBorder?: boolean;\n responsiveBounds?: boolean;\n fullscreen?: boolean;\n keyboard?: boolean;\n afterOpenChange?: (open: boolean) => void;\n getContainer?: (() => HTMLElement) | false;\n /** @internal used by static methods to pass modal type for icon styling */\n _modalType?: string;\n}\n\ninterface OriginModalProps extends ModalProps {\n onTopChange?: (isTop: boolean) => void;\n}\n\nexport interface ModalFuncProps {\n title?: React.ReactNode;\n subTitle?: React.ReactNode;\n content?: React.ReactNode;\n icon?: React.ReactElement;\n okText?: React.ReactNode;\n cancelText?: React.ReactNode;\n okButtonProps?: IButtonProps;\n cancelButtonProps?: IButtonProps;\n okType?: ButtonType;\n onOk?: (...args: any[]) => any;\n onCancel?: (...args: any[]) => any;\n width?: number | string;\n className?: string;\n /** @deprecated Use `className` instead. Preserved for antd v4 compat. */\n wrapClassName?: string;\n closable?: boolean;\n type?: 'info' | 'success' | 'error' | 'warn' | 'warning' | 'confirm';\n centered?: boolean;\n maskClosable?: boolean;\n}\n\nconst DEFAULT_WIDTH = 552;\nconst modalEscapeEvents = new WeakSet<KeyboardEvent>();\n\nfunction shouldCancelTopModal(event: KeyboardEvent) {\n return (\n !event.cancelBubble &&\n (!event.defaultPrevented || modalEscapeEvents.has(event))\n );\n}\n\nfunction ModalContentProviders({\n layerId,\n floatingLevel,\n children,\n}: {\n layerId: number;\n floatingLevel: number;\n children: React.ReactNode;\n}) {\n return (\n <ModalLayerProvider id={layerId}>\n <FloatingLayerProvider value={floatingLevel}>\n {children}\n </FloatingLayerProvider>\n </ModalLayerProvider>\n );\n}\n\nconst ModalTitle = (\n { icon, title, subTitle }: Pick<ModalProps, 'icon' | 'title' | 'subTitle'>,\n type?: string,\n) => (\n <div className=\"ald-modal-title-container tw-flex tw-items-center tw-gap-4\">\n {icon && (\n <div\n className={cn(\n 'ald-modal-icon-container tw-grid tw-size-10 tw-shrink-0 tw-place-items-center tw-rounded-[var(--global-grid-250)]',\n type === 'info' &&\n 'ald-modal-cion-info-container tw-bg-[var(--background-informative-muted)]',\n type === 'success' &&\n 'ald-modal-cion-success-container tw-bg-[var(--background-positive-muted)]',\n type === 'warning' &&\n 'ald-modal-cion-warning-container tw-bg-[var(--background-warning-muted)]',\n type === 'warn' &&\n 'ald-modal-cion-warning-container tw-bg-[var(--background-warning-muted)]',\n type === 'error' &&\n 'ald-modal-cion-error-container tw-bg-[var(--background-negative-muted)]',\n type === 'confirm' &&\n 'ald-modal-cion-confirm-container tw-bg-[var(--background-brand-muted)]',\n )}\n >\n {icon}\n </div>\n )}\n <div className=\"ald-modal-text-container\">\n {title && (\n <div\n className={cn(\n 'ald-modal-text-title tw-text-lg tw-font-semibold tw-leading-7 tw-text-[var(--content-primary)]',\n !subTitle && 'ald-modal-text-title-only tw-text-xl',\n )}\n >\n {title}\n </div>\n )}\n {subTitle && (\n <div className=\"ald-modal-text-sub-title tw-mt-1 tw-text-xs tw-leading-4 tw-text-[var(--content-secondary)]\">\n {subTitle}\n </div>\n )}\n </div>\n </div>\n);\n\nfunction getIcon(\n type: 'info' | 'success' | 'error' | 'warn' | 'warning' | 'confirm',\n) {\n if (type === 'success')\n return (\n <CheckCircleLightLine\n fill=\"var(--content-inverted-primary)\"\n color=\"var(--background-positive-strong)\"\n size={24}\n />\n );\n if (type === 'error')\n return (\n <AttentionTriangleLightLine\n color=\"var(--background-negative-strong)\"\n fill=\"var(--content-inverted-primary)\"\n size={24}\n />\n );\n if (type === 'warning' || type === 'warn')\n return (\n <AttentionTriangleLightLine\n color=\"var(--background-warning-strong)\"\n size={24}\n />\n );\n return (\n <InformationCircleLightLine\n size={24}\n color=\"var(--action-primary-normal)\"\n />\n );\n}\n\nfunction OriginModal(props: OriginModalProps) {\n const { locale } = useContext(LocaleContext);\n const t = getTranslator(locale);\n const {\n className,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n children,\n okType = 'primary',\n width,\n closeIcon,\n subTitle,\n okButtonProps = {},\n cancelButtonProps = {},\n okText = t.Modal.sure,\n cancelText = t.Modal.cancel,\n icon,\n title,\n paddingLess,\n responsiveBounds,\n hideHeaderBottomBorder,\n virtualScrollBar,\n style,\n maskClosable = false,\n fullscreen,\n open = false,\n onOk,\n onCancel,\n footer,\n confirmLoading,\n closable = true,\n zIndex = 1000,\n bodyStyle,\n keyboard = true,\n afterOpenChange,\n wrapClassName,\n _modalType,\n onTopChange,\n } = props;\n\n const prevOpenRef = useRef(open);\n const contentRef = useRef<HTMLDivElement>(null);\n const modalRef = useRef<HTMLDivElement>(null);\n const modalLayer = useModalLayer(open, zIndex);\n const { id: modalLayerId, maskZIndex, contentZIndex, isTop } = modalLayer;\n const nextFloatingLevel =\n (maskZIndex - FLOATING_LAYER_BASE_Z_INDEX) / FLOATING_LAYER_STEP + 1;\n\n useLayoutEffect(() => {\n onTopChange?.(isTop);\n }, [isTop, onTopChange]);\n\n useEffect(() => {\n if (prevOpenRef.current !== open) {\n prevOpenRef.current = open;\n afterOpenChange?.(open);\n }\n }, [open, afterOpenChange]);\n\n // ---- modal={false} 补偿:aria-hidden(屏幕阅读器只感知弹窗) ----\n useEffect(() => {\n if (!open || !isTop || !contentRef.current) return;\n return hideOthers(contentRef.current);\n }, [isTop, open]);\n\n // ---- modal={false} 补偿:Tab 焦点循环 ----\n useEffect(() => {\n if (!open || !isTop || !contentRef.current) return;\n const container = contentRef.current;\n\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\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\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isTop, open]);\n\n useEffect(() => {\n if (!open || !isTop || !keyboard) return;\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n // Radix observes Escape during document capture, so child overlays can\n // only finish their own propagation handling later in the event cycle.\n queueMicrotask(() => {\n if (shouldCancelTopModal(event)) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n }\n });\n };\n\n window.addEventListener('keydown', handleEscape, true);\n return () => window.removeEventListener('keydown', handleEscape, true);\n }, [isTop, keyboard, onCancel, open]);\n\n const responsiveBoundsStyle = useMemo(() => {\n if (!responsiveBounds) return {};\n return {\n width: 'calc(100% - 160px)',\n maxWidth: '1680px',\n minWidth: '1280px',\n height: 'calc(100% - 48px)',\n maxHeight: '900px',\n minHeight: '640px',\n };\n }, [responsiveBounds]);\n\n const mergedOkProps = { loading: confirmLoading, ...okButtonProps };\n\n const renderFooter = () => {\n if (footer === null) return null;\n if (footer)\n return (\n // antd 兼容:antd .ant-modal-footer 使用 text-align:right 让 inline 按钮右对齐,\n // 即使消费方传入 width:100% 的子容器,内部 inline 元素仍能右对齐。\n // 此处同时使用 tw-flex tw-justify-end(flexbox 对齐)和 tw-text-right(继承式对齐)保持兼容。\n <div className=\"ald-modal-footer ant-modal-footer tw-flex tw-items-center tw-justify-end tw-gap-2 tw-border-t tw-border-solid tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-px-6 tw-py-3 tw-text-right\">\n {footer}\n </div>\n );\n return (\n <div className=\"ald-modal-footer ant-modal-footer tw-flex tw-justify-end tw-gap-2 tw-border-t tw-border-solid tw-border-[var(--border-default)] tw-px-6 tw-py-4\">\n <Button\n type=\"secondary\"\n size=\"middle\"\n {...cancelButtonProps}\n onClick={onCancel}\n >\n {cancelText}\n </Button>\n <Button type={okType} size=\"middle\" {...mergedOkProps} onClick={onOk}>\n {okText}\n </Button>\n </div>\n );\n };\n\n return (\n <DialogPrimitive.Root open={open} modal={false}>\n <DialogPrimitive.Portal>\n {/* modal={false} 时 DialogPrimitive.Overlay 不渲染,用普通 div 替代 */}\n {isTop && (\n <div\n className=\"ald-modal-mask tw-animate-in tw-fade-in-0 tw-fixed tw-inset-0 tw-bg-[var(--background-inverted)] tw-opacity-45\"\n style={{ zIndex: maskZIndex }}\n onPointerDown={() => {\n if (maskClosable) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n }\n }}\n />\n )}\n {/* Centering wrapper — replaces transform centering so consumer CSS (top/left overrides) works */}\n <div\n ref={contentRef}\n {...(!isTop ? { inert: '' } : {})}\n aria-hidden={!isTop || undefined}\n className={cn(\n // antd 兼容:保留 ant-modal-wrap class,消费方 CSS 通过 wrapClassName + :global(.ant-modal) 控制弹窗宽高\n 'ald-modal-wrap ant-modal-wrap tw-pointer-events-none tw-fixed tw-inset-0 tw-flex tw-items-center tw-justify-center',\n wrapClassName,\n )}\n style={{ zIndex: contentZIndex }}\n >\n <DialogPrimitive.Content\n ref={modalRef}\n tabIndex={-1}\n data-testid={dataTestId}\n aria-label={ariaLabel}\n className={cn(\n // antd 兼容:保留 ant-modal class,消费方 CSS 通过 .ant-modal 选择器控制弹窗宽高等样式\n // tw-outline-none:Radix 打开时会聚焦 Content,不抑制 outline 会渲染出蓝色焦点框\n 'ald-modal ant-modal tw-pointer-events-auto tw-box-border tw-flex tw-flex-col tw-overflow-hidden tw-bg-[var(--background-default)] tw-shadow-[var(--elevation-bottom-bottom-lg)] tw-outline-none',\n fullscreen\n ? 'ald-modal-fullscreen tw-fixed tw-inset-0 tw-size-full tw-rounded-none'\n : 'tw-rounded-r-75',\n !fullscreen &&\n 'tw-border tw-border-solid tw-border-[var(--border-default)]',\n paddingLess && 'ald-modal-padding-less',\n virtualScrollBar && 'ald-modal-virtual-scroll-bar',\n hideHeaderBottomBorder && 'ald-modal-hide-header-bottom-border',\n responsiveBounds && 'ald-modal-responsive-bounds',\n className,\n )}\n style={{\n ...(fullscreen\n ? {}\n : {\n width: responsiveBounds\n ? responsiveBoundsStyle.width\n : width || DEFAULT_WIDTH,\n ...responsiveBoundsStyle,\n }),\n ...style,\n }}\n onOpenAutoFocus={(event) => {\n event.preventDefault();\n requestAnimationFrame(() => {\n const modal = modalRef.current;\n const activeElement = document.activeElement;\n const activeOverlay =\n activeElement instanceof HTMLElement\n ? activeElement.closest(\n '[role=\"dialog\"], [role=\"menu\"], [role=\"listbox\"]',\n )\n : null;\n\n // A nested overlay may open together with the modal and owns\n // focus already. Do not steal focus back from that overlay.\n if (\n !modal ||\n (activeOverlay &&\n !activeOverlay.classList.contains('ald-modal') &&\n activeOverlay !== modal &&\n !modal.contains(activeOverlay))\n ) {\n return;\n }\n modal.focus({ preventScroll: true });\n });\n }}\n onEscapeKeyDown={(event) => {\n if (!event.defaultPrevented) modalEscapeEvents.add(event);\n event.preventDefault();\n }}\n onPointerDownOutside={(e) => {\n if (maskClosable) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n } else {\n e.preventDefault();\n }\n }}\n onInteractOutside={(e) => {\n if (!maskClosable) {\n e.preventDefault();\n }\n }}\n >\n {/* ant-modal-content compat wrapper — matches antd DOM nesting for consumer CSS */}\n <div className=\"ant-modal-content tw-flex tw-h-full tw-flex-col\">\n <ModalContentProviders\n layerId={modalLayerId}\n floatingLevel={nextFloatingLevel}\n >\n {!fullscreen && (\n <div\n className={cn(\n 'ald-modal-header ant-modal-header tw-flex tw-items-start tw-justify-between tw-bg-[var(--background-default)] tw-px-6 tw-py-4',\n !hideHeaderBottomBorder &&\n 'tw-border-b tw-border-solid tw-border-[var(--border-default)]',\n )}\n >\n <DialogPrimitive.Title asChild>\n <div className=\"tw-flex-1\">\n {ModalTitle({ icon, title, subTitle }, _modalType)}\n </div>\n </DialogPrimitive.Title>\n {closable && (\n <DialogPrimitive.Close asChild>\n <span className=\"ant-modal-close\" onClick={onCancel}>\n {closeIcon || (\n <IconButton\n icon={<CloseLLine size={20} />}\n size=\"middle\"\n />\n )}\n </span>\n </DialogPrimitive.Close>\n )}\n </div>\n )}\n {/* Hidden title for accessibility when fullscreen hides the header */}\n {fullscreen && (\n <DialogPrimitive.Title className=\"tw-sr-only\">\n {title}\n </DialogPrimitive.Title>\n )}\n <div\n className={cn(\n 'ald-modal-body ant-modal-body tw-flex-1 tw-text-sm tw-leading-5',\n fullscreen\n ? 'tw-h-full tw-overflow-auto tw-p-0'\n : 'tw-min-h-[130px]',\n !fullscreen &&\n (virtualScrollBar\n ? 'tw-overflow-hidden tw-p-0'\n : 'tw-overflow-auto'),\n !fullscreen &&\n !responsiveBounds &&\n !virtualScrollBar &&\n 'tw-max-h-[68vh]',\n !fullscreen &&\n !paddingLess &&\n !virtualScrollBar &&\n 'tw-p-6',\n )}\n style={bodyStyle}\n >\n {virtualScrollBar ? (\n <ScrollArea\n className=\"ald-modal-body-wrap !tw-h-auto\"\n innerClassName={cn(\n 'ald-modal-body-wrap-inner tw-max-h-[68vh]',\n paddingLess ? 'tw-p-0' : 'tw-px-[23px] tw-py-0',\n )}\n >\n {children}\n </ScrollArea>\n ) : (\n children\n )}\n </div>\n {!fullscreen && renderFooter()}\n </ModalContentProviders>\n </div>\n </DialogPrimitive.Content>\n </div>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n}\n\n// Static method helper\nfunction createStaticModal(\n type: ModalFuncProps['type'],\n props: ModalFuncProps,\n) {\n const focusTarget = document.activeElement as HTMLElement | null;\n const container = document.createElement('div');\n document.body.appendChild(container);\n const root = createRoot(container);\n\n let currentProps = { ...props };\n let destroyed = false;\n let isTop = true;\n\n const destroy = () => {\n if (destroyed) return;\n destroyed = true;\n const shouldRestoreFocus = isTop;\n root.unmount();\n container.remove();\n const idx = destroyFns.indexOf(destroy);\n if (idx >= 0) destroyFns.splice(idx, 1);\n queueMicrotask(() => {\n if (shouldRestoreFocus && focusTarget?.isConnected) focusTarget.focus();\n });\n };\n\n const update = (newProps: Partial<ModalFuncProps>) => {\n currentProps = { ...currentProps, ...newProps };\n render(currentProps);\n };\n\n const isConfirm = type === 'confirm';\n\n const render = (p: ModalFuncProps) => {\n const handleOk = () => {\n p.onOk?.();\n destroy();\n };\n const handleCancel = () => {\n p.onCancel?.();\n destroy();\n };\n\n root.render(\n <OriginModal\n open={true}\n title={p.title}\n subTitle={p.subTitle}\n icon={p.icon || getIcon(type || 'info')}\n onOk={handleOk}\n onCancel={handleCancel}\n okText={p.okText}\n cancelText={p.cancelText}\n okButtonProps={p.okButtonProps}\n cancelButtonProps={p.cancelButtonProps}\n okType={p.okType || (isConfirm ? 'dangerous' : 'primary')}\n width={p.width || DEFAULT_WIDTH}\n className={cn('ald-modal', p.className)}\n closable={p.closable}\n maskClosable={p.maskClosable}\n _modalType={type}\n onTopChange={(nextIsTop) => {\n isTop = nextIsTop;\n }}\n footer={\n isConfirm ? undefined : (\n <Button\n type=\"primary\"\n size=\"middle\"\n {...(p.okButtonProps || {})}\n onClick={handleOk}\n >\n {p.okText || 'OK'}\n </Button>\n )\n }\n >\n {p.content}\n </OriginModal>,\n );\n };\n\n destroyFns.push(destroy);\n render(currentProps);\n\n return { destroy, update };\n}\n\n// Attach static methods\ntype ModalFunc = (props: ModalFuncProps) => {\n destroy: () => void;\n update: (props: Partial<ModalFuncProps>) => void;\n};\n\n// ---------- useModal hook ----------\n\ninterface ModalInstance {\n id: number;\n type: ModalFuncProps['type'];\n props: ModalFuncProps;\n open: boolean;\n}\n\nexport interface ModalApiInstance {\n destroy: () => void;\n update: (newProps: Partial<ModalFuncProps>) => void;\n}\n\nexport interface ModalStaticFunctions {\n info: (props: ModalFuncProps) => ModalApiInstance;\n success: (props: ModalFuncProps) => ModalApiInstance;\n error: (props: ModalFuncProps) => ModalApiInstance;\n warning: (props: ModalFuncProps) => ModalApiInstance;\n confirm: (props: ModalFuncProps) => ModalApiInstance;\n}\n\nfunction useModal(): [ModalStaticFunctions, React.ReactElement] {\n const [modals, setModals] = useState<ModalInstance[]>([]);\n const idCounter = useRef(0);\n\n const removeModal = useCallback((id: number) => {\n setModals((prev) =>\n prev.map((m) => (m.id === id ? { ...m, open: false } : m)),\n );\n // Remove from DOM after animation\n setTimeout(() => {\n setModals((prev) => prev.filter((m) => m.id !== id));\n }, 300);\n }, []);\n\n const updateModal = useCallback(\n (id: number, newProps: Partial<ModalFuncProps>) => {\n setModals((prev) =>\n prev.map((m) =>\n m.id === id ? { ...m, props: { ...m.props, ...newProps } } : m,\n ),\n );\n },\n [],\n );\n\n const openModal = useCallback(\n (type: ModalFuncProps['type'], props: ModalFuncProps): ModalApiInstance => {\n const id = ++idCounter.current;\n const instance: ModalInstance = { id, type, props, open: true };\n setModals((prev) => [...prev, instance]);\n\n return {\n destroy: () => removeModal(id),\n update: (newProps: Partial<ModalFuncProps>) =>\n updateModal(id, newProps),\n };\n },\n [removeModal, updateModal],\n );\n\n const api = useMemo<ModalStaticFunctions>(\n () => ({\n info: (props) => openModal('info', props),\n success: (props) => openModal('success', props),\n error: (props) => openModal('error', props),\n warning: (props) => openModal('warning', props),\n confirm: (props) =>\n openModal('confirm', { ...props, type: props.type || 'confirm' }),\n }),\n [openModal],\n );\n\n const contextHolder = (\n <>\n {modals.map((m) => {\n const isConfirmType = m.type === 'confirm';\n const handleOk = () => {\n m.props.onOk?.();\n removeModal(m.id);\n };\n const handleCancel = () => {\n m.props.onCancel?.();\n removeModal(m.id);\n };\n return (\n <OriginModal\n key={m.id}\n open={m.open}\n title={m.props.title}\n subTitle={m.props.subTitle}\n icon={m.props.icon || getIcon(m.type || 'info')}\n onOk={handleOk}\n onCancel={handleCancel}\n okText={m.props.okText}\n cancelText={m.props.cancelText}\n okButtonProps={m.props.okButtonProps}\n cancelButtonProps={m.props.cancelButtonProps}\n okType={m.props.okType || (isConfirmType ? 'dangerous' : 'primary')}\n width={m.props.width || DEFAULT_WIDTH}\n className={cn('ald-modal', m.props.className)}\n closable={m.props.closable}\n maskClosable={m.props.maskClosable}\n _modalType={m.type}\n footer={\n isConfirmType ? undefined : (\n <Button\n type=\"primary\"\n size=\"middle\"\n {...(m.props.okButtonProps || {})}\n onClick={handleOk}\n >\n {m.props.okText || 'OK'}\n </Button>\n )\n }\n >\n {m.props.content}\n </OriginModal>\n );\n })}\n </>\n );\n\n return [api, contextHolder];\n}\n\n// ---------- end useModal ----------\n\nconst Modal = OriginModal as typeof OriginModal & {\n info: ModalFunc;\n success: ModalFunc;\n error: ModalFunc;\n warning: ModalFunc;\n confirm: ModalFunc;\n destroyAll: () => void;\n useModal: typeof useModal;\n config: (config: any) => void;\n};\n\nModal.info = (props) => createStaticModal('info', props);\nModal.success = (props) => createStaticModal('success', props);\nModal.error = (props) => createStaticModal('error', props);\nModal.warning = (props) => createStaticModal('warning', props);\nModal.confirm = (props) =>\n createStaticModal('confirm', { ...props, type: props.type || 'confirm' });\n\nModal.destroyAll = () => {\n while (destroyFns.length) {\n const close = destroyFns.pop();\n if (close) close();\n }\n};\n\nModal.useModal = useModal;\nModal.config = () => {};\n\nexport default Modal;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/Modal/index.tsx"],"sourcesContent":["import * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { hideOthers } from 'aria-hidden';\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { createRoot } from 'react-dom/client';\nimport Button, { ButtonType, IButtonProps } from '../Button';\nimport {\n AttentionTriangleLightLine,\n CheckCircleLightLine,\n CloseLLine,\n InformationCircleLightLine,\n} from '../Icon';\nimport '../IconButton/icon-button.css';\nimport ScrollArea from '../ScrollArea';\nimport {\n FLOATING_LAYER_BASE_Z_INDEX,\n FLOATING_LAYER_STEP,\n FloatingLayerProvider,\n} from '../_utils/floatingLayer';\nimport {\n ModalLayerProvider,\n useModalLayer,\n} from '../_utils/overlayCoordinator';\nimport {\n focusInitialDialogTarget,\n markDialogEscapeEvent,\n restoreDialogFocus,\n useDialogAccessibility,\n} from '../_utils/dialogAccessibility';\nimport { LocaleContext, getTranslator } from '../locale/default';\nimport { cn } from '../lib/utils';\n\nexport const destroyFns: Array<() => void> = [];\n\nexport interface ModalProps {\n open?: boolean;\n onOk?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n onCancel?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n afterClose?: () => void;\n title?: React.ReactNode;\n subTitle?: React.ReactNode;\n icon?: React.ReactElement;\n width?: number | string;\n footer?: React.ReactNode | null;\n okText?: React.ReactNode;\n cancelText?: React.ReactNode;\n okButtonProps?: IButtonProps;\n cancelButtonProps?: IButtonProps;\n okType?: ButtonType;\n confirmLoading?: boolean;\n maskClosable?: boolean;\n closable?: boolean;\n closeIcon?: React.ReactNode;\n centered?: boolean;\n destroyOnClose?: boolean;\n className?: string;\n /** Pass through to the modal content root for automated testing. */\n 'data-testid'?: string;\n /** Pass through to the modal content root for accessibility and automated testing. */\n 'aria-label'?: string;\n /** Dialog semantic role. Use alertdialog only for explicitly urgent confirmation flows. */\n role?: 'dialog' | 'alertdialog';\n /** Applied to the outer wrap layer (matches antd wrapClassName behavior) */\n wrapClassName?: string;\n style?: React.CSSProperties;\n bodyStyle?: React.CSSProperties;\n zIndex?: number;\n children?: React.ReactNode;\n paddingLess?: boolean;\n virtualScrollBar?: boolean;\n hideHeaderBottomBorder?: boolean;\n responsiveBounds?: boolean;\n fullscreen?: boolean;\n keyboard?: boolean;\n afterOpenChange?: (open: boolean) => void;\n getContainer?: (() => HTMLElement) | false;\n /** @internal used by static methods to pass modal type for icon styling */\n _modalType?: string;\n}\n\ninterface OriginModalProps extends ModalProps {\n onTopChange?: (isTop: boolean) => void;\n}\n\nexport interface ModalFuncProps {\n title?: React.ReactNode;\n subTitle?: React.ReactNode;\n content?: React.ReactNode;\n icon?: React.ReactElement;\n okText?: React.ReactNode;\n cancelText?: React.ReactNode;\n okButtonProps?: IButtonProps;\n cancelButtonProps?: IButtonProps;\n okType?: ButtonType;\n onOk?: (...args: any[]) => any;\n onCancel?: (...args: any[]) => any;\n width?: number | string;\n className?: string;\n /** @deprecated Use `className` instead. Preserved for antd v4 compat. */\n wrapClassName?: string;\n closable?: boolean;\n type?: 'info' | 'success' | 'error' | 'warn' | 'warning' | 'confirm';\n centered?: boolean;\n maskClosable?: boolean;\n /** Dialog semantic role. Use alertdialog only for explicitly urgent confirmation flows. */\n role?: 'dialog' | 'alertdialog';\n}\n\nconst DEFAULT_WIDTH = 552;\nfunction ModalContentProviders({\n layerId,\n floatingLevel,\n children,\n}: {\n layerId: number;\n floatingLevel: number;\n children: React.ReactNode;\n}) {\n return (\n <ModalLayerProvider id={layerId}>\n <FloatingLayerProvider value={floatingLevel}>\n {children}\n </FloatingLayerProvider>\n </ModalLayerProvider>\n );\n}\n\nconst ModalTitle = (\n {\n icon,\n title,\n subTitle,\n titleId,\n descriptionId,\n }: Pick<ModalProps, 'icon' | 'title' | 'subTitle'> & {\n titleId?: string;\n descriptionId?: string;\n },\n type?: string,\n) => (\n <div className=\"ald-modal-title-container tw-flex tw-items-center tw-gap-4\">\n {icon && (\n <div\n className={cn(\n 'ald-modal-icon-container tw-grid tw-size-10 tw-shrink-0 tw-place-items-center tw-rounded-[var(--global-grid-250)]',\n type === 'info' &&\n 'ald-modal-cion-info-container tw-bg-[var(--background-informative-muted)]',\n type === 'success' &&\n 'ald-modal-cion-success-container tw-bg-[var(--background-positive-muted)]',\n type === 'warning' &&\n 'ald-modal-cion-warning-container tw-bg-[var(--background-warning-muted)]',\n type === 'warn' &&\n 'ald-modal-cion-warning-container tw-bg-[var(--background-warning-muted)]',\n type === 'error' &&\n 'ald-modal-cion-error-container tw-bg-[var(--background-negative-muted)]',\n type === 'confirm' &&\n 'ald-modal-cion-confirm-container tw-bg-[var(--background-brand-muted)]',\n )}\n >\n {icon}\n </div>\n )}\n <div className=\"ald-modal-text-container\">\n {title && (\n <div\n id={titleId}\n className={cn(\n 'ald-modal-text-title tw-text-lg tw-font-semibold tw-leading-7 tw-text-[var(--content-primary)]',\n !subTitle && 'ald-modal-text-title-only tw-text-xl',\n )}\n >\n {title}\n </div>\n )}\n {subTitle && (\n <div\n id={descriptionId}\n className=\"ald-modal-text-sub-title tw-mt-1 tw-text-xs tw-leading-4 tw-text-[var(--content-secondary)]\"\n >\n {subTitle}\n </div>\n )}\n </div>\n </div>\n);\n\nfunction getIcon(\n type: 'info' | 'success' | 'error' | 'warn' | 'warning' | 'confirm',\n) {\n if (type === 'success')\n return (\n <CheckCircleLightLine\n fill=\"var(--content-inverted-primary)\"\n color=\"var(--background-positive-strong)\"\n size={24}\n />\n );\n if (type === 'error')\n return (\n <AttentionTriangleLightLine\n color=\"var(--background-negative-strong)\"\n fill=\"var(--content-inverted-primary)\"\n size={24}\n />\n );\n if (type === 'warning' || type === 'warn')\n return (\n <AttentionTriangleLightLine\n color=\"var(--background-warning-strong)\"\n size={24}\n />\n );\n return (\n <InformationCircleLightLine\n size={24}\n color=\"var(--action-primary-normal)\"\n />\n );\n}\n\nfunction OriginModal(props: OriginModalProps) {\n const { locale } = useContext(LocaleContext);\n const t = getTranslator(locale);\n const {\n className,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n role = 'dialog',\n children,\n okType = 'primary',\n width,\n closeIcon,\n subTitle,\n okButtonProps = {},\n cancelButtonProps = {},\n okText = t.Modal.sure,\n cancelText = t.Modal.cancel,\n icon,\n title,\n paddingLess,\n responsiveBounds,\n hideHeaderBottomBorder,\n virtualScrollBar,\n style,\n maskClosable = false,\n fullscreen,\n open = false,\n onOk,\n onCancel,\n footer,\n confirmLoading,\n closable = true,\n zIndex = 1000,\n bodyStyle,\n keyboard = true,\n afterOpenChange,\n wrapClassName,\n _modalType,\n onTopChange,\n } = props;\n\n const prevOpenRef = useRef(open);\n const contentRef = useRef<HTMLDivElement>(null);\n const modalRef = useRef<HTMLDivElement>(null);\n const generatedId = React.useId();\n const titleId = `${generatedId}-title`;\n const descriptionId = `${generatedId}-description`;\n const modalLayer = useModalLayer(open, zIndex);\n const { id: modalLayerId, maskZIndex, contentZIndex, isTop } = modalLayer;\n const nextFloatingLevel =\n (maskZIndex - FLOATING_LAYER_BASE_Z_INDEX) / FLOATING_LAYER_STEP + 1;\n\n useDialogAccessibility({\n open,\n isTop,\n keyboard,\n containerRef: modalRef,\n onEscape: () => onCancel?.({} as React.MouseEvent<HTMLButtonElement>),\n });\n\n useLayoutEffect(() => {\n onTopChange?.(isTop);\n }, [isTop, onTopChange]);\n\n useEffect(() => {\n if (prevOpenRef.current !== open) {\n prevOpenRef.current = open;\n afterOpenChange?.(open);\n }\n }, [open, afterOpenChange]);\n\n // ---- modal={false} 补偿:aria-hidden(屏幕阅读器只感知弹窗) ----\n useEffect(() => {\n if (!open || !isTop || !contentRef.current) return;\n return hideOthers(contentRef.current);\n }, [isTop, open]);\n\n const responsiveBoundsStyle = useMemo(() => {\n if (!responsiveBounds) return {};\n return {\n width: 'calc(100% - 160px)',\n maxWidth: '1680px',\n minWidth: '1280px',\n height: 'calc(100% - 48px)',\n maxHeight: '900px',\n minHeight: '640px',\n };\n }, [responsiveBounds]);\n\n const mergedOkProps = { loading: confirmLoading, ...okButtonProps };\n const headerBorderClassName = hideHeaderBottomBorder\n ? '!tw-border-0'\n : 'tw-border-b tw-border-solid tw-border-[var(--border-default)] !tw-border-x-0 !tw-border-t-0';\n\n const renderFooter = () => {\n if (footer === null) return null;\n const footerBorderClassName =\n 'tw-border-t tw-border-solid tw-border-[var(--border-default)] !tw-border-x-0 !tw-border-b-0';\n if (footer)\n return (\n // antd 兼容:antd .ant-modal-footer 使用 text-align:right 让 inline 按钮右对齐,\n // 即使消费方传入 width:100% 的子容器,内部 inline 元素仍能右对齐。\n // 此处同时使用 tw-flex tw-justify-end(flexbox 对齐)和 tw-text-right(继承式对齐)保持兼容。\n <div\n className={cn(\n 'ald-modal-footer ant-modal-footer tw-flex tw-items-center tw-justify-end tw-gap-2 tw-bg-[var(--background-default)] tw-px-6 tw-py-3 tw-text-right',\n footerBorderClassName,\n )}\n >\n {footer}\n </div>\n );\n return (\n <div\n className={cn(\n 'ald-modal-footer ant-modal-footer tw-flex tw-justify-end tw-gap-2 tw-px-6 tw-py-4',\n footerBorderClassName,\n )}\n >\n <Button\n type=\"secondary\"\n size=\"middle\"\n {...cancelButtonProps}\n onClick={onCancel}\n >\n {cancelText}\n </Button>\n <Button type={okType} size=\"middle\" {...mergedOkProps} onClick={onOk}>\n {okText}\n </Button>\n </div>\n );\n };\n\n return (\n <DialogPrimitive.Root open={open} modal={false}>\n <DialogPrimitive.Portal>\n {/* modal={false} 时 DialogPrimitive.Overlay 不渲染,用普通 div 替代 */}\n {isTop && (\n <div\n className=\"ald-modal-mask tw-animate-in tw-fade-in-0 tw-fixed tw-inset-0 tw-bg-[var(--background-inverted)] tw-opacity-45\"\n style={{ zIndex: maskZIndex }}\n onPointerDown={() => {\n if (maskClosable) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n }\n }}\n />\n )}\n {/* Centering wrapper — replaces transform centering so consumer CSS (top/left overrides) works */}\n <div\n ref={contentRef}\n {...(!isTop ? { inert: '' } : {})}\n aria-hidden={!isTop || undefined}\n className={cn(\n // antd 兼容:保留 ant-modal-wrap class,消费方 CSS 通过 wrapClassName + :global(.ant-modal) 控制弹窗宽高\n 'ald-modal-wrap ant-modal-wrap tw-pointer-events-none tw-fixed tw-inset-0 tw-flex tw-items-center tw-justify-center',\n wrapClassName,\n )}\n style={{ zIndex: contentZIndex }}\n >\n <DialogPrimitive.Content\n ref={modalRef}\n tabIndex={-1}\n role={role}\n data-testid={dataTestId}\n aria-modal={isTop || undefined}\n aria-labelledby={title ? titleId : undefined}\n aria-describedby={subTitle ? descriptionId : undefined}\n aria-label={ariaLabel}\n className={cn(\n // antd 兼容:保留 ant-modal class,消费方 CSS 通过 .ant-modal 选择器控制弹窗宽高等样式\n // tw-outline-none:Radix 打开时会聚焦 Content,不抑制 outline 会渲染出蓝色焦点框\n 'ald-modal ant-modal tw-pointer-events-auto tw-box-border tw-flex tw-flex-col tw-overflow-hidden tw-border-0 tw-bg-[var(--background-default)] tw-shadow-none tw-outline-none',\n fullscreen\n ? 'ald-modal-fullscreen tw-fixed tw-inset-0 tw-size-full tw-rounded-none'\n : 'tw-rounded-r-75',\n paddingLess && 'ald-modal-padding-less',\n virtualScrollBar && 'ald-modal-virtual-scroll-bar',\n hideHeaderBottomBorder && 'ald-modal-hide-header-bottom-border',\n responsiveBounds && 'ald-modal-responsive-bounds',\n className,\n )}\n style={{\n ...(fullscreen\n ? {}\n : {\n width: responsiveBounds\n ? responsiveBoundsStyle.width\n : width || DEFAULT_WIDTH,\n ...responsiveBoundsStyle,\n }),\n ...style,\n }}\n onOpenAutoFocus={(event) => {\n event.preventDefault();\n requestAnimationFrame(() => {\n const modal = modalRef.current;\n if (modal) focusInitialDialogTarget(modal);\n });\n }}\n onEscapeKeyDown={(event) => {\n if (!event.defaultPrevented) markDialogEscapeEvent(event);\n event.preventDefault();\n }}\n onPointerDownOutside={(e) => {\n if (maskClosable) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n } else {\n e.preventDefault();\n }\n }}\n onInteractOutside={(e) => {\n if (!maskClosable) {\n e.preventDefault();\n }\n }}\n >\n {/* ant-modal-content compat wrapper — matches antd DOM nesting for consumer CSS.\n Visual chrome is owned by .ald-modal to avoid nested antd styles adding\n an extra footer-side/bottom edge. */}\n <div className=\"ant-modal-content tw-flex tw-h-full tw-flex-col !tw-rounded-none !tw-border-0 !tw-bg-transparent !tw-p-0 !tw-shadow-none\">\n <ModalContentProviders\n layerId={modalLayerId}\n floatingLevel={nextFloatingLevel}\n >\n {!fullscreen && (\n <div\n className={cn(\n 'ald-modal-header ant-modal-header tw-flex tw-items-start tw-justify-between tw-bg-[var(--background-default)] tw-px-6 tw-py-4',\n headerBorderClassName,\n )}\n >\n <DialogPrimitive.Title asChild>\n <div className=\"tw-flex-1\">\n {ModalTitle(\n { icon, title, subTitle, titleId, descriptionId },\n _modalType,\n )}\n </div>\n </DialogPrimitive.Title>\n {closable && (\n <DialogPrimitive.Close asChild>\n <button\n type=\"button\"\n className=\"ant-modal-close ald-icon-button ald-icon-button-middle focus-visible:tw-outline focus-visible:tw-outline-2 focus-visible:tw-outline-offset-2 focus-visible:tw-outline-[var(--focus-ring)] forced-colors:focus-visible:tw-outline-[Highlight]\"\n aria-label=\"Close\"\n data-overlay-close=\"true\"\n onClick={onCancel}\n >\n <span className=\"ald-icon-button-wrap\">\n {closeIcon || <CloseLLine size={20} />}\n </span>\n </button>\n </DialogPrimitive.Close>\n )}\n </div>\n )}\n {/* Hidden title for accessibility when fullscreen hides the header */}\n {fullscreen && (\n <DialogPrimitive.Title asChild>\n <div className=\"tw-sr-only\">\n {title && <span id={titleId}>{title}</span>}\n </div>\n </DialogPrimitive.Title>\n )}\n {subTitle && (\n <DialogPrimitive.Description className=\"tw-sr-only\">\n {subTitle}\n </DialogPrimitive.Description>\n )}\n <div\n className={cn(\n 'ald-modal-body ant-modal-body tw-flex-1 tw-text-sm tw-leading-5',\n fullscreen\n ? 'tw-h-full tw-overflow-auto tw-p-0'\n : 'tw-min-h-[130px]',\n !fullscreen &&\n (virtualScrollBar\n ? 'tw-overflow-hidden tw-p-0'\n : 'tw-overflow-auto'),\n !fullscreen &&\n !responsiveBounds &&\n !virtualScrollBar &&\n 'tw-max-h-[68vh]',\n !fullscreen &&\n !paddingLess &&\n !virtualScrollBar &&\n 'tw-p-6',\n )}\n style={bodyStyle}\n >\n {virtualScrollBar ? (\n <ScrollArea\n className=\"ald-modal-body-wrap !tw-h-auto\"\n innerClassName={cn(\n 'ald-modal-body-wrap-inner tw-max-h-[68vh]',\n paddingLess ? 'tw-p-0' : 'tw-px-[23px] tw-py-0',\n )}\n >\n {children}\n </ScrollArea>\n ) : (\n children\n )}\n </div>\n {!fullscreen && renderFooter()}\n </ModalContentProviders>\n </div>\n </DialogPrimitive.Content>\n </div>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n}\n\n// Static method helper\nfunction createStaticModal(\n type: ModalFuncProps['type'],\n props: ModalFuncProps,\n) {\n const focusTarget = document.activeElement as HTMLElement | null;\n const container = document.createElement('div');\n document.body.appendChild(container);\n const root = createRoot(container);\n\n let currentProps = { ...props };\n let destroyed = false;\n let isTop = true;\n\n const destroy = () => {\n if (destroyed) return;\n destroyed = true;\n const shouldRestoreFocus = isTop;\n root.unmount();\n container.remove();\n const idx = destroyFns.indexOf(destroy);\n if (idx >= 0) destroyFns.splice(idx, 1);\n if (shouldRestoreFocus) restoreDialogFocus(focusTarget);\n };\n\n const update = (newProps: Partial<ModalFuncProps>) => {\n currentProps = { ...currentProps, ...newProps };\n render(currentProps);\n };\n\n const isConfirm = type === 'confirm';\n\n const render = (p: ModalFuncProps) => {\n const handleOk = () => {\n p.onOk?.();\n destroy();\n };\n const handleCancel = () => {\n p.onCancel?.();\n destroy();\n };\n\n root.render(\n <OriginModal\n open={true}\n title={p.title}\n subTitle={p.subTitle}\n icon={p.icon || getIcon(type || 'info')}\n onOk={handleOk}\n onCancel={handleCancel}\n okText={p.okText}\n cancelText={p.cancelText}\n okButtonProps={p.okButtonProps}\n cancelButtonProps={p.cancelButtonProps}\n okType={p.okType || (isConfirm ? 'dangerous' : 'primary')}\n width={p.width || DEFAULT_WIDTH}\n className={cn('ald-modal', p.className)}\n closable={p.closable}\n maskClosable={p.maskClosable}\n role={p.role}\n _modalType={type}\n onTopChange={(nextIsTop) => {\n isTop = nextIsTop;\n }}\n footer={\n isConfirm ? undefined : (\n <Button\n type=\"primary\"\n size=\"middle\"\n {...(p.okButtonProps || {})}\n onClick={handleOk}\n >\n {p.okText || 'OK'}\n </Button>\n )\n }\n >\n {p.content}\n </OriginModal>,\n );\n };\n\n destroyFns.push(destroy);\n render(currentProps);\n\n return { destroy, update };\n}\n\n// Attach static methods\ntype ModalFunc = (props: ModalFuncProps) => {\n destroy: () => void;\n update: (props: Partial<ModalFuncProps>) => void;\n};\n\n// ---------- useModal hook ----------\n\ninterface ModalInstance {\n id: number;\n type: ModalFuncProps['type'];\n props: ModalFuncProps;\n open: boolean;\n}\n\nexport interface ModalApiInstance {\n destroy: () => void;\n update: (newProps: Partial<ModalFuncProps>) => void;\n}\n\nexport interface ModalStaticFunctions {\n info: (props: ModalFuncProps) => ModalApiInstance;\n success: (props: ModalFuncProps) => ModalApiInstance;\n error: (props: ModalFuncProps) => ModalApiInstance;\n warning: (props: ModalFuncProps) => ModalApiInstance;\n confirm: (props: ModalFuncProps) => ModalApiInstance;\n}\n\nfunction useModal(): [ModalStaticFunctions, React.ReactElement] {\n const [modals, setModals] = useState<ModalInstance[]>([]);\n const idCounter = useRef(0);\n\n const removeModal = useCallback((id: number) => {\n setModals((prev) =>\n prev.map((m) => (m.id === id ? { ...m, open: false } : m)),\n );\n // Remove from DOM after animation\n setTimeout(() => {\n setModals((prev) => prev.filter((m) => m.id !== id));\n }, 300);\n }, []);\n\n const updateModal = useCallback(\n (id: number, newProps: Partial<ModalFuncProps>) => {\n setModals((prev) =>\n prev.map((m) =>\n m.id === id ? { ...m, props: { ...m.props, ...newProps } } : m,\n ),\n );\n },\n [],\n );\n\n const openModal = useCallback(\n (type: ModalFuncProps['type'], props: ModalFuncProps): ModalApiInstance => {\n const id = ++idCounter.current;\n const instance: ModalInstance = { id, type, props, open: true };\n setModals((prev) => [...prev, instance]);\n\n return {\n destroy: () => removeModal(id),\n update: (newProps: Partial<ModalFuncProps>) =>\n updateModal(id, newProps),\n };\n },\n [removeModal, updateModal],\n );\n\n const api = useMemo<ModalStaticFunctions>(\n () => ({\n info: (props) => openModal('info', props),\n success: (props) => openModal('success', props),\n error: (props) => openModal('error', props),\n warning: (props) => openModal('warning', props),\n confirm: (props) =>\n openModal('confirm', { ...props, type: props.type || 'confirm' }),\n }),\n [openModal],\n );\n\n const contextHolder = (\n <>\n {modals.map((m) => {\n const isConfirmType = m.type === 'confirm';\n const handleOk = () => {\n m.props.onOk?.();\n removeModal(m.id);\n };\n const handleCancel = () => {\n m.props.onCancel?.();\n removeModal(m.id);\n };\n return (\n <OriginModal\n key={m.id}\n open={m.open}\n title={m.props.title}\n subTitle={m.props.subTitle}\n icon={m.props.icon || getIcon(m.type || 'info')}\n onOk={handleOk}\n onCancel={handleCancel}\n okText={m.props.okText}\n cancelText={m.props.cancelText}\n okButtonProps={m.props.okButtonProps}\n cancelButtonProps={m.props.cancelButtonProps}\n okType={m.props.okType || (isConfirmType ? 'dangerous' : 'primary')}\n width={m.props.width || DEFAULT_WIDTH}\n className={cn('ald-modal', m.props.className)}\n closable={m.props.closable}\n maskClosable={m.props.maskClosable}\n role={m.props.role}\n _modalType={m.type}\n footer={\n isConfirmType ? undefined : (\n <Button\n type=\"primary\"\n size=\"middle\"\n {...(m.props.okButtonProps || {})}\n onClick={handleOk}\n >\n {m.props.okText || 'OK'}\n </Button>\n )\n }\n >\n {m.props.content}\n </OriginModal>\n );\n })}\n </>\n );\n\n return [api, contextHolder];\n}\n\n// ---------- end useModal ----------\n\nconst Modal = OriginModal as typeof OriginModal & {\n info: ModalFunc;\n success: ModalFunc;\n error: ModalFunc;\n warning: ModalFunc;\n confirm: ModalFunc;\n destroyAll: () => void;\n useModal: typeof useModal;\n config: (config: any) => void;\n};\n\nModal.info = (props) => createStaticModal('info', props);\nModal.success = (props) => createStaticModal('success', props);\nModal.error = (props) => createStaticModal('error', props);\nModal.warning = (props) => createStaticModal('warning', props);\nModal.confirm = (props) =>\n createStaticModal('confirm', { ...props, type: props.type || 'confirm' });\n\nModal.destroyAll = () => {\n while (destroyFns.length) {\n const close = destroyFns.pop();\n if (close) close();\n }\n};\n\nModal.useModal = useModal;\nModal.config = () => {};\n\nexport default Modal;\n"],"mappings":"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"}
|
|
@@ -48,6 +48,16 @@ function OverflowCount(props) {
|
|
|
48
48
|
onOpenChange: (open) => setIsPopupOpen(open),
|
|
49
49
|
children: /* @__PURE__ */ jsx("div", {
|
|
50
50
|
className: cn(prefixCls("rest-btn"), "tw-flex tw-cursor-pointer tw-items-center"),
|
|
51
|
+
role: "button",
|
|
52
|
+
tabIndex: 0,
|
|
53
|
+
"aria-label": `Show ${omittedItems.length} more items`,
|
|
54
|
+
"aria-expanded": isPopupOpen,
|
|
55
|
+
onKeyDown: (event) => {
|
|
56
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
setIsPopupOpen((open) => !open);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
51
61
|
children: /* @__PURE__ */ jsx(Badge, {
|
|
52
62
|
count: `+${omittedItems.length}`,
|
|
53
63
|
status: "info",
|