@aloudata/aloudata-design 3.0.8 → 3.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/Button/index.d.ts +2 -0
  2. package/dist/Button/index.js.map +1 -1
  3. package/dist/Checkbox/index.js +3 -1
  4. package/dist/Checkbox/index.js.map +1 -1
  5. package/dist/Checkbox/type.d.ts +4 -0
  6. package/dist/DataPreviewTable/components/Body/Error.d.ts +2 -0
  7. package/dist/DataPreviewTable/components/Body/Error.js +7 -3
  8. package/dist/DataPreviewTable/components/Body/Error.js.map +1 -1
  9. package/dist/DataPreviewTable/index.js +3 -1
  10. package/dist/DataPreviewTable/index.js.map +1 -1
  11. package/dist/IconButton/index.d.ts +4 -0
  12. package/dist/IconButton/index.js +8 -2
  13. package/dist/IconButton/index.js.map +1 -1
  14. package/dist/Input/components/Input/index.d.ts +4 -0
  15. package/dist/Input/components/Input/index.js +4 -2
  16. package/dist/Input/components/Input/index.js.map +1 -1
  17. package/dist/InputNumber/index.js +5 -1
  18. package/dist/InputNumber/index.js.map +1 -1
  19. package/dist/InputNumber/type.d.ts +4 -0
  20. package/dist/InputSearch/index.d.ts +4 -0
  21. package/dist/InputSearch/index.js +3 -1
  22. package/dist/InputSearch/index.js.map +1 -1
  23. package/dist/MemberPicker/index.js +3 -1
  24. package/dist/MemberPicker/index.js.map +1 -1
  25. package/dist/Modal/index.d.ts +4 -0
  26. package/dist/Modal/index.js +3 -1
  27. package/dist/Modal/index.js.map +1 -1
  28. package/dist/Radio/components/Group/index.js +3 -1
  29. package/dist/Radio/components/Group/index.js.map +1 -1
  30. package/dist/Radio/interface/radioGroup.d.ts +4 -0
  31. package/dist/Select/BaseSelect.js +3 -1
  32. package/dist/Select/BaseSelect.js.map +1 -1
  33. package/dist/Select/interface.d.ts +4 -0
  34. package/dist/Switch/index.d.ts +4 -0
  35. package/dist/Switch/index.js +3 -1
  36. package/dist/Switch/index.js.map +1 -1
  37. package/dist/Tabs/index.d.ts +4 -0
  38. package/dist/Tabs/index.js +3 -1
  39. package/dist/Tabs/index.js.map +1 -1
  40. package/package.json +1 -1
@@ -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 '--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"}
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 'data-testid': dataTestid,\n 'aria-label': ariaLabel,\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 data-testid={dataTestid}\n aria-label={ariaLabel}\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 /** 透传到内部 input 元素的 data-testid,用于自动化测试定位 */\n 'data-testid'?: string;\n /** 透传到内部 input 元素的 aria-label,用于可访问性与自动化测试定位 */\n 'aria-label'?: string;\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,UACA,eAAe,YACf,cAAc,cACZ;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,eAAa;GACb,cAAY;GACZ,GAAK,eACD,EAAE,OAAO,cAAc,GACvB,EAAgB,cAAc;GAClC,SAAS,MAAM;AACb,QAAI,OACF,QAAO,cAAc,EAAE;;GAG3B,CAAA;EACE,CAAA"}
@@ -19,7 +19,7 @@ var DEFAULT_MULTIPLE_DROPDOWN_WIDTH = 480;
19
19
  var Component = (props) => {
20
20
  const { locale } = useContext(LocaleContext);
21
21
  const t = getTranslator(locale);
22
- const { value, type = EMemberPicker.USER, onChange, multiple, dropdownWidth, open, onOpenChange, placeholder = t.MemberPicker.select, className, allowClear, disabled, onClear, size, prefix: propPrefix, lockedIds = [], footer, onCancel, filterItem, mode: propsMode, renderItem, renderSelectedTag, ...restProps } = props;
22
+ const { value, type = EMemberPicker.USER, onChange, multiple, dropdownWidth, open, onOpenChange, placeholder = t.MemberPicker.select, className, allowClear, disabled, onClear, size, prefix: propPrefix, lockedIds = [], footer, onCancel, filterItem, mode: propsMode, renderItem, renderSelectedTag, "data-testid": dataTestId, "aria-label": ariaLabel, ...restProps } = props;
23
23
  const allowOverlap = props.allowOverlap ?? false;
24
24
  const { getUsersByIds, getUsersByKeywords } = AldCustomConfigProvider.useGetUserList();
25
25
  const [selectedUserList, setSelectedUserList] = useState([]);
@@ -171,6 +171,8 @@ var Component = (props) => {
171
171
  return /* @__PURE__ */ jsx(Select_default, {
172
172
  prefix: propPrefix,
173
173
  ...restProps,
174
+ "data-testid": dataTestId,
175
+ "aria-label": ariaLabel,
174
176
  size,
175
177
  className: cn("ald-member-picker-select", className),
176
178
  value: selectedUserList.map((item) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/MemberPicker/index.tsx"],"sourcesContent":["import { usePrevious, useRequest } from 'ahooks';\nimport { cn } from '../lib/utils';\nimport _ from 'lodash';\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport Avatar from '../Avatar';\nimport ConfigProvider from '../ConfigProvider';\nimport './member-picker.css';\nimport {\n EUserType,\n IUser,\n IUserGroup,\n TUser,\n} from '../ConfigProvider/getUserList';\nimport { LocaleContext, getTranslator } from '../locale/default';\nimport message from '../message';\nimport Panel from './components/Panel';\nimport MemberPanel from './components/PanelWrapper';\nimport {\n EMemberPicker,\n IMemberPickerProps,\n TUserGroupValue,\n TUserValue,\n} from './interface';\nimport { isUser, isUserGroup } from './utils/getUsersWithUserId';\nimport Select from '../Select';\nimport { Mode } from '../Select/BaseSelect';\n\nconst DEFAULT_MULTIPLE_DROPDOWN_WIDTH = 480;\n\nconst Component: React.FC<IMemberPickerProps> = (props) => {\n const { locale } = useContext(LocaleContext);\n const t = getTranslator(locale);\n\n const {\n value,\n type = EMemberPicker.USER,\n onChange,\n multiple,\n dropdownWidth,\n open,\n onOpenChange,\n placeholder = t.MemberPicker.select,\n className,\n allowClear,\n disabled,\n onClear,\n size,\n prefix: propPrefix,\n lockedIds = [],\n footer,\n onCancel,\n filterItem,\n mode: propsMode,\n renderItem,\n renderSelectedTag,\n ...restProps\n } = props;\n const allowOverlap = props.allowOverlap ?? false;\n const { getUsersByIds, getUsersByKeywords } = ConfigProvider.useGetUserList();\n const [selectedUserList, setSelectedUserList] = useState<TUser>([]);\n const prevValue = usePrevious(value);\n const [searchUserList, setSearchUserList] = useState<TUser>([]);\n const [searchString, setSearchString] = useState<string>('');\n const [dropdownContentWidth, setDropdownContentWidth] =\n useState(dropdownWidth);\n // 单选默认浮窗跟触发器等宽(true),调用方传 dropdownWidth 时用具体数字;\n // 多选默认 480,单条记录只有 头像+nickname 时触发器太窄装不下选中标签,故固定值。\n const panelWidth: number | boolean =\n dropdownWidth ?? (multiple ? DEFAULT_MULTIPLE_DROPDOWN_WIDTH : true);\n\n const triggerRef = useRef<HTMLDivElement>(null);\n const onSearchValueChange = useCallback((v: string) => {\n setSearchString(v);\n }, []);\n const [dropdownOpen, setDropdownOpen] = useState<boolean>(!!open);\n const queryByKeywords = useMemo(() => {\n if (getUsersByKeywords) {\n return getUsersByKeywords;\n }\n\n return (_params = {}) =>\n Promise.reject({\n message: t.MemberPicker.pleaseConfigGetUserByKeywordsMethod,\n });\n }, [getUsersByKeywords, t.MemberPicker.pleaseConfigGetUserByKeywordsMethod]);\n const queryByIds = useMemo(() => {\n if (getUsersByIds) {\n return getUsersByIds;\n }\n\n return (_params = {}) =>\n Promise.reject({\n message: t.MemberPicker.pleaseConfigGetUserByIdsMethod,\n });\n }, [getUsersByIds, t.MemberPicker.pleaseConfigGetUserByIdsMethod]);\n const { loading, run } = useRequest(() => queryByKeywords(searchString), {\n refreshDeps: [searchString],\n manual: true,\n cacheKey: 'member-selector',\n cacheTime: 1000 * 60 * 2, // 2分钟内不重复请求\n onSuccess: (result) => {\n setSearchUserList(result);\n },\n onError: (error) => {\n message.error(error.message);\n },\n });\n\n const totalUserList: TUser = useMemo(() => {\n const totalUsers = searchUserList.concat(\n selectedUserList.filter((item) => {\n const name =\n (item.type === EUserType.USER ? item.nickname : item.name) || '';\n\n return name.toUpperCase().includes(searchString.trim().toUpperCase());\n }),\n );\n\n return _.uniqBy(totalUsers, (data: IUser | IUserGroup) => {\n if (data.type === EUserType.USER) return data.userId;\n\n return data.groupId;\n }).filter((item) => {\n if (filterItem) {\n return filterItem(item);\n }\n\n return true;\n });\n }, [filterItem, searchString, searchUserList, selectedUserList]);\n\n useEffect(() => {\n if (!dropdownOpen) return;\n run();\n }, [dropdownOpen, run, searchString]);\n\n useEffect(() => {\n if (_.isEqual(value, prevValue)) {\n return;\n }\n if (Array.isArray(value) && (isUser(value[0]) || isUserGroup(value[0]))) {\n setSelectedUserList(value as TUser);\n } else if (isUser(value) || isUserGroup(value)) {\n setSelectedUserList([value]);\n } else {\n let param: Array<TUserValue | TUserGroupValue> = [];\n if (!value) return;\n if (Array.isArray(value) && value.length === 0) {\n setSelectedUserList([]);\n\n return;\n }\n if (!Array.isArray(value)) {\n param = [value];\n } else {\n param = value;\n }\n queryByIds(param).then((result) => {\n // 如果用户已被删除,则需要展示出id\n const valueNotInResult: TUser = param\n .filter((item) => {\n if (item.type === EUserType.USER) {\n return result\n .filter(isUser)\n .every((user) => user.userId !== item.userId);\n }\n\n return result\n .filter(isUserGroup)\n .every((user) => user.groupId !== item.groupId);\n })\n .map((item) => {\n if (item.type === EUserType.USER) {\n return {\n type: EUserType.USER,\n userId: item.userId,\n } as IUser;\n }\n\n return {\n type: EUserType.USER_GROUP,\n groupId: item.groupId,\n } as IUserGroup;\n });\n\n setSelectedUserList([...result, ...valueNotInResult]);\n });\n }\n }, [value, queryByIds, prevValue]);\n\n const onSelectedChange = useCallback(\n (users: TUser) => {\n if (multiple) {\n setSelectedUserList(users);\n onChange?.(users);\n } else {\n setSelectedUserList(users);\n onChange?.(users[0]);\n }\n setDropdownOpen(false);\n },\n [multiple, onChange, setDropdownOpen],\n );\n\n useEffect(() => {\n if (typeof open === 'boolean') {\n setDropdownOpen(open);\n }\n }, [open]);\n\n useEffect(() => {\n if (!dropdownContentWidth) {\n const resizeEle = triggerRef.current;\n if (!resizeEle) return;\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width } = entry.contentRect;\n setDropdownContentWidth(width);\n }\n });\n resizeObserver.observe(resizeEle);\n\n return () => {\n resizeObserver.unobserve(resizeEle);\n };\n }\n }, [triggerRef, dropdownContentWidth]);\n const onDropdownOpenChange = useCallback(\n (open: boolean) => {\n setDropdownOpen(open);\n onOpenChange?.(open);\n },\n [onOpenChange],\n );\n const panelKey = useMemo(() => {\n if (dropdownOpen) {\n return _.sampleSize('abcdefghijklmnopqrstuvwxyz0123456789', 8).join('');\n }\n }, [dropdownOpen]);\n const mode = useMemo(() => {\n if (multiple === true) {\n if (typeof propsMode === 'object')\n return {\n ...(propsMode || {}),\n type: 'multiple',\n responsive: _.isNil(propsMode.responsive)\n ? true\n : propsMode.responsive,\n } as Mode;\n return {\n type: 'multiple',\n responsive: true,\n } as Mode;\n }\n\n return multiple ? (multiple as Mode) : propsMode;\n }, [multiple, propsMode]);\n\n const selectOpen = typeof open === 'boolean' ? open : dropdownOpen;\n\n return (\n <Select\n prefix={propPrefix}\n {...restProps}\n size={size}\n className={cn('ald-member-picker-select', className)}\n value={selectedUserList.map((item) => {\n if (item.type === EUserType.USER_GROUP) {\n return item.groupId;\n } else {\n return item.userId;\n }\n })}\n onChange={(value) => {\n if (_.isEmpty(value)) {\n setSelectedUserList([]);\n if (multiple) {\n onChange?.([]);\n } else {\n onChange?.();\n }\n } else {\n const valueList = Array.isArray(value) ? value : [value];\n if (multiple) {\n const users = valueList\n .map((item) => {\n const user = totalUserList.find((user) => {\n if (user.type === EUserType.USER) {\n return user.userId === item;\n }\n\n return user.groupId === item;\n });\n\n return user;\n })\n .filter(Boolean) as TUser;\n setSelectedUserList(users);\n onChange?.(users);\n } else {\n const user = totalUserList.find((user) => {\n if (user.type === EUserType.USER) {\n return user.userId === value;\n }\n\n return user.groupId === value;\n });\n if (user) {\n setSelectedUserList([user]);\n onChange?.(user);\n } else {\n setSelectedUserList([]);\n onChange?.();\n }\n }\n }\n }}\n disabled={disabled}\n allowClear={allowClear}\n onClear={() => {\n setSelectedUserList([]);\n if (multiple) {\n onChange?.([]);\n } else {\n onChange?.();\n }\n onClear?.();\n }}\n popupClassName={cn(\n 'ald-member-picker-popup',\n allowOverlap && 'ald-member-picker-popup-adaptive',\n props.popupClassName,\n )}\n mode={mode}\n options={selectedUserList.map((item) => {\n if (item.type === EUserType.USER_GROUP)\n return {\n label: item.name || item.groupId,\n value: item.groupId,\n tag: (\n <div className={'ald-member-picker-tag'}>\n <Avatar type=\"team\" size={20}>\n {item.name || item.groupId}\n </Avatar>\n {item.name || item.groupId}\n </div>\n ),\n };\n\n return {\n label: item.nickname || item.name || item.userId,\n value: item.userId,\n tag: (\n <div className={'ald-member-picker-tag'}>\n <Avatar\n size={20}\n src={item.photo}\n type={item.type === EUserType.USER ? 'user' : 'team'}\n >\n {item.nickname || item.name || item.userId}\n </Avatar>\n {item.nickname || item.name || item.userId}\n </div>\n ),\n };\n })}\n optionLabelProp={multiple ? 'label' : 'tag'}\n open={selectOpen}\n onOpenChange={onDropdownOpenChange}\n popupMatchSelectWidth={panelWidth}\n allowOverlap={allowOverlap}\n placeholder={placeholder}\n dropdownRender={() => {\n return (\n <div\n ref={triggerRef}\n className={cn({\n 'ald-member-picker-popup-body': allowOverlap,\n })}\n >\n <Panel\n type={type}\n footer={footer}\n value={selectedUserList}\n dataList={totalUserList}\n lockedIds={lockedIds}\n multiple={!!multiple}\n key={panelKey}\n loading={loading}\n dropdownWidth={dropdownContentWidth}\n onSearchValueChange={onSearchValueChange}\n onChange={onSelectedChange}\n onCancel={() => {\n onCancel?.();\n setDropdownOpen(false);\n }}\n renderItem={renderItem}\n renderSelectedTag={renderSelectedTag}\n ></Panel>\n </div>\n );\n }}\n ></Select>\n );\n};\n\nconst MemberSelector = Component as React.FC<IMemberPickerProps> & {\n MemberPanel: typeof MemberPanel;\n};\n\nMemberSelector.MemberPanel = MemberPanel;\nexport default MemberSelector;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/MemberPicker/index.tsx"],"sourcesContent":["import { usePrevious, useRequest } from 'ahooks';\nimport { cn } from '../lib/utils';\nimport _ from 'lodash';\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport Avatar from '../Avatar';\nimport ConfigProvider from '../ConfigProvider';\nimport './member-picker.css';\nimport {\n EUserType,\n IUser,\n IUserGroup,\n TUser,\n} from '../ConfigProvider/getUserList';\nimport { LocaleContext, getTranslator } from '../locale/default';\nimport message from '../message';\nimport Panel from './components/Panel';\nimport MemberPanel from './components/PanelWrapper';\nimport {\n EMemberPicker,\n IMemberPickerProps,\n TUserGroupValue,\n TUserValue,\n} from './interface';\nimport { isUser, isUserGroup } from './utils/getUsersWithUserId';\nimport Select from '../Select';\nimport { Mode } from '../Select/BaseSelect';\n\nconst DEFAULT_MULTIPLE_DROPDOWN_WIDTH = 480;\n\nconst Component: React.FC<IMemberPickerProps> = (props) => {\n const { locale } = useContext(LocaleContext);\n const t = getTranslator(locale);\n\n const {\n value,\n type = EMemberPicker.USER,\n onChange,\n multiple,\n dropdownWidth,\n open,\n onOpenChange,\n placeholder = t.MemberPicker.select,\n className,\n allowClear,\n disabled,\n onClear,\n size,\n prefix: propPrefix,\n lockedIds = [],\n footer,\n onCancel,\n filterItem,\n mode: propsMode,\n renderItem,\n renderSelectedTag,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n ...restProps\n } = props;\n const allowOverlap = props.allowOverlap ?? false;\n const { getUsersByIds, getUsersByKeywords } = ConfigProvider.useGetUserList();\n const [selectedUserList, setSelectedUserList] = useState<TUser>([]);\n const prevValue = usePrevious(value);\n const [searchUserList, setSearchUserList] = useState<TUser>([]);\n const [searchString, setSearchString] = useState<string>('');\n const [dropdownContentWidth, setDropdownContentWidth] =\n useState(dropdownWidth);\n // 单选默认浮窗跟触发器等宽(true),调用方传 dropdownWidth 时用具体数字;\n // 多选默认 480,单条记录只有 头像+nickname 时触发器太窄装不下选中标签,故固定值。\n const panelWidth: number | boolean =\n dropdownWidth ?? (multiple ? DEFAULT_MULTIPLE_DROPDOWN_WIDTH : true);\n\n const triggerRef = useRef<HTMLDivElement>(null);\n const onSearchValueChange = useCallback((v: string) => {\n setSearchString(v);\n }, []);\n const [dropdownOpen, setDropdownOpen] = useState<boolean>(!!open);\n const queryByKeywords = useMemo(() => {\n if (getUsersByKeywords) {\n return getUsersByKeywords;\n }\n\n return (_params = {}) =>\n Promise.reject({\n message: t.MemberPicker.pleaseConfigGetUserByKeywordsMethod,\n });\n }, [getUsersByKeywords, t.MemberPicker.pleaseConfigGetUserByKeywordsMethod]);\n const queryByIds = useMemo(() => {\n if (getUsersByIds) {\n return getUsersByIds;\n }\n\n return (_params = {}) =>\n Promise.reject({\n message: t.MemberPicker.pleaseConfigGetUserByIdsMethod,\n });\n }, [getUsersByIds, t.MemberPicker.pleaseConfigGetUserByIdsMethod]);\n const { loading, run } = useRequest(() => queryByKeywords(searchString), {\n refreshDeps: [searchString],\n manual: true,\n cacheKey: 'member-selector',\n cacheTime: 1000 * 60 * 2, // 2分钟内不重复请求\n onSuccess: (result) => {\n setSearchUserList(result);\n },\n onError: (error) => {\n message.error(error.message);\n },\n });\n\n const totalUserList: TUser = useMemo(() => {\n const totalUsers = searchUserList.concat(\n selectedUserList.filter((item) => {\n const name =\n (item.type === EUserType.USER ? item.nickname : item.name) || '';\n\n return name.toUpperCase().includes(searchString.trim().toUpperCase());\n }),\n );\n\n return _.uniqBy(totalUsers, (data: IUser | IUserGroup) => {\n if (data.type === EUserType.USER) return data.userId;\n\n return data.groupId;\n }).filter((item) => {\n if (filterItem) {\n return filterItem(item);\n }\n\n return true;\n });\n }, [filterItem, searchString, searchUserList, selectedUserList]);\n\n useEffect(() => {\n if (!dropdownOpen) return;\n run();\n }, [dropdownOpen, run, searchString]);\n\n useEffect(() => {\n if (_.isEqual(value, prevValue)) {\n return;\n }\n if (Array.isArray(value) && (isUser(value[0]) || isUserGroup(value[0]))) {\n setSelectedUserList(value as TUser);\n } else if (isUser(value) || isUserGroup(value)) {\n setSelectedUserList([value]);\n } else {\n let param: Array<TUserValue | TUserGroupValue> = [];\n if (!value) return;\n if (Array.isArray(value) && value.length === 0) {\n setSelectedUserList([]);\n\n return;\n }\n if (!Array.isArray(value)) {\n param = [value];\n } else {\n param = value;\n }\n queryByIds(param).then((result) => {\n // 如果用户已被删除,则需要展示出id\n const valueNotInResult: TUser = param\n .filter((item) => {\n if (item.type === EUserType.USER) {\n return result\n .filter(isUser)\n .every((user) => user.userId !== item.userId);\n }\n\n return result\n .filter(isUserGroup)\n .every((user) => user.groupId !== item.groupId);\n })\n .map((item) => {\n if (item.type === EUserType.USER) {\n return {\n type: EUserType.USER,\n userId: item.userId,\n } as IUser;\n }\n\n return {\n type: EUserType.USER_GROUP,\n groupId: item.groupId,\n } as IUserGroup;\n });\n\n setSelectedUserList([...result, ...valueNotInResult]);\n });\n }\n }, [value, queryByIds, prevValue]);\n\n const onSelectedChange = useCallback(\n (users: TUser) => {\n if (multiple) {\n setSelectedUserList(users);\n onChange?.(users);\n } else {\n setSelectedUserList(users);\n onChange?.(users[0]);\n }\n setDropdownOpen(false);\n },\n [multiple, onChange, setDropdownOpen],\n );\n\n useEffect(() => {\n if (typeof open === 'boolean') {\n setDropdownOpen(open);\n }\n }, [open]);\n\n useEffect(() => {\n if (!dropdownContentWidth) {\n const resizeEle = triggerRef.current;\n if (!resizeEle) return;\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width } = entry.contentRect;\n setDropdownContentWidth(width);\n }\n });\n resizeObserver.observe(resizeEle);\n\n return () => {\n resizeObserver.unobserve(resizeEle);\n };\n }\n }, [triggerRef, dropdownContentWidth]);\n const onDropdownOpenChange = useCallback(\n (open: boolean) => {\n setDropdownOpen(open);\n onOpenChange?.(open);\n },\n [onOpenChange],\n );\n const panelKey = useMemo(() => {\n if (dropdownOpen) {\n return _.sampleSize('abcdefghijklmnopqrstuvwxyz0123456789', 8).join('');\n }\n }, [dropdownOpen]);\n const mode = useMemo(() => {\n if (multiple === true) {\n if (typeof propsMode === 'object')\n return {\n ...(propsMode || {}),\n type: 'multiple',\n responsive: _.isNil(propsMode.responsive)\n ? true\n : propsMode.responsive,\n } as Mode;\n return {\n type: 'multiple',\n responsive: true,\n } as Mode;\n }\n\n return multiple ? (multiple as Mode) : propsMode;\n }, [multiple, propsMode]);\n\n const selectOpen = typeof open === 'boolean' ? open : dropdownOpen;\n\n return (\n <Select\n prefix={propPrefix}\n {...restProps}\n data-testid={dataTestId}\n aria-label={ariaLabel}\n size={size}\n className={cn('ald-member-picker-select', className)}\n value={selectedUserList.map((item) => {\n if (item.type === EUserType.USER_GROUP) {\n return item.groupId;\n } else {\n return item.userId;\n }\n })}\n onChange={(value) => {\n if (_.isEmpty(value)) {\n setSelectedUserList([]);\n if (multiple) {\n onChange?.([]);\n } else {\n onChange?.();\n }\n } else {\n const valueList = Array.isArray(value) ? value : [value];\n if (multiple) {\n const users = valueList\n .map((item) => {\n const user = totalUserList.find((user) => {\n if (user.type === EUserType.USER) {\n return user.userId === item;\n }\n\n return user.groupId === item;\n });\n\n return user;\n })\n .filter(Boolean) as TUser;\n setSelectedUserList(users);\n onChange?.(users);\n } else {\n const user = totalUserList.find((user) => {\n if (user.type === EUserType.USER) {\n return user.userId === value;\n }\n\n return user.groupId === value;\n });\n if (user) {\n setSelectedUserList([user]);\n onChange?.(user);\n } else {\n setSelectedUserList([]);\n onChange?.();\n }\n }\n }\n }}\n disabled={disabled}\n allowClear={allowClear}\n onClear={() => {\n setSelectedUserList([]);\n if (multiple) {\n onChange?.([]);\n } else {\n onChange?.();\n }\n onClear?.();\n }}\n popupClassName={cn(\n 'ald-member-picker-popup',\n allowOverlap && 'ald-member-picker-popup-adaptive',\n props.popupClassName,\n )}\n mode={mode}\n options={selectedUserList.map((item) => {\n if (item.type === EUserType.USER_GROUP)\n return {\n label: item.name || item.groupId,\n value: item.groupId,\n tag: (\n <div className={'ald-member-picker-tag'}>\n <Avatar type=\"team\" size={20}>\n {item.name || item.groupId}\n </Avatar>\n {item.name || item.groupId}\n </div>\n ),\n };\n\n return {\n label: item.nickname || item.name || item.userId,\n value: item.userId,\n tag: (\n <div className={'ald-member-picker-tag'}>\n <Avatar\n size={20}\n src={item.photo}\n type={item.type === EUserType.USER ? 'user' : 'team'}\n >\n {item.nickname || item.name || item.userId}\n </Avatar>\n {item.nickname || item.name || item.userId}\n </div>\n ),\n };\n })}\n optionLabelProp={multiple ? 'label' : 'tag'}\n open={selectOpen}\n onOpenChange={onDropdownOpenChange}\n popupMatchSelectWidth={panelWidth}\n allowOverlap={allowOverlap}\n placeholder={placeholder}\n dropdownRender={() => {\n return (\n <div\n ref={triggerRef}\n className={cn({\n 'ald-member-picker-popup-body': allowOverlap,\n })}\n >\n <Panel\n type={type}\n footer={footer}\n value={selectedUserList}\n dataList={totalUserList}\n lockedIds={lockedIds}\n multiple={!!multiple}\n key={panelKey}\n loading={loading}\n dropdownWidth={dropdownContentWidth}\n onSearchValueChange={onSearchValueChange}\n onChange={onSelectedChange}\n onCancel={() => {\n onCancel?.();\n setDropdownOpen(false);\n }}\n renderItem={renderItem}\n renderSelectedTag={renderSelectedTag}\n ></Panel>\n </div>\n );\n }}\n ></Select>\n );\n};\n\nconst MemberSelector = Component as React.FC<IMemberPickerProps> & {\n MemberPanel: typeof MemberPanel;\n};\n\nMemberSelector.MemberPanel = MemberPanel;\nexport default MemberSelector;\n"],"mappings":"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"}
@@ -23,6 +23,10 @@ export interface ModalProps {
23
23
  centered?: boolean;
24
24
  destroyOnClose?: boolean;
25
25
  className?: string;
26
+ /** Pass through to the modal content root for automated testing. */
27
+ 'data-testid'?: string;
28
+ /** Pass through to the modal content root for accessibility and automated testing. */
29
+ 'aria-label'?: string;
26
30
  /** Applied to the outer wrap layer (matches antd wrapClassName behavior) */
27
31
  wrapClassName?: string;
28
32
  style?: React.CSSProperties;
@@ -55,7 +55,7 @@ function getIcon(type) {
55
55
  function OriginModal(props) {
56
56
  const { locale } = useContext(LocaleContext);
57
57
  const t = getTranslator(locale);
58
- const { className, children, okType = "primary", width, closeIcon, subTitle, okButtonProps = {}, cancelButtonProps = {}, okText = t.Modal.sure, cancelText = t.Modal.cancel, icon, title, paddingLess, responsiveBounds, hideHeaderBottomBorder, virtualScrollBar, style, maskClosable = false, fullscreen, open = false, onOk, onCancel, footer, confirmLoading, closable = true, zIndex = 1e3, bodyStyle, keyboard = true, afterOpenChange, wrapClassName, _modalType } = props;
58
+ const { className, "data-testid": dataTestId, "aria-label": ariaLabel, children, okType = "primary", width, closeIcon, subTitle, okButtonProps = {}, cancelButtonProps = {}, okText = t.Modal.sure, cancelText = t.Modal.cancel, icon, title, paddingLess, responsiveBounds, hideHeaderBottomBorder, virtualScrollBar, style, maskClosable = false, fullscreen, open = false, onOk, onCancel, footer, confirmLoading, closable = true, zIndex = 1e3, bodyStyle, keyboard = true, afterOpenChange, wrapClassName, _modalType } = props;
59
59
  const prevOpenRef = useRef(open);
60
60
  const contentRef = useRef(null);
61
61
  useEffect(() => {
@@ -151,6 +151,8 @@ function OriginModal(props) {
151
151
  className: cn("ald-modal-wrap ant-modal-wrap tw-pointer-events-none tw-fixed tw-inset-0 tw-flex tw-items-center tw-justify-center", wrapClassName),
152
152
  style: { zIndex: contentZIndex },
153
153
  children: /* @__PURE__ */ jsx(DialogPrimitive.Content, {
154
+ "data-testid": dataTestId,
155
+ "aria-label": ariaLabel,
154
156
  className: cn("ald-modal ant-modal tw-pointer-events-auto tw-box-border tw-flex tw-flex-col tw-overflow-hidden tw-bg-[var(--alias-colors-bg-skeleton-subtler)] tw-shadow-[var(--elevation-bottom-bottom-lg)] tw-outline-none", fullscreen ? "ald-modal-fullscreen tw-fixed tw-inset-0 tw-size-full tw-rounded-none" : "tw-rounded-r-75", !fullscreen && "tw-border tw-border-solid tw-border-[var(--border-default)]", paddingLess && "ald-modal-padding-less", virtualScrollBar && "ald-modal-virtual-scroll-bar", hideHeaderBottomBorder && "ald-modal-hide-header-bottom-border", responsiveBounds && "ald-modal-responsive-bounds", className),
155
157
  style: {
156
158
  ...fullscreen ? {} : {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/Modal/index.tsx"],"sourcesContent":["import * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { hideOthers } from 'aria-hidden';\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { createRoot } from 'react-dom/client';\nimport Button, { ButtonType, IButtonProps } from '../Button';\nimport {\n AttentionTriangleLightLine,\n CheckCircleLightLine,\n CloseLLine,\n InformationCircleLightLine,\n} from '../Icon';\nimport IconButton from '../IconButton';\nimport ScrollArea from '../ScrollArea';\nimport {\n FloatingLayerProvider,\n useFloatingLayer,\n} from '../_utils/floatingLayer';\nimport { LocaleContext, getTranslator } from '../locale/default';\nimport { cn } from '../lib/utils';\n\nexport const destroyFns: Array<() => void> = [];\n\nexport interface ModalProps {\n open?: boolean;\n onOk?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n onCancel?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n afterClose?: () => void;\n title?: React.ReactNode;\n subTitle?: React.ReactNode;\n icon?: React.ReactElement;\n width?: number | string;\n footer?: React.ReactNode | null;\n okText?: React.ReactNode;\n cancelText?: React.ReactNode;\n okButtonProps?: IButtonProps;\n cancelButtonProps?: IButtonProps;\n okType?: ButtonType;\n confirmLoading?: boolean;\n maskClosable?: boolean;\n closable?: boolean;\n closeIcon?: React.ReactNode;\n centered?: boolean;\n destroyOnClose?: boolean;\n className?: string;\n /** Applied to the outer wrap layer (matches antd wrapClassName behavior) */\n wrapClassName?: string;\n style?: React.CSSProperties;\n bodyStyle?: React.CSSProperties;\n zIndex?: number;\n children?: React.ReactNode;\n paddingLess?: boolean;\n virtualScrollBar?: boolean;\n hideHeaderBottomBorder?: boolean;\n responsiveBounds?: boolean;\n fullscreen?: boolean;\n keyboard?: boolean;\n afterOpenChange?: (open: boolean) => void;\n getContainer?: (() => HTMLElement) | false;\n /** @internal used by static methods to pass modal type for icon styling */\n _modalType?: string;\n}\n\nexport interface ModalFuncProps {\n title?: React.ReactNode;\n subTitle?: React.ReactNode;\n content?: React.ReactNode;\n icon?: React.ReactElement;\n okText?: React.ReactNode;\n cancelText?: React.ReactNode;\n okButtonProps?: IButtonProps;\n cancelButtonProps?: IButtonProps;\n okType?: ButtonType;\n onOk?: (...args: any[]) => any;\n onCancel?: (...args: any[]) => any;\n width?: number | string;\n className?: string;\n /** @deprecated Use `className` instead. Preserved for antd v4 compat. */\n wrapClassName?: string;\n closable?: boolean;\n type?: 'info' | 'success' | 'error' | 'warn' | 'warning' | 'confirm';\n centered?: boolean;\n maskClosable?: boolean;\n}\n\nconst DEFAULT_WIDTH = 552;\n\nconst ModalTitle = (\n { icon, title, subTitle }: Pick<ModalProps, 'icon' | 'title' | 'subTitle'>,\n type?: string,\n) => (\n <div className=\"ald-modal-title-container tw-flex tw-items-center tw-gap-4\">\n {icon && (\n <div\n className={cn(\n 'ald-modal-icon-container tw-grid tw-size-10 tw-shrink-0 tw-place-items-center tw-rounded-[var(--global-grid-250)]',\n type === 'info' &&\n 'ald-modal-cion-info-container tw-bg-[var(--action-primary-subtle-hover)]',\n type === 'success' &&\n 'ald-modal-cion-success-container tw-bg-[var(--background-positive-muted)]',\n type === 'warning' &&\n 'ald-modal-cion-warning-container tw-bg-[var(--background-warning-muted)]',\n type === 'warn' &&\n 'ald-modal-cion-warning-container tw-bg-[var(--background-warning-muted)]',\n type === 'error' &&\n 'ald-modal-cion-error-container tw-bg-[var(--background-negative-muted)]',\n type === 'confirm' &&\n 'ald-modal-cion-confirm-container tw-bg-[var(--action-primary-subtle-hover)]',\n )}\n >\n {icon}\n </div>\n )}\n <div className=\"ald-modal-text-container\">\n {title && (\n <div\n className={cn(\n 'ald-modal-text-title tw-text-lg tw-font-semibold tw-leading-7 tw-text-[var(--alias-colors-text-strong)]',\n !subTitle && 'ald-modal-text-title-only tw-text-xl',\n )}\n >\n {title}\n </div>\n )}\n {subTitle && (\n <div className=\"ald-modal-text-sub-title tw-mt-1 tw-text-xs tw-leading-4 tw-text-[var(--alias-colors-text-subtle)]\">\n {subTitle}\n </div>\n )}\n </div>\n </div>\n);\n\nfunction getIcon(\n type: 'info' | 'success' | 'error' | 'warn' | 'warning' | 'confirm',\n) {\n if (type === 'success')\n return (\n <CheckCircleLightLine\n fill=\"var(--content-inverted-primary)\"\n color=\"var(--background-positive-strong)\"\n size={24}\n />\n );\n if (type === 'error')\n return (\n <AttentionTriangleLightLine\n color=\"var(--background-negative-strong)\"\n fill=\"var(--content-inverted-primary)\"\n size={24}\n />\n );\n if (type === 'warning' || type === 'warn')\n return (\n <AttentionTriangleLightLine\n color=\"var(--background-warning-strong)\"\n size={24}\n />\n );\n return (\n <InformationCircleLightLine\n size={24}\n color=\"var(--interaction-default-normal)\"\n />\n );\n}\n\nfunction OriginModal(props: ModalProps) {\n const { locale } = useContext(LocaleContext);\n const t = getTranslator(locale);\n const {\n className,\n children,\n okType = 'primary',\n width,\n closeIcon,\n subTitle,\n okButtonProps = {},\n cancelButtonProps = {},\n okText = t.Modal.sure,\n cancelText = t.Modal.cancel,\n icon,\n title,\n paddingLess,\n responsiveBounds,\n hideHeaderBottomBorder,\n virtualScrollBar,\n style,\n maskClosable = false,\n fullscreen,\n open = false,\n onOk,\n onCancel,\n footer,\n confirmLoading,\n closable = true,\n zIndex = 1000,\n bodyStyle,\n keyboard = true,\n afterOpenChange,\n wrapClassName,\n _modalType,\n } = props;\n\n const prevOpenRef = useRef(open);\n const contentRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (prevOpenRef.current !== open) {\n prevOpenRef.current = open;\n afterOpenChange?.(open);\n }\n }, [open, afterOpenChange]);\n\n // ---- modal={false} 补偿:锁定背景滚动 ----\n useEffect(() => {\n if (!open) return;\n const prev = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n return () => {\n document.body.style.overflow = prev;\n };\n }, [open]);\n\n // ---- modal={false} 补偿:aria-hidden(屏幕阅读器只感知弹窗) ----\n useEffect(() => {\n if (!open || !contentRef.current) return;\n return hideOthers(contentRef.current);\n }, [open]);\n\n // ---- modal={false} 补偿:Tab 焦点循环 ----\n useEffect(() => {\n if (!open || !contentRef.current) return;\n const container = contentRef.current;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Tab') return;\n const focusable = container.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]):not([disabled])',\n );\n if (focusable.length === 0) return;\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (\n document.activeElement === first ||\n !container.contains(document.activeElement)\n ) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (\n document.activeElement === last ||\n !container.contains(document.activeElement)\n ) {\n e.preventDefault();\n first.focus();\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [open]);\n\n const responsiveBoundsStyle = useMemo(() => {\n if (!responsiveBounds) return {};\n return {\n width: 'calc(100% - 160px)',\n maxWidth: '1680px',\n minWidth: '1280px',\n height: 'calc(100% - 48px)',\n maxHeight: '900px',\n minHeight: '640px',\n };\n }, [responsiveBounds]);\n\n const mergedOkProps = { loading: confirmLoading, ...okButtonProps };\n const { maskZIndex, contentZIndex, nextLevel } = useFloatingLayer(zIndex);\n\n const renderFooter = () => {\n if (footer === null) return null;\n if (footer)\n return (\n // antd 兼容:antd .ant-modal-footer 使用 text-align:right 让 inline 按钮右对齐,\n // 即使消费方传入 width:100% 的子容器,内部 inline 元素仍能右对齐。\n // 此处同时使用 tw-flex tw-justify-end(flexbox 对齐)和 tw-text-right(继承式对齐)保持兼容。\n <div className=\"ald-modal-footer ant-modal-footer tw-flex tw-items-center tw-justify-end tw-gap-2 tw-border-t tw-border-solid tw-border-[var(--global-cool-grey-100)] tw-bg-[var(--alias-colors-bg-skeleton-subtler)] tw-px-6 tw-py-3 tw-text-right\">\n {footer}\n </div>\n );\n return (\n <div className=\"ald-modal-footer ant-modal-footer tw-flex tw-justify-end tw-gap-2 tw-border-t tw-border-solid tw-border-[var(--border-default)] tw-px-6 tw-py-4\">\n <Button\n type=\"secondary\"\n size=\"middle\"\n {...cancelButtonProps}\n onClick={onCancel}\n >\n {cancelText}\n </Button>\n <Button type={okType} size=\"middle\" {...mergedOkProps} onClick={onOk}>\n {okText}\n </Button>\n </div>\n );\n };\n\n return (\n <DialogPrimitive.Root open={open} modal={false}>\n <DialogPrimitive.Portal>\n {/* modal={false} 时 DialogPrimitive.Overlay 不渲染,用普通 div 替代 */}\n <div\n className=\"ald-modal-mask tw-animate-in tw-fade-in-0 tw-fixed tw-inset-0 tw-bg-black/45\"\n style={{ zIndex: maskZIndex }}\n onPointerDown={() => {\n if (maskClosable) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n }\n }}\n />\n {/* Centering wrapper — replaces transform centering so consumer CSS (top/left overrides) works */}\n <div\n ref={contentRef}\n className={cn(\n // antd 兼容:保留 ant-modal-wrap class,消费方 CSS 通过 wrapClassName + :global(.ant-modal) 控制弹窗宽高\n 'ald-modal-wrap ant-modal-wrap tw-pointer-events-none tw-fixed tw-inset-0 tw-flex tw-items-center tw-justify-center',\n wrapClassName,\n )}\n style={{ zIndex: contentZIndex }}\n >\n <DialogPrimitive.Content\n className={cn(\n // antd 兼容:保留 ant-modal class,消费方 CSS 通过 .ant-modal 选择器控制弹窗宽高等样式\n // tw-outline-none:Radix 打开时会聚焦 Content,不抑制 outline 会渲染出蓝色焦点框\n 'ald-modal ant-modal tw-pointer-events-auto tw-box-border tw-flex tw-flex-col tw-overflow-hidden tw-bg-[var(--alias-colors-bg-skeleton-subtler)] tw-shadow-[var(--elevation-bottom-bottom-lg)] tw-outline-none',\n fullscreen\n ? 'ald-modal-fullscreen tw-fixed tw-inset-0 tw-size-full tw-rounded-none'\n : 'tw-rounded-r-75',\n !fullscreen &&\n 'tw-border tw-border-solid tw-border-[var(--border-default)]',\n paddingLess && 'ald-modal-padding-less',\n virtualScrollBar && 'ald-modal-virtual-scroll-bar',\n hideHeaderBottomBorder && 'ald-modal-hide-header-bottom-border',\n responsiveBounds && 'ald-modal-responsive-bounds',\n className,\n )}\n style={{\n ...(fullscreen\n ? {}\n : {\n width: responsiveBounds\n ? responsiveBoundsStyle.width\n : width || DEFAULT_WIDTH,\n ...responsiveBoundsStyle,\n }),\n ...style,\n }}\n onEscapeKeyDown={(e) => {\n if (keyboard) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n } else {\n e.preventDefault();\n }\n }}\n onPointerDownOutside={(e) => {\n if (maskClosable) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n } else {\n e.preventDefault();\n }\n }}\n onInteractOutside={(e) => {\n if (!maskClosable) {\n e.preventDefault();\n }\n }}\n >\n {/* ant-modal-content compat wrapper — matches antd DOM nesting for consumer CSS */}\n <div className=\"ant-modal-content tw-flex tw-h-full tw-flex-col\">\n <FloatingLayerProvider value={nextLevel}>\n {!fullscreen && (\n <div\n className={cn(\n 'ald-modal-header ant-modal-header tw-flex tw-items-start tw-justify-between tw-bg-[var(--alias-colors-bg-skeleton-subtler)] tw-px-6 tw-py-4',\n !hideHeaderBottomBorder &&\n 'tw-border-b tw-border-solid tw-border-[var(--global-cool-grey-100)]',\n )}\n >\n <DialogPrimitive.Title asChild>\n <div className=\"tw-flex-1\">\n {ModalTitle({ icon, title, subTitle }, _modalType)}\n </div>\n </DialogPrimitive.Title>\n {closable && (\n <DialogPrimitive.Close asChild>\n <span className=\"ant-modal-close\" onClick={onCancel}>\n {closeIcon || (\n <IconButton\n icon={<CloseLLine size={20} />}\n size=\"middle\"\n />\n )}\n </span>\n </DialogPrimitive.Close>\n )}\n </div>\n )}\n {/* Hidden title for accessibility when fullscreen hides the header */}\n {fullscreen && (\n <DialogPrimitive.Title className=\"tw-sr-only\">\n {title}\n </DialogPrimitive.Title>\n )}\n <div\n className={cn(\n 'ald-modal-body ant-modal-body tw-flex-1 tw-text-sm tw-leading-5',\n fullscreen\n ? 'tw-h-full tw-overflow-hidden tw-p-0'\n : 'tw-min-h-[130px]',\n !fullscreen &&\n (virtualScrollBar\n ? 'tw-overflow-hidden tw-p-0'\n : 'tw-overflow-auto'),\n !fullscreen &&\n !responsiveBounds &&\n !virtualScrollBar &&\n 'tw-max-h-[68vh]',\n !fullscreen &&\n !paddingLess &&\n !virtualScrollBar &&\n 'tw-p-6',\n )}\n style={bodyStyle}\n >\n {virtualScrollBar ? (\n <ScrollArea\n className=\"ald-modal-body-wrap !tw-h-auto\"\n innerClassName={cn(\n 'ald-modal-body-wrap-inner tw-max-h-[68vh]',\n paddingLess ? 'tw-p-0' : 'tw-px-[23px] tw-py-0',\n )}\n >\n {children}\n </ScrollArea>\n ) : (\n children\n )}\n </div>\n {!fullscreen && renderFooter()}\n </FloatingLayerProvider>\n </div>\n </DialogPrimitive.Content>\n </div>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n}\n\n// Static method helper\nfunction createStaticModal(\n type: ModalFuncProps['type'],\n props: ModalFuncProps,\n) {\n const container = document.createElement('div');\n document.body.appendChild(container);\n const root = createRoot(container);\n\n let currentProps = { ...props };\n\n const destroy = () => {\n root.unmount();\n container.remove();\n const idx = destroyFns.indexOf(destroy);\n if (idx >= 0) destroyFns.splice(idx, 1);\n };\n\n const update = (newProps: Partial<ModalFuncProps>) => {\n currentProps = { ...currentProps, ...newProps };\n render(currentProps);\n };\n\n const isConfirm = type === 'confirm';\n\n const render = (p: ModalFuncProps) => {\n const handleOk = () => {\n p.onOk?.();\n destroy();\n };\n const handleCancel = () => {\n p.onCancel?.();\n destroy();\n };\n\n root.render(\n <OriginModal\n open={true}\n title={p.title}\n subTitle={p.subTitle}\n icon={p.icon || getIcon(type || 'info')}\n onOk={handleOk}\n onCancel={handleCancel}\n okText={p.okText}\n cancelText={p.cancelText}\n okButtonProps={p.okButtonProps}\n cancelButtonProps={p.cancelButtonProps}\n okType={p.okType || (isConfirm ? 'dangerous' : 'primary')}\n width={p.width || DEFAULT_WIDTH}\n className={cn('ald-modal', p.className)}\n closable={p.closable}\n maskClosable={p.maskClosable}\n _modalType={type}\n footer={\n isConfirm ? undefined : (\n <Button\n type=\"primary\"\n size=\"middle\"\n {...(p.okButtonProps || {})}\n onClick={handleOk}\n >\n {p.okText || 'OK'}\n </Button>\n )\n }\n >\n {p.content}\n </OriginModal>,\n );\n };\n\n destroyFns.push(destroy);\n render(currentProps);\n\n return { destroy, update };\n}\n\n// Attach static methods\ntype ModalFunc = (props: ModalFuncProps) => {\n destroy: () => void;\n update: (props: Partial<ModalFuncProps>) => void;\n};\n\n// ---------- useModal hook ----------\n\ninterface ModalInstance {\n id: number;\n type: ModalFuncProps['type'];\n props: ModalFuncProps;\n open: boolean;\n}\n\nexport interface ModalApiInstance {\n destroy: () => void;\n update: (newProps: Partial<ModalFuncProps>) => void;\n}\n\nexport interface ModalStaticFunctions {\n info: (props: ModalFuncProps) => ModalApiInstance;\n success: (props: ModalFuncProps) => ModalApiInstance;\n error: (props: ModalFuncProps) => ModalApiInstance;\n warning: (props: ModalFuncProps) => ModalApiInstance;\n confirm: (props: ModalFuncProps) => ModalApiInstance;\n}\n\nfunction useModal(): [ModalStaticFunctions, React.ReactElement] {\n const [modals, setModals] = useState<ModalInstance[]>([]);\n const idCounter = useRef(0);\n\n const removeModal = useCallback((id: number) => {\n setModals((prev) =>\n prev.map((m) => (m.id === id ? { ...m, open: false } : m)),\n );\n // Remove from DOM after animation\n setTimeout(() => {\n setModals((prev) => prev.filter((m) => m.id !== id));\n }, 300);\n }, []);\n\n const updateModal = useCallback(\n (id: number, newProps: Partial<ModalFuncProps>) => {\n setModals((prev) =>\n prev.map((m) =>\n m.id === id ? { ...m, props: { ...m.props, ...newProps } } : m,\n ),\n );\n },\n [],\n );\n\n const openModal = useCallback(\n (type: ModalFuncProps['type'], props: ModalFuncProps): ModalApiInstance => {\n const id = ++idCounter.current;\n const instance: ModalInstance = { id, type, props, open: true };\n setModals((prev) => [...prev, instance]);\n\n return {\n destroy: () => removeModal(id),\n update: (newProps: Partial<ModalFuncProps>) =>\n updateModal(id, newProps),\n };\n },\n [removeModal, updateModal],\n );\n\n const api = useMemo<ModalStaticFunctions>(\n () => ({\n info: (props) => openModal('info', props),\n success: (props) => openModal('success', props),\n error: (props) => openModal('error', props),\n warning: (props) => openModal('warning', props),\n confirm: (props) =>\n openModal('confirm', { ...props, type: props.type || 'confirm' }),\n }),\n [openModal],\n );\n\n const contextHolder = (\n <>\n {modals.map((m) => {\n const isConfirmType = m.type === 'confirm';\n const handleOk = () => {\n m.props.onOk?.();\n removeModal(m.id);\n };\n const handleCancel = () => {\n m.props.onCancel?.();\n removeModal(m.id);\n };\n return (\n <OriginModal\n key={m.id}\n open={m.open}\n title={m.props.title}\n subTitle={m.props.subTitle}\n icon={m.props.icon || getIcon(m.type || 'info')}\n onOk={handleOk}\n onCancel={handleCancel}\n okText={m.props.okText}\n cancelText={m.props.cancelText}\n okButtonProps={m.props.okButtonProps}\n cancelButtonProps={m.props.cancelButtonProps}\n okType={m.props.okType || (isConfirmType ? 'dangerous' : 'primary')}\n width={m.props.width || DEFAULT_WIDTH}\n className={cn('ald-modal', m.props.className)}\n closable={m.props.closable}\n maskClosable={m.props.maskClosable}\n _modalType={m.type}\n footer={\n isConfirmType ? undefined : (\n <Button\n type=\"primary\"\n size=\"middle\"\n {...(m.props.okButtonProps || {})}\n onClick={handleOk}\n >\n {m.props.okText || 'OK'}\n </Button>\n )\n }\n >\n {m.props.content}\n </OriginModal>\n );\n })}\n </>\n );\n\n return [api, contextHolder];\n}\n\n// ---------- end useModal ----------\n\nconst Modal = OriginModal as typeof OriginModal & {\n info: ModalFunc;\n success: ModalFunc;\n error: ModalFunc;\n warning: ModalFunc;\n confirm: ModalFunc;\n destroyAll: () => void;\n useModal: typeof useModal;\n config: (config: any) => void;\n};\n\nModal.info = (props) => createStaticModal('info', props);\nModal.success = (props) => createStaticModal('success', props);\nModal.error = (props) => createStaticModal('error', props);\nModal.warning = (props) => createStaticModal('warning', props);\nModal.confirm = (props) =>\n createStaticModal('confirm', { ...props, type: props.type || 'confirm' });\n\nModal.destroyAll = () => {\n while (destroyFns.length) {\n const close = destroyFns.pop();\n if (close) close();\n }\n};\n\nModal.useModal = useModal;\nModal.config = () => {};\n\nexport default Modal;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/Modal/index.tsx"],"sourcesContent":["import * as DialogPrimitive from '@radix-ui/react-dialog';\nimport { hideOthers } from 'aria-hidden';\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { createRoot } from 'react-dom/client';\nimport Button, { ButtonType, IButtonProps } from '../Button';\nimport {\n AttentionTriangleLightLine,\n CheckCircleLightLine,\n CloseLLine,\n InformationCircleLightLine,\n} from '../Icon';\nimport IconButton from '../IconButton';\nimport ScrollArea from '../ScrollArea';\nimport {\n FloatingLayerProvider,\n useFloatingLayer,\n} from '../_utils/floatingLayer';\nimport { LocaleContext, getTranslator } from '../locale/default';\nimport { cn } from '../lib/utils';\n\nexport const destroyFns: Array<() => void> = [];\n\nexport interface ModalProps {\n open?: boolean;\n onOk?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n onCancel?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n afterClose?: () => void;\n title?: React.ReactNode;\n subTitle?: React.ReactNode;\n icon?: React.ReactElement;\n width?: number | string;\n footer?: React.ReactNode | null;\n okText?: React.ReactNode;\n cancelText?: React.ReactNode;\n okButtonProps?: IButtonProps;\n cancelButtonProps?: IButtonProps;\n okType?: ButtonType;\n confirmLoading?: boolean;\n maskClosable?: boolean;\n closable?: boolean;\n closeIcon?: React.ReactNode;\n centered?: boolean;\n destroyOnClose?: boolean;\n className?: string;\n /** Pass through to the modal content root for automated testing. */\n 'data-testid'?: string;\n /** Pass through to the modal content root for accessibility and automated testing. */\n 'aria-label'?: string;\n /** Applied to the outer wrap layer (matches antd wrapClassName behavior) */\n wrapClassName?: string;\n style?: React.CSSProperties;\n bodyStyle?: React.CSSProperties;\n zIndex?: number;\n children?: React.ReactNode;\n paddingLess?: boolean;\n virtualScrollBar?: boolean;\n hideHeaderBottomBorder?: boolean;\n responsiveBounds?: boolean;\n fullscreen?: boolean;\n keyboard?: boolean;\n afterOpenChange?: (open: boolean) => void;\n getContainer?: (() => HTMLElement) | false;\n /** @internal used by static methods to pass modal type for icon styling */\n _modalType?: string;\n}\n\nexport interface ModalFuncProps {\n title?: React.ReactNode;\n subTitle?: React.ReactNode;\n content?: React.ReactNode;\n icon?: React.ReactElement;\n okText?: React.ReactNode;\n cancelText?: React.ReactNode;\n okButtonProps?: IButtonProps;\n cancelButtonProps?: IButtonProps;\n okType?: ButtonType;\n onOk?: (...args: any[]) => any;\n onCancel?: (...args: any[]) => any;\n width?: number | string;\n className?: string;\n /** @deprecated Use `className` instead. Preserved for antd v4 compat. */\n wrapClassName?: string;\n closable?: boolean;\n type?: 'info' | 'success' | 'error' | 'warn' | 'warning' | 'confirm';\n centered?: boolean;\n maskClosable?: boolean;\n}\n\nconst DEFAULT_WIDTH = 552;\n\nconst ModalTitle = (\n { icon, title, subTitle }: Pick<ModalProps, 'icon' | 'title' | 'subTitle'>,\n type?: string,\n) => (\n <div className=\"ald-modal-title-container tw-flex tw-items-center tw-gap-4\">\n {icon && (\n <div\n className={cn(\n 'ald-modal-icon-container tw-grid tw-size-10 tw-shrink-0 tw-place-items-center tw-rounded-[var(--global-grid-250)]',\n type === 'info' &&\n 'ald-modal-cion-info-container tw-bg-[var(--action-primary-subtle-hover)]',\n type === 'success' &&\n 'ald-modal-cion-success-container tw-bg-[var(--background-positive-muted)]',\n type === 'warning' &&\n 'ald-modal-cion-warning-container tw-bg-[var(--background-warning-muted)]',\n type === 'warn' &&\n 'ald-modal-cion-warning-container tw-bg-[var(--background-warning-muted)]',\n type === 'error' &&\n 'ald-modal-cion-error-container tw-bg-[var(--background-negative-muted)]',\n type === 'confirm' &&\n 'ald-modal-cion-confirm-container tw-bg-[var(--action-primary-subtle-hover)]',\n )}\n >\n {icon}\n </div>\n )}\n <div className=\"ald-modal-text-container\">\n {title && (\n <div\n className={cn(\n 'ald-modal-text-title tw-text-lg tw-font-semibold tw-leading-7 tw-text-[var(--alias-colors-text-strong)]',\n !subTitle && 'ald-modal-text-title-only tw-text-xl',\n )}\n >\n {title}\n </div>\n )}\n {subTitle && (\n <div className=\"ald-modal-text-sub-title tw-mt-1 tw-text-xs tw-leading-4 tw-text-[var(--alias-colors-text-subtle)]\">\n {subTitle}\n </div>\n )}\n </div>\n </div>\n);\n\nfunction getIcon(\n type: 'info' | 'success' | 'error' | 'warn' | 'warning' | 'confirm',\n) {\n if (type === 'success')\n return (\n <CheckCircleLightLine\n fill=\"var(--content-inverted-primary)\"\n color=\"var(--background-positive-strong)\"\n size={24}\n />\n );\n if (type === 'error')\n return (\n <AttentionTriangleLightLine\n color=\"var(--background-negative-strong)\"\n fill=\"var(--content-inverted-primary)\"\n size={24}\n />\n );\n if (type === 'warning' || type === 'warn')\n return (\n <AttentionTriangleLightLine\n color=\"var(--background-warning-strong)\"\n size={24}\n />\n );\n return (\n <InformationCircleLightLine\n size={24}\n color=\"var(--interaction-default-normal)\"\n />\n );\n}\n\nfunction OriginModal(props: ModalProps) {\n const { locale } = useContext(LocaleContext);\n const t = getTranslator(locale);\n const {\n className,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n children,\n okType = 'primary',\n width,\n closeIcon,\n subTitle,\n okButtonProps = {},\n cancelButtonProps = {},\n okText = t.Modal.sure,\n cancelText = t.Modal.cancel,\n icon,\n title,\n paddingLess,\n responsiveBounds,\n hideHeaderBottomBorder,\n virtualScrollBar,\n style,\n maskClosable = false,\n fullscreen,\n open = false,\n onOk,\n onCancel,\n footer,\n confirmLoading,\n closable = true,\n zIndex = 1000,\n bodyStyle,\n keyboard = true,\n afterOpenChange,\n wrapClassName,\n _modalType,\n } = props;\n\n const prevOpenRef = useRef(open);\n const contentRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (prevOpenRef.current !== open) {\n prevOpenRef.current = open;\n afterOpenChange?.(open);\n }\n }, [open, afterOpenChange]);\n\n // ---- modal={false} 补偿:锁定背景滚动 ----\n useEffect(() => {\n if (!open) return;\n const prev = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n return () => {\n document.body.style.overflow = prev;\n };\n }, [open]);\n\n // ---- modal={false} 补偿:aria-hidden(屏幕阅读器只感知弹窗) ----\n useEffect(() => {\n if (!open || !contentRef.current) return;\n return hideOthers(contentRef.current);\n }, [open]);\n\n // ---- modal={false} 补偿:Tab 焦点循环 ----\n useEffect(() => {\n if (!open || !contentRef.current) return;\n const container = contentRef.current;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Tab') return;\n const focusable = container.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]):not([disabled])',\n );\n if (focusable.length === 0) return;\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (\n document.activeElement === first ||\n !container.contains(document.activeElement)\n ) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (\n document.activeElement === last ||\n !container.contains(document.activeElement)\n ) {\n e.preventDefault();\n first.focus();\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [open]);\n\n const responsiveBoundsStyle = useMemo(() => {\n if (!responsiveBounds) return {};\n return {\n width: 'calc(100% - 160px)',\n maxWidth: '1680px',\n minWidth: '1280px',\n height: 'calc(100% - 48px)',\n maxHeight: '900px',\n minHeight: '640px',\n };\n }, [responsiveBounds]);\n\n const mergedOkProps = { loading: confirmLoading, ...okButtonProps };\n const { maskZIndex, contentZIndex, nextLevel } = useFloatingLayer(zIndex);\n\n const renderFooter = () => {\n if (footer === null) return null;\n if (footer)\n return (\n // antd 兼容:antd .ant-modal-footer 使用 text-align:right 让 inline 按钮右对齐,\n // 即使消费方传入 width:100% 的子容器,内部 inline 元素仍能右对齐。\n // 此处同时使用 tw-flex tw-justify-end(flexbox 对齐)和 tw-text-right(继承式对齐)保持兼容。\n <div className=\"ald-modal-footer ant-modal-footer tw-flex tw-items-center tw-justify-end tw-gap-2 tw-border-t tw-border-solid tw-border-[var(--global-cool-grey-100)] tw-bg-[var(--alias-colors-bg-skeleton-subtler)] tw-px-6 tw-py-3 tw-text-right\">\n {footer}\n </div>\n );\n return (\n <div className=\"ald-modal-footer ant-modal-footer tw-flex tw-justify-end tw-gap-2 tw-border-t tw-border-solid tw-border-[var(--border-default)] tw-px-6 tw-py-4\">\n <Button\n type=\"secondary\"\n size=\"middle\"\n {...cancelButtonProps}\n onClick={onCancel}\n >\n {cancelText}\n </Button>\n <Button type={okType} size=\"middle\" {...mergedOkProps} onClick={onOk}>\n {okText}\n </Button>\n </div>\n );\n };\n\n return (\n <DialogPrimitive.Root open={open} modal={false}>\n <DialogPrimitive.Portal>\n {/* modal={false} 时 DialogPrimitive.Overlay 不渲染,用普通 div 替代 */}\n <div\n className=\"ald-modal-mask tw-animate-in tw-fade-in-0 tw-fixed tw-inset-0 tw-bg-black/45\"\n style={{ zIndex: maskZIndex }}\n onPointerDown={() => {\n if (maskClosable) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n }\n }}\n />\n {/* Centering wrapper — replaces transform centering so consumer CSS (top/left overrides) works */}\n <div\n ref={contentRef}\n className={cn(\n // antd 兼容:保留 ant-modal-wrap class,消费方 CSS 通过 wrapClassName + :global(.ant-modal) 控制弹窗宽高\n 'ald-modal-wrap ant-modal-wrap tw-pointer-events-none tw-fixed tw-inset-0 tw-flex tw-items-center tw-justify-center',\n wrapClassName,\n )}\n style={{ zIndex: contentZIndex }}\n >\n <DialogPrimitive.Content\n data-testid={dataTestId}\n aria-label={ariaLabel}\n className={cn(\n // antd 兼容:保留 ant-modal class,消费方 CSS 通过 .ant-modal 选择器控制弹窗宽高等样式\n // tw-outline-none:Radix 打开时会聚焦 Content,不抑制 outline 会渲染出蓝色焦点框\n 'ald-modal ant-modal tw-pointer-events-auto tw-box-border tw-flex tw-flex-col tw-overflow-hidden tw-bg-[var(--alias-colors-bg-skeleton-subtler)] tw-shadow-[var(--elevation-bottom-bottom-lg)] tw-outline-none',\n fullscreen\n ? 'ald-modal-fullscreen tw-fixed tw-inset-0 tw-size-full tw-rounded-none'\n : 'tw-rounded-r-75',\n !fullscreen &&\n 'tw-border tw-border-solid tw-border-[var(--border-default)]',\n paddingLess && 'ald-modal-padding-less',\n virtualScrollBar && 'ald-modal-virtual-scroll-bar',\n hideHeaderBottomBorder && 'ald-modal-hide-header-bottom-border',\n responsiveBounds && 'ald-modal-responsive-bounds',\n className,\n )}\n style={{\n ...(fullscreen\n ? {}\n : {\n width: responsiveBounds\n ? responsiveBoundsStyle.width\n : width || DEFAULT_WIDTH,\n ...responsiveBoundsStyle,\n }),\n ...style,\n }}\n onEscapeKeyDown={(e) => {\n if (keyboard) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n } else {\n e.preventDefault();\n }\n }}\n onPointerDownOutside={(e) => {\n if (maskClosable) {\n onCancel?.({} as React.MouseEvent<HTMLButtonElement>);\n } else {\n e.preventDefault();\n }\n }}\n onInteractOutside={(e) => {\n if (!maskClosable) {\n e.preventDefault();\n }\n }}\n >\n {/* ant-modal-content compat wrapper — matches antd DOM nesting for consumer CSS */}\n <div className=\"ant-modal-content tw-flex tw-h-full tw-flex-col\">\n <FloatingLayerProvider value={nextLevel}>\n {!fullscreen && (\n <div\n className={cn(\n 'ald-modal-header ant-modal-header tw-flex tw-items-start tw-justify-between tw-bg-[var(--alias-colors-bg-skeleton-subtler)] tw-px-6 tw-py-4',\n !hideHeaderBottomBorder &&\n 'tw-border-b tw-border-solid tw-border-[var(--global-cool-grey-100)]',\n )}\n >\n <DialogPrimitive.Title asChild>\n <div className=\"tw-flex-1\">\n {ModalTitle({ icon, title, subTitle }, _modalType)}\n </div>\n </DialogPrimitive.Title>\n {closable && (\n <DialogPrimitive.Close asChild>\n <span className=\"ant-modal-close\" onClick={onCancel}>\n {closeIcon || (\n <IconButton\n icon={<CloseLLine size={20} />}\n size=\"middle\"\n />\n )}\n </span>\n </DialogPrimitive.Close>\n )}\n </div>\n )}\n {/* Hidden title for accessibility when fullscreen hides the header */}\n {fullscreen && (\n <DialogPrimitive.Title className=\"tw-sr-only\">\n {title}\n </DialogPrimitive.Title>\n )}\n <div\n className={cn(\n 'ald-modal-body ant-modal-body tw-flex-1 tw-text-sm tw-leading-5',\n fullscreen\n ? 'tw-h-full tw-overflow-hidden tw-p-0'\n : 'tw-min-h-[130px]',\n !fullscreen &&\n (virtualScrollBar\n ? 'tw-overflow-hidden tw-p-0'\n : 'tw-overflow-auto'),\n !fullscreen &&\n !responsiveBounds &&\n !virtualScrollBar &&\n 'tw-max-h-[68vh]',\n !fullscreen &&\n !paddingLess &&\n !virtualScrollBar &&\n 'tw-p-6',\n )}\n style={bodyStyle}\n >\n {virtualScrollBar ? (\n <ScrollArea\n className=\"ald-modal-body-wrap !tw-h-auto\"\n innerClassName={cn(\n 'ald-modal-body-wrap-inner tw-max-h-[68vh]',\n paddingLess ? 'tw-p-0' : 'tw-px-[23px] tw-py-0',\n )}\n >\n {children}\n </ScrollArea>\n ) : (\n children\n )}\n </div>\n {!fullscreen && renderFooter()}\n </FloatingLayerProvider>\n </div>\n </DialogPrimitive.Content>\n </div>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n );\n}\n\n// Static method helper\nfunction createStaticModal(\n type: ModalFuncProps['type'],\n props: ModalFuncProps,\n) {\n const container = document.createElement('div');\n document.body.appendChild(container);\n const root = createRoot(container);\n\n let currentProps = { ...props };\n\n const destroy = () => {\n root.unmount();\n container.remove();\n const idx = destroyFns.indexOf(destroy);\n if (idx >= 0) destroyFns.splice(idx, 1);\n };\n\n const update = (newProps: Partial<ModalFuncProps>) => {\n currentProps = { ...currentProps, ...newProps };\n render(currentProps);\n };\n\n const isConfirm = type === 'confirm';\n\n const render = (p: ModalFuncProps) => {\n const handleOk = () => {\n p.onOk?.();\n destroy();\n };\n const handleCancel = () => {\n p.onCancel?.();\n destroy();\n };\n\n root.render(\n <OriginModal\n open={true}\n title={p.title}\n subTitle={p.subTitle}\n icon={p.icon || getIcon(type || 'info')}\n onOk={handleOk}\n onCancel={handleCancel}\n okText={p.okText}\n cancelText={p.cancelText}\n okButtonProps={p.okButtonProps}\n cancelButtonProps={p.cancelButtonProps}\n okType={p.okType || (isConfirm ? 'dangerous' : 'primary')}\n width={p.width || DEFAULT_WIDTH}\n className={cn('ald-modal', p.className)}\n closable={p.closable}\n maskClosable={p.maskClosable}\n _modalType={type}\n footer={\n isConfirm ? undefined : (\n <Button\n type=\"primary\"\n size=\"middle\"\n {...(p.okButtonProps || {})}\n onClick={handleOk}\n >\n {p.okText || 'OK'}\n </Button>\n )\n }\n >\n {p.content}\n </OriginModal>,\n );\n };\n\n destroyFns.push(destroy);\n render(currentProps);\n\n return { destroy, update };\n}\n\n// Attach static methods\ntype ModalFunc = (props: ModalFuncProps) => {\n destroy: () => void;\n update: (props: Partial<ModalFuncProps>) => void;\n};\n\n// ---------- useModal hook ----------\n\ninterface ModalInstance {\n id: number;\n type: ModalFuncProps['type'];\n props: ModalFuncProps;\n open: boolean;\n}\n\nexport interface ModalApiInstance {\n destroy: () => void;\n update: (newProps: Partial<ModalFuncProps>) => void;\n}\n\nexport interface ModalStaticFunctions {\n info: (props: ModalFuncProps) => ModalApiInstance;\n success: (props: ModalFuncProps) => ModalApiInstance;\n error: (props: ModalFuncProps) => ModalApiInstance;\n warning: (props: ModalFuncProps) => ModalApiInstance;\n confirm: (props: ModalFuncProps) => ModalApiInstance;\n}\n\nfunction useModal(): [ModalStaticFunctions, React.ReactElement] {\n const [modals, setModals] = useState<ModalInstance[]>([]);\n const idCounter = useRef(0);\n\n const removeModal = useCallback((id: number) => {\n setModals((prev) =>\n prev.map((m) => (m.id === id ? { ...m, open: false } : m)),\n );\n // Remove from DOM after animation\n setTimeout(() => {\n setModals((prev) => prev.filter((m) => m.id !== id));\n }, 300);\n }, []);\n\n const updateModal = useCallback(\n (id: number, newProps: Partial<ModalFuncProps>) => {\n setModals((prev) =>\n prev.map((m) =>\n m.id === id ? { ...m, props: { ...m.props, ...newProps } } : m,\n ),\n );\n },\n [],\n );\n\n const openModal = useCallback(\n (type: ModalFuncProps['type'], props: ModalFuncProps): ModalApiInstance => {\n const id = ++idCounter.current;\n const instance: ModalInstance = { id, type, props, open: true };\n setModals((prev) => [...prev, instance]);\n\n return {\n destroy: () => removeModal(id),\n update: (newProps: Partial<ModalFuncProps>) =>\n updateModal(id, newProps),\n };\n },\n [removeModal, updateModal],\n );\n\n const api = useMemo<ModalStaticFunctions>(\n () => ({\n info: (props) => openModal('info', props),\n success: (props) => openModal('success', props),\n error: (props) => openModal('error', props),\n warning: (props) => openModal('warning', props),\n confirm: (props) =>\n openModal('confirm', { ...props, type: props.type || 'confirm' }),\n }),\n [openModal],\n );\n\n const contextHolder = (\n <>\n {modals.map((m) => {\n const isConfirmType = m.type === 'confirm';\n const handleOk = () => {\n m.props.onOk?.();\n removeModal(m.id);\n };\n const handleCancel = () => {\n m.props.onCancel?.();\n removeModal(m.id);\n };\n return (\n <OriginModal\n key={m.id}\n open={m.open}\n title={m.props.title}\n subTitle={m.props.subTitle}\n icon={m.props.icon || getIcon(m.type || 'info')}\n onOk={handleOk}\n onCancel={handleCancel}\n okText={m.props.okText}\n cancelText={m.props.cancelText}\n okButtonProps={m.props.okButtonProps}\n cancelButtonProps={m.props.cancelButtonProps}\n okType={m.props.okType || (isConfirmType ? 'dangerous' : 'primary')}\n width={m.props.width || DEFAULT_WIDTH}\n className={cn('ald-modal', m.props.className)}\n closable={m.props.closable}\n maskClosable={m.props.maskClosable}\n _modalType={m.type}\n footer={\n isConfirmType ? undefined : (\n <Button\n type=\"primary\"\n size=\"middle\"\n {...(m.props.okButtonProps || {})}\n onClick={handleOk}\n >\n {m.props.okText || 'OK'}\n </Button>\n )\n }\n >\n {m.props.content}\n </OriginModal>\n );\n })}\n </>\n );\n\n return [api, contextHolder];\n}\n\n// ---------- end useModal ----------\n\nconst Modal = OriginModal as typeof OriginModal & {\n info: ModalFunc;\n success: ModalFunc;\n error: ModalFunc;\n warning: ModalFunc;\n confirm: ModalFunc;\n destroyAll: () => void;\n useModal: typeof useModal;\n config: (config: any) => void;\n};\n\nModal.info = (props) => createStaticModal('info', props);\nModal.success = (props) => createStaticModal('success', props);\nModal.error = (props) => createStaticModal('error', props);\nModal.warning = (props) => createStaticModal('warning', props);\nModal.confirm = (props) =>\n createStaticModal('confirm', { ...props, type: props.type || 'confirm' });\n\nModal.destroyAll = () => {\n while (destroyFns.length) {\n const close = destroyFns.pop();\n if (close) close();\n }\n};\n\nModal.useModal = useModal;\nModal.config = () => {};\n\nexport default Modal;\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { jsx } from "react/jsx-runtime";
5
5
  //#region src/Radio/components/Group/index.tsx
6
6
  var RadioGroupContext = createContext({});
7
7
  function RadioGroup(props) {
8
- const { children, radioGroupStyle = "filled", size = "middle", type = "radio", className, disabled: customDisabled } = props;
8
+ const { children, radioGroupStyle = "filled", size = "middle", type = "radio", className, disabled: customDisabled, "data-testid": dataTestId, "aria-label": ariaLabel } = props;
9
9
  const isControlled = "value" in props && props.value !== void 0;
10
10
  const [innerValue, setInnerValue] = useState(props.defaultValue);
11
11
  useEffect(() => {
@@ -41,6 +41,8 @@ function RadioGroup(props) {
41
41
  },
42
42
  children: /* @__PURE__ */ jsx("div", {
43
43
  className: getWrapperClass(),
44
+ "data-testid": dataTestId,
45
+ "aria-label": ariaLabel,
44
46
  children
45
47
  })
46
48
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/Radio/components/Group/index.tsx"],"sourcesContent":["import { cn } from '../../../lib/utils';\nimport React, { createContext, useEffect, useState } from 'react';\nimport DisabledContext from '../../../ConfigProvider/DisabledContext';\nimport { IRadioGroupProps } from '../../interface/radioGroup';\n\nexport const RadioGroupContext = createContext<\n Omit<IRadioGroupProps, 'children' | 'className'>\n>({});\n\nexport default function RadioGroup(props: IRadioGroupProps) {\n const {\n children,\n radioGroupStyle = 'filled',\n size = 'middle',\n type = 'radio',\n className,\n disabled: customDisabled,\n } = props;\n const isControlled = 'value' in props && props.value !== undefined;\n const [innerValue, setInnerValue] = useState(props.defaultValue);\n\n useEffect(() => {\n if (isControlled) {\n setInnerValue(props.value);\n }\n }, [props.value, isControlled]);\n\n const value = isControlled ? props.value : innerValue;\n const setValue = (v: any) => {\n if (!isControlled) {\n setInnerValue(v);\n }\n };\n // ===================== Disabled =====================\n const disabled = React.useContext(DisabledContext);\n const mergedDisabled = customDisabled ?? disabled;\n const onRadioChange = (selectedValue: any) => {\n const lastValue = value;\n\n setValue(selectedValue);\n const { onChange } = props;\n if (onChange && selectedValue !== lastValue) {\n onChange(selectedValue);\n }\n };\n\n const getWrapperClass = () => {\n const isButton = ['button', 'iconButton'].includes(type);\n const tempType = type === 'iconButton' ? 'icon-button' : type;\n return cn('ald-radio-group', className, `ald-radio-group-${tempType}`, {\n // 约束只能在type为button和iconbutton的时候才可以设置样式和大小\n [`ald-radio-group-${radioGroupStyle}`]: isButton,\n [`ald-radio-group-${size}`]: isButton,\n });\n };\n\n return (\n <RadioGroupContext.Provider\n value={{\n onChange: onRadioChange,\n value,\n radioGroupStyle,\n size,\n type,\n disabled: mergedDisabled,\n }}\n >\n <div className={getWrapperClass()}>{children}</div>\n </RadioGroupContext.Provider>\n );\n}\n"],"mappings":";;;;;AAKA,IAAa,oBAAoB,cAE/B,EAAE,CAAC;AAEL,SAAwB,WAAW,OAAyB;CAC1D,MAAM,EACJ,UACA,kBAAkB,UAClB,OAAO,UACP,OAAO,SACP,WACA,UAAU,mBACR;CACJ,MAAM,eAAe,WAAW,SAAS,MAAM,UAAU;CACzD,MAAM,CAAC,YAAY,iBAAiB,SAAS,MAAM,aAAa;AAEhE,iBAAgB;AACd,MAAI,aACF,eAAc,MAAM,MAAM;IAE3B,CAAC,MAAM,OAAO,aAAa,CAAC;CAE/B,MAAM,QAAQ,eAAe,MAAM,QAAQ;CAC3C,MAAM,YAAY,MAAW;AAC3B,MAAI,CAAC,aACH,eAAc,EAAE;;CAIpB,MAAM,WAAW,MAAM,WAAW,gBAAgB;CAClD,MAAM,iBAAiB,kBAAkB;CACzC,MAAM,iBAAiB,kBAAuB;EAC5C,MAAM,YAAY;AAElB,WAAS,cAAc;EACvB,MAAM,EAAE,aAAa;AACrB,MAAI,YAAY,kBAAkB,UAChC,UAAS,cAAc;;CAI3B,MAAM,wBAAwB;EAC5B,MAAM,WAAW,CAAC,UAAU,aAAa,CAAC,SAAS,KAAK;AAExD,SAAO,GAAG,mBAAmB,WAAW,mBADvB,SAAS,eAAe,gBAAgB,QACc;IAEpE,mBAAmB,oBAAoB;IACvC,mBAAmB,SAAS;GAC9B,CAAC;;AAGJ,QACE,oBAAC,kBAAkB,UAAnB;EACE,OAAO;GACL,UAAU;GACV;GACA;GACA;GACA;GACA,UAAU;GACX;YAED,oBAAC,OAAD;GAAK,WAAW,iBAAiB;GAAG;GAAe,CAAA;EACxB,CAAA"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/Radio/components/Group/index.tsx"],"sourcesContent":["import { cn } from '../../../lib/utils';\nimport React, { createContext, useEffect, useState } from 'react';\nimport DisabledContext from '../../../ConfigProvider/DisabledContext';\nimport { IRadioGroupProps } from '../../interface/radioGroup';\n\nexport const RadioGroupContext = createContext<\n Omit<IRadioGroupProps, 'children' | 'className'>\n>({});\n\nexport default function RadioGroup(props: IRadioGroupProps) {\n const {\n children,\n radioGroupStyle = 'filled',\n size = 'middle',\n type = 'radio',\n className,\n disabled: customDisabled,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n } = props;\n const isControlled = 'value' in props && props.value !== undefined;\n const [innerValue, setInnerValue] = useState(props.defaultValue);\n\n useEffect(() => {\n if (isControlled) {\n setInnerValue(props.value);\n }\n }, [props.value, isControlled]);\n\n const value = isControlled ? props.value : innerValue;\n const setValue = (v: any) => {\n if (!isControlled) {\n setInnerValue(v);\n }\n };\n // ===================== Disabled =====================\n const disabled = React.useContext(DisabledContext);\n const mergedDisabled = customDisabled ?? disabled;\n const onRadioChange = (selectedValue: any) => {\n const lastValue = value;\n\n setValue(selectedValue);\n const { onChange } = props;\n if (onChange && selectedValue !== lastValue) {\n onChange(selectedValue);\n }\n };\n\n const getWrapperClass = () => {\n const isButton = ['button', 'iconButton'].includes(type);\n const tempType = type === 'iconButton' ? 'icon-button' : type;\n return cn('ald-radio-group', className, `ald-radio-group-${tempType}`, {\n // 约束只能在type为button和iconbutton的时候才可以设置样式和大小\n [`ald-radio-group-${radioGroupStyle}`]: isButton,\n [`ald-radio-group-${size}`]: isButton,\n });\n };\n\n return (\n <RadioGroupContext.Provider\n value={{\n onChange: onRadioChange,\n value,\n radioGroupStyle,\n size,\n type,\n disabled: mergedDisabled,\n }}\n >\n <div\n className={getWrapperClass()}\n data-testid={dataTestId}\n aria-label={ariaLabel}\n >\n {children}\n </div>\n </RadioGroupContext.Provider>\n );\n}\n"],"mappings":";;;;;AAKA,IAAa,oBAAoB,cAE/B,EAAE,CAAC;AAEL,SAAwB,WAAW,OAAyB;CAC1D,MAAM,EACJ,UACA,kBAAkB,UAClB,OAAO,UACP,OAAO,SACP,WACA,UAAU,gBACV,eAAe,YACf,cAAc,cACZ;CACJ,MAAM,eAAe,WAAW,SAAS,MAAM,UAAU;CACzD,MAAM,CAAC,YAAY,iBAAiB,SAAS,MAAM,aAAa;AAEhE,iBAAgB;AACd,MAAI,aACF,eAAc,MAAM,MAAM;IAE3B,CAAC,MAAM,OAAO,aAAa,CAAC;CAE/B,MAAM,QAAQ,eAAe,MAAM,QAAQ;CAC3C,MAAM,YAAY,MAAW;AAC3B,MAAI,CAAC,aACH,eAAc,EAAE;;CAIpB,MAAM,WAAW,MAAM,WAAW,gBAAgB;CAClD,MAAM,iBAAiB,kBAAkB;CACzC,MAAM,iBAAiB,kBAAuB;EAC5C,MAAM,YAAY;AAElB,WAAS,cAAc;EACvB,MAAM,EAAE,aAAa;AACrB,MAAI,YAAY,kBAAkB,UAChC,UAAS,cAAc;;CAI3B,MAAM,wBAAwB;EAC5B,MAAM,WAAW,CAAC,UAAU,aAAa,CAAC,SAAS,KAAK;AAExD,SAAO,GAAG,mBAAmB,WAAW,mBADvB,SAAS,eAAe,gBAAgB,QACc;IAEpE,mBAAmB,oBAAoB;IACvC,mBAAmB,SAAS;GAC9B,CAAC;;AAGJ,QACE,oBAAC,kBAAkB,UAAnB;EACE,OAAO;GACL,UAAU;GACV;GACA;GACA;GACA;GACA,UAAU;GACX;YAED,oBAAC,OAAD;GACE,WAAW,iBAAiB;GAC5B,eAAa;GACb,cAAY;GAEX;GACG,CAAA;EACqB,CAAA"}
@@ -44,4 +44,8 @@ export interface IRadioGroupProps {
44
44
  */
45
45
  className?: string;
46
46
  children?: ReactNode[] | ReactNode;
47
+ /** 透传到 RadioGroup 根容器的 data-testid,用于自动化测试定位 */
48
+ 'data-testid'?: string;
49
+ /** 透传到 RadioGroup 根容器的 aria-label,用于可访问性与自动化测试定位 */
50
+ 'aria-label'?: string;
47
51
  }
@@ -26,7 +26,7 @@ function isShowSelectedSection(mode) {
26
26
  return typeof mode === "object" && mode.showSelectedSection && mode.responsive;
27
27
  }
28
28
  var BaseSelect = React$1.forwardRef((props, ref) => {
29
- const { id, className, displayValues, onDisplayValuesChange, displayMenu, notFoundContent, onClear, width, mode, status: customStatus, onOptionSelect, onClick, size: customSize, borderLess = false, disabled, placeholder, loading = false, open, defaultOpen, onOpenChange, showSearch, innerSearchValue, setInnerSearchValue, allowClear, showArrow = true, prefix, suffixIcon, dropdownRender, overlayStyle, dropdownStyle, popupMatchSelectWidth = true, placement, popupClassName, allowOverlap, style, ...restProps } = props;
29
+ const { id, className, displayValues, onDisplayValuesChange, displayMenu, notFoundContent, onClear, width, mode, status: customStatus, onOptionSelect, onClick, size: customSize, borderLess = false, disabled, placeholder, loading = false, open, defaultOpen, onOpenChange, showSearch, innerSearchValue, setInnerSearchValue, allowClear, showArrow = true, prefix, suffixIcon, dropdownRender, overlayStyle, dropdownStyle, popupMatchSelectWidth = true, placement, popupClassName, allowOverlap, style, "data-testid": dataTestid, "aria-label": ariaLabel, ...restProps } = props;
30
30
  const setClassNames = prefixCls("select");
31
31
  const selectRef = useRef(null);
32
32
  const widthStyle = getWidthStyle(width);
@@ -141,6 +141,8 @@ var BaseSelect = React$1.forwardRef((props, ref) => {
141
141
  ref: selectRef,
142
142
  id,
143
143
  onClick: onSelectClick,
144
+ "data-testid": dataTestid,
145
+ "aria-label": ariaLabel,
144
146
  children: [/* @__PURE__ */ jsx(RefSelectTrigger, {
145
147
  ...restProps,
146
148
  open: !!mergedOpen,
@@ -1 +1 @@
1
- {"version":3,"file":"BaseSelect.js","names":[],"sources":["../../src/Select/BaseSelect.tsx"],"sourcesContent":["import './ald-select.css';\nimport * as React from 'react';\nimport useMergedState from 'rc-util/es/hooks/useMergedState';\nimport { cn } from '../lib/utils';\nimport prefixCls from '../_utils/prefixCls';\n\n/** Align config type (locally defined to avoid rc-trigger dependency) */\nexport interface AlignType {\n points?: string[];\n offset?: (number | string)[];\n targetOffset?: (number | string)[];\n overflow?: { adjustX?: boolean; adjustY?: boolean };\n _experimental?: Record<string, any>;\n}\nimport SelectTrigger, { RefTriggerProps } from './SelectTrigger';\nimport Selector from './Selector';\nimport _ from 'lodash';\nimport { useContext, useRef, useState } from 'react';\nimport { FormItemInputContext } from '../Form/FormItemContext';\nimport getWidthStyle from './utils/getWidthStyle';\nimport Suffix from './components/Suffix';\nimport { PlacementType } from '../Dropdown';\nimport {\n BaseSelectRef,\n DisplayValueType,\n ISelectProps,\n LabelInValueType,\n SelectMenuProps,\n} from './interface';\nimport SizeContext from '../ConfigProvider/sizeContext';\nimport { ConfigContext } from '../ConfigProvider';\nimport { useCompactItemContext } from '../Space/CompactContext';\nimport { MenuInfo } from '../Menu';\n\nexport type RenderNode = React.ReactNode | ((props: any) => React.ReactNode);\n\nexport type RenderDOMFunc = (props: any) => HTMLElement;\n\nexport type Mode =\n | 'multiple'\n | {\n type: 'multiple';\n responsive?: boolean;\n maxRows?: number;\n showSelectedSection?: boolean;\n };\n\nexport type RawValueType = string | number;\n\nexport type CustomTagProps = {\n label: React.ReactNode;\n value: any;\n disabled: boolean;\n onClose: (event?: React.MouseEvent<HTMLElement, MouseEvent>) => void;\n closable: boolean;\n};\nexport interface BaseSelectPrivateProps {\n // >>> MISC\n omitDomProps?: string[];\n\n // >>> Value\n displayValues: LabelInValueType[];\n onDisplayValuesChange: (\n values: LabelInValueType[],\n info: {\n type: 'add' | 'remove' | 'clear';\n values: LabelInValueType[];\n },\n ) => void;\n\n // >>> Active\n /** Current dropdown list active item string value */\n activeValue?: string;\n /** Link search input with target element */\n activeDescendantId?: string;\n onActiveValueChange?: (value: string | null) => void;\n}\n\nexport type BaseSelectPropsWithoutPrivate = Omit<\n BaseSelectProps,\n keyof BaseSelectPrivateProps\n>;\n\nexport interface BaseSelectProps\n extends BaseSelectPrivateProps,\n ISelectProps,\n React.AriaAttributes {\n className?: string;\n style?: React.CSSProperties;\n notFoundContent?: React.ReactNode;\n onClear?: () => void;\n innerSearchValue?: string;\n setInnerSearchValue?: (value: string) => void;\n displayMenu?: SelectMenuProps;\n // >>> Open\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n onOptionSelect?: (val: RawValueType) => void;\n\n // >>> Icons\n allowClear?: boolean;\n showArrow?: boolean;\n suffixIcon?: React.ReactNode;\n\n // >>> Dropdown\n dropdownAlign?: AlignType;\n placement?: PlacementType;\n getPopupContainer?: () => HTMLElement;\n\n // >>> Focus\n onBlur?: React.FocusEventHandler<HTMLElement>;\n onFocus?: React.FocusEventHandler<HTMLElement>;\n\n // >>> Rest Events\n onKeyUp?: React.KeyboardEventHandler<HTMLDivElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;\n onMouseDown?: React.MouseEventHandler<HTMLDivElement>;\n onPopupScroll?: React.UIEventHandler<HTMLDivElement>;\n onInputKeyDown?: React.KeyboardEventHandler<\n HTMLInputElement | HTMLTextAreaElement\n >;\n onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;\n onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;\n onClick?: React.MouseEventHandler<HTMLDivElement>;\n}\n\nexport function isMultiple(mode?: Mode) {\n return !!mode;\n}\nexport function isResponsive(mode?: Mode) {\n return mode === 'multiple' || (typeof mode === 'object' && mode?.responsive);\n}\nexport function isShowSelectedSection(mode?: Mode) {\n if (!mode || mode === 'multiple') {\n return false;\n }\n\n return (\n typeof mode === 'object' && mode.showSelectedSection && mode.responsive\n );\n}\nconst BaseSelect = React.forwardRef(\n (props: BaseSelectProps, ref: React.Ref<BaseSelectRef>) => {\n const {\n id,\n className,\n // Value\n displayValues,\n onDisplayValuesChange,\n displayMenu,\n notFoundContent,\n onClear,\n width,\n mode,\n status: customStatus,\n onOptionSelect,\n onClick,\n size: customSize,\n borderLess = false,\n // Status\n disabled,\n placeholder,\n loading = false,\n\n // Open\n open,\n defaultOpen,\n onOpenChange,\n showSearch,\n innerSearchValue,\n setInnerSearchValue,\n // Icons\n allowClear,\n showArrow = true,\n prefix,\n suffixIcon,\n dropdownRender,\n overlayStyle,\n dropdownStyle,\n popupMatchSelectWidth = true,\n placement,\n popupClassName,\n allowOverlap,\n style,\n ...restProps\n // Rest Props\n } = props;\n const setClassNames = prefixCls('select');\n const selectRef = useRef<HTMLDivElement>(null);\n const widthStyle = getWidthStyle(width);\n const dropdownRef = useRef<RefTriggerProps>(null);\n const isResponsiveMode = isResponsive(mode);\n const isMultipleMode = isMultiple(mode);\n /** Used for component focused management */\n const contentSize = useContext(SizeContext);\n const { direction } = React.useContext(ConfigContext);\n // ===================== Compact Item =====================\n const { compactSize, compactItemClassnames } = useCompactItemContext(\n 'ald-select',\n direction,\n );\n const size = compactSize || customSize || contentSize || 'middle';\n const {\n status: contextStatus,\n // hasFeedback,\n // isFormItemInput,\n // feedbackIcon,\n } = useContext(FormItemInputContext);\n\n const mergedStatus = customStatus || contextStatus || undefined;\n\n // =========================== Imperative ===========================\n React.useImperativeHandle(ref, () => ({\n focus: () => setFocus(true),\n blur: () => setFocus(false),\n open: () => onToggleOpen(true),\n close: () => {\n console.log('ref close');\n onToggleOpen(false);\n },\n }));\n const [focus, setFocus] = useState(false);\n const [isHover, setIsHover] = useState(false);\n // ============================== Open ==============================\n const [innerOpen, setInnerOpen] = useMergedState<boolean>(false, {\n defaultValue: defaultOpen,\n value: open,\n });\n const mergedOpen = innerOpen;\n const onToggleOpen = React.useCallback(\n (newOpen?: boolean) => {\n const nextOpen = newOpen !== undefined ? newOpen : !mergedOpen;\n if (!nextOpen) {\n setShowResponsiveSelectedSection(false);\n setFocus(false);\n }\n if (mergedOpen !== nextOpen && !disabled) {\n setInnerOpen(nextOpen);\n onOpenChange?.(nextOpen);\n }\n },\n [mergedOpen, disabled, setInnerOpen, onOpenChange],\n );\n const [showResponsiveSelectedSection, setShowResponsiveSelectedSection] =\n useState(false);\n // 多选 responsive 进入 -1 收纳态(仅\"首 tag + +N\")时为 true,\n // width:auto 下据此给根节点加 overflow-collapsed 钳住 min-width 链,\n // 抵抗父 flex 行因 intrinsic 低估造成的假压缩(详见 ald-select.css 对应段)\n const [overflowCollapsed, setOverflowCollapsed] = useState(false);\n\n // ============================ Selector ============================\n const onSelectorRemove = (val: DisplayValueType) => {\n const newValues = displayValues.filter((i) => i !== val);\n\n onDisplayValuesChange(newValues, {\n type: 'remove',\n values: [\n {\n label: val.label,\n value: val.value as RawValueType,\n },\n ],\n });\n };\n\n const mergedClassName = cn(\n setClassNames('beta-ald-select', size, {\n active: mergedOpen || focus,\n borderless: borderLess,\n disabled: disabled,\n loading: loading,\n [`${mergedStatus}`]: !!mergedStatus,\n 'multiple-responsive': isResponsiveMode,\n 'multiple-default': isMultipleMode && !isResponsiveMode,\n // 仅 width:auto 生效:固定宽度下 -1 收纳态的收缩省略是预期行为,\n // 钳 min-width 反而会把固定宽撑破\n 'overflow-collapsed':\n overflowCollapsed && width === 'auto' && !_.isEmpty(displayValues),\n }),\n className,\n compactItemClassnames,\n );\n const showMenu = React.useMemo(() => {\n if (!displayMenu) {\n return undefined;\n }\n\n return {\n ...displayMenu,\n onClick: (info: MenuInfo) => {\n displayMenu?.onClick?.(info);\n if (isMultipleMode) {\n // 多选默认选中后不收起下拉:Dropdown 在 menu.onClick 之后读\n // info.keepOpen 决定是否 onChangeOpen(false),不设则每次点击都被\n // 当成关闭信号。用 ?? 保留用户在自己的 onClick 里显式设 false 的能力\n info.keepOpen = info.keepOpen ?? true;\n } else if (displayMenu) {\n onToggleOpen(false);\n setFocus(false);\n }\n setIsHover(false);\n onOptionSelect?.(info.key);\n },\n };\n }, [displayMenu, isMultipleMode, onToggleOpen, onOptionSelect]);\n const onSelectClick = React.useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) {\n return;\n }\n onClick?.(e);\n },\n [disabled, onClick],\n );\n React.useEffect(() => {\n const element = selectRef.current;\n if (element) {\n const handleMouseOver = () => setIsHover(true);\n const handleMouseOut = () => setIsHover(false);\n\n element.addEventListener('mouseover', handleMouseOver);\n element.addEventListener('mouseout', handleMouseOut);\n\n return () => {\n element.removeEventListener('mouseover', handleMouseOver);\n element.removeEventListener('mouseout', handleMouseOut);\n };\n }\n }, []);\n return (\n <div\n className={mergedClassName}\n style={{\n ...widthStyle,\n // width:auto 且无选中值时锁 shrink:Chromium 对该子树给父 flex 行的\n // intrinsic 宽度贡献恒少约 14px,父行按低估值布局后回头压缩根节点,\n // placeholder 右侧会被裁;有选中值时必须保持可压缩,rc-overflow\n // 才能在父行变窄时把放不下的 tag 收纳成 \"+N\"\n ...(width === 'auto' && _.isEmpty(displayValues)\n ? { flexShrink: 0 }\n : {}),\n ...style,\n }}\n ref={selectRef}\n id={id}\n onClick={onSelectClick}\n >\n <SelectTrigger\n {...restProps}\n open={!!mergedOpen}\n notFoundContent={notFoundContent}\n menu={showMenu}\n ref={dropdownRef}\n showSearch={showSearch}\n searchValue={innerSearchValue}\n setInnerSearchValue={setInnerSearchValue}\n popupMatchSelectWidth={popupMatchSelectWidth}\n overlayClassName={popupClassName}\n // @ts-ignore\n dropdownRender={dropdownRender}\n overlayStyle={overlayStyle || dropdownStyle}\n placement={placement}\n allowOverlap={allowOverlap}\n onOpenChange={(open) => {\n if (isResponsiveMode) {\n if (\n !mergedOpen &&\n !showResponsiveSelectedSection &&\n displayValues.length > 0 &&\n isShowSelectedSection(mode)\n ) {\n setShowResponsiveSelectedSection(true);\n } else {\n onToggleOpen(open);\n }\n } else {\n onToggleOpen(open);\n }\n }}\n >\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n <div className={cn(setClassNames('trigger'), 'ant-select-selector')}>\n {prefix && <div className={setClassNames('prefix')}>{prefix}</div>}\n {_.isEmpty(displayValues) && (\n <div\n className={cn(\n setClassNames('placeholder'),\n 'ant-select-selection-placeholder',\n )}\n >\n {placeholder}\n </div>\n )}\n {!_.isEmpty(displayValues) && (\n <Selector\n {...restProps}\n suffixIcon={suffixIcon}\n size={size}\n disabled={disabled}\n mode={mode}\n dropdownRef={dropdownRef}\n displayValues={displayValues}\n onToggleOpen={onToggleOpen}\n onRemove={onSelectorRemove}\n showResponsiveSelectedSection={showResponsiveSelectedSection}\n onOverflowCollapsedChange={setOverflowCollapsed}\n ></Selector>\n )}\n </div>\n </SelectTrigger>\n <Suffix\n showArrow={showArrow}\n allowClear={allowClear}\n disabled={disabled}\n loading={loading}\n isHover={isHover}\n onClear={() => {\n onToggleOpen(false);\n\n onDisplayValuesChange([], {\n type: 'clear',\n values: displayValues,\n });\n onClear?.();\n }}\n isActive={innerOpen}\n icon={suffixIcon}\n displayValues={displayValues}\n ></Suffix>\n </div>\n );\n },\n);\n\nexport default BaseSelect;\n"],"mappings":"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"}
1
+ {"version":3,"file":"BaseSelect.js","names":[],"sources":["../../src/Select/BaseSelect.tsx"],"sourcesContent":["import './ald-select.css';\nimport * as React from 'react';\nimport useMergedState from 'rc-util/es/hooks/useMergedState';\nimport { cn } from '../lib/utils';\nimport prefixCls from '../_utils/prefixCls';\n\n/** Align config type (locally defined to avoid rc-trigger dependency) */\nexport interface AlignType {\n points?: string[];\n offset?: (number | string)[];\n targetOffset?: (number | string)[];\n overflow?: { adjustX?: boolean; adjustY?: boolean };\n _experimental?: Record<string, any>;\n}\nimport SelectTrigger, { RefTriggerProps } from './SelectTrigger';\nimport Selector from './Selector';\nimport _ from 'lodash';\nimport { useContext, useRef, useState } from 'react';\nimport { FormItemInputContext } from '../Form/FormItemContext';\nimport getWidthStyle from './utils/getWidthStyle';\nimport Suffix from './components/Suffix';\nimport { PlacementType } from '../Dropdown';\nimport {\n BaseSelectRef,\n DisplayValueType,\n ISelectProps,\n LabelInValueType,\n SelectMenuProps,\n} from './interface';\nimport SizeContext from '../ConfigProvider/sizeContext';\nimport { ConfigContext } from '../ConfigProvider';\nimport { useCompactItemContext } from '../Space/CompactContext';\nimport { MenuInfo } from '../Menu';\n\nexport type RenderNode = React.ReactNode | ((props: any) => React.ReactNode);\n\nexport type RenderDOMFunc = (props: any) => HTMLElement;\n\nexport type Mode =\n | 'multiple'\n | {\n type: 'multiple';\n responsive?: boolean;\n maxRows?: number;\n showSelectedSection?: boolean;\n };\n\nexport type RawValueType = string | number;\n\nexport type CustomTagProps = {\n label: React.ReactNode;\n value: any;\n disabled: boolean;\n onClose: (event?: React.MouseEvent<HTMLElement, MouseEvent>) => void;\n closable: boolean;\n};\nexport interface BaseSelectPrivateProps {\n // >>> MISC\n omitDomProps?: string[];\n\n // >>> Value\n displayValues: LabelInValueType[];\n onDisplayValuesChange: (\n values: LabelInValueType[],\n info: {\n type: 'add' | 'remove' | 'clear';\n values: LabelInValueType[];\n },\n ) => void;\n\n // >>> Active\n /** Current dropdown list active item string value */\n activeValue?: string;\n /** Link search input with target element */\n activeDescendantId?: string;\n onActiveValueChange?: (value: string | null) => void;\n}\n\nexport type BaseSelectPropsWithoutPrivate = Omit<\n BaseSelectProps,\n keyof BaseSelectPrivateProps\n>;\n\nexport interface BaseSelectProps\n extends BaseSelectPrivateProps,\n ISelectProps,\n React.AriaAttributes {\n className?: string;\n style?: React.CSSProperties;\n notFoundContent?: React.ReactNode;\n onClear?: () => void;\n innerSearchValue?: string;\n setInnerSearchValue?: (value: string) => void;\n displayMenu?: SelectMenuProps;\n // >>> Open\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n onOptionSelect?: (val: RawValueType) => void;\n\n // >>> Icons\n allowClear?: boolean;\n showArrow?: boolean;\n suffixIcon?: React.ReactNode;\n\n // >>> Dropdown\n dropdownAlign?: AlignType;\n placement?: PlacementType;\n getPopupContainer?: () => HTMLElement;\n\n // >>> Focus\n onBlur?: React.FocusEventHandler<HTMLElement>;\n onFocus?: React.FocusEventHandler<HTMLElement>;\n\n // >>> Rest Events\n onKeyUp?: React.KeyboardEventHandler<HTMLDivElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;\n onMouseDown?: React.MouseEventHandler<HTMLDivElement>;\n onPopupScroll?: React.UIEventHandler<HTMLDivElement>;\n onInputKeyDown?: React.KeyboardEventHandler<\n HTMLInputElement | HTMLTextAreaElement\n >;\n onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;\n onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;\n onClick?: React.MouseEventHandler<HTMLDivElement>;\n}\n\nexport function isMultiple(mode?: Mode) {\n return !!mode;\n}\nexport function isResponsive(mode?: Mode) {\n return mode === 'multiple' || (typeof mode === 'object' && mode?.responsive);\n}\nexport function isShowSelectedSection(mode?: Mode) {\n if (!mode || mode === 'multiple') {\n return false;\n }\n\n return (\n typeof mode === 'object' && mode.showSelectedSection && mode.responsive\n );\n}\nconst BaseSelect = React.forwardRef(\n (props: BaseSelectProps, ref: React.Ref<BaseSelectRef>) => {\n const {\n id,\n className,\n // Value\n displayValues,\n onDisplayValuesChange,\n displayMenu,\n notFoundContent,\n onClear,\n width,\n mode,\n status: customStatus,\n onOptionSelect,\n onClick,\n size: customSize,\n borderLess = false,\n // Status\n disabled,\n placeholder,\n loading = false,\n\n // Open\n open,\n defaultOpen,\n onOpenChange,\n showSearch,\n innerSearchValue,\n setInnerSearchValue,\n // Icons\n allowClear,\n showArrow = true,\n prefix,\n suffixIcon,\n dropdownRender,\n overlayStyle,\n dropdownStyle,\n popupMatchSelectWidth = true,\n placement,\n popupClassName,\n allowOverlap,\n style,\n 'data-testid': dataTestid,\n 'aria-label': ariaLabel,\n ...restProps\n // Rest Props\n } = props;\n const setClassNames = prefixCls('select');\n const selectRef = useRef<HTMLDivElement>(null);\n const widthStyle = getWidthStyle(width);\n const dropdownRef = useRef<RefTriggerProps>(null);\n const isResponsiveMode = isResponsive(mode);\n const isMultipleMode = isMultiple(mode);\n /** Used for component focused management */\n const contentSize = useContext(SizeContext);\n const { direction } = React.useContext(ConfigContext);\n // ===================== Compact Item =====================\n const { compactSize, compactItemClassnames } = useCompactItemContext(\n 'ald-select',\n direction,\n );\n const size = compactSize || customSize || contentSize || 'middle';\n const {\n status: contextStatus,\n // hasFeedback,\n // isFormItemInput,\n // feedbackIcon,\n } = useContext(FormItemInputContext);\n\n const mergedStatus = customStatus || contextStatus || undefined;\n\n // =========================== Imperative ===========================\n React.useImperativeHandle(ref, () => ({\n focus: () => setFocus(true),\n blur: () => setFocus(false),\n open: () => onToggleOpen(true),\n close: () => {\n console.log('ref close');\n onToggleOpen(false);\n },\n }));\n const [focus, setFocus] = useState(false);\n const [isHover, setIsHover] = useState(false);\n // ============================== Open ==============================\n const [innerOpen, setInnerOpen] = useMergedState<boolean>(false, {\n defaultValue: defaultOpen,\n value: open,\n });\n const mergedOpen = innerOpen;\n const onToggleOpen = React.useCallback(\n (newOpen?: boolean) => {\n const nextOpen = newOpen !== undefined ? newOpen : !mergedOpen;\n if (!nextOpen) {\n setShowResponsiveSelectedSection(false);\n setFocus(false);\n }\n if (mergedOpen !== nextOpen && !disabled) {\n setInnerOpen(nextOpen);\n onOpenChange?.(nextOpen);\n }\n },\n [mergedOpen, disabled, setInnerOpen, onOpenChange],\n );\n const [showResponsiveSelectedSection, setShowResponsiveSelectedSection] =\n useState(false);\n // 多选 responsive 进入 -1 收纳态(仅\"首 tag + +N\")时为 true,\n // width:auto 下据此给根节点加 overflow-collapsed 钳住 min-width 链,\n // 抵抗父 flex 行因 intrinsic 低估造成的假压缩(详见 ald-select.css 对应段)\n const [overflowCollapsed, setOverflowCollapsed] = useState(false);\n\n // ============================ Selector ============================\n const onSelectorRemove = (val: DisplayValueType) => {\n const newValues = displayValues.filter((i) => i !== val);\n\n onDisplayValuesChange(newValues, {\n type: 'remove',\n values: [\n {\n label: val.label,\n value: val.value as RawValueType,\n },\n ],\n });\n };\n\n const mergedClassName = cn(\n setClassNames('beta-ald-select', size, {\n active: mergedOpen || focus,\n borderless: borderLess,\n disabled: disabled,\n loading: loading,\n [`${mergedStatus}`]: !!mergedStatus,\n 'multiple-responsive': isResponsiveMode,\n 'multiple-default': isMultipleMode && !isResponsiveMode,\n // 仅 width:auto 生效:固定宽度下 -1 收纳态的收缩省略是预期行为,\n // 钳 min-width 反而会把固定宽撑破\n 'overflow-collapsed':\n overflowCollapsed && width === 'auto' && !_.isEmpty(displayValues),\n }),\n className,\n compactItemClassnames,\n );\n const showMenu = React.useMemo(() => {\n if (!displayMenu) {\n return undefined;\n }\n\n return {\n ...displayMenu,\n onClick: (info: MenuInfo) => {\n displayMenu?.onClick?.(info);\n if (isMultipleMode) {\n // 多选默认选中后不收起下拉:Dropdown 在 menu.onClick 之后读\n // info.keepOpen 决定是否 onChangeOpen(false),不设则每次点击都被\n // 当成关闭信号。用 ?? 保留用户在自己的 onClick 里显式设 false 的能力\n info.keepOpen = info.keepOpen ?? true;\n } else if (displayMenu) {\n onToggleOpen(false);\n setFocus(false);\n }\n setIsHover(false);\n onOptionSelect?.(info.key);\n },\n };\n }, [displayMenu, isMultipleMode, onToggleOpen, onOptionSelect]);\n const onSelectClick = React.useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) {\n return;\n }\n onClick?.(e);\n },\n [disabled, onClick],\n );\n React.useEffect(() => {\n const element = selectRef.current;\n if (element) {\n const handleMouseOver = () => setIsHover(true);\n const handleMouseOut = () => setIsHover(false);\n\n element.addEventListener('mouseover', handleMouseOver);\n element.addEventListener('mouseout', handleMouseOut);\n\n return () => {\n element.removeEventListener('mouseover', handleMouseOver);\n element.removeEventListener('mouseout', handleMouseOut);\n };\n }\n }, []);\n return (\n <div\n className={mergedClassName}\n style={{\n ...widthStyle,\n // width:auto 且无选中值时锁 shrink:Chromium 对该子树给父 flex 行的\n // intrinsic 宽度贡献恒少约 14px,父行按低估值布局后回头压缩根节点,\n // placeholder 右侧会被裁;有选中值时必须保持可压缩,rc-overflow\n // 才能在父行变窄时把放不下的 tag 收纳成 \"+N\"\n ...(width === 'auto' && _.isEmpty(displayValues)\n ? { flexShrink: 0 }\n : {}),\n ...style,\n }}\n ref={selectRef}\n id={id}\n onClick={onSelectClick}\n data-testid={dataTestid}\n aria-label={ariaLabel}\n >\n <SelectTrigger\n {...restProps}\n open={!!mergedOpen}\n notFoundContent={notFoundContent}\n menu={showMenu}\n ref={dropdownRef}\n showSearch={showSearch}\n searchValue={innerSearchValue}\n setInnerSearchValue={setInnerSearchValue}\n popupMatchSelectWidth={popupMatchSelectWidth}\n overlayClassName={popupClassName}\n // @ts-ignore\n dropdownRender={dropdownRender}\n overlayStyle={overlayStyle || dropdownStyle}\n placement={placement}\n allowOverlap={allowOverlap}\n onOpenChange={(open) => {\n if (isResponsiveMode) {\n if (\n !mergedOpen &&\n !showResponsiveSelectedSection &&\n displayValues.length > 0 &&\n isShowSelectedSection(mode)\n ) {\n setShowResponsiveSelectedSection(true);\n } else {\n onToggleOpen(open);\n }\n } else {\n onToggleOpen(open);\n }\n }}\n >\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n <div className={cn(setClassNames('trigger'), 'ant-select-selector')}>\n {prefix && <div className={setClassNames('prefix')}>{prefix}</div>}\n {_.isEmpty(displayValues) && (\n <div\n className={cn(\n setClassNames('placeholder'),\n 'ant-select-selection-placeholder',\n )}\n >\n {placeholder}\n </div>\n )}\n {!_.isEmpty(displayValues) && (\n <Selector\n {...restProps}\n suffixIcon={suffixIcon}\n size={size}\n disabled={disabled}\n mode={mode}\n dropdownRef={dropdownRef}\n displayValues={displayValues}\n onToggleOpen={onToggleOpen}\n onRemove={onSelectorRemove}\n showResponsiveSelectedSection={showResponsiveSelectedSection}\n onOverflowCollapsedChange={setOverflowCollapsed}\n ></Selector>\n )}\n </div>\n </SelectTrigger>\n <Suffix\n showArrow={showArrow}\n allowClear={allowClear}\n disabled={disabled}\n loading={loading}\n isHover={isHover}\n onClear={() => {\n onToggleOpen(false);\n\n onDisplayValuesChange([], {\n type: 'clear',\n values: displayValues,\n });\n onClear?.();\n }}\n isActive={innerOpen}\n icon={suffixIcon}\n displayValues={displayValues}\n ></Suffix>\n </div>\n );\n },\n);\n\nexport default BaseSelect;\n"],"mappings":"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"}
@@ -59,6 +59,10 @@ export interface ISelectProps<ValueType = any, OptionType extends BaseOptionType
59
59
  maxTagPlaceholder?: React.ReactNode | ((omittedValues: DisplayValueType[]) => React.ReactNode);
60
60
  onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
61
61
  optionLabelProp?: string;
62
+ /** 透传到 select 根 DOM 的 data-testid,用于自动化测试定位 */
63
+ 'data-testid'?: string;
64
+ /** 透传到 select 根 DOM 的 aria-label,用于可访问性与自动化测试定位 */
65
+ 'aria-label'?: string;
62
66
  }
63
67
  export interface BaseOptionType {
64
68
  disabled?: boolean;
@@ -12,6 +12,10 @@ export interface ISwitchProps {
12
12
  onClick?: SwitchChangeEventHandler;
13
13
  onChange?: SwitchChangeEventHandler;
14
14
  children?: React.ReactNode;
15
+ /** 透传到内部 switch 按钮元素的 data-testid,用于自动化测试定位 */
16
+ 'data-testid'?: string;
17
+ /** 透传到内部 switch 按钮元素的 aria-label,用于可访问性与自动化测试定位 */
18
+ 'aria-label'?: string;
15
19
  }
16
20
  declare const Switch: React.FC<ISwitchProps>;
17
21
  export default Switch;
@@ -21,7 +21,7 @@ var switchSizeConfig = {
21
21
  thumbSize: 8
22
22
  }
23
23
  };
24
- var Switch = ({ className = "", disabled: customDisabled, loading = false, size: customSize, checked, defaultChecked, onChange, onClick, children }) => {
24
+ var Switch = ({ className = "", disabled: customDisabled, loading = false, size: customSize, checked, defaultChecked, onChange, onClick, children, "data-testid": dataTestid, "aria-label": ariaLabel }) => {
25
25
  const contentSize = useContext(SizeContext);
26
26
  const size = customSize || contentSize || "middle";
27
27
  const [userChecked, setUserChecked] = useState(typeof checked === "undefined" ? defaultChecked : checked);
@@ -49,6 +49,8 @@ var Switch = ({ className = "", disabled: customDisabled, loading = false, size:
49
49
  type: "button",
50
50
  role: "switch",
51
51
  "aria-checked": !!userChecked,
52
+ "data-testid": dataTestid,
53
+ "aria-label": ariaLabel,
52
54
  disabled: currentDisabled,
53
55
  className: cn("ald-switch-btn tw-relative tw-inline-flex tw-cursor-pointer tw-items-center tw-rounded-full tw-border-0 tw-p-0 tw-transition-colors tw-duration-200", userChecked ? "tw-bg-[var(--alias-colors-icon-brand)] hover:tw-bg-[var(--alias-colors-icon-selected)]" : "tw-bg-[var(--alias-colors-icon-subtler)] hover:tw-bg-[var(--alias-colors-icon-subtle)]", currentDisabled && "tw-cursor-not-allowed tw-opacity-40"),
54
56
  style: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/Switch/index.tsx"],"sourcesContent":["import React, { useContext, useEffect, useState } from 'react';\nimport DisabledContext from '../ConfigProvider/DisabledContext';\nimport SizeContext from '../ConfigProvider/sizeContext';\nimport { cn } from '../lib/utils';\n\nexport type SwitchChangeEventHandler = (\n checked: boolean,\n event: React.MouseEvent<HTMLButtonElement>,\n) => void;\nexport type SwitchClickEventHandler = SwitchChangeEventHandler;\nexport type SwitchSize = 'large' | 'middle' | 'small';\n\nexport interface ISwitchProps {\n className?: string;\n checked?: boolean;\n defaultChecked?: boolean;\n disabled?: boolean;\n loading?: boolean;\n size?: SwitchSize;\n onClick?: SwitchChangeEventHandler;\n onChange?: SwitchChangeEventHandler;\n children?: React.ReactNode;\n}\n\nconst switchSizeConfig: Record<\n SwitchSize,\n {\n trackW: number;\n trackH: number;\n thumbSize: number;\n }\n> = {\n large: {\n trackW: 36,\n trackH: 20,\n thumbSize: 16,\n },\n middle: {\n trackW: 28,\n trackH: 16,\n thumbSize: 12,\n },\n small: {\n trackW: 22,\n trackH: 12,\n thumbSize: 8,\n },\n};\n\nconst Switch: React.FC<ISwitchProps> = ({\n className = '',\n disabled: customDisabled,\n loading = false,\n size: customSize,\n checked,\n defaultChecked,\n onChange,\n onClick,\n children,\n}) => {\n const contentSize = useContext(SizeContext);\n const size = customSize || contentSize || 'middle';\n\n const [userChecked, setUserChecked] = useState(\n typeof checked === 'undefined' ? defaultChecked : checked,\n );\n\n const disabled = useContext(DisabledContext);\n const mergedDisabled = customDisabled ?? disabled;\n\n const currentDisabled = loading ? true : mergedDisabled;\n\n useEffect(() => {\n if (typeof checked === 'boolean') {\n setUserChecked(checked);\n }\n }, [checked]);\n\n const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n if (currentDisabled) return;\n const newChecked = !userChecked;\n if (checked === undefined) {\n setUserChecked(newChecked);\n }\n onChange?.(newChecked, e);\n onClick?.(newChecked, e);\n };\n\n const { trackW, trackH, thumbSize } = switchSizeConfig[size];\n const thumbOffset = 2;\n const thumbTranslate = trackW - thumbSize - thumbOffset * 2;\n\n return (\n <span\n className={cn(\n className,\n 'ald-switch tw-inline-flex tw-items-center tw-gap-1.5 tw-text-[0]',\n `ald-switch-${size}`,\n currentDisabled && 'tw-pointer-events-none tw-cursor-default',\n {\n 'ald-switch-disabled': currentDisabled,\n 'ald-switch-checked': userChecked,\n },\n )}\n >\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={!!userChecked}\n disabled={currentDisabled}\n className={cn(\n 'ald-switch-btn tw-relative tw-inline-flex tw-cursor-pointer tw-items-center tw-rounded-full tw-border-0 tw-p-0 tw-transition-colors tw-duration-200',\n userChecked\n ? 'tw-bg-[var(--alias-colors-icon-brand)] hover:tw-bg-[var(--alias-colors-icon-selected)]'\n : 'tw-bg-[var(--alias-colors-icon-subtler)] hover:tw-bg-[var(--alias-colors-icon-subtle)]',\n currentDisabled && 'tw-cursor-not-allowed tw-opacity-40',\n )}\n style={{ width: trackW, height: trackH }}\n onClick={handleClick}\n >\n <span\n className={cn(\n 'tw-block tw-rounded-full tw-bg-white tw-shadow-sm tw-transition-transform tw-duration-200',\n )}\n style={{\n width: thumbSize,\n height: thumbSize,\n marginLeft: thumbOffset,\n transform: userChecked\n ? `translateX(${thumbTranslate}px)`\n : 'translateX(0)',\n }}\n />\n </button>\n {children && (\n <span\n className={cn(\n 'ald-switch-text tw-inline-flex tw-items-center tw-align-middle tw-text-[var(--alias-colors-text-default)]',\n size === 'large' && 'tw-h-5 tw-text-base tw-leading-5',\n size === 'middle' && 'tw-h-4 tw-text-sm tw-leading-4',\n size === 'small' && 'tw-h-3 tw-text-xs tw-leading-3',\n currentDisabled && 'tw-opacity-50',\n )}\n >\n {children}\n </span>\n )}\n </span>\n );\n};\n\nexport default Switch;\n"],"mappings":";;;;;;AAwBA,IAAM,mBAOF;CACF,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,WAAW;EACZ;CACD,QAAQ;EACN,QAAQ;EACR,QAAQ;EACR,WAAW;EACZ;CACD,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,WAAW;EACZ;CACF;AAED,IAAM,UAAkC,EACtC,YAAY,IACZ,UAAU,gBACV,UAAU,OACV,MAAM,YACN,SACA,gBACA,UACA,SACA,eACI;CACJ,MAAM,cAAc,WAAW,YAAY;CAC3C,MAAM,OAAO,cAAc,eAAe;CAE1C,MAAM,CAAC,aAAa,kBAAkB,SACpC,OAAO,YAAY,cAAc,iBAAiB,QACnD;CAED,MAAM,WAAW,WAAW,gBAAgB;CAG5C,MAAM,kBAAkB,UAAU,OAFX,kBAAkB;AAIzC,iBAAgB;AACd,MAAI,OAAO,YAAY,UACrB,gBAAe,QAAQ;IAExB,CAAC,QAAQ,CAAC;CAEb,MAAM,eAAe,MAA2C;AAC9D,MAAI,gBAAiB;EACrB,MAAM,aAAa,CAAC;AACpB,MAAI,YAAY,OACd,gBAAe,WAAW;AAE5B,aAAW,YAAY,EAAE;AACzB,YAAU,YAAY,EAAE;;CAG1B,MAAM,EAAE,QAAQ,QAAQ,cAAc,iBAAiB;CACvD,MAAM,cAAc;CACpB,MAAM,iBAAiB,SAAS,YAAY,cAAc;AAE1D,QACE,qBAAC,QAAD;EACE,WAAW,GACT,WACA,oEACA,cAAc,QACd,mBAAmB,4CACnB;GACE,uBAAuB;GACvB,sBAAsB;GACvB,CACF;YAVH,CAYE,oBAAC,UAAD;GACE,MAAK;GACL,MAAK;GACL,gBAAc,CAAC,CAAC;GAChB,UAAU;GACV,WAAW,GACT,uJACA,cACI,2FACA,0FACJ,mBAAmB,sCACpB;GACD,OAAO;IAAE,OAAO;IAAQ,QAAQ;IAAQ;GACxC,SAAS;aAET,oBAAC,QAAD;IACE,WAAW,GACT,4FACD;IACD,OAAO;KACL,OAAO;KACP,QAAQ;KACR,YAAY;KACZ,WAAW,cACP,cAAc,eAAe,OAC7B;KACL;IACD,CAAA;GACK,CAAA,EACR,YACC,oBAAC,QAAD;GACE,WAAW,GACT,6GACA,SAAS,WAAW,oCACpB,SAAS,YAAY,kCACrB,SAAS,WAAW,kCACpB,mBAAmB,gBACpB;GAEA;GACI,CAAA,CAEJ"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/Switch/index.tsx"],"sourcesContent":["import React, { useContext, useEffect, useState } from 'react';\nimport DisabledContext from '../ConfigProvider/DisabledContext';\nimport SizeContext from '../ConfigProvider/sizeContext';\nimport { cn } from '../lib/utils';\n\nexport type SwitchChangeEventHandler = (\n checked: boolean,\n event: React.MouseEvent<HTMLButtonElement>,\n) => void;\nexport type SwitchClickEventHandler = SwitchChangeEventHandler;\nexport type SwitchSize = 'large' | 'middle' | 'small';\n\nexport interface ISwitchProps {\n className?: string;\n checked?: boolean;\n defaultChecked?: boolean;\n disabled?: boolean;\n loading?: boolean;\n size?: SwitchSize;\n onClick?: SwitchChangeEventHandler;\n onChange?: SwitchChangeEventHandler;\n children?: React.ReactNode;\n /** 透传到内部 switch 按钮元素的 data-testid,用于自动化测试定位 */\n 'data-testid'?: string;\n /** 透传到内部 switch 按钮元素的 aria-label,用于可访问性与自动化测试定位 */\n 'aria-label'?: string;\n}\n\nconst switchSizeConfig: Record<\n SwitchSize,\n {\n trackW: number;\n trackH: number;\n thumbSize: number;\n }\n> = {\n large: {\n trackW: 36,\n trackH: 20,\n thumbSize: 16,\n },\n middle: {\n trackW: 28,\n trackH: 16,\n thumbSize: 12,\n },\n small: {\n trackW: 22,\n trackH: 12,\n thumbSize: 8,\n },\n};\n\nconst Switch: React.FC<ISwitchProps> = ({\n className = '',\n disabled: customDisabled,\n loading = false,\n size: customSize,\n checked,\n defaultChecked,\n onChange,\n onClick,\n children,\n 'data-testid': dataTestid,\n 'aria-label': ariaLabel,\n}) => {\n const contentSize = useContext(SizeContext);\n const size = customSize || contentSize || 'middle';\n\n const [userChecked, setUserChecked] = useState(\n typeof checked === 'undefined' ? defaultChecked : checked,\n );\n\n const disabled = useContext(DisabledContext);\n const mergedDisabled = customDisabled ?? disabled;\n\n const currentDisabled = loading ? true : mergedDisabled;\n\n useEffect(() => {\n if (typeof checked === 'boolean') {\n setUserChecked(checked);\n }\n }, [checked]);\n\n const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n if (currentDisabled) return;\n const newChecked = !userChecked;\n if (checked === undefined) {\n setUserChecked(newChecked);\n }\n onChange?.(newChecked, e);\n onClick?.(newChecked, e);\n };\n\n const { trackW, trackH, thumbSize } = switchSizeConfig[size];\n const thumbOffset = 2;\n const thumbTranslate = trackW - thumbSize - thumbOffset * 2;\n\n return (\n <span\n className={cn(\n className,\n 'ald-switch tw-inline-flex tw-items-center tw-gap-1.5 tw-text-[0]',\n `ald-switch-${size}`,\n currentDisabled && 'tw-pointer-events-none tw-cursor-default',\n {\n 'ald-switch-disabled': currentDisabled,\n 'ald-switch-checked': userChecked,\n },\n )}\n >\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={!!userChecked}\n data-testid={dataTestid}\n aria-label={ariaLabel}\n disabled={currentDisabled}\n className={cn(\n 'ald-switch-btn tw-relative tw-inline-flex tw-cursor-pointer tw-items-center tw-rounded-full tw-border-0 tw-p-0 tw-transition-colors tw-duration-200',\n userChecked\n ? 'tw-bg-[var(--alias-colors-icon-brand)] hover:tw-bg-[var(--alias-colors-icon-selected)]'\n : 'tw-bg-[var(--alias-colors-icon-subtler)] hover:tw-bg-[var(--alias-colors-icon-subtle)]',\n currentDisabled && 'tw-cursor-not-allowed tw-opacity-40',\n )}\n style={{ width: trackW, height: trackH }}\n onClick={handleClick}\n >\n <span\n className={cn(\n 'tw-block tw-rounded-full tw-bg-white tw-shadow-sm tw-transition-transform tw-duration-200',\n )}\n style={{\n width: thumbSize,\n height: thumbSize,\n marginLeft: thumbOffset,\n transform: userChecked\n ? `translateX(${thumbTranslate}px)`\n : 'translateX(0)',\n }}\n />\n </button>\n {children && (\n <span\n className={cn(\n 'ald-switch-text tw-inline-flex tw-items-center tw-align-middle tw-text-[var(--alias-colors-text-default)]',\n size === 'large' && 'tw-h-5 tw-text-base tw-leading-5',\n size === 'middle' && 'tw-h-4 tw-text-sm tw-leading-4',\n size === 'small' && 'tw-h-3 tw-text-xs tw-leading-3',\n currentDisabled && 'tw-opacity-50',\n )}\n >\n {children}\n </span>\n )}\n </span>\n );\n};\n\nexport default Switch;\n"],"mappings":";;;;;;AA4BA,IAAM,mBAOF;CACF,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,WAAW;EACZ;CACD,QAAQ;EACN,QAAQ;EACR,QAAQ;EACR,WAAW;EACZ;CACD,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,WAAW;EACZ;CACF;AAED,IAAM,UAAkC,EACtC,YAAY,IACZ,UAAU,gBACV,UAAU,OACV,MAAM,YACN,SACA,gBACA,UACA,SACA,UACA,eAAe,YACf,cAAc,gBACV;CACJ,MAAM,cAAc,WAAW,YAAY;CAC3C,MAAM,OAAO,cAAc,eAAe;CAE1C,MAAM,CAAC,aAAa,kBAAkB,SACpC,OAAO,YAAY,cAAc,iBAAiB,QACnD;CAED,MAAM,WAAW,WAAW,gBAAgB;CAG5C,MAAM,kBAAkB,UAAU,OAFX,kBAAkB;AAIzC,iBAAgB;AACd,MAAI,OAAO,YAAY,UACrB,gBAAe,QAAQ;IAExB,CAAC,QAAQ,CAAC;CAEb,MAAM,eAAe,MAA2C;AAC9D,MAAI,gBAAiB;EACrB,MAAM,aAAa,CAAC;AACpB,MAAI,YAAY,OACd,gBAAe,WAAW;AAE5B,aAAW,YAAY,EAAE;AACzB,YAAU,YAAY,EAAE;;CAG1B,MAAM,EAAE,QAAQ,QAAQ,cAAc,iBAAiB;CACvD,MAAM,cAAc;CACpB,MAAM,iBAAiB,SAAS,YAAY,cAAc;AAE1D,QACE,qBAAC,QAAD;EACE,WAAW,GACT,WACA,oEACA,cAAc,QACd,mBAAmB,4CACnB;GACE,uBAAuB;GACvB,sBAAsB;GACvB,CACF;YAVH,CAYE,oBAAC,UAAD;GACE,MAAK;GACL,MAAK;GACL,gBAAc,CAAC,CAAC;GAChB,eAAa;GACb,cAAY;GACZ,UAAU;GACV,WAAW,GACT,uJACA,cACI,2FACA,0FACJ,mBAAmB,sCACpB;GACD,OAAO;IAAE,OAAO;IAAQ,QAAQ;IAAQ;GACxC,SAAS;aAET,oBAAC,QAAD;IACE,WAAW,GACT,4FACD;IACD,OAAO;KACL,OAAO;KACP,QAAQ;KACR,YAAY;KACZ,WAAW,cACP,cAAc,eAAe,OAC7B;KACL;IACD,CAAA;GACK,CAAA,EACR,YACC,oBAAC,QAAD;GACE,WAAW,GACT,6GACA,SAAS,WAAW,oCACpB,SAAS,YAAY,kCACrB,SAAS,WAAW,kCACpB,mBAAmB,gBACpB;GAEA;GACI,CAAA,CAEJ"}
@@ -39,6 +39,10 @@ export interface ITabsProps {
39
39
  popupClassName?: string;
40
40
  tabBarGutter?: number;
41
41
  moreIcon?: React.ReactNode;
42
+ /** 透传到 Tabs 根容器的 data-testid,用于自动化测试定位 */
43
+ 'data-testid'?: string;
44
+ /** 透传到 Tabs 根容器的 aria-label,用于可访问性与自动化测试定位 */
45
+ 'aria-label'?: string;
42
46
  }
43
47
  declare function Tabs(props: ITabsProps): import("react/jsx-runtime").JSX.Element;
44
48
  declare namespace Tabs {