@aloudata/aloudata-design 3.0.0 → 3.0.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/Dropdown/index.d.ts +8 -1
- package/dist/Dropdown/index.js +3 -1
- package/dist/Dropdown/index.js.map +1 -1
- package/dist/Form/index.js +1 -1
- package/dist/Form/index.js.map +1 -1
- package/dist/InputNumber/index.js +1 -0
- package/dist/InputNumber/index.js.map +1 -1
- package/dist/InputSearch/index.d.ts +3 -0
- package/dist/InputSearch/index.js +3 -1
- package/dist/InputSearch/index.js.map +1 -1
- package/dist/Tabs/index.js +3 -1
- package/dist/Tabs/index.js.map +1 -1
- package/dist/Tree/Tree.d.ts +11 -0
- package/dist/Tree/Tree2.js +84 -6
- package/dist/Tree/Tree2.js.map +1 -1
- package/dist/Tree/utils/composeAllowDrop.d.ts +14 -0
- package/dist/Tree/utils/composeAllowDrop.js +20 -0
- package/dist/Tree/utils/composeAllowDrop.js.map +1 -0
- package/dist/aloudata-design.css +1 -1
- package/dist/locale/zh_CN.js +1 -0
- package/dist/locale/zh_CN.js.map +1 -1
- package/package.json +2 -2
package/dist/Dropdown/index.d.ts
CHANGED
|
@@ -52,10 +52,17 @@ export interface IDropdownProps {
|
|
|
52
52
|
*/
|
|
53
53
|
onOpenChange?: (open: boolean) => void;
|
|
54
54
|
/**
|
|
55
|
-
* @description
|
|
55
|
+
* @description 下拉框外层 overlay 的内联样式(与定位 transform 合并)
|
|
56
56
|
* @default -
|
|
57
57
|
*/
|
|
58
58
|
overlayStyle?: React.CSSProperties;
|
|
59
|
+
/**
|
|
60
|
+
* @description 下拉框内层 surface 的内联样式。
|
|
61
|
+
* 用于覆盖 surface 默认约束(默认 min-width:160px、max-width:320px);
|
|
62
|
+
* 自定义 dropdownRender 内容若需大于 320px 宽,传 `{ width: 400, maxWidth: 'none' }` 即可。
|
|
63
|
+
* @default -
|
|
64
|
+
*/
|
|
65
|
+
overlayInnerStyle?: React.CSSProperties;
|
|
59
66
|
/**
|
|
60
67
|
* @description 自定义下拉框内容
|
|
61
68
|
* @default -
|
package/dist/Dropdown/index.js
CHANGED
|
@@ -19,7 +19,7 @@ function resolvePlacementSide(currentPlacement) {
|
|
|
19
19
|
return "bottom";
|
|
20
20
|
}
|
|
21
21
|
function Dropdown(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;
|
|
22
|
+
const { children, destroyPopupOnHide = true, getPopupContainer, menu, overlayClassName, placement = "bottom-start", trigger = "click", open, onOpenChange = () => {}, overlayStyle, overlayInnerStyle, dropdownRender, disabled, offset: offsetProps = 4, delay = 0, autoUpdatePos = false, initialFocus = -1, popupMatchTriggerWidth = false, allowOverlap = false } = props;
|
|
23
23
|
const [isOpen, setIsOpen] = useState(open || false);
|
|
24
24
|
const [isAnimatingOut, setIsAnimatingOut] = useState(false);
|
|
25
25
|
const closeAnimationTimerRef = useRef(null);
|
|
@@ -214,6 +214,7 @@ function Dropdown(props) {
|
|
|
214
214
|
...isAnimatingOut ? {} : getFloatingProps(),
|
|
215
215
|
children: /* @__PURE__ */ jsx("div", {
|
|
216
216
|
className: cn("ald-dropdown-surface", "tw-flex tw-flex-col tw-items-start tw-text-sm"),
|
|
217
|
+
style: overlayInnerStyle,
|
|
217
218
|
"data-state": isOpen ? "open" : "closed",
|
|
218
219
|
"data-side": resolvedFloatingSide,
|
|
219
220
|
children: popupElement
|
|
@@ -236,6 +237,7 @@ function Dropdown(props) {
|
|
|
236
237
|
refs.setFloating,
|
|
237
238
|
overlayClassName,
|
|
238
239
|
overlayStyle,
|
|
240
|
+
overlayInnerStyle,
|
|
239
241
|
popupZIndex,
|
|
240
242
|
overlayHidden,
|
|
241
243
|
isAnimatingOut,
|
|
@@ -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 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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"}
|
|
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 下拉框外层 overlay 的内联样式(与定位 transform 合并)\n * @default -\n */\n overlayStyle?: React.CSSProperties;\n /**\n * @description 下拉框内层 surface 的内联样式。\n * 用于覆盖 surface 默认约束(默认 min-width:160px、max-width:320px);\n * 自定义 dropdownRender 内容若需大于 320px 宽,传 `{ width: 400, maxWidth: 'none' }` 即可。\n * @default -\n */\n overlayInnerStyle?: 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 overlayInnerStyle,\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 style={overlayInnerStyle}\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 overlayInnerStyle,\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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"}
|
package/dist/Form/index.js
CHANGED
|
@@ -121,7 +121,7 @@ function FormItemLayout({ label, children, meta, help, extra, required, rules, h
|
|
|
121
121
|
const displayMessages = help !== null && help !== void 0 ? [help] : errors;
|
|
122
122
|
const hasError = status === "error" || errors.length > 0 && help === null;
|
|
123
123
|
const hasWarning = status === "warning" || warnings.length > 0 && help === null;
|
|
124
|
-
const labelNode = label !== null && label !== void 0 ? /* @__PURE__ */ jsx("div", {
|
|
124
|
+
const labelNode = label !== null && label !== void 0 && label !== "" ? /* @__PURE__ */ jsx("div", {
|
|
125
125
|
className: cn("ald-form-item-label ant-form-item-label", layout === "vertical" && "tw-mb-1 tw-block", layout === "horizontal" && "tw-mr-3 tw-shrink-0"),
|
|
126
126
|
style: useGridLayout ? colStyle(resolvedLabelCol) : void 0,
|
|
127
127
|
children: /* @__PURE__ */ jsxs("label", {
|
package/dist/Form/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/Form/index.tsx"],"sourcesContent":["import RcForm, {\n Field,\n FormInstance as RcFormInstance,\n FormProvider,\n List,\n useForm as rcUseForm,\n useWatch,\n} from 'rc-field-form';\nimport type { FormProps as RcFormProps } from 'rc-field-form';\nimport FieldContext from 'rc-field-form/es/FieldContext';\nimport type { Rule, RuleObject, RuleRender } from 'rc-field-form/es/interface';\nimport type { Meta, NamePath } from 'rc-field-form/es/interface';\nimport React, { forwardRef, useContext, useMemo } from 'react';\nimport SizeContext, {\n SizeContextProvider,\n} from '../ConfigProvider/sizeContext';\nimport DisabledContext from '../ConfigProvider/DisabledContext';\nimport { cn } from '../lib/utils';\nimport {\n FormContext,\n FormItemInputContext,\n type ValidateStatus,\n} from './FormItemContext';\n\n/**\n * Loose NamePath: accepts string, number, or array of them.\n * antd v4 uses loose paths; rc-field-form v2 uses strict DeepNamePath.\n * We override to keep backward compatibility.\n */\ntype LooseNamePath = string | number | (string | number)[];\n\n/**\n * FormInstance — extends rc-field-form FormInstance with loose-typed overloads\n * to maintain antd v4 backward compatibility. Uses intersection so that both\n * strict DeepNamePath and loose LooseNamePath signatures are accepted.\n */\nexport type FormInstance<Values = any> = RcFormInstance<Values> & {\n getFieldValue(name: LooseNamePath): any;\n setFieldValue(name: LooseNamePath, value: any): void;\n setFieldsValue(values: Record<string, any>): void;\n getFieldsValue(): Values;\n getFieldsValue(\n nameList: LooseNamePath[] | true,\n filterFunc?: (meta: Meta) => boolean,\n ): any;\n getFieldError(name: LooseNamePath): string[];\n getFieldsError(\n nameList?: LooseNamePath[],\n ): { name: (string | number)[]; errors: string[] }[];\n getFieldWarning(name: LooseNamePath): string[];\n isFieldTouched(name: LooseNamePath): boolean;\n isFieldsTouched(\n nameList?: LooseNamePath[],\n allFieldsTouched?: boolean,\n ): boolean;\n isFieldValidating(name: LooseNamePath): boolean;\n isFieldsValidating(nameList?: LooseNamePath[]): boolean;\n setFields(fields: FieldData[]): void;\n resetFields(fields?: LooseNamePath[]): void;\n validateFields(nameList?: LooseNamePath[]): Promise<Values>;\n /** Scroll to field position (antd-compatible extension) */\n scrollToField?(\n name: LooseNamePath,\n options?: { behavior?: 'smooth' | 'auto' },\n ): void;\n};\n\n// FormProps compatible with antd\nexport interface FormProps<Values = any> extends Omit<RcFormProps, 'form'> {\n form?: FormInstance<Values>;\n layout?: 'horizontal' | 'vertical' | 'inline';\n size?: 'small' | 'middle' | 'large';\n colon?: boolean;\n disabled?: boolean;\n labelCol?: { span?: number; offset?: number };\n wrapperCol?: { span?: number; offset?: number };\n className?: string;\n style?: React.CSSProperties;\n requiredMark?: boolean | 'optional';\n labelWidth?: number;\n labelAlign?: 'left' | 'right';\n}\n\n// FormItemProps\nexport interface FormItemProps {\n name?: NamePath;\n label?: React.ReactNode;\n rules?: Rule[];\n children?: React.ReactNode | ((form: RcFormInstance) => React.ReactNode);\n className?: string;\n style?: React.CSSProperties;\n required?: boolean;\n hidden?: boolean;\n initialValue?: any;\n dependencies?: NamePath[];\n shouldUpdate?: boolean | ((prevValues: any, curValues: any) => boolean);\n help?: React.ReactNode;\n extra?: React.ReactNode;\n validateTrigger?: string | string[];\n valuePropName?: string;\n getValueFromEvent?: (...args: any[]) => any;\n noStyle?: boolean;\n labelWidth?: number;\n tooltip?:\n | React.ReactNode\n | { title?: React.ReactNode; icon?: React.ReactNode };\n labelCol?: { span?: number; offset?: number; [key: string]: any };\n wrapperCol?: { span?: number; offset?: number; [key: string]: any };\n validateStatus?: ValidateStatus;\n colon?: boolean;\n trigger?: string;\n normalize?: (value: any, prevValue: any, allValues: any) => any;\n getValueProps?: (value: any) => Record<string, any>;\n}\n\n/** antd v4 compat: FormLabelAlign */\nexport type FormLabelAlign = 'left' | 'right';\n\n/** antd v4 compat: FieldData */\nexport type FieldData = {\n name: NamePath;\n value?: any;\n touched?: boolean;\n validating?: boolean;\n errors?: string[];\n};\n\nexport interface ErrorListProps {\n errors?: React.ReactNode[];\n help?: React.ReactNode;\n className?: string;\n}\n\nexport type FormListFieldData = {\n name: number;\n key: number;\n isListField: boolean;\n};\n\nexport type FormListOperation = {\n add: (defaultValue?: any, insertIndex?: number) => void;\n remove: (index: number | number[]) => void;\n move: (from: number, to: number) => void;\n};\n\nexport type FormListProps = {\n name: NamePath;\n rules?: Rule[];\n children: (\n fields: FormListFieldData[],\n operation: FormListOperation,\n meta: { errors: React.ReactNode[] },\n ) => React.ReactNode;\n initialValue?: any[];\n};\n\n// ============== Helpers ==============\n\n/** Convert a 24-column span/offset to Tailwind-compatible inline styles */\nfunction colStyle(col?: {\n span?: number;\n offset?: number;\n}): React.CSSProperties | undefined {\n if (!col) return undefined;\n const s: React.CSSProperties = {};\n if (col.span !== null && col.span !== undefined) {\n // 24-column grid: width = span / 24 * 100%\n s.width = `${(col.span / 24) * 100}%`;\n s.flex = `0 0 ${(col.span / 24) * 100}%`;\n }\n if (col.offset !== null && col.offset !== undefined && col.offset > 0) {\n s.marginLeft = `${(col.offset / 24) * 100}%`;\n }\n return s;\n}\n\nfunction mergeControlProps(\n childProps: Record<string, any>,\n control: Record<string, any>,\n) {\n const mergedControl = { ...control };\n\n Object.keys(control).forEach((key) => {\n const controlHandler = control[key];\n const childHandler = childProps[key];\n\n if (\n typeof controlHandler === 'function' &&\n typeof childHandler === 'function'\n ) {\n mergedControl[key] = (...args: any[]) => {\n controlHandler(...args);\n childHandler(...args);\n };\n }\n });\n\n return mergedControl;\n}\n\n// ============== Form ==============\n\nconst AldForm = forwardRef((props: any, ref: any) => {\n const contextSize = useContext(SizeContext);\n const {\n children,\n size = contextSize,\n labelWidth,\n style = {},\n className,\n layout = 'horizontal',\n disabled,\n labelCol,\n wrapperCol,\n colon = false,\n requiredMark,\n labelAlign,\n ...restProps\n } = props;\n const customStyle = {\n ...style,\n ...(labelWidth ? { '--label-width': `${labelWidth}px` } : {}),\n ...(labelAlign ? { '--label-align': labelAlign } : {}),\n };\n\n const formContextValue = useMemo(\n () => ({\n layout,\n labelCol,\n wrapperCol,\n colon,\n requiredMark,\n labelWidth,\n labelAlign,\n }),\n [layout, labelCol, wrapperCol, colon, requiredMark, labelWidth, labelAlign],\n );\n\n return (\n <FormContext.Provider value={formContextValue}>\n <DisabledContext.Provider value={disabled}>\n <SizeContextProvider size={size}>\n <RcForm\n style={customStyle}\n className={cn(\n 'ald-form ant-form',\n `ald-form-${layout}`,\n `ant-form-${layout}`,\n className,\n )}\n {...restProps}\n ref={ref}\n >\n {children}\n </RcForm>\n </SizeContextProvider>\n </DisabledContext.Provider>\n </FormContext.Provider>\n );\n}) as <Values = any>(\n props: React.PropsWithChildren<FormProps<Values>> & {\n ref?: React.Ref<FormInstance<Values>>;\n labelWidth?: number;\n },\n) => React.ReactElement;\n\n// ============== Form.Item ==============\n\ninterface IFormItemProps extends FormItemProps {\n labelWidth?: number;\n labelAlign?: 'left' | 'right';\n}\n\n/** Derive status from meta or manual validateStatus */\nfunction deriveStatus(\n meta?: Meta,\n validateStatus?: ValidateStatus,\n): ValidateStatus {\n if (validateStatus) return validateStatus;\n if (!meta) return '';\n if (meta.validating) return 'validating';\n if (meta.errors && meta.errors.length > 0) return 'error';\n if (meta.warnings && meta.warnings.length > 0) return 'warning';\n if (meta.touched) return 'success';\n return '';\n}\n\n/** Status-based border class for the control wrapper */\nfunction statusClassName(status: ValidateStatus): string {\n switch (status) {\n case 'error':\n return 'ald-form-item-has-error';\n case 'warning':\n return 'ald-form-item-has-warning';\n case 'success':\n return 'ald-form-item-has-success';\n case 'validating':\n return 'ald-form-item-is-validating';\n default:\n return '';\n }\n}\n\n/** Render the inner label + control layout, receiving meta from Field */\nfunction FormItemLayout({\n label,\n children,\n meta,\n help,\n extra,\n required,\n rules,\n hidden,\n className,\n customStyle,\n noStyle,\n labelCol: itemLabelCol,\n wrapperCol: itemWrapperCol,\n validateStatus: manualStatus,\n colon: itemColon,\n formContext,\n}: {\n label?: React.ReactNode;\n children: React.ReactNode;\n meta?: Meta;\n help?: React.ReactNode;\n extra?: React.ReactNode;\n required?: boolean;\n rules?: Rule[];\n hidden?: boolean;\n className?: string;\n customStyle?: React.CSSProperties;\n noStyle?: boolean;\n labelCol?: { span?: number; offset?: number };\n wrapperCol?: { span?: number; offset?: number };\n validateStatus?: ValidateStatus;\n colon?: boolean;\n formContext: {\n layout?: string;\n labelCol?: { span?: number; offset?: number };\n wrapperCol?: { span?: number; offset?: number };\n colon?: boolean;\n requiredMark?: boolean | 'optional';\n labelWidth?: number;\n };\n}) {\n const status = deriveStatus(meta, manualStatus);\n const errors = useMemo(() => meta?.errors ?? [], [meta?.errors]);\n const warnings = useMemo(() => meta?.warnings ?? [], [meta?.warnings]);\n\n // Provide status context to child controls\n const itemInputContextValue = useMemo(\n () => ({\n status,\n isFormItemInput: true,\n errors,\n warnings,\n }),\n [status, errors, warnings],\n );\n\n if (noStyle) {\n return <>{children}</>;\n }\n\n // Determine if we should show required mark\n const { requiredMark } = formContext;\n const rulesRequired =\n rules && rules.some((r: any) => typeof r === 'object' && r && r.required);\n const isRequired =\n required || rulesRequired || (meta && (meta as any).required);\n const showRequired = requiredMark !== false && isRequired;\n const showOptional = requiredMark === 'optional' && !isRequired;\n\n // Resolve cols: item-level overrides form-level\n const resolvedLabelCol = itemLabelCol ?? formContext.labelCol;\n const resolvedWrapperCol = itemWrapperCol ?? formContext.wrapperCol;\n const layout = formContext.layout || 'horizontal';\n const showColon =\n (itemColon ?? formContext.colon) !== false && layout === 'horizontal';\n\n // Decide whether to use grid-style layout\n const useGridLayout =\n layout === 'horizontal' && (resolvedLabelCol || resolvedWrapperCol);\n\n // Determine display errors: if help is provided, show help instead of validation errors\n const displayMessages = help !== null && help !== undefined ? [help] : errors;\n const hasError = status === 'error' || (errors.length > 0 && help === null);\n const hasWarning =\n status === 'warning' || (warnings.length > 0 && help === null);\n\n const labelNode =\n label !== null && label !== undefined ? (\n <div\n className={cn(\n 'ald-form-item-label ant-form-item-label',\n // tw-block 不能省:label 容器同时挂了 ant-form-item-label 兼容 class,\n // 消费方残留的 antd 样式会把它设为 inline-block,导致 vertical 布局下\n // label 缩成内容宽而非整行铺在控件上方\n layout === 'vertical' && 'tw-mb-1 tw-block',\n layout === 'horizontal' && 'tw-mr-3 tw-shrink-0',\n )}\n style={useGridLayout ? colStyle(resolvedLabelCol) : undefined}\n >\n <label\n className={cn(\n 'tw-text-sm tw-font-medium tw-text-[var(--alias-colors-text-subtle,var(--content-secondary))]',\n !showColon && 'ant-form-item-no-colon',\n )}\n >\n {showRequired && (\n <span className=\"tw-mr-1 tw-text-[var(--content-negative-primary)]\">\n *\n </span>\n )}\n {label}\n {showOptional && (\n <span className=\"tw-ml-1 tw-text-xs tw-font-normal tw-text-[var(--content-secondary)]\">\n (optional)\n </span>\n )}\n {showColon && label ? ':' : null}\n </label>\n </div>\n ) : null;\n\n const controlNode = (\n <div\n className={cn(\n 'ald-form-item-control ant-form-item-control',\n layout === 'horizontal' && 'tw-flex-1',\n )}\n style={useGridLayout ? colStyle(resolvedWrapperCol) : undefined}\n >\n <FormItemInputContext.Provider value={itemInputContextValue}>\n <div className=\"ald-form-item-control-input\">{children}</div>\n </FormItemInputContext.Provider>\n {/* 始终渲染错误容器,避免 DOM 增删触发 Radix FocusScope MutationObserver 劫持焦点 */}\n <div\n className={cn(\n 'ald-form-item-explain ant-form-item-explain tw-text-xs tw-transition-all tw-duration-200',\n displayMessages.length > 0 && 'tw-mt-1',\n hasError && 'tw-text-[var(--content-negative-secondary)]',\n hasWarning &&\n !hasError &&\n 'tw-text-[color:var(--content-warning-primary,#faad14)]',\n !hasError &&\n !hasWarning &&\n help !== null &&\n help !== undefined &&\n 'tw-text-[var(--content-secondary)]',\n )}\n style={displayMessages.length === 0 ? { display: 'none' } : undefined}\n >\n {displayMessages.map((msg, i) => (\n <div key={i}>{msg}</div>\n ))}\n </div>\n {extra && (\n <div className=\"ald-form-item-extra tw-mt-1 tw-text-xs tw-text-[var(--content-secondary)]\">\n {extra}\n </div>\n )}\n </div>\n );\n\n return (\n <div\n className={cn(\n 'ald-form-item ant-form-item ant-row tw-mb-6',\n hidden && 'tw-hidden',\n showRequired && 'ald-form-item-required',\n statusClassName(status),\n layout === 'horizontal' && 'tw-flex tw-flex-row tw-items-start',\n layout === 'inline' &&\n 'tw-mr-4 tw-inline-flex tw-flex-row tw-items-start',\n className,\n )}\n style={customStyle as React.CSSProperties}\n >\n {labelNode}\n {controlNode}\n </div>\n );\n}\n\nconst AldFormItem = function (props: IFormItemProps) {\n const {\n labelWidth,\n style = {},\n label,\n name,\n rules,\n children,\n className,\n required,\n hidden,\n initialValue,\n dependencies,\n shouldUpdate,\n help,\n extra,\n validateTrigger,\n valuePropName,\n getValueFromEvent,\n normalize,\n getValueProps,\n noStyle,\n labelCol,\n wrapperCol,\n validateStatus,\n colon,\n trigger,\n } = props;\n\n const formContext = useContext(FormContext);\n\n const customStyle = {\n ...style,\n ...(labelWidth ? { '--label-width': `${labelWidth}px` } : {}),\n ...(props.labelAlign ? { '--label-align': props.labelAlign } : {}),\n };\n\n // If no name is provided (e.g. a submit button wrapper), we don't need Field\n // Also when shouldUpdate or dependencies are used without name, Field is still needed for re-render\n const needField =\n (name !== null && name !== undefined) ||\n (shouldUpdate !== null && shouldUpdate !== undefined) ||\n (dependencies !== null && dependencies !== undefined);\n\n if (!needField) {\n return (\n <FormItemLayout\n label={label}\n help={help}\n extra={extra}\n required={required}\n rules={rules}\n hidden={hidden}\n className={className}\n customStyle={customStyle as React.CSSProperties}\n noStyle={noStyle}\n labelCol={labelCol}\n wrapperCol={wrapperCol}\n validateStatus={validateStatus}\n colon={colon}\n formContext={formContext}\n >\n {children as React.ReactNode}\n </FormItemLayout>\n );\n }\n\n return (\n <Field\n name={name}\n rules={rules}\n initialValue={initialValue}\n dependencies={dependencies}\n shouldUpdate={shouldUpdate}\n validateTrigger={validateTrigger}\n trigger={trigger}\n valuePropName={valuePropName}\n getValueFromEvent={getValueFromEvent}\n normalize={normalize}\n getValueProps={getValueProps}\n >\n {(control, meta, form) => {\n // If children is a render function (shouldUpdate / dependencies pattern),\n // call it with the form instance and wrap in layout\n if (typeof children === 'function') {\n const childContent = (\n children as (form: RcFormInstance) => React.ReactNode\n )(form);\n if (noStyle) {\n return childContent;\n }\n return (\n <FormItemLayout\n label={label}\n meta={meta}\n help={help}\n extra={extra}\n required={required}\n rules={rules}\n hidden={hidden}\n className={className}\n customStyle={customStyle as React.CSSProperties}\n noStyle={noStyle}\n labelCol={labelCol}\n wrapperCol={wrapperCol}\n validateStatus={validateStatus}\n colon={colon}\n formContext={formContext}\n >\n {childContent}\n </FormItemLayout>\n );\n }\n\n // For noStyle, just clone with control props\n if (noStyle) {\n if (React.isValidElement(children)) {\n return React.cloneElement(\n children as React.ReactElement<any>,\n mergeControlProps(\n (children as React.ReactElement<any>).props,\n control,\n ),\n );\n }\n return children;\n }\n\n // Clone control props onto the single child element\n let childNode: React.ReactNode = children;\n if (React.isValidElement(children)) {\n childNode = React.cloneElement(\n children as React.ReactElement<any>,\n mergeControlProps(\n (children as React.ReactElement<any>).props,\n control,\n ),\n );\n }\n\n return (\n <FormItemLayout\n label={label}\n meta={meta}\n help={help}\n extra={extra}\n required={required}\n rules={rules}\n hidden={hidden}\n className={className}\n customStyle={customStyle as React.CSSProperties}\n labelCol={labelCol}\n wrapperCol={wrapperCol}\n validateStatus={validateStatus}\n colon={colon}\n formContext={formContext}\n >\n {childNode}\n </FormItemLayout>\n );\n }}\n </Field>\n );\n};\n\nfunction useFormItemStatus() {\n const ctx = useContext(FormItemInputContext);\n return {\n status: ctx.status,\n errors: ctx.errors ?? [],\n warnings: ctx.warnings ?? [],\n };\n}\n\nAldFormItem.useStatus = useFormItemStatus;\n\n// ============== ErrorList ==============\n\nfunction ErrorListComponent(props: ErrorListProps) {\n const { errors, className } = props;\n if (!errors || errors.length === 0) return null;\n return (\n <div className={cn('ald-form-error-list', className)}>\n {errors.map((err, i) => (\n <div\n key={i}\n className=\"tw-text-xs tw-text-[var(--content-negative-secondary)]\"\n >\n {err}\n </div>\n ))}\n </div>\n );\n}\n\n// ============== useFormInstance ==============\n\nfunction useFormInstance<T = any>(): FormInstance<T> {\n const form = useContext(FieldContext);\n return form as unknown as FormInstance<T>;\n}\n\n// ============== Compound component ==============\n\ntype InternalFormType = typeof AldForm;\ntype CompoundedComponent = InternalFormType & {\n useForm: <T = any>(...args: any[]) => [FormInstance<T>];\n useFormInstance: typeof useFormInstance;\n /** Loose-typed useWatch for antd v4 compat */\n useWatch: <T = any>(name: LooseNamePath, form?: FormInstance) => T;\n Item: typeof AldFormItem;\n List: typeof List;\n ErrorList: typeof ErrorListComponent;\n Provider: typeof FormProvider;\n create: () => void;\n};\n\nconst Form = AldForm as CompoundedComponent;\n\nForm.Item = AldFormItem;\nForm.List = List;\nForm.ErrorList = ErrorListComponent;\nForm.useForm = rcUseForm as CompoundedComponent['useForm'];\nForm.useFormInstance = useFormInstance;\nForm.useWatch = useWatch;\nForm.Provider = FormProvider;\nForm.create = () => {\n console.warn('Form.create is deprecated. Please use Form.useForm() instead.');\n};\n\nexport type { Rule, RuleObject, RuleRender };\nexport default Form;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/Form/index.tsx"],"sourcesContent":["import RcForm, {\n Field,\n FormInstance as RcFormInstance,\n FormProvider,\n List,\n useForm as rcUseForm,\n useWatch,\n} from 'rc-field-form';\nimport type { FormProps as RcFormProps } from 'rc-field-form';\nimport FieldContext from 'rc-field-form/es/FieldContext';\nimport type { Rule, RuleObject, RuleRender } from 'rc-field-form/es/interface';\nimport type { Meta, NamePath } from 'rc-field-form/es/interface';\nimport React, { forwardRef, useContext, useMemo } from 'react';\nimport SizeContext, {\n SizeContextProvider,\n} from '../ConfigProvider/sizeContext';\nimport DisabledContext from '../ConfigProvider/DisabledContext';\nimport { cn } from '../lib/utils';\nimport {\n FormContext,\n FormItemInputContext,\n type ValidateStatus,\n} from './FormItemContext';\n\n/**\n * Loose NamePath: accepts string, number, or array of them.\n * antd v4 uses loose paths; rc-field-form v2 uses strict DeepNamePath.\n * We override to keep backward compatibility.\n */\ntype LooseNamePath = string | number | (string | number)[];\n\n/**\n * FormInstance — extends rc-field-form FormInstance with loose-typed overloads\n * to maintain antd v4 backward compatibility. Uses intersection so that both\n * strict DeepNamePath and loose LooseNamePath signatures are accepted.\n */\nexport type FormInstance<Values = any> = RcFormInstance<Values> & {\n getFieldValue(name: LooseNamePath): any;\n setFieldValue(name: LooseNamePath, value: any): void;\n setFieldsValue(values: Record<string, any>): void;\n getFieldsValue(): Values;\n getFieldsValue(\n nameList: LooseNamePath[] | true,\n filterFunc?: (meta: Meta) => boolean,\n ): any;\n getFieldError(name: LooseNamePath): string[];\n getFieldsError(\n nameList?: LooseNamePath[],\n ): { name: (string | number)[]; errors: string[] }[];\n getFieldWarning(name: LooseNamePath): string[];\n isFieldTouched(name: LooseNamePath): boolean;\n isFieldsTouched(\n nameList?: LooseNamePath[],\n allFieldsTouched?: boolean,\n ): boolean;\n isFieldValidating(name: LooseNamePath): boolean;\n isFieldsValidating(nameList?: LooseNamePath[]): boolean;\n setFields(fields: FieldData[]): void;\n resetFields(fields?: LooseNamePath[]): void;\n validateFields(nameList?: LooseNamePath[]): Promise<Values>;\n /** Scroll to field position (antd-compatible extension) */\n scrollToField?(\n name: LooseNamePath,\n options?: { behavior?: 'smooth' | 'auto' },\n ): void;\n};\n\n// FormProps compatible with antd\nexport interface FormProps<Values = any> extends Omit<RcFormProps, 'form'> {\n form?: FormInstance<Values>;\n layout?: 'horizontal' | 'vertical' | 'inline';\n size?: 'small' | 'middle' | 'large';\n colon?: boolean;\n disabled?: boolean;\n labelCol?: { span?: number; offset?: number };\n wrapperCol?: { span?: number; offset?: number };\n className?: string;\n style?: React.CSSProperties;\n requiredMark?: boolean | 'optional';\n labelWidth?: number;\n labelAlign?: 'left' | 'right';\n}\n\n// FormItemProps\nexport interface FormItemProps {\n name?: NamePath;\n label?: React.ReactNode;\n rules?: Rule[];\n children?: React.ReactNode | ((form: RcFormInstance) => React.ReactNode);\n className?: string;\n style?: React.CSSProperties;\n required?: boolean;\n hidden?: boolean;\n initialValue?: any;\n dependencies?: NamePath[];\n shouldUpdate?: boolean | ((prevValues: any, curValues: any) => boolean);\n help?: React.ReactNode;\n extra?: React.ReactNode;\n validateTrigger?: string | string[];\n valuePropName?: string;\n getValueFromEvent?: (...args: any[]) => any;\n noStyle?: boolean;\n labelWidth?: number;\n tooltip?:\n | React.ReactNode\n | { title?: React.ReactNode; icon?: React.ReactNode };\n labelCol?: { span?: number; offset?: number; [key: string]: any };\n wrapperCol?: { span?: number; offset?: number; [key: string]: any };\n validateStatus?: ValidateStatus;\n colon?: boolean;\n trigger?: string;\n normalize?: (value: any, prevValue: any, allValues: any) => any;\n getValueProps?: (value: any) => Record<string, any>;\n}\n\n/** antd v4 compat: FormLabelAlign */\nexport type FormLabelAlign = 'left' | 'right';\n\n/** antd v4 compat: FieldData */\nexport type FieldData = {\n name: NamePath;\n value?: any;\n touched?: boolean;\n validating?: boolean;\n errors?: string[];\n};\n\nexport interface ErrorListProps {\n errors?: React.ReactNode[];\n help?: React.ReactNode;\n className?: string;\n}\n\nexport type FormListFieldData = {\n name: number;\n key: number;\n isListField: boolean;\n};\n\nexport type FormListOperation = {\n add: (defaultValue?: any, insertIndex?: number) => void;\n remove: (index: number | number[]) => void;\n move: (from: number, to: number) => void;\n};\n\nexport type FormListProps = {\n name: NamePath;\n rules?: Rule[];\n children: (\n fields: FormListFieldData[],\n operation: FormListOperation,\n meta: { errors: React.ReactNode[] },\n ) => React.ReactNode;\n initialValue?: any[];\n};\n\n// ============== Helpers ==============\n\n/** Convert a 24-column span/offset to Tailwind-compatible inline styles */\nfunction colStyle(col?: {\n span?: number;\n offset?: number;\n}): React.CSSProperties | undefined {\n if (!col) return undefined;\n const s: React.CSSProperties = {};\n if (col.span !== null && col.span !== undefined) {\n // 24-column grid: width = span / 24 * 100%\n s.width = `${(col.span / 24) * 100}%`;\n s.flex = `0 0 ${(col.span / 24) * 100}%`;\n }\n if (col.offset !== null && col.offset !== undefined && col.offset > 0) {\n s.marginLeft = `${(col.offset / 24) * 100}%`;\n }\n return s;\n}\n\nfunction mergeControlProps(\n childProps: Record<string, any>,\n control: Record<string, any>,\n) {\n const mergedControl = { ...control };\n\n Object.keys(control).forEach((key) => {\n const controlHandler = control[key];\n const childHandler = childProps[key];\n\n if (\n typeof controlHandler === 'function' &&\n typeof childHandler === 'function'\n ) {\n mergedControl[key] = (...args: any[]) => {\n controlHandler(...args);\n childHandler(...args);\n };\n }\n });\n\n return mergedControl;\n}\n\n// ============== Form ==============\n\nconst AldForm = forwardRef((props: any, ref: any) => {\n const contextSize = useContext(SizeContext);\n const {\n children,\n size = contextSize,\n labelWidth,\n style = {},\n className,\n layout = 'horizontal',\n disabled,\n labelCol,\n wrapperCol,\n colon = false,\n requiredMark,\n labelAlign,\n ...restProps\n } = props;\n const customStyle = {\n ...style,\n ...(labelWidth ? { '--label-width': `${labelWidth}px` } : {}),\n ...(labelAlign ? { '--label-align': labelAlign } : {}),\n };\n\n const formContextValue = useMemo(\n () => ({\n layout,\n labelCol,\n wrapperCol,\n colon,\n requiredMark,\n labelWidth,\n labelAlign,\n }),\n [layout, labelCol, wrapperCol, colon, requiredMark, labelWidth, labelAlign],\n );\n\n return (\n <FormContext.Provider value={formContextValue}>\n <DisabledContext.Provider value={disabled}>\n <SizeContextProvider size={size}>\n <RcForm\n style={customStyle}\n className={cn(\n 'ald-form ant-form',\n `ald-form-${layout}`,\n `ant-form-${layout}`,\n className,\n )}\n {...restProps}\n ref={ref}\n >\n {children}\n </RcForm>\n </SizeContextProvider>\n </DisabledContext.Provider>\n </FormContext.Provider>\n );\n}) as <Values = any>(\n props: React.PropsWithChildren<FormProps<Values>> & {\n ref?: React.Ref<FormInstance<Values>>;\n labelWidth?: number;\n },\n) => React.ReactElement;\n\n// ============== Form.Item ==============\n\ninterface IFormItemProps extends FormItemProps {\n labelWidth?: number;\n labelAlign?: 'left' | 'right';\n}\n\n/** Derive status from meta or manual validateStatus */\nfunction deriveStatus(\n meta?: Meta,\n validateStatus?: ValidateStatus,\n): ValidateStatus {\n if (validateStatus) return validateStatus;\n if (!meta) return '';\n if (meta.validating) return 'validating';\n if (meta.errors && meta.errors.length > 0) return 'error';\n if (meta.warnings && meta.warnings.length > 0) return 'warning';\n if (meta.touched) return 'success';\n return '';\n}\n\n/** Status-based border class for the control wrapper */\nfunction statusClassName(status: ValidateStatus): string {\n switch (status) {\n case 'error':\n return 'ald-form-item-has-error';\n case 'warning':\n return 'ald-form-item-has-warning';\n case 'success':\n return 'ald-form-item-has-success';\n case 'validating':\n return 'ald-form-item-is-validating';\n default:\n return '';\n }\n}\n\n/** Render the inner label + control layout, receiving meta from Field */\nfunction FormItemLayout({\n label,\n children,\n meta,\n help,\n extra,\n required,\n rules,\n hidden,\n className,\n customStyle,\n noStyle,\n labelCol: itemLabelCol,\n wrapperCol: itemWrapperCol,\n validateStatus: manualStatus,\n colon: itemColon,\n formContext,\n}: {\n label?: React.ReactNode;\n children: React.ReactNode;\n meta?: Meta;\n help?: React.ReactNode;\n extra?: React.ReactNode;\n required?: boolean;\n rules?: Rule[];\n hidden?: boolean;\n className?: string;\n customStyle?: React.CSSProperties;\n noStyle?: boolean;\n labelCol?: { span?: number; offset?: number };\n wrapperCol?: { span?: number; offset?: number };\n validateStatus?: ValidateStatus;\n colon?: boolean;\n formContext: {\n layout?: string;\n labelCol?: { span?: number; offset?: number };\n wrapperCol?: { span?: number; offset?: number };\n colon?: boolean;\n requiredMark?: boolean | 'optional';\n labelWidth?: number;\n };\n}) {\n const status = deriveStatus(meta, manualStatus);\n const errors = useMemo(() => meta?.errors ?? [], [meta?.errors]);\n const warnings = useMemo(() => meta?.warnings ?? [], [meta?.warnings]);\n\n // Provide status context to child controls\n const itemInputContextValue = useMemo(\n () => ({\n status,\n isFormItemInput: true,\n errors,\n warnings,\n }),\n [status, errors, warnings],\n );\n\n if (noStyle) {\n return <>{children}</>;\n }\n\n // Determine if we should show required mark\n const { requiredMark } = formContext;\n const rulesRequired =\n rules && rules.some((r: any) => typeof r === 'object' && r && r.required);\n const isRequired =\n required || rulesRequired || (meta && (meta as any).required);\n const showRequired = requiredMark !== false && isRequired;\n const showOptional = requiredMark === 'optional' && !isRequired;\n\n // Resolve cols: item-level overrides form-level\n const resolvedLabelCol = itemLabelCol ?? formContext.labelCol;\n const resolvedWrapperCol = itemWrapperCol ?? formContext.wrapperCol;\n const layout = formContext.layout || 'horizontal';\n const showColon =\n (itemColon ?? formContext.colon) !== false && layout === 'horizontal';\n\n // Decide whether to use grid-style layout\n const useGridLayout =\n layout === 'horizontal' && (resolvedLabelCol || resolvedWrapperCol);\n\n // Determine display errors: if help is provided, show help instead of validation errors\n const displayMessages = help !== null && help !== undefined ? [help] : errors;\n const hasError = status === 'error' || (errors.length > 0 && help === null);\n const hasWarning =\n status === 'warning' || (warnings.length > 0 && help === null);\n const hasLabel = label !== null && label !== undefined && label !== '';\n\n const labelNode = hasLabel ? (\n <div\n className={cn(\n 'ald-form-item-label ant-form-item-label',\n // tw-block 不能省:label 容器同时挂了 ant-form-item-label 兼容 class,\n // 消费方残留的 antd 样式会把它设为 inline-block,导致 vertical 布局下\n // label 缩成内容宽而非整行铺在控件上方\n layout === 'vertical' && 'tw-mb-1 tw-block',\n layout === 'horizontal' && 'tw-mr-3 tw-shrink-0',\n )}\n style={useGridLayout ? colStyle(resolvedLabelCol) : undefined}\n >\n <label\n className={cn(\n 'tw-text-sm tw-font-medium tw-text-[var(--alias-colors-text-subtle,var(--content-secondary))]',\n !showColon && 'ant-form-item-no-colon',\n )}\n >\n {showRequired && (\n <span className=\"tw-mr-1 tw-text-[var(--content-negative-primary)]\">\n *\n </span>\n )}\n {label}\n {showOptional && (\n <span className=\"tw-ml-1 tw-text-xs tw-font-normal tw-text-[var(--content-secondary)]\">\n (optional)\n </span>\n )}\n {showColon && label ? ':' : null}\n </label>\n </div>\n ) : null;\n\n const controlNode = (\n <div\n className={cn(\n 'ald-form-item-control ant-form-item-control',\n layout === 'horizontal' && 'tw-flex-1',\n )}\n style={useGridLayout ? colStyle(resolvedWrapperCol) : undefined}\n >\n <FormItemInputContext.Provider value={itemInputContextValue}>\n <div className=\"ald-form-item-control-input\">{children}</div>\n </FormItemInputContext.Provider>\n {/* 始终渲染错误容器,避免 DOM 增删触发 Radix FocusScope MutationObserver 劫持焦点 */}\n <div\n className={cn(\n 'ald-form-item-explain ant-form-item-explain tw-text-xs tw-transition-all tw-duration-200',\n displayMessages.length > 0 && 'tw-mt-1',\n hasError && 'tw-text-[var(--content-negative-secondary)]',\n hasWarning &&\n !hasError &&\n 'tw-text-[color:var(--content-warning-primary,#faad14)]',\n !hasError &&\n !hasWarning &&\n help !== null &&\n help !== undefined &&\n 'tw-text-[var(--content-secondary)]',\n )}\n style={displayMessages.length === 0 ? { display: 'none' } : undefined}\n >\n {displayMessages.map((msg, i) => (\n <div key={i}>{msg}</div>\n ))}\n </div>\n {extra && (\n <div className=\"ald-form-item-extra tw-mt-1 tw-text-xs tw-text-[var(--content-secondary)]\">\n {extra}\n </div>\n )}\n </div>\n );\n\n return (\n <div\n className={cn(\n 'ald-form-item ant-form-item ant-row tw-mb-6',\n hidden && 'tw-hidden',\n showRequired && 'ald-form-item-required',\n statusClassName(status),\n layout === 'horizontal' && 'tw-flex tw-flex-row tw-items-start',\n layout === 'inline' &&\n 'tw-mr-4 tw-inline-flex tw-flex-row tw-items-start',\n className,\n )}\n style={customStyle as React.CSSProperties}\n >\n {labelNode}\n {controlNode}\n </div>\n );\n}\n\nconst AldFormItem = function (props: IFormItemProps) {\n const {\n labelWidth,\n style = {},\n label,\n name,\n rules,\n children,\n className,\n required,\n hidden,\n initialValue,\n dependencies,\n shouldUpdate,\n help,\n extra,\n validateTrigger,\n valuePropName,\n getValueFromEvent,\n normalize,\n getValueProps,\n noStyle,\n labelCol,\n wrapperCol,\n validateStatus,\n colon,\n trigger,\n } = props;\n\n const formContext = useContext(FormContext);\n\n const customStyle = {\n ...style,\n ...(labelWidth ? { '--label-width': `${labelWidth}px` } : {}),\n ...(props.labelAlign ? { '--label-align': props.labelAlign } : {}),\n };\n\n // If no name is provided (e.g. a submit button wrapper), we don't need Field\n // Also when shouldUpdate or dependencies are used without name, Field is still needed for re-render\n const needField =\n (name !== null && name !== undefined) ||\n (shouldUpdate !== null && shouldUpdate !== undefined) ||\n (dependencies !== null && dependencies !== undefined);\n\n if (!needField) {\n return (\n <FormItemLayout\n label={label}\n help={help}\n extra={extra}\n required={required}\n rules={rules}\n hidden={hidden}\n className={className}\n customStyle={customStyle as React.CSSProperties}\n noStyle={noStyle}\n labelCol={labelCol}\n wrapperCol={wrapperCol}\n validateStatus={validateStatus}\n colon={colon}\n formContext={formContext}\n >\n {children as React.ReactNode}\n </FormItemLayout>\n );\n }\n\n return (\n <Field\n name={name}\n rules={rules}\n initialValue={initialValue}\n dependencies={dependencies}\n shouldUpdate={shouldUpdate}\n validateTrigger={validateTrigger}\n trigger={trigger}\n valuePropName={valuePropName}\n getValueFromEvent={getValueFromEvent}\n normalize={normalize}\n getValueProps={getValueProps}\n >\n {(control, meta, form) => {\n // If children is a render function (shouldUpdate / dependencies pattern),\n // call it with the form instance and wrap in layout\n if (typeof children === 'function') {\n const childContent = (\n children as (form: RcFormInstance) => React.ReactNode\n )(form);\n if (noStyle) {\n return childContent;\n }\n return (\n <FormItemLayout\n label={label}\n meta={meta}\n help={help}\n extra={extra}\n required={required}\n rules={rules}\n hidden={hidden}\n className={className}\n customStyle={customStyle as React.CSSProperties}\n noStyle={noStyle}\n labelCol={labelCol}\n wrapperCol={wrapperCol}\n validateStatus={validateStatus}\n colon={colon}\n formContext={formContext}\n >\n {childContent}\n </FormItemLayout>\n );\n }\n\n // For noStyle, just clone with control props\n if (noStyle) {\n if (React.isValidElement(children)) {\n return React.cloneElement(\n children as React.ReactElement<any>,\n mergeControlProps(\n (children as React.ReactElement<any>).props,\n control,\n ),\n );\n }\n return children;\n }\n\n // Clone control props onto the single child element\n let childNode: React.ReactNode = children;\n if (React.isValidElement(children)) {\n childNode = React.cloneElement(\n children as React.ReactElement<any>,\n mergeControlProps(\n (children as React.ReactElement<any>).props,\n control,\n ),\n );\n }\n\n return (\n <FormItemLayout\n label={label}\n meta={meta}\n help={help}\n extra={extra}\n required={required}\n rules={rules}\n hidden={hidden}\n className={className}\n customStyle={customStyle as React.CSSProperties}\n labelCol={labelCol}\n wrapperCol={wrapperCol}\n validateStatus={validateStatus}\n colon={colon}\n formContext={formContext}\n >\n {childNode}\n </FormItemLayout>\n );\n }}\n </Field>\n );\n};\n\nfunction useFormItemStatus() {\n const ctx = useContext(FormItemInputContext);\n return {\n status: ctx.status,\n errors: ctx.errors ?? [],\n warnings: ctx.warnings ?? [],\n };\n}\n\nAldFormItem.useStatus = useFormItemStatus;\n\n// ============== ErrorList ==============\n\nfunction ErrorListComponent(props: ErrorListProps) {\n const { errors, className } = props;\n if (!errors || errors.length === 0) return null;\n return (\n <div className={cn('ald-form-error-list', className)}>\n {errors.map((err, i) => (\n <div\n key={i}\n className=\"tw-text-xs tw-text-[var(--content-negative-secondary)]\"\n >\n {err}\n </div>\n ))}\n </div>\n );\n}\n\n// ============== useFormInstance ==============\n\nfunction useFormInstance<T = any>(): FormInstance<T> {\n const form = useContext(FieldContext);\n return form as unknown as FormInstance<T>;\n}\n\n// ============== Compound component ==============\n\ntype InternalFormType = typeof AldForm;\ntype CompoundedComponent = InternalFormType & {\n useForm: <T = any>(...args: any[]) => [FormInstance<T>];\n useFormInstance: typeof useFormInstance;\n /** Loose-typed useWatch for antd v4 compat */\n useWatch: <T = any>(name: LooseNamePath, form?: FormInstance) => T;\n Item: typeof AldFormItem;\n List: typeof List;\n ErrorList: typeof ErrorListComponent;\n Provider: typeof FormProvider;\n create: () => void;\n};\n\nconst Form = AldForm as CompoundedComponent;\n\nForm.Item = AldFormItem;\nForm.List = List;\nForm.ErrorList = ErrorListComponent;\nForm.useForm = rcUseForm as CompoundedComponent['useForm'];\nForm.useFormInstance = useFormInstance;\nForm.useWatch = useWatch;\nForm.Provider = FormProvider;\nForm.create = () => {\n console.warn('Form.create is deprecated. Please use Form.useForm() instead.');\n};\n\nexport type { Rule, RuleObject, RuleRender };\nexport default Form;\n"],"mappings":"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"}
|
|
@@ -88,6 +88,7 @@ function InputNumber(props) {
|
|
|
88
88
|
id,
|
|
89
89
|
type: "text",
|
|
90
90
|
inputMode: "numeric",
|
|
91
|
+
size: 1,
|
|
91
92
|
className: cn("tw-min-w-0 tw-flex-1 tw-border-0 tw-bg-transparent tw-px-[7px] tw-text-inherit tw-outline-none", mergedDisabled && "tw-cursor-not-allowed tw-text-[var(--content-secondary)]"),
|
|
92
93
|
value: displayValue,
|
|
93
94
|
onChange: handleChange,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/InputNumber/index.tsx"],"sourcesContent":["import React, {\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport DisabledContext from '../ConfigProvider/DisabledContext';\nimport SizeContext from '../ConfigProvider/sizeContext';\nimport { cn } from '../lib/utils';\nimport { IInputNumberProps } from './type';\n\nexport default function InputNumber(props: IInputNumberProps) {\n const {\n className,\n disabled: customDisabled,\n size: customSize,\n status,\n value: controlledValue,\n defaultValue,\n min = -Infinity,\n max = Infinity,\n step = 1,\n precision,\n onChange,\n onPressEnter,\n onBlur,\n onFocus,\n formatter,\n parser,\n prefix,\n addonBefore,\n addonAfter,\n placeholder,\n autoFocus,\n bordered = true,\n keyboard = true,\n readonly: readOnly,\n style,\n id,\n } = props;\n\n const contentSize = useContext(SizeContext);\n const size = customSize || contentSize || 'middle';\n const disabled = useContext(DisabledContext);\n const mergedDisabled = customDisabled ?? disabled;\n\n const isControlled = 'value' in props;\n const [innerValue, setInnerValue] = useState<number | null | undefined>(\n defaultValue ?? null,\n );\n const currentValue = isControlled ? controlledValue : innerValue;\n\n const [inputStr, setInputStr] = useState(\n currentValue !== null && currentValue !== undefined\n ? String(currentValue)\n : '',\n );\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (currentValue !== null && currentValue !== undefined) {\n setInputStr(String(currentValue));\n } else {\n setInputStr('');\n }\n }, [currentValue]);\n\n const clamp = useCallback(\n (val: number) => {\n let v = Math.max(min, Math.min(max, val));\n if (precision !== undefined) {\n v = Number(v.toFixed(precision));\n }\n return v;\n },\n [min, max, precision],\n );\n\n const updateValue = useCallback(\n (newVal: number | null) => {\n const clamped = newVal !== null ? clamp(newVal) : null;\n if (!isControlled) setInnerValue(clamped);\n onChange?.(clamped);\n },\n [clamp, isControlled, onChange],\n );\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const raw = e.target.value;\n setInputStr(raw);\n if (raw === '' || raw === '-') return;\n const parsed = parser ? parser(raw) : Number(raw);\n if (!isNaN(parsed)) {\n updateValue(parsed);\n }\n };\n\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n if (inputStr === '' || inputStr === '-') {\n updateValue(null);\n setInputStr('');\n } else {\n const parsed = parser ? parser(inputStr) : Number(inputStr);\n if (!isNaN(parsed)) {\n const clamped = clamp(parsed);\n updateValue(clamped);\n setInputStr(String(clamped));\n }\n }\n onBlur?.(e);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n onPressEnter?.(e);\n }\n if (!keyboard) return;\n const numStep = typeof step === 'string' ? Number(step) : step;\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n updateValue(clamp((currentValue ?? 0) + numStep));\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n updateValue(clamp((currentValue ?? 0) - numStep));\n }\n };\n\n const displayValue = formatter\n ? formatter(currentValue ?? undefined, {\n userTyping: document.activeElement === inputRef.current,\n input: inputStr,\n })\n : inputStr;\n\n const hasAddon = addonBefore || addonAfter;\n\n const sizeClasses = cn(\n size === 'large' && 'ald-input-number-large tw-h-9 tw-text-base',\n size === 'small' && 'ald-input-number-small tw-h-7 tw-text-xs',\n size !== 'large' &&\n size !== 'small' &&\n 'ald-input-number-middle tw-h-8 tw-text-sm',\n );\n\n const radiusClasses = cn(\n size === 'large' && 'tw-rounded-[8px]',\n size === 'small' && 'tw-rounded-[4px]',\n size !== 'large' && size !== 'small' && 'tw-rounded-[6px]',\n );\n\n const inputBox = (\n <div\n className={cn(\n 'ald-input-number tw-inline-flex tw-min-w-0 tw-items-center tw-overflow-hidden',\n bordered &&\n 'tw-border tw-border-solid tw-border-[var(--interaction-border-neutral-normal)]',\n mergedDisabled\n ? 'ald-input-number-disabled tw-cursor-not-allowed tw-bg-[var(--global-cool-gray-alpha-50)] tw-text-[var(--content-secondary)]'\n : 'tw-bg-[var(--interaction-background-form-field)] tw-text-[var(--content-primary)] hover:tw-border-[var(--interaction-border-hover)]',\n !hasAddon && sizeClasses,\n hasAddon\n ? 'tw-h-auto tw-flex-1 tw-self-stretch tw-rounded-none'\n : radiusClasses,\n status === 'error' && 'tw-border-[var(--border-negative-strong)]',\n status === 'warning' && 'tw-border-[var(--border-warning-subtle)]',\n 'focus-within:tw-border-[var(--interaction-border-hover)] focus-within:tw-outline focus-within:tw-outline-1 focus-within:tw-outline-[var(--global-blue-500)]',\n !hasAddon && className,\n )}\n style={!hasAddon ? style : undefined}\n >\n {prefix && (\n <span className=\"tw-px-2 tw-text-[var(--content-secondary)]\">\n {prefix}\n </span>\n )}\n <input\n ref={inputRef}\n id={id}\n type=\"text\"\n inputMode=\"numeric\"\n className={cn(\n 'tw-min-w-0 tw-flex-1 tw-border-0 tw-bg-transparent tw-px-[7px] tw-text-inherit tw-outline-none',\n mergedDisabled &&\n 'tw-cursor-not-allowed tw-text-[var(--content-secondary)]',\n )}\n value={displayValue}\n onChange={handleChange}\n onBlur={handleBlur}\n onFocus={onFocus}\n onKeyDown={handleKeyDown}\n disabled={mergedDisabled}\n readOnly={readOnly}\n autoFocus={autoFocus}\n placeholder={placeholder}\n />\n </div>\n );\n\n if (!hasAddon) return inputBox;\n\n return (\n <div\n className={cn(\n 'ald-input-number-group tw-inline-flex tw-w-full tw-items-stretch',\n sizeClasses,\n radiusClasses,\n mergedDisabled && 'ald-input-number-disabled',\n className,\n )}\n style={style}\n >\n {addonBefore && (\n <span\n className={cn(\n 'ald-input-number-addon tw-flex tw-shrink-0 tw-items-center tw-border tw-border-r-0 tw-border-solid tw-border-[var(--interaction-border-neutral-normal)] tw-bg-[var(--background-neutral-subtle)] tw-px-3 tw-text-[var(--content-secondary)]',\n size === 'large' && 'tw-rounded-l-[8px]',\n size === 'small' && 'tw-rounded-l-[4px]',\n size !== 'large' && size !== 'small' && 'tw-rounded-l-[6px]',\n )}\n >\n {addonBefore}\n </span>\n )}\n {inputBox}\n {addonAfter && (\n <span\n className={cn(\n 'ald-input-number-addon tw-flex tw-shrink-0 tw-items-center tw-border tw-border-l-0 tw-border-solid tw-border-[var(--interaction-border-neutral-normal)] tw-bg-[var(--background-neutral-subtle)] tw-px-3 tw-text-[var(--content-secondary)]',\n size === 'large' && 'tw-rounded-r-[8px]',\n size === 'small' && 'tw-rounded-r-[4px]',\n size !== 'large' && size !== 'small' && 'tw-rounded-r-[6px]',\n )}\n >\n {addonAfter}\n </span>\n )}\n </div>\n );\n}\n\nexport type { IInputNumberProps };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/InputNumber/index.tsx"],"sourcesContent":["import React, {\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport DisabledContext from '../ConfigProvider/DisabledContext';\nimport SizeContext from '../ConfigProvider/sizeContext';\nimport { cn } from '../lib/utils';\nimport { IInputNumberProps } from './type';\n\nexport default function InputNumber(props: IInputNumberProps) {\n const {\n className,\n disabled: customDisabled,\n size: customSize,\n status,\n value: controlledValue,\n defaultValue,\n min = -Infinity,\n max = Infinity,\n step = 1,\n precision,\n onChange,\n onPressEnter,\n onBlur,\n onFocus,\n formatter,\n parser,\n prefix,\n addonBefore,\n addonAfter,\n placeholder,\n autoFocus,\n bordered = true,\n keyboard = true,\n readonly: readOnly,\n style,\n id,\n } = props;\n\n const contentSize = useContext(SizeContext);\n const size = customSize || contentSize || 'middle';\n const disabled = useContext(DisabledContext);\n const mergedDisabled = customDisabled ?? disabled;\n\n const isControlled = 'value' in props;\n const [innerValue, setInnerValue] = useState<number | null | undefined>(\n defaultValue ?? null,\n );\n const currentValue = isControlled ? controlledValue : innerValue;\n\n const [inputStr, setInputStr] = useState(\n currentValue !== null && currentValue !== undefined\n ? String(currentValue)\n : '',\n );\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (currentValue !== null && currentValue !== undefined) {\n setInputStr(String(currentValue));\n } else {\n setInputStr('');\n }\n }, [currentValue]);\n\n const clamp = useCallback(\n (val: number) => {\n let v = Math.max(min, Math.min(max, val));\n if (precision !== undefined) {\n v = Number(v.toFixed(precision));\n }\n return v;\n },\n [min, max, precision],\n );\n\n const updateValue = useCallback(\n (newVal: number | null) => {\n const clamped = newVal !== null ? clamp(newVal) : null;\n if (!isControlled) setInnerValue(clamped);\n onChange?.(clamped);\n },\n [clamp, isControlled, onChange],\n );\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const raw = e.target.value;\n setInputStr(raw);\n if (raw === '' || raw === '-') return;\n const parsed = parser ? parser(raw) : Number(raw);\n if (!isNaN(parsed)) {\n updateValue(parsed);\n }\n };\n\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n if (inputStr === '' || inputStr === '-') {\n updateValue(null);\n setInputStr('');\n } else {\n const parsed = parser ? parser(inputStr) : Number(inputStr);\n if (!isNaN(parsed)) {\n const clamped = clamp(parsed);\n updateValue(clamped);\n setInputStr(String(clamped));\n }\n }\n onBlur?.(e);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n onPressEnter?.(e);\n }\n if (!keyboard) return;\n const numStep = typeof step === 'string' ? Number(step) : step;\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n updateValue(clamp((currentValue ?? 0) + numStep));\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n updateValue(clamp((currentValue ?? 0) - numStep));\n }\n };\n\n const displayValue = formatter\n ? formatter(currentValue ?? undefined, {\n userTyping: document.activeElement === inputRef.current,\n input: inputStr,\n })\n : inputStr;\n\n const hasAddon = addonBefore || addonAfter;\n\n const sizeClasses = cn(\n size === 'large' && 'ald-input-number-large tw-h-9 tw-text-base',\n size === 'small' && 'ald-input-number-small tw-h-7 tw-text-xs',\n size !== 'large' &&\n size !== 'small' &&\n 'ald-input-number-middle tw-h-8 tw-text-sm',\n );\n\n const radiusClasses = cn(\n size === 'large' && 'tw-rounded-[8px]',\n size === 'small' && 'tw-rounded-[4px]',\n size !== 'large' && size !== 'small' && 'tw-rounded-[6px]',\n );\n\n const inputBox = (\n <div\n className={cn(\n 'ald-input-number tw-inline-flex tw-min-w-0 tw-items-center tw-overflow-hidden',\n bordered &&\n 'tw-border tw-border-solid tw-border-[var(--interaction-border-neutral-normal)]',\n mergedDisabled\n ? 'ald-input-number-disabled tw-cursor-not-allowed tw-bg-[var(--global-cool-gray-alpha-50)] tw-text-[var(--content-secondary)]'\n : 'tw-bg-[var(--interaction-background-form-field)] tw-text-[var(--content-primary)] hover:tw-border-[var(--interaction-border-hover)]',\n !hasAddon && sizeClasses,\n hasAddon\n ? 'tw-h-auto tw-flex-1 tw-self-stretch tw-rounded-none'\n : radiusClasses,\n status === 'error' && 'tw-border-[var(--border-negative-strong)]',\n status === 'warning' && 'tw-border-[var(--border-warning-subtle)]',\n 'focus-within:tw-border-[var(--interaction-border-hover)] focus-within:tw-outline focus-within:tw-outline-1 focus-within:tw-outline-[var(--global-blue-500)]',\n !hasAddon && className,\n )}\n style={!hasAddon ? style : undefined}\n >\n {prefix && (\n <span className=\"tw-px-2 tw-text-[var(--content-secondary)]\">\n {prefix}\n </span>\n )}\n <input\n ref={inputRef}\n id={id}\n type=\"text\"\n inputMode=\"numeric\"\n // size=1 让 <input> 的 intrinsic 宽度坍缩到 1 个字符,\n // 在 flex 父容器中按 width / flex-1 受控,避免默认 size=20 把 inline-flex 外层撑出 ~150px 内容宽度。\n size={1}\n className={cn(\n 'tw-min-w-0 tw-flex-1 tw-border-0 tw-bg-transparent tw-px-[7px] tw-text-inherit tw-outline-none',\n mergedDisabled &&\n 'tw-cursor-not-allowed tw-text-[var(--content-secondary)]',\n )}\n value={displayValue}\n onChange={handleChange}\n onBlur={handleBlur}\n onFocus={onFocus}\n onKeyDown={handleKeyDown}\n disabled={mergedDisabled}\n readOnly={readOnly}\n autoFocus={autoFocus}\n placeholder={placeholder}\n />\n </div>\n );\n\n if (!hasAddon) return inputBox;\n\n return (\n <div\n className={cn(\n 'ald-input-number-group tw-inline-flex tw-w-full tw-items-stretch',\n sizeClasses,\n radiusClasses,\n mergedDisabled && 'ald-input-number-disabled',\n className,\n )}\n style={style}\n >\n {addonBefore && (\n <span\n className={cn(\n 'ald-input-number-addon tw-flex tw-shrink-0 tw-items-center tw-border tw-border-r-0 tw-border-solid tw-border-[var(--interaction-border-neutral-normal)] tw-bg-[var(--background-neutral-subtle)] tw-px-3 tw-text-[var(--content-secondary)]',\n size === 'large' && 'tw-rounded-l-[8px]',\n size === 'small' && 'tw-rounded-l-[4px]',\n size !== 'large' && size !== 'small' && 'tw-rounded-l-[6px]',\n )}\n >\n {addonBefore}\n </span>\n )}\n {inputBox}\n {addonAfter && (\n <span\n className={cn(\n 'ald-input-number-addon tw-flex tw-shrink-0 tw-items-center tw-border tw-border-l-0 tw-border-solid tw-border-[var(--interaction-border-neutral-normal)] tw-bg-[var(--background-neutral-subtle)] tw-px-3 tw-text-[var(--content-secondary)]',\n size === 'large' && 'tw-rounded-r-[8px]',\n size === 'small' && 'tw-rounded-r-[4px]',\n size !== 'large' && size !== 'small' && 'tw-rounded-r-[6px]',\n )}\n >\n {addonAfter}\n </span>\n )}\n </div>\n );\n}\n\nexport type { IInputNumberProps };\n"],"mappings":"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"}
|
|
@@ -11,6 +11,9 @@ interface IProps {
|
|
|
11
11
|
placeholder?: string;
|
|
12
12
|
size?: 'small' | 'middle' | 'large';
|
|
13
13
|
initWidth?: number;
|
|
14
|
+
/** 展开态(hover / focus / 有值)宽度,默认 200px。
|
|
15
|
+
* 收起态宽度仍由 initWidth 控制;inputMode 始终 100%,不受本参数影响。 */
|
|
16
|
+
expandedWidth?: number;
|
|
14
17
|
defaultValue?: string;
|
|
15
18
|
value?: string;
|
|
16
19
|
inputMode?: boolean;
|
|
@@ -8,6 +8,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
8
8
|
import _ from "lodash";
|
|
9
9
|
import { useDebounceFn } from "ahooks";
|
|
10
10
|
//#region src/InputSearch/index.tsx
|
|
11
|
+
var DEFAULT_EXPANDED_WIDTH = 200;
|
|
11
12
|
var DEFAULT_SMALL_WIDTH = 68;
|
|
12
13
|
var DEFAULT_WIDTH = 78;
|
|
13
14
|
var DEFAULT_EN_SMALL_WIDTH = 88;
|
|
@@ -83,7 +84,8 @@ function InputSearch(props) {
|
|
|
83
84
|
}),
|
|
84
85
|
style: {
|
|
85
86
|
...style,
|
|
86
|
-
"--init-width": (props.initWidth || defaultWidth) + "px"
|
|
87
|
+
"--init-width": (props.initWidth || defaultWidth) + "px",
|
|
88
|
+
"--expanded-width": (props.expandedWidth || DEFAULT_EXPANDED_WIDTH) + "px"
|
|
87
89
|
},
|
|
88
90
|
children: /* @__PURE__ */ jsx(Input, {
|
|
89
91
|
className: cn({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/InputSearch/index.tsx"],"sourcesContent":["import { useDebounceFn } from 'ahooks';\nimport { cn } from '../lib/utils';\nimport _ from 'lodash';\nimport React, {\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { SearchLine } from '../Icon';\nimport Input from '../Input';\nimport { ELangType, LocaleContext, getTranslator } from '../locale/default';\nimport './input-search.css';\n\ninterface ICustomCSSProperties extends React.CSSProperties {\n '--init-width'?: string;\n}\n\nconst DEFAULT_SMALL_WIDTH = 68;\nconst DEFAULT_WIDTH = 78;\nconst DEFAULT_EN_SMALL_WIDTH = 88;\nconst DEFAULT_EN_WIDTH = 98;\nconst DEFAULT_LARGE_WIDTH = 88;\nconst DEFAULT_EN_LARGE_WIDTH = 108;\n\nexport default function InputSearch(props: IProps) {\n const { locale } = useContext(LocaleContext);\n const t = getTranslator(locale);\n\n const {\n onSearch,\n onChange,\n className,\n debounce = true,\n placeholder,\n size = 'small',\n defaultValue,\n value,\n inputMode = false,\n style,\n onBlur,\n disabled,\n } = props;\n\n const defaultWidth = useMemo(() => {\n if (size === 'small') {\n if (locale === ELangType.EN) {\n return DEFAULT_EN_SMALL_WIDTH;\n }\n return DEFAULT_SMALL_WIDTH;\n } else if (size === 'middle') {\n if (locale === ELangType.EN) {\n return DEFAULT_EN_WIDTH;\n }\n return DEFAULT_WIDTH;\n } else {\n if (locale === ELangType.EN) {\n return DEFAULT_EN_LARGE_WIDTH;\n }\n return DEFAULT_LARGE_WIDTH;\n }\n }, [locale, size]);\n\n // 判断是否为受控模式\n const isControlled = 'value' in props;\n const [searchValue, setSearchValue] = useState(defaultValue || '');\n\n // 获取当前值:受控模式使用 value,非受控模式使用内部状态\n const currentValue = isControlled ? value ?? '' : searchValue;\n\n const isComposing = useRef(false);\n\n const onPressEnter = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!isComposing.current) {\n onSearch(_.trim((e.target as HTMLInputElement).value));\n }\n },\n [onSearch],\n );\n\n const DEFAULT_DEBOUNCE_TIME = 500;\n const { run: debounceSearch } = useDebounceFn<(val: string) => void>(\n (val) => {\n if (!isComposing.current) {\n onSearch(val);\n }\n },\n {\n wait: DEFAULT_DEBOUNCE_TIME,\n },\n );\n\n const onChangeValue = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n\n // 非受控模式才更新内部状态\n if (!isControlled) {\n setSearchValue(newValue);\n } else {\n onChange?.(newValue);\n return;\n }\n\n if (!isComposing.current) {\n // 受控的时候debounce不生效\n if (debounce && !isControlled) {\n debounceSearch(newValue);\n } else {\n onSearch(newValue);\n }\n }\n },\n [debounce, debounceSearch, onSearch, isControlled, onChange],\n );\n\n const handleCompositionStart = useCallback(() => {\n isComposing.current = true;\n }, []);\n\n const handleCompositionEnd = useCallback(\n (e: React.CompositionEvent<HTMLInputElement>) => {\n if (isControlled) {\n return;\n }\n isComposing.current = false;\n // 在输入法结束后触发一次搜索\n const value = (e.target as HTMLInputElement).value;\n if (debounce) {\n debounceSearch(value);\n } else {\n onSearch(value);\n }\n },\n [debounce, debounceSearch, isControlled, onSearch],\n );\n\n const iconSize = useMemo(() => {\n if (size === 'middle' || size === 'large') {\n return 20;\n }\n return 16;\n }, [size]);\n\n return (\n <div\n className={cn('ald-input-search', className, {\n ['input-search-size-small']: size === 'small',\n ['input-search-size-middle']: size === 'middle',\n ['input-search-size-large']: size === 'large',\n })}\n style={\n {\n ...style,\n '--init-width': (props.initWidth || defaultWidth) + 'px',\n } as ICustomCSSProperties\n }\n >\n <Input\n className={cn({\n ['input-search-has-value']: currentValue.length !== 0 || inputMode,\n ['input-search-has-content']: currentValue.length !== 0,\n ['inputMode']: inputMode,\n })}\n size={size}\n onChange={onChangeValue}\n onPressEnter={onPressEnter}\n onCompositionStart={handleCompositionStart}\n onCompositionEnd={handleCompositionEnd}\n prefix={<SearchLine size={iconSize} />}\n placeholder={placeholder || t.InputSearch.search}\n allowClear\n disabled={disabled}\n {...(isControlled\n ? { value: currentValue }\n : { defaultValue: defaultValue })}\n onBlur={(e) => {\n if (onBlur) {\n onBlur(currentValue, e);\n }\n }}\n />\n </div>\n );\n}\n\ninterface IProps {\n /** 搜索回调,在输入完成时触发(回车、输入法结束、非输入法输入时) */\n onSearch: (value: string) => void;\n /** 值变化回调(受控模式时推荐使用,每次输入都触发,包括输入法期间) */\n onChange?: (value: string) => void;\n onBlur?: (value: string, e: React.FocusEvent<HTMLInputElement>) => void;\n className?: string;\n // 是否开启防抖\n debounce?: boolean;\n placeholder?: string;\n size?: 'small' | 'middle' | 'large';\n initWidth?: number;\n defaultValue?: string;\n // 受控模式的值\n value?: string;\n inputMode?: boolean;\n style?: React.CSSProperties;\n disabled?: boolean;\n}\n"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/InputSearch/index.tsx"],"sourcesContent":["import { useDebounceFn } from 'ahooks';\nimport { cn } from '../lib/utils';\nimport _ from 'lodash';\nimport React, {\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { SearchLine } from '../Icon';\nimport Input from '../Input';\nimport { ELangType, LocaleContext, getTranslator } from '../locale/default';\nimport './input-search.css';\n\ninterface ICustomCSSProperties extends React.CSSProperties {\n '--init-width'?: string;\n '--expanded-width'?: string;\n}\n\nconst DEFAULT_EXPANDED_WIDTH = 200;\n\nconst DEFAULT_SMALL_WIDTH = 68;\nconst DEFAULT_WIDTH = 78;\nconst DEFAULT_EN_SMALL_WIDTH = 88;\nconst DEFAULT_EN_WIDTH = 98;\nconst DEFAULT_LARGE_WIDTH = 88;\nconst DEFAULT_EN_LARGE_WIDTH = 108;\n\nexport default function InputSearch(props: IProps) {\n const { locale } = useContext(LocaleContext);\n const t = getTranslator(locale);\n\n const {\n onSearch,\n onChange,\n className,\n debounce = true,\n placeholder,\n size = 'small',\n defaultValue,\n value,\n inputMode = false,\n style,\n onBlur,\n disabled,\n } = props;\n\n const defaultWidth = useMemo(() => {\n if (size === 'small') {\n if (locale === ELangType.EN) {\n return DEFAULT_EN_SMALL_WIDTH;\n }\n return DEFAULT_SMALL_WIDTH;\n } else if (size === 'middle') {\n if (locale === ELangType.EN) {\n return DEFAULT_EN_WIDTH;\n }\n return DEFAULT_WIDTH;\n } else {\n if (locale === ELangType.EN) {\n return DEFAULT_EN_LARGE_WIDTH;\n }\n return DEFAULT_LARGE_WIDTH;\n }\n }, [locale, size]);\n\n // 判断是否为受控模式\n const isControlled = 'value' in props;\n const [searchValue, setSearchValue] = useState(defaultValue || '');\n\n // 获取当前值:受控模式使用 value,非受控模式使用内部状态\n const currentValue = isControlled ? value ?? '' : searchValue;\n\n const isComposing = useRef(false);\n\n const onPressEnter = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!isComposing.current) {\n onSearch(_.trim((e.target as HTMLInputElement).value));\n }\n },\n [onSearch],\n );\n\n const DEFAULT_DEBOUNCE_TIME = 500;\n const { run: debounceSearch } = useDebounceFn<(val: string) => void>(\n (val) => {\n if (!isComposing.current) {\n onSearch(val);\n }\n },\n {\n wait: DEFAULT_DEBOUNCE_TIME,\n },\n );\n\n const onChangeValue = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n\n // 非受控模式才更新内部状态\n if (!isControlled) {\n setSearchValue(newValue);\n } else {\n onChange?.(newValue);\n return;\n }\n\n if (!isComposing.current) {\n // 受控的时候debounce不生效\n if (debounce && !isControlled) {\n debounceSearch(newValue);\n } else {\n onSearch(newValue);\n }\n }\n },\n [debounce, debounceSearch, onSearch, isControlled, onChange],\n );\n\n const handleCompositionStart = useCallback(() => {\n isComposing.current = true;\n }, []);\n\n const handleCompositionEnd = useCallback(\n (e: React.CompositionEvent<HTMLInputElement>) => {\n if (isControlled) {\n return;\n }\n isComposing.current = false;\n // 在输入法结束后触发一次搜索\n const value = (e.target as HTMLInputElement).value;\n if (debounce) {\n debounceSearch(value);\n } else {\n onSearch(value);\n }\n },\n [debounce, debounceSearch, isControlled, onSearch],\n );\n\n const iconSize = useMemo(() => {\n if (size === 'middle' || size === 'large') {\n return 20;\n }\n return 16;\n }, [size]);\n\n return (\n <div\n className={cn('ald-input-search', className, {\n ['input-search-size-small']: size === 'small',\n ['input-search-size-middle']: size === 'middle',\n ['input-search-size-large']: size === 'large',\n })}\n style={\n {\n ...style,\n '--init-width': (props.initWidth || defaultWidth) + 'px',\n '--expanded-width':\n (props.expandedWidth || DEFAULT_EXPANDED_WIDTH) + 'px',\n } as ICustomCSSProperties\n }\n >\n <Input\n className={cn({\n ['input-search-has-value']: currentValue.length !== 0 || inputMode,\n ['input-search-has-content']: currentValue.length !== 0,\n ['inputMode']: inputMode,\n })}\n size={size}\n onChange={onChangeValue}\n onPressEnter={onPressEnter}\n onCompositionStart={handleCompositionStart}\n onCompositionEnd={handleCompositionEnd}\n prefix={<SearchLine size={iconSize} />}\n placeholder={placeholder || t.InputSearch.search}\n allowClear\n disabled={disabled}\n {...(isControlled\n ? { value: currentValue }\n : { defaultValue: defaultValue })}\n onBlur={(e) => {\n if (onBlur) {\n onBlur(currentValue, e);\n }\n }}\n />\n </div>\n );\n}\n\ninterface IProps {\n /** 搜索回调,在输入完成时触发(回车、输入法结束、非输入法输入时) */\n onSearch: (value: string) => void;\n /** 值变化回调(受控模式时推荐使用,每次输入都触发,包括输入法期间) */\n onChange?: (value: string) => void;\n onBlur?: (value: string, e: React.FocusEvent<HTMLInputElement>) => void;\n className?: string;\n // 是否开启防抖\n debounce?: boolean;\n placeholder?: string;\n size?: 'small' | 'middle' | 'large';\n initWidth?: number;\n /** 展开态(hover / focus / 有值)宽度,默认 200px。\n * 收起态宽度仍由 initWidth 控制;inputMode 始终 100%,不受本参数影响。 */\n expandedWidth?: number;\n defaultValue?: string;\n // 受控模式的值\n value?: string;\n inputMode?: boolean;\n style?: React.CSSProperties;\n disabled?: boolean;\n}\n"],"mappings":";;;;;;;;;;AAoBA,IAAM,yBAAyB;AAE/B,IAAM,sBAAsB;AAC5B,IAAM,gBAAgB;AACtB,IAAM,yBAAyB;AAC/B,IAAM,mBAAmB;AACzB,IAAM,sBAAsB;AAC5B,IAAM,yBAAyB;AAE/B,SAAwB,YAAY,OAAe;CACjD,MAAM,EAAE,WAAW,WAAW,cAAc;CAC5C,MAAM,IAAI,cAAc,OAAO;CAE/B,MAAM,EACJ,UACA,UACA,WACA,WAAW,MACX,aACA,OAAO,SACP,cACA,OACA,YAAY,OACZ,OACA,QACA,aACE;CAEJ,MAAM,eAAe,cAAc;AACjC,MAAI,SAAS,SAAS;AACpB,OAAI,WAAW,UAAU,GACvB,QAAO;AAET,UAAO;aACE,SAAS,UAAU;AAC5B,OAAI,WAAW,UAAU,GACvB,QAAO;AAET,UAAO;SACF;AACL,OAAI,WAAW,UAAU,GACvB,QAAO;AAET,UAAO;;IAER,CAAC,QAAQ,KAAK,CAAC;CAGlB,MAAM,eAAe,WAAW;CAChC,MAAM,CAAC,aAAa,kBAAkB,SAAS,gBAAgB,GAAG;CAGlE,MAAM,eAAe,eAAe,SAAS,KAAK;CAElD,MAAM,cAAc,OAAO,MAAM;CAEjC,MAAM,eAAe,aAClB,MAA6C;AAC5C,MAAI,CAAC,YAAY,QACf,UAAS,EAAE,KAAM,EAAE,OAA4B,MAAM,CAAC;IAG1D,CAAC,SAAS,CACX;CAGD,MAAM,EAAE,KAAK,mBAAmB,eAC7B,QAAQ;AACP,MAAI,CAAC,YAAY,QACf,UAAS,IAAI;IAGjB,EACE,MAR0B,KAS3B,CACF;CAED,MAAM,gBAAgB,aACnB,MAA2C;EAC1C,MAAM,WAAW,EAAE,OAAO;AAG1B,MAAI,CAAC,aACH,gBAAe,SAAS;OACnB;AACL,cAAW,SAAS;AACpB;;AAGF,MAAI,CAAC,YAAY,QAEf,KAAI,YAAY,CAAC,aACf,gBAAe,SAAS;MAExB,UAAS,SAAS;IAIxB;EAAC;EAAU;EAAgB;EAAU;EAAc;EAAS,CAC7D;CAED,MAAM,yBAAyB,kBAAkB;AAC/C,cAAY,UAAU;IACrB,EAAE,CAAC;CAEN,MAAM,uBAAuB,aAC1B,MAAgD;AAC/C,MAAI,aACF;AAEF,cAAY,UAAU;EAEtB,MAAM,QAAS,EAAE,OAA4B;AAC7C,MAAI,SACF,gBAAe,MAAM;MAErB,UAAS,MAAM;IAGnB;EAAC;EAAU;EAAgB;EAAc;EAAS,CACnD;CAED,MAAM,WAAW,cAAc;AAC7B,MAAI,SAAS,YAAY,SAAS,QAChC,QAAO;AAET,SAAO;IACN,CAAC,KAAK,CAAC;AAEV,QACE,oBAAC,OAAD;EACE,WAAW,GAAG,oBAAoB,WAAW;IAC1C,4BAA4B,SAAS;IACrC,6BAA6B,SAAS;IACtC,4BAA4B,SAAS;GACvC,CAAC;EACF,OACE;GACE,GAAG;GACH,iBAAiB,MAAM,aAAa,gBAAgB;GACpD,qBACG,MAAM,iBAAiB,0BAA0B;GACrD;YAGH,oBAAC,OAAD;GACE,WAAW,GAAG;KACX,2BAA2B,aAAa,WAAW,KAAK;KACxD,6BAA6B,aAAa,WAAW;KACrD,cAAc;IAChB,CAAC;GACI;GACN,UAAU;GACI;GACd,oBAAoB;GACpB,kBAAkB;GAClB,QAAQ,oBAAC,MAAD,EAAY,MAAM,UAAY,CAAA;GACtC,aAAa,eAAe,EAAE,YAAY;GAC1C,YAAA;GACU;GACV,GAAK,eACD,EAAE,OAAO,cAAc,GACvB,EAAgB,cAAc;GAClC,SAAS,MAAM;AACb,QAAI,OACF,QAAO,cAAc,EAAE;;GAG3B,CAAA;EACE,CAAA"}
|
package/dist/Tabs/index.js
CHANGED
|
@@ -92,7 +92,7 @@ function Tabs(props) {
|
|
|
92
92
|
"--tabs-padding": `${paddingVal}px`
|
|
93
93
|
},
|
|
94
94
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
95
|
-
className: cn("ald-tabs-nav ant-tabs-nav tw-flex tw-items-center", !isVertical &&
|
|
95
|
+
className: cn("ald-tabs-nav ant-tabs-nav tw-flex tw-items-center", !isVertical && "tw-mb-5", !isVertical && hasDividing && "tw-border-0 tw-border-b tw-border-solid tw-border-b-[var(--global-cool-grey-100)]", !isVertical && compact && "!tw-mb-0", isVertical && "tw-flex-col tw-border-0 tw-border-r tw-border-solid tw-border-r-[var(--global-cool-grey-100)]"),
|
|
96
96
|
style: headerBackgroundColor ? { backgroundColor: headerBackgroundColor } : void 0,
|
|
97
97
|
children: [
|
|
98
98
|
extraLeft,
|
|
@@ -105,6 +105,7 @@ function Tabs(props) {
|
|
|
105
105
|
}),
|
|
106
106
|
/* @__PURE__ */ jsx("div", {
|
|
107
107
|
className: "ald-tabs-nav-wrap ant-tabs-nav-wrap tw-min-w-0 tw-flex-1",
|
|
108
|
+
style: paddingVal ? { margin: `0 ${paddingVal}px` } : void 0,
|
|
108
109
|
children: /* @__PURE__ */ jsx("div", {
|
|
109
110
|
ref: navListRef,
|
|
110
111
|
className: cn("ald-tabs-nav-list ant-tabs-nav-list tw-flex tw-overflow-hidden", isVertical && "tw-flex-col", monospace && "[&>*]:tw-flex-1", isCard ? "tw-gap-1" : !monospace && "tw-gap-8"),
|
|
@@ -176,6 +177,7 @@ function Tabs(props) {
|
|
|
176
177
|
]
|
|
177
178
|
}), /* @__PURE__ */ jsx("div", {
|
|
178
179
|
className: cn("ald-tabs-content ant-tabs-content ant-tabs-content-holder tw-min-h-0 tw-flex-1", adaptHeight && "tw-h-full"),
|
|
180
|
+
style: paddingVal ? { padding: `0 ${paddingVal}px ${paddingVal}px` } : void 0,
|
|
179
181
|
children: resolvedItems.map((item) => {
|
|
180
182
|
const isActive = item.key === activeKey;
|
|
181
183
|
if (!isActive && destroyInactiveTabPane && !item.forceRender) return null;
|
package/dist/Tabs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/Tabs/index.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { cn } from '../lib/utils';\nimport { ChevronLeftLine, ChevronRightLine, CloseLightLine } from '../Icon';\nimport TabPane from './TabPane';\n\nexport type TabsSize = 'default' | 'small';\n\ninterface TabItem {\n key: string;\n label: React.ReactNode;\n children?: React.ReactNode;\n disabled?: boolean;\n closable?: boolean;\n icon?: React.ReactNode;\n forceRender?: boolean;\n className?: string;\n}\n\nexport interface ITabsProps {\n size?: TabsSize;\n activeKey?: string;\n defaultActiveKey?: string;\n onChange?: (activeKey: string) => void;\n onTabClick?: (activeKey: string, e: React.MouseEvent) => void;\n destroyInactiveTabPane?: boolean;\n centered?: boolean;\n adaptHeight?: boolean;\n tabPosition?: 'left' | 'right' | 'top' | 'bottom';\n className?: string;\n children?: React.ReactNode;\n headerBackgroundColor?: string;\n monospace?: boolean;\n padding?: boolean | number;\n compact?: boolean;\n hasDividing?: boolean;\n items?: TabItem[];\n type?: 'line' | 'card' | 'editable-card';\n tabBarExtraContent?:\n | React.ReactNode\n | { left?: React.ReactNode; right?: React.ReactNode };\n onEdit?: (\n targetKey: string | React.MouseEvent | React.KeyboardEvent,\n action: 'add' | 'remove',\n ) => void;\n hideAdd?: boolean;\n style?: React.CSSProperties;\n popupClassName?: string;\n tabBarGutter?: number;\n moreIcon?: React.ReactNode;\n}\n\nexport default function Tabs(props: ITabsProps) {\n const {\n size,\n className,\n adaptHeight,\n style = {},\n monospace: propsMonospace,\n tabPosition = 'top',\n padding: propsPadding = false,\n compact,\n hasDividing = true,\n items,\n activeKey: controlledActiveKey,\n defaultActiveKey,\n onChange,\n onTabClick,\n destroyInactiveTabPane,\n tabBarExtraContent,\n headerBackgroundColor,\n children,\n type,\n onEdit,\n hideAdd,\n } = props;\n\n const isEditable = type === 'editable-card';\n const isCard = type === 'card' || type === 'editable-card';\n\n // Derive items from children if not provided\n const resolvedItems: TabItem[] = useMemo(() => {\n if (items) return items;\n return React.Children.toArray(children)\n .filter(React.isValidElement)\n .map((child: any) => ({\n key: child.key || child.props.key || '',\n label: child.props.tab,\n children: child.props.children,\n disabled: child.props.disabled,\n closable: child.props.closable,\n forceRender: child.props.forceRender,\n }));\n }, [items, children]);\n\n const firstKey = resolvedItems[0]?.key || '';\n const [innerActiveKey, setInnerActiveKey] = useState(\n defaultActiveKey || firstKey,\n );\n const mergedActiveKey =\n controlledActiveKey !== undefined ? controlledActiveKey : innerActiveKey;\n const activeKey = resolvedItems.some((item) => item.key === mergedActiveKey)\n ? mergedActiveKey\n : firstKey;\n\n const handleTabClick = (key: string, e: React.MouseEvent) => {\n if (controlledActiveKey === undefined) {\n setInnerActiveKey(key);\n }\n onChange?.(key);\n onTabClick?.(key, e);\n };\n\n const handleRemove = (key: string, e: React.MouseEvent) => {\n e.stopPropagation();\n onEdit?.(key, 'remove');\n };\n\n const handleAdd = (e: React.MouseEvent) => {\n onEdit?.(e, 'add');\n };\n\n const monospace = tabPosition !== 'top' ? false : propsMonospace;\n const paddingVal = useMemo(() => {\n if (tabPosition !== 'top') return 0;\n if (typeof propsPadding === 'number') return propsPadding;\n if (typeof propsPadding === 'boolean' && propsPadding) return 20;\n return 0;\n }, [propsPadding, tabPosition]);\n\n const isVertical = tabPosition === 'left' || tabPosition === 'right';\n\n const extraLeft =\n tabBarExtraContent &&\n typeof tabBarExtraContent === 'object' &&\n 'left' in tabBarExtraContent\n ? tabBarExtraContent.left\n : null;\n const extraRight = tabBarExtraContent\n ? typeof tabBarExtraContent === 'object' && 'right' in tabBarExtraContent\n ? tabBarExtraContent.right\n : React.isValidElement(tabBarExtraContent)\n ? tabBarExtraContent\n : null\n : null;\n\n // Scroll state for overflow\n const navListRef = useRef<HTMLDivElement>(null);\n const [canScrollLeft, setCanScrollLeft] = useState(false);\n const [canScrollRight, setCanScrollRight] = useState(false);\n\n const checkScroll = useCallback(() => {\n const el = navListRef.current;\n if (!el || isVertical) {\n setCanScrollLeft(false);\n setCanScrollRight(false);\n return;\n }\n const { scrollLeft, scrollWidth, clientWidth } = el;\n setCanScrollLeft(scrollLeft > 1);\n setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1);\n }, [isVertical]);\n\n useEffect(() => {\n checkScroll();\n const el = navListRef.current;\n if (!el) return;\n // Use ResizeObserver to detect size changes\n let ro: ResizeObserver | undefined;\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(() => checkScroll());\n ro.observe(el);\n }\n el.addEventListener('scroll', checkScroll, { passive: true });\n return () => {\n el.removeEventListener('scroll', checkScroll);\n ro?.disconnect();\n };\n }, [checkScroll, resolvedItems.length]);\n\n const scrollBy = (delta: number) => {\n const el = navListRef.current;\n if (el) {\n el.scrollBy({ left: delta, behavior: 'smooth' });\n }\n };\n\n const showScrollButtons = canScrollLeft || canScrollRight;\n\n return (\n <div\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs ant-tabs tw-flex',\n isVertical ? 'tw-flex-row' : 'tw-flex-col',\n adaptHeight && 'ald-adapt-height tw-h-full',\n size !== 'small' && 'ald-tabs-default',\n monospace && 'ald-tabs-monospace',\n compact && 'ald-tabs-compact',\n !hasDividing && 'ald-tabs-no-dividing',\n className,\n )}\n style={\n {\n ...style,\n '--header-bg-color': headerBackgroundColor,\n '--tabs-padding': `${paddingVal}px`,\n } as React.CSSProperties\n }\n >\n {/* Tab nav */}\n <div\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-nav ant-tabs-nav tw-flex tw-items-center',\n !isVertical &&\n hasDividing &&\n 'tw-mb-5 tw-border-0 tw-border-b tw-border-solid tw-border-b-[var(--global-cool-grey-100)]',\n !isVertical && compact && '!tw-mb-0',\n isVertical &&\n 'tw-flex-col tw-border-0 tw-border-r tw-border-solid tw-border-r-[var(--global-cool-grey-100)]',\n paddingVal && `tw-px-[${paddingVal}px]`,\n )}\n style={\n headerBackgroundColor\n ? { backgroundColor: headerBackgroundColor }\n : undefined\n }\n >\n {extraLeft}\n\n {/* Scroll left button */}\n {showScrollButtons && !isVertical && (\n <button\n type=\"button\"\n className={cn(\n 'ald-tabs-scroll-btn tw-flex tw-shrink-0 tw-items-center tw-justify-center tw-border-none tw-bg-transparent tw-p-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]',\n !canScrollLeft && 'tw-invisible',\n )}\n onClick={() => scrollBy(-200)}\n aria-label=\"Scroll tabs left\"\n >\n <ChevronLeftLine size={16} />\n </button>\n )}\n\n <div className=\"ald-tabs-nav-wrap ant-tabs-nav-wrap tw-min-w-0 tw-flex-1\">\n <div\n ref={navListRef}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-nav-list ant-tabs-nav-list tw-flex tw-overflow-hidden',\n isVertical && 'tw-flex-col',\n monospace && '[&>*]:tw-flex-1',\n isCard ? 'tw-gap-1' : !monospace && 'tw-gap-8',\n )}\n style={\n !isVertical\n ? { scrollbarWidth: 'none', msOverflowStyle: 'none' }\n : undefined\n }\n >\n {resolvedItems.map((item) => {\n const isActive = activeKey === item.key;\n // For editable-card, closable defaults to true unless explicitly set to false\n const showClose = isEditable && item.closable !== false;\n\n return (\n <div\n key={item.key}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-tab ant-tabs-tab tw-relative tw-flex tw-shrink-0 tw-cursor-pointer tw-items-center tw-gap-2 tw-whitespace-nowrap tw-transition-colors',\n // Card / editable-card styling\n isCard\n ? cn(\n 'tw-h-10 tw-rounded-t-[6px] tw-border tw-border-b-0 tw-border-solid tw-px-4 tw-text-sm tw-leading-5',\n 'tw-gap-sp-75',\n isActive\n ? 'tw-border-[var(--alias-colors-border-default)] tw-bg-[var(--background-default)] tw-font-medium tw-text-[var(--alias-colors-text-selected)]'\n : 'tw-border-[var(--alias-colors-border-default)] tw-bg-[var(--alias-colors-bg-skeleton-subtler)] tw-text-[var(--alias-colors-text-subtle)] hover:tw-text-inherit',\n )\n : cn(\n size === 'small'\n ? 'tw-py-2 tw-text-xs tw-leading-4'\n : 'tw-py-2.5 tw-text-sm tw-leading-5',\n monospace && 'tw-justify-center',\n isActive\n ? 'tw-font-medium tw-text-[var(--alias-colors-text-selected)]'\n : 'tw-font-medium tw-text-[var(--alias-colors-text-subtle)] hover:tw-text-inherit',\n ),\n item.disabled &&\n 'tw-pointer-events-none tw-cursor-default tw-opacity-50',\n )}\n onClick={\n item.disabled\n ? undefined\n : (e) => handleTabClick(item.key, e)\n }\n >\n {item.icon}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n <span className=\"ant-tabs-tab-btn\">{item.label}</span>\n {/* Close button for editable-card */}\n {showClose && (\n <span\n className=\"ald-tabs-tab-remove tw-m-0 tw-grid tw-size-4 tw-cursor-pointer tw-place-items-center tw-p-0 tw-text-[var(--alias-colors-icon-subtle)] tw-transition-colors hover:tw-text-[var(--alias-colors-text-default)]\"\n onClick={(e) => handleRemove(item.key, e)}\n aria-label={`Remove ${item.label}`}\n >\n <CloseLightLine size={12} />\n </span>\n )}\n {/* Active indicator for non-card line tabs */}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n {!isCard && isActive && !isVertical && (\n <div className=\"ant-tabs-ink-bar tw-absolute tw-inset-x-0 tw--bottom-px tw-h-[2px] tw-rounded-[2px] tw-bg-[var(--alias-colors-border-selected)]\" />\n )}\n {!isCard && isActive && isVertical && (\n <div className=\"tw-absolute tw-inset-y-0 tw--right-px tw-w-[2px] tw-rounded-[2px] tw-bg-[var(--alias-colors-border-selected)]\" />\n )}\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Scroll right button */}\n {showScrollButtons && !isVertical && (\n <button\n type=\"button\"\n className={cn(\n 'ald-tabs-scroll-btn tw-flex tw-shrink-0 tw-items-center tw-justify-center tw-border-none tw-bg-transparent tw-p-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]',\n !canScrollRight && 'tw-invisible',\n )}\n onClick={() => scrollBy(200)}\n aria-label=\"Scroll tabs right\"\n >\n <ChevronRightLine size={16} />\n </button>\n )}\n\n {/* Add button for editable-card */}\n {isEditable && !hideAdd && (\n <button\n type=\"button\"\n className=\"ald-tabs-nav-add tw-ml-1 tw-flex tw-shrink-0 tw-cursor-pointer tw-items-center tw-justify-center tw-rounded tw-border tw-border-solid tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-px-2 tw-py-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]\"\n onClick={handleAdd}\n aria-label=\"Add tab\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </button>\n )}\n\n {extraRight}\n </div>\n\n {/* Tab content */}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n <div\n className={cn(\n 'ald-tabs-content ant-tabs-content ant-tabs-content-holder tw-min-h-0 tw-flex-1',\n adaptHeight && 'tw-h-full',\n )}\n >\n {resolvedItems.map((item) => {\n const isActive = item.key === activeKey;\n if (!isActive && destroyInactiveTabPane && !item.forceRender) {\n return null;\n }\n return (\n <div\n key={item.key}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-tabpane ant-tabs-tabpane',\n // v2 行为:adaptHeight 时 tabpane 撑满内容区,子元素的百分比高度才能解析\n adaptHeight && 'tw-h-full tw-overflow-y-auto',\n isActive ? 'ant-tabs-tabpane-active tw-block' : 'tw-hidden',\n )}\n role=\"tabpanel\"\n >\n {item.children}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nTabs.TabPane = TabPane;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/Tabs/index.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { cn } from '../lib/utils';\nimport { ChevronLeftLine, ChevronRightLine, CloseLightLine } from '../Icon';\nimport TabPane from './TabPane';\n\nexport type TabsSize = 'default' | 'small';\n\ninterface TabItem {\n key: string;\n label: React.ReactNode;\n children?: React.ReactNode;\n disabled?: boolean;\n closable?: boolean;\n icon?: React.ReactNode;\n forceRender?: boolean;\n className?: string;\n}\n\nexport interface ITabsProps {\n size?: TabsSize;\n activeKey?: string;\n defaultActiveKey?: string;\n onChange?: (activeKey: string) => void;\n onTabClick?: (activeKey: string, e: React.MouseEvent) => void;\n destroyInactiveTabPane?: boolean;\n centered?: boolean;\n adaptHeight?: boolean;\n tabPosition?: 'left' | 'right' | 'top' | 'bottom';\n className?: string;\n children?: React.ReactNode;\n headerBackgroundColor?: string;\n monospace?: boolean;\n padding?: boolean | number;\n compact?: boolean;\n hasDividing?: boolean;\n items?: TabItem[];\n type?: 'line' | 'card' | 'editable-card';\n tabBarExtraContent?:\n | React.ReactNode\n | { left?: React.ReactNode; right?: React.ReactNode };\n onEdit?: (\n targetKey: string | React.MouseEvent | React.KeyboardEvent,\n action: 'add' | 'remove',\n ) => void;\n hideAdd?: boolean;\n style?: React.CSSProperties;\n popupClassName?: string;\n tabBarGutter?: number;\n moreIcon?: React.ReactNode;\n}\n\nexport default function Tabs(props: ITabsProps) {\n const {\n size,\n className,\n adaptHeight,\n style = {},\n monospace: propsMonospace,\n tabPosition = 'top',\n padding: propsPadding = false,\n compact,\n hasDividing = true,\n items,\n activeKey: controlledActiveKey,\n defaultActiveKey,\n onChange,\n onTabClick,\n destroyInactiveTabPane,\n tabBarExtraContent,\n headerBackgroundColor,\n children,\n type,\n onEdit,\n hideAdd,\n } = props;\n\n const isEditable = type === 'editable-card';\n const isCard = type === 'card' || type === 'editable-card';\n\n // Derive items from children if not provided\n const resolvedItems: TabItem[] = useMemo(() => {\n if (items) return items;\n return React.Children.toArray(children)\n .filter(React.isValidElement)\n .map((child: any) => ({\n key: child.key || child.props.key || '',\n label: child.props.tab,\n children: child.props.children,\n disabled: child.props.disabled,\n closable: child.props.closable,\n forceRender: child.props.forceRender,\n }));\n }, [items, children]);\n\n const firstKey = resolvedItems[0]?.key || '';\n const [innerActiveKey, setInnerActiveKey] = useState(\n defaultActiveKey || firstKey,\n );\n const mergedActiveKey =\n controlledActiveKey !== undefined ? controlledActiveKey : innerActiveKey;\n const activeKey = resolvedItems.some((item) => item.key === mergedActiveKey)\n ? mergedActiveKey\n : firstKey;\n\n const handleTabClick = (key: string, e: React.MouseEvent) => {\n if (controlledActiveKey === undefined) {\n setInnerActiveKey(key);\n }\n onChange?.(key);\n onTabClick?.(key, e);\n };\n\n const handleRemove = (key: string, e: React.MouseEvent) => {\n e.stopPropagation();\n onEdit?.(key, 'remove');\n };\n\n const handleAdd = (e: React.MouseEvent) => {\n onEdit?.(e, 'add');\n };\n\n const monospace = tabPosition !== 'top' ? false : propsMonospace;\n const paddingVal = useMemo(() => {\n if (tabPosition !== 'top') return 0;\n if (typeof propsPadding === 'number') return propsPadding;\n if (typeof propsPadding === 'boolean' && propsPadding) return 20;\n return 0;\n }, [propsPadding, tabPosition]);\n\n const isVertical = tabPosition === 'left' || tabPosition === 'right';\n\n const extraLeft =\n tabBarExtraContent &&\n typeof tabBarExtraContent === 'object' &&\n 'left' in tabBarExtraContent\n ? tabBarExtraContent.left\n : null;\n const extraRight = tabBarExtraContent\n ? typeof tabBarExtraContent === 'object' && 'right' in tabBarExtraContent\n ? tabBarExtraContent.right\n : React.isValidElement(tabBarExtraContent)\n ? tabBarExtraContent\n : null\n : null;\n\n // Scroll state for overflow\n const navListRef = useRef<HTMLDivElement>(null);\n const [canScrollLeft, setCanScrollLeft] = useState(false);\n const [canScrollRight, setCanScrollRight] = useState(false);\n\n const checkScroll = useCallback(() => {\n const el = navListRef.current;\n if (!el || isVertical) {\n setCanScrollLeft(false);\n setCanScrollRight(false);\n return;\n }\n const { scrollLeft, scrollWidth, clientWidth } = el;\n setCanScrollLeft(scrollLeft > 1);\n setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1);\n }, [isVertical]);\n\n useEffect(() => {\n checkScroll();\n const el = navListRef.current;\n if (!el) return;\n // Use ResizeObserver to detect size changes\n let ro: ResizeObserver | undefined;\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(() => checkScroll());\n ro.observe(el);\n }\n el.addEventListener('scroll', checkScroll, { passive: true });\n return () => {\n el.removeEventListener('scroll', checkScroll);\n ro?.disconnect();\n };\n }, [checkScroll, resolvedItems.length]);\n\n const scrollBy = (delta: number) => {\n const el = navListRef.current;\n if (el) {\n el.scrollBy({ left: delta, behavior: 'smooth' });\n }\n };\n\n const showScrollButtons = canScrollLeft || canScrollRight;\n\n return (\n <div\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs ant-tabs tw-flex',\n isVertical ? 'tw-flex-row' : 'tw-flex-col',\n adaptHeight && 'ald-adapt-height tw-h-full',\n size !== 'small' && 'ald-tabs-default',\n monospace && 'ald-tabs-monospace',\n compact && 'ald-tabs-compact',\n !hasDividing && 'ald-tabs-no-dividing',\n className,\n )}\n style={\n {\n ...style,\n '--header-bg-color': headerBackgroundColor,\n '--tabs-padding': `${paddingVal}px`,\n } as React.CSSProperties\n }\n >\n {/* Tab nav */}\n <div\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-nav ant-tabs-nav tw-flex tw-items-center',\n !isVertical && 'tw-mb-5',\n !isVertical &&\n hasDividing &&\n 'tw-border-0 tw-border-b tw-border-solid tw-border-b-[var(--global-cool-grey-100)]',\n !isVertical && compact && '!tw-mb-0',\n isVertical &&\n 'tw-flex-col tw-border-0 tw-border-r tw-border-solid tw-border-r-[var(--global-cool-grey-100)]',\n )}\n style={\n headerBackgroundColor\n ? { backgroundColor: headerBackgroundColor }\n : undefined\n }\n >\n {extraLeft}\n\n {/* Scroll left button */}\n {showScrollButtons && !isVertical && (\n <button\n type=\"button\"\n className={cn(\n 'ald-tabs-scroll-btn tw-flex tw-shrink-0 tw-items-center tw-justify-center tw-border-none tw-bg-transparent tw-p-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]',\n !canScrollLeft && 'tw-invisible',\n )}\n onClick={() => scrollBy(-200)}\n aria-label=\"Scroll tabs left\"\n >\n <ChevronLeftLine size={16} />\n </button>\n )}\n\n <div\n className=\"ald-tabs-nav-wrap ant-tabs-nav-wrap tw-min-w-0 tw-flex-1\"\n style={paddingVal ? { margin: `0 ${paddingVal}px` } : undefined}\n >\n <div\n ref={navListRef}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-nav-list ant-tabs-nav-list tw-flex tw-overflow-hidden',\n isVertical && 'tw-flex-col',\n monospace && '[&>*]:tw-flex-1',\n isCard ? 'tw-gap-1' : !monospace && 'tw-gap-8',\n )}\n style={\n !isVertical\n ? { scrollbarWidth: 'none', msOverflowStyle: 'none' }\n : undefined\n }\n >\n {resolvedItems.map((item) => {\n const isActive = activeKey === item.key;\n // For editable-card, closable defaults to true unless explicitly set to false\n const showClose = isEditable && item.closable !== false;\n\n return (\n <div\n key={item.key}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-tab ant-tabs-tab tw-relative tw-flex tw-shrink-0 tw-cursor-pointer tw-items-center tw-gap-2 tw-whitespace-nowrap tw-transition-colors',\n // Card / editable-card styling\n isCard\n ? cn(\n 'tw-h-10 tw-rounded-t-[6px] tw-border tw-border-b-0 tw-border-solid tw-px-4 tw-text-sm tw-leading-5',\n 'tw-gap-sp-75',\n isActive\n ? 'tw-border-[var(--alias-colors-border-default)] tw-bg-[var(--background-default)] tw-font-medium tw-text-[var(--alias-colors-text-selected)]'\n : 'tw-border-[var(--alias-colors-border-default)] tw-bg-[var(--alias-colors-bg-skeleton-subtler)] tw-text-[var(--alias-colors-text-subtle)] hover:tw-text-inherit',\n )\n : cn(\n size === 'small'\n ? 'tw-py-2 tw-text-xs tw-leading-4'\n : 'tw-py-2.5 tw-text-sm tw-leading-5',\n monospace && 'tw-justify-center',\n isActive\n ? 'tw-font-medium tw-text-[var(--alias-colors-text-selected)]'\n : 'tw-font-medium tw-text-[var(--alias-colors-text-subtle)] hover:tw-text-inherit',\n ),\n item.disabled &&\n 'tw-pointer-events-none tw-cursor-default tw-opacity-50',\n )}\n onClick={\n item.disabled\n ? undefined\n : (e) => handleTabClick(item.key, e)\n }\n >\n {item.icon}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n <span className=\"ant-tabs-tab-btn\">{item.label}</span>\n {/* Close button for editable-card */}\n {showClose && (\n <span\n className=\"ald-tabs-tab-remove tw-m-0 tw-grid tw-size-4 tw-cursor-pointer tw-place-items-center tw-p-0 tw-text-[var(--alias-colors-icon-subtle)] tw-transition-colors hover:tw-text-[var(--alias-colors-text-default)]\"\n onClick={(e) => handleRemove(item.key, e)}\n aria-label={`Remove ${item.label}`}\n >\n <CloseLightLine size={12} />\n </span>\n )}\n {/* Active indicator for non-card line tabs */}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n {!isCard && isActive && !isVertical && (\n <div className=\"ant-tabs-ink-bar tw-absolute tw-inset-x-0 tw--bottom-px tw-h-[2px] tw-rounded-[2px] tw-bg-[var(--alias-colors-border-selected)]\" />\n )}\n {!isCard && isActive && isVertical && (\n <div className=\"tw-absolute tw-inset-y-0 tw--right-px tw-w-[2px] tw-rounded-[2px] tw-bg-[var(--alias-colors-border-selected)]\" />\n )}\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Scroll right button */}\n {showScrollButtons && !isVertical && (\n <button\n type=\"button\"\n className={cn(\n 'ald-tabs-scroll-btn tw-flex tw-shrink-0 tw-items-center tw-justify-center tw-border-none tw-bg-transparent tw-p-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]',\n !canScrollRight && 'tw-invisible',\n )}\n onClick={() => scrollBy(200)}\n aria-label=\"Scroll tabs right\"\n >\n <ChevronRightLine size={16} />\n </button>\n )}\n\n {/* Add button for editable-card */}\n {isEditable && !hideAdd && (\n <button\n type=\"button\"\n className=\"ald-tabs-nav-add tw-ml-1 tw-flex tw-shrink-0 tw-cursor-pointer tw-items-center tw-justify-center tw-rounded tw-border tw-border-solid tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-px-2 tw-py-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]\"\n onClick={handleAdd}\n aria-label=\"Add tab\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </button>\n )}\n\n {extraRight}\n </div>\n\n {/* Tab content */}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n <div\n className={cn(\n 'ald-tabs-content ant-tabs-content ant-tabs-content-holder tw-min-h-0 tw-flex-1',\n adaptHeight && 'tw-h-full',\n )}\n style={\n paddingVal\n ? { padding: `0 ${paddingVal}px ${paddingVal}px` }\n : undefined\n }\n >\n {resolvedItems.map((item) => {\n const isActive = item.key === activeKey;\n if (!isActive && destroyInactiveTabPane && !item.forceRender) {\n return null;\n }\n return (\n <div\n key={item.key}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-tabpane ant-tabs-tabpane',\n // v2 行为:adaptHeight 时 tabpane 撑满内容区,子元素的百分比高度才能解析\n adaptHeight && 'tw-h-full tw-overflow-y-auto',\n isActive ? 'ant-tabs-tabpane-active tw-block' : 'tw-hidden',\n )}\n role=\"tabpanel\"\n >\n {item.children}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nTabs.TabPane = TabPane;\n"],"mappings":"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"}
|
package/dist/Tree/Tree.d.ts
CHANGED
|
@@ -77,7 +77,18 @@ export type TreeNodeNormal = DataNode;
|
|
|
77
77
|
type DraggableFn = (node: DataNode) => boolean;
|
|
78
78
|
interface DraggableConfig {
|
|
79
79
|
icon?: React.ReactNode | false;
|
|
80
|
+
/** 节点是否可作为 drag source(拖起来)。返回 false:不显示 drag handle、不能起拖。 */
|
|
80
81
|
nodeDraggable?: DraggableFn;
|
|
82
|
+
/**
|
|
83
|
+
* 节点是否可作为 drop target(接收落入)。返回 true:即使 nodeDraggable=false 仍注册
|
|
84
|
+
* onDragOver/onDrop 等 listener,浏览器才会真正派发 drop 事件。
|
|
85
|
+
*
|
|
86
|
+
* 解决 rc-tree 5.x 把"可拖"与"可放"绑到同一个 nodeDraggable 的限制——之前要让"类目可接收
|
|
87
|
+
* 资源拖入但本身不可拖"只能让 nodeDraggable 全返回 true,再用业务侧 CSS hack 隐藏 drag icon。
|
|
88
|
+
*
|
|
89
|
+
* 默认不传 = 沿用 nodeDraggable 行为(向后兼容)。
|
|
90
|
+
*/
|
|
91
|
+
nodeDroppable?: DraggableFn;
|
|
81
92
|
}
|
|
82
93
|
export interface TreeProps<T extends BasicDataNode = DataNode> extends Omit<RcTreeProps<T>, 'prefixCls' | 'showLine' | 'direction' | 'draggable' | 'icon' | 'switcherIcon' | 'filterTreeNode'> {
|
|
83
94
|
showLine?: boolean | {
|