@canlooks/can-ui 0.0.66 → 0.0.68

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 (55) hide show
  1. package/dist/cjs/components/anchorList/anchorList.js +26 -20
  2. package/dist/cjs/components/button/button.js +1 -1
  3. package/dist/cjs/components/cascade/cascade.js +2 -2
  4. package/dist/cjs/components/curd/curdColumnConfig.js +2 -1
  5. package/dist/cjs/components/dataGrid/dataGrid.js +3 -2
  6. package/dist/cjs/components/gallery/gallery.js +2 -2
  7. package/dist/cjs/components/menu/menu.js +2 -2
  8. package/dist/cjs/components/overlayBase/overlayBase.d.ts +3 -1
  9. package/dist/cjs/components/overlayBase/overlayBase.js +5 -5
  10. package/dist/cjs/components/popper/popper.d.ts +3 -1
  11. package/dist/cjs/components/popper/popper.js +6 -7
  12. package/dist/cjs/components/progress/progress.js +4 -2
  13. package/dist/cjs/components/snackbarBase/snackbarBase.d.ts +3 -2
  14. package/dist/cjs/components/snackbarBase/snackbarBase.js +3 -3
  15. package/dist/cjs/components/theme/themeVariables.d.ts +1 -0
  16. package/dist/cjs/components/theme/themeVariables.js +1 -0
  17. package/dist/cjs/components/touchRipple/index.d.ts +1 -0
  18. package/dist/cjs/components/touchRipple/index.js +1 -0
  19. package/dist/cjs/components/touchRipple/touchRipple.d.ts +6 -14
  20. package/dist/cjs/components/touchRipple/touchRipple.js +54 -39
  21. package/dist/cjs/components/touchRipple/touchRipple.style.js +25 -27
  22. package/dist/cjs/components/transfer/transfer.js +2 -2
  23. package/dist/cjs/components/transfer/transferPanel.js +2 -1
  24. package/dist/cjs/components/upload/upload.js +2 -2
  25. package/dist/cjs/components/waterfall/waterfallItem.js +1 -1
  26. package/dist/cjs/utils/hooks.d.ts +8 -0
  27. package/dist/cjs/utils/hooks.js +22 -0
  28. package/dist/esm/components/anchorList/anchorList.js +26 -20
  29. package/dist/esm/components/button/button.js +1 -1
  30. package/dist/esm/components/cascade/cascade.js +2 -2
  31. package/dist/esm/components/curd/curdColumnConfig.js +2 -1
  32. package/dist/esm/components/dataGrid/dataGrid.js +3 -2
  33. package/dist/esm/components/gallery/gallery.js +2 -2
  34. package/dist/esm/components/menu/menu.js +2 -2
  35. package/dist/esm/components/overlayBase/overlayBase.d.ts +3 -1
  36. package/dist/esm/components/overlayBase/overlayBase.js +6 -6
  37. package/dist/esm/components/popper/popper.d.ts +3 -1
  38. package/dist/esm/components/popper/popper.js +7 -8
  39. package/dist/esm/components/progress/progress.js +4 -2
  40. package/dist/esm/components/snackbarBase/snackbarBase.d.ts +3 -2
  41. package/dist/esm/components/snackbarBase/snackbarBase.js +4 -4
  42. package/dist/esm/components/theme/themeVariables.d.ts +1 -0
  43. package/dist/esm/components/theme/themeVariables.js +1 -0
  44. package/dist/esm/components/touchRipple/index.d.ts +1 -0
  45. package/dist/esm/components/touchRipple/index.js +1 -0
  46. package/dist/esm/components/touchRipple/touchRipple.d.ts +6 -14
  47. package/dist/esm/components/touchRipple/touchRipple.js +54 -39
  48. package/dist/esm/components/touchRipple/touchRipple.style.js +25 -27
  49. package/dist/esm/components/transfer/transfer.js +2 -2
  50. package/dist/esm/components/transfer/transferPanel.js +2 -1
  51. package/dist/esm/components/upload/upload.js +2 -2
  52. package/dist/esm/components/waterfall/waterfallItem.js +2 -2
  53. package/dist/esm/utils/hooks.d.ts +8 -0
  54. package/dist/esm/utils/hooks.js +21 -0
  55. package/package.json +1 -1
@@ -24,7 +24,7 @@ const markFileId = (files) => {
24
24
  }
25
25
  }
26
26
  };
27
- exports.Upload = (0, react_1.memo)(({ inputProps, type = 'file', accept = type === 'image' ? 'image/*' : void 0, max = Infinity, showButton = true, buttonProps, buttonText = '选择文件', variant = 'square', sortable, droppable, defaultValue = [], value, onChange, onUpload, ...props }) => {
27
+ exports.Upload = (0, react_1.memo)(({ inputProps, type = 'file', accept = type === 'image' ? 'image/*' : void 0, max = Infinity, showButton = true, buttonProps, buttonText = '选择文件', variant = 'square', sortable, droppable, defaultValue, value, onChange, onUpload, ...props }) => {
28
28
  const wrapperRef = (0, react_1.useRef)(null);
29
29
  const itemRefs = (0, react_1.useRef)(new Map());
30
30
  (0, react_1.useImperativeHandle)(props.ref, () => {
@@ -54,7 +54,7 @@ exports.Upload = (0, react_1.memo)(({ inputProps, type = 'file', accept = type =
54
54
  };
55
55
  return wrapperRef.current;
56
56
  });
57
- const [innerValue, setInnerValue] = (0, utils_1.useControlled)(defaultValue, value, value => {
57
+ const [innerValue, setInnerValue] = (0, utils_1.useControlled)(defaultValue || [], value, value => {
58
58
  markFileId(value);
59
59
  onChange?.(value);
60
60
  });
@@ -6,7 +6,7 @@ const waterfall_style_1 = require("./waterfall.style");
6
6
  const utils_1 = require("../../utils");
7
7
  const WaterfallItem = ({ ref, onLoad, child }) => {
8
8
  const innerRef = (0, react_1.useRef)(null);
9
- (0, react_1.useLayoutEffect)(() => {
9
+ (0, react_1.useEffect)(() => {
10
10
  const el = innerRef.current;
11
11
  if (!el) {
12
12
  throw Error(`Children of <Waterfall> must expose 'ref' prop`);
@@ -1,4 +1,5 @@
1
1
  import { RefObject, Dispatch, SetStateAction } from 'react';
2
+ import { DefineElement } from '../types';
2
3
  /**
3
4
  * 获取渲染前的值
4
5
  * @param value
@@ -48,3 +49,10 @@ export declare function useLoading<A extends any[], R>(fn: (...args: A) => R | P
48
49
  (...args: A) => Promise<R>,
49
50
  Dispatch<SetStateAction<boolean>>
50
51
  ];
52
+ /**
53
+ * 获取容器元素,通常用于`container`或`effectContainer`属性
54
+ * @param container
55
+ * @param effectContainer
56
+ * @param defaultContainer 默认为`document.body`
57
+ */
58
+ export declare function useContainer<T extends HTMLElement | null>(container?: DefineElement<T>, effectContainer?: DefineElement<T>, defaultContainer?: T): RefObject<T>;
@@ -8,6 +8,7 @@ exports.useDerivedState = useDerivedState;
8
8
  exports.useUnmounted = useUnmounted;
9
9
  exports.useControlled = useControlled;
10
10
  exports.useLoading = useLoading;
11
+ exports.useContainer = useContainer;
11
12
  const react_1 = require("react");
12
13
  const utils_1 = require("./utils");
13
14
  /**
@@ -123,3 +124,24 @@ function useLoading(fn, referredLoading = false) {
123
124
  setLoading
124
125
  ];
125
126
  }
127
+ /**
128
+ * 获取容器元素,通常用于`container`或`effectContainer`属性
129
+ * @param container
130
+ * @param effectContainer
131
+ * @param defaultContainer 默认为`document.body`
132
+ */
133
+ function useContainer(container, effectContainer, defaultContainer = document.body) {
134
+ const [containerEl, setContainerEl] = useDerivedState(prev => {
135
+ if (container) {
136
+ return typeof container === 'function' ? container() : container;
137
+ }
138
+ return prev || defaultContainer;
139
+ }, [container, defaultContainer]);
140
+ (0, react_1.useEffect)(() => {
141
+ if (effectContainer) {
142
+ const el = typeof effectContainer === 'function' ? effectContainer() : effectContainer;
143
+ setContainerEl(el);
144
+ }
145
+ }, []);
146
+ return containerEl;
147
+ }
@@ -18,10 +18,11 @@ export const AnchorList = memo(({ anchors, renderAnchorItem, indent = 24, scroll
18
18
  });
19
19
  const scrollToId = (id) => {
20
20
  const targetEl = document.getElementById(id);
21
- if (!targetEl) {
21
+ const scrollerEl = getScroller();
22
+ if (!targetEl || !scrollerEl) {
22
23
  return false;
23
24
  }
24
- getScroller().scrollTo({
25
+ scrollerEl.scrollTo({
25
26
  top: targetEl.offsetTop - offset,
26
27
  // 初始化之前无需平滑滚动
27
28
  behavior: initialized.current ? scrollBehavior : 'instant'
@@ -50,29 +51,34 @@ export const AnchorList = memo(({ anchors, renderAnchorItem, indent = 24, scroll
50
51
  * 监听滚动设置高亮
51
52
  */
52
53
  const getScroller = () => {
53
- return (typeof scroller === 'function' ? scroller() : scroller) || document.documentElement;
54
+ if (scroller) {
55
+ return typeof scroller === 'function' ? scroller() : scroller;
56
+ }
57
+ return document.documentElement;
54
58
  };
55
59
  const [activeId, setActiveId] = useSyncState();
56
60
  useEffect(() => {
57
61
  const scrollerEl = getScroller();
58
- const scroll = () => {
59
- let nearest;
60
- let minDistance = Infinity;
61
- const targets = anchors?.map(item => document.getElementById(item.id));
62
- targets?.forEach(target => {
63
- const top = target?.getBoundingClientRect().top;
64
- if (typeof top === 'number') {
65
- const distance = Math.abs(top - offset);
66
- if (distance < minDistance) {
67
- minDistance = distance;
68
- nearest = target;
62
+ if (scrollerEl) {
63
+ const scroll = () => {
64
+ let nearest;
65
+ let minDistance = Infinity;
66
+ const targets = anchors?.map(item => document.getElementById(item.id));
67
+ targets?.forEach(target => {
68
+ const top = target?.getBoundingClientRect().top;
69
+ if (typeof top === 'number') {
70
+ const distance = Math.abs(top - offset);
71
+ if (distance < minDistance) {
72
+ minDistance = distance;
73
+ nearest = target;
74
+ }
69
75
  }
70
- }
71
- });
72
- nearest && setActiveId(nearest.id);
73
- };
74
- !activeId.current && scroll();
75
- return listenAllPredecessorsScroll(scrollerEl === document.documentElement ? document : scrollerEl, scroll);
76
+ });
77
+ nearest && setActiveId(nearest.id);
78
+ };
79
+ !activeId.current && scroll();
80
+ return listenAllPredecessorsScroll(scrollerEl === document.documentElement ? document : scrollerEl, scroll);
81
+ }
76
82
  }, [anchors, scroller, offset]);
77
83
  const [animating, setAnimating] = useDerivedState(prev => typeof prev !== 'undefined', [activeId.current]);
78
84
  return (_jsxs(Flex, { direction: "column", alignItems: "flex-start", ...props, css: style, className: clsx(classes.root, props.className), "data-animating": animating.current, children: [anchors?.map(item => {
@@ -28,7 +28,7 @@ export const Button = ({ component: Component = 'button', color = 'primary', sha
28
28
  ? actualPrefix
29
29
  ? _jsx(LoadingIndicator, { color: reverseTextColor })
30
30
  : _jsx(Collapse, { orientation: "horizontal", in: true, children: _jsx(LoadingIndicator, { color: reverseTextColor }) })
31
- : _jsx("div", { className: classes.prefix, children: actualPrefix }), !!actualChildren &&
31
+ : actualPrefix, !!actualChildren &&
32
32
  _jsx("div", { className: classes.content, children: actualChildren }), !!suffix &&
33
33
  _jsx("div", { className: classes.suffix, children: suffix })] }));
34
34
  };
@@ -16,7 +16,7 @@ const CascadeContext = createContext({});
16
16
  export function useCascadeContext() {
17
17
  return useContext(CascadeContext);
18
18
  }
19
- export const Cascade = memo(({ inputProps, defaultOpen = false, open, onOpenChange, children, loadOptions, multiple = false, showCheckbox = !!multiple, defaultValue = [], value, onChange, renderBackfill, searchable, defaultSearchValue = '', searchValue, onSearchChange, searchInputProps, popperProps, popperRef, clearable = !!multiple, integration = 'deepest',
19
+ export const Cascade = memo(({ inputProps, defaultOpen = false, open, onOpenChange, children, loadOptions, multiple = false, showCheckbox = !!multiple, defaultValue, value, onChange, renderBackfill, searchable, defaultSearchValue = '', searchValue, onSearchChange, searchInputProps, popperProps, popperRef, clearable = !!multiple, integration = 'deepest',
20
20
  // 共享属性,从OptionsBaseSharedProps继承
21
21
  loading, options, labelKey = 'label', primaryKey = 'value', childrenKey = 'children', searchTokenKey = 'searchToken', ...props }) => {
22
22
  /**
@@ -75,7 +75,7 @@ loading, options, labelKey = 'label', primaryKey = 'value', childrenKey = 'child
75
75
  * --------------------------------------------------------------------
76
76
  * 控制选中状态
77
77
  */
78
- const [pathifiedValue, setPathifiedValue] = useControlled(defaultValue, value, onChange);
78
+ const [pathifiedValue, setPathifiedValue] = useControlled(defaultValue || [], value, onChange);
79
79
  // 路径转单一键
80
80
  const toStandardValue = (path) => {
81
81
  if (!path) {
@@ -11,7 +11,8 @@ import { SortableContext } from '@dnd-kit/sortable';
11
11
  import { isUnset, onDndDragEnd, useDndSensors } from '../../utils';
12
12
  import { Icon } from '../..';
13
13
  import { faGear } from '@fortawesome/free-solid-svg-icons/faGear';
14
- export const CurdColumnConfig = memo(({ columns = [], innerVisible, setInnerVisible, setInnerOrder, }) => {
14
+ export const CurdColumnConfig = memo(({ columns, innerVisible, setInnerVisible, setInnerOrder, }) => {
15
+ columns ||= [];
15
16
  const dragEndHandler = (e) => {
16
17
  const newColumns = onDndDragEnd(e, columns, '_key');
17
18
  newColumns && setInnerOrder(newColumns.flatMap(col => col._key ?? []));
@@ -14,7 +14,7 @@ const DataGridContext = createContext({});
14
14
  export function useDataGridContext() {
15
15
  return useContext(DataGridContext);
16
16
  }
17
- export const DataGrid = memo(({ columns, rows, rowProps, primaryKey = 'id', childrenKey = null, defaultOrderColumn, orderColumn, defaultOrderType = 'descend', orderType, onOrderChange, selectable, relation = 'dependent', integration = 'shallowest', allowSelectAll = true, clickRowToSelect = true, selectorProps, indent = 24, renderExpandIcon, defaultExpanded = [], expanded, onExpandedChange, paginatable = true, paginationProps = {}, renderPagination, loading, emptyPlaceholder, columnResizable = false, size, bordered, striped, tableProps, multiple, defaultValue, value, onChange, ...props }) => {
17
+ export const DataGrid = memo(({ columns, rows, rowProps, primaryKey = 'id', childrenKey = null, defaultOrderColumn, orderColumn, defaultOrderType = 'descend', orderType, onOrderChange, selectable, relation = 'dependent', integration = 'shallowest', allowSelectAll = true, clickRowToSelect = true, selectorProps, indent = 24, renderExpandIcon, defaultExpanded, expanded, onExpandedChange, paginatable = true, paginationProps, renderPagination, loading, emptyPlaceholder, columnResizable = false, size, bordered, striped, tableProps, multiple, defaultValue, value, onChange, ...props }) => {
18
18
  /**
19
19
  * ---------------------------------------------------------------
20
20
  * 选择行
@@ -61,7 +61,7 @@ export const DataGrid = memo(({ columns, rows, rowProps, primaryKey = 'id', chil
61
61
  * ---------------------------------------------------------------
62
62
  * 展开行
63
63
  */
64
- const [innerExpanded, setInnerExpanded] = useControlled(defaultExpanded, expanded);
64
+ const [innerExpanded, setInnerExpanded] = useControlled(defaultExpanded || [], expanded);
65
65
  const expandedSet = useMemo(() => {
66
66
  return new Set(innerExpanded.current);
67
67
  }, [innerExpanded.current]);
@@ -79,6 +79,7 @@ export const DataGrid = memo(({ columns, rows, rowProps, primaryKey = 'id', chil
79
79
  * ---------------------------------------------------------------
80
80
  * 分页
81
81
  */
82
+ paginationProps ||= {};
82
83
  const [innerPage, setInnerPage] = useControlled(paginationProps.defaultPage ?? 1, paginationProps.page, paginationProps.onPageChange);
83
84
  const [innerPageSize, setInnerPageSize] = useControlled(paginationProps.defaultPageSize ?? 10, paginationProps.pageSize, paginationProps.onPageSizeChange);
84
85
  const pageChangeHandler = (page, pageSize) => {
@@ -22,8 +22,8 @@ const commonControlProps = {
22
22
  color: 'text'
23
23
  };
24
24
  const bounceBezier = cubicBezier(0, 0, 0, 1);
25
- export const Gallery = memo(({ src = [], defaultIndex = 0, index, onIndexChange, defaultOpen = false, open, onOpenChange, showRotation = true, showZoom = true, showClose = true, renderControl, bounceElementTranslate = 24, bounceDragDistance = 240, effectiveSpeed = 450, ...props }) => {
26
- const srcArr = useSync(toArray(src));
25
+ export const Gallery = memo(({ src, defaultIndex = 0, index, onIndexChange, defaultOpen = false, open, onOpenChange, showRotation = true, showZoom = true, showClose = true, renderControl, bounceElementTranslate = 24, bounceDragDistance = 240, effectiveSpeed = 450, ...props }) => {
26
+ const srcArr = useSync(toArray(src || []));
27
27
  const [innerOpen, setInnerOpen] = useControlled(defaultOpen, open, onOpenChange);
28
28
  const close = () => {
29
29
  setInnerOpen(false);
@@ -12,10 +12,10 @@ export function useMenuContext() {
12
12
  const { size = theme.size, ellipsis = true, indent = theme.spacing[8], ...context } = useContext(MenuContext);
13
13
  return { size, ellipsis, indent, ...context };
14
14
  }
15
- export const Menu = memo(({ items, primaryKey = 'value', labelKey = 'label', childrenKey = 'children', defaultExpanded = [], expanded, onExpandedChange, multiple, defaultValue, value, onChange,
15
+ export const Menu = memo(({ items, primaryKey = 'value', labelKey = 'label', childrenKey = 'children', defaultExpanded, expanded, onExpandedChange, multiple, defaultValue, value, onChange,
16
16
  // 以下属性传递给<MenuItem/>
17
17
  size = 'large', showCheckbox, ellipsis, indent, ...props }) => {
18
- const [innerExpanded, setInnerExpanded] = useControlled(defaultExpanded, expanded);
18
+ const [innerExpanded, setInnerExpanded] = useControlled(defaultExpanded || [], expanded);
19
19
  const expandedSet = useMemo(() => {
20
20
  return new Set(innerExpanded.current);
21
21
  }, [innerExpanded.current]);
@@ -4,6 +4,8 @@ import { TransitionBaseProps } from '../transitionBase';
4
4
  export interface OverlayBaseProps extends DivProps {
5
5
  /** 模态的容器元素,默认为document.body */
6
6
  container?: DefineElement<HTMLElement>;
7
+ /** 同{@link container},但会在useEffect后取值,且只会执行一次 */
8
+ effectContainer?: DefineElement<HTMLElement>;
7
9
  /**
8
10
  * @enum {true} 跟随父组件强制渲染
9
11
  * @enum {false} 打开时渲染,关闭后销毁
@@ -22,4 +24,4 @@ export interface OverlayBaseProps extends DivProps {
22
24
  removeFocusOnOpen?: boolean;
23
25
  }
24
26
  export declare const overlayBaseTransitionDuration = 300;
25
- export declare function OverlayBase({ container, forceRender, open, onMaskClick, singleLayer, onOpened, onClosed, maskProps, removeFocusOnOpen, ...props }: OverlayBaseProps): false | React.ReactPortal;
27
+ export declare function OverlayBase({ container, effectContainer, forceRender, open, onMaskClick, singleLayer, onOpened, onClosed, maskProps, removeFocusOnOpen, ...props }: OverlayBaseProps): false | React.ReactPortal;
@@ -1,26 +1,26 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  import { useEffect } from 'react';
3
3
  import { classes, style } from './overlayBase.style';
4
- import { clsx, useDerivedState } from '../../utils';
4
+ import { clsx, useContainer, useDerivedState } from '../../utils';
5
5
  import { createPortal } from 'react-dom';
6
6
  import { Fade } from '../transitionBase';
7
7
  export const overlayBaseTransitionDuration = 300;
8
- export function OverlayBase({ container, forceRender, open, onMaskClick, singleLayer, onOpened, onClosed, maskProps, removeFocusOnOpen = true, ...props }) {
8
+ export function OverlayBase({ container, effectContainer, forceRender, open, onMaskClick, singleLayer, onOpened, onClosed, maskProps, removeFocusOnOpen = true, ...props }) {
9
9
  const [shouldRender, setShouldRender] = useDerivedState((prev = false) => {
10
10
  if (open) {
11
11
  return true;
12
12
  }
13
13
  return forceRender === true || prev;
14
14
  }, [open, forceRender]);
15
- const containerEl = (typeof container === 'function' ? container() : container) || document.body;
15
+ const containerEl = useContainer(container, effectContainer);
16
16
  useEffect(() => {
17
17
  if (!open) {
18
18
  return;
19
19
  }
20
20
  removeFocusOnOpen && document.activeElement?.blur?.();
21
- containerEl.style.overflow = 'hidden';
21
+ containerEl.current.style.overflow = 'hidden';
22
22
  return () => {
23
- containerEl.style.overflow = '';
23
+ containerEl.current.style.overflow = '';
24
24
  };
25
25
  }, [open]);
26
26
  const clickHandler = (e) => {
@@ -36,5 +36,5 @@ export function OverlayBase({ container, forceRender, open, onMaskClick, singleL
36
36
  onClosed?.();
37
37
  forceRender === false && setShouldRender(false);
38
38
  };
39
- return shouldRender.current && createPortal(_jsxs("div", { ...props, css: style, className: clsx(classes.root, props.className), "data-open": open, "data-custom-container": containerEl !== document.body, children: [_jsx(Fade, { timeout: overlayBaseTransitionDuration, ...maskProps, in: open, className: clsx(classes.mask, maskProps?.className), onClick: clickHandler, onEntered: onEntered, onExited: onExited }), props.children] }), containerEl);
39
+ return shouldRender.current && createPortal(_jsxs("div", { ...props, css: style, className: clsx(classes.root, props.className), "data-open": open, "data-custom-container": containerEl.current !== document.body, children: [_jsx(Fade, { timeout: overlayBaseTransitionDuration, ...maskProps, in: open, className: clsx(classes.mask, maskProps?.className), onClick: clickHandler, onEntered: onEntered, onExited: onExited }), props.children] }), containerEl.current);
40
40
  }
@@ -7,6 +7,8 @@ export interface PopperProps extends Omit<DivProps, 'content' | 'children'> {
7
7
  anchorElement?: DefineElement<HTMLElement>;
8
8
  /** 弹框渲染的容器元素,默认为{@link document.body} */
9
9
  container?: DefineElement<HTMLElement>;
10
+ /** 同{@link container},但会在useEffect后取值,且只会执行一次 */
11
+ effectContainer?: DefineElement<HTMLElement>;
10
12
  /** 汽泡里的内容 */
11
13
  content?: ReactNode;
12
14
  /** 弹框偏离元素的距离 */
@@ -46,4 +48,4 @@ export interface PopperRef extends HTMLDivElement {
46
48
  openAnimation?: boolean;
47
49
  }, beforeOpen?: () => void): void;
48
50
  }
49
- export declare function Popper({ ref, popperRef, anchorElement, container, content, offset, trigger, placement, variant, sizeAdaptable, mouseEnterDelay, mouseLeaveDelay, defaultOpen, open, onOpenChange, onOpenChangeEnd, disabled, autoClose, forceRender, children, ...props }: PopperProps): import("@emotion/react/jsx-runtime").JSX.Element;
51
+ export declare function Popper({ ref, popperRef, anchorElement, container, effectContainer, content, offset, trigger, placement, variant, sizeAdaptable, mouseEnterDelay, mouseLeaveDelay, defaultOpen, open, onOpenChange, onOpenChangeEnd, disabled, autoClose, forceRender, children, ...props }: PopperProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  import { cloneElement, isValidElement, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
- import { clsx, cloneRef, isElementVisibleCompletely, listenAllPredecessorsScroll, toArray, useControlled, useDerivedState, useForceUpdate, useSync, useSyncState, useUnmounted } from '../../utils';
4
+ import { clsx, cloneRef, isElementVisibleCompletely, listenAllPredecessorsScroll, toArray, useControlled, useDerivedState, useForceUpdate, useSync, useSyncState, useUnmounted, useContainer } from '../../utils';
5
5
  import { ClickAway } from '../clickAway';
6
6
  import { classes, style } from './popper.style';
7
7
  import { PopperContext, usePopperContext } from './popperContext';
@@ -19,7 +19,7 @@ const getAttemptOrder = (placement) => {
19
19
  }
20
20
  return order;
21
21
  };
22
- export function Popper({ ref, popperRef, anchorElement, container = document.body, content, offset, trigger = 'hover', placement = 'top', variant = 'zoom', sizeAdaptable = variant === 'collapse', mouseEnterDelay = 100, mouseLeaveDelay = 150, defaultOpen = false, open, onOpenChange, onOpenChangeEnd, disabled, autoClose = false, forceRender, children, ...props }) {
22
+ export function Popper({ ref, popperRef, anchorElement, container = document.body, effectContainer, content, offset, trigger = 'hover', placement = 'top', variant = 'zoom', sizeAdaptable = variant === 'collapse', mouseEnterDelay = 100, mouseLeaveDelay = 150, defaultOpen = false, open, onOpenChange, onOpenChangeEnd, disabled, autoClose = false, forceRender, children, ...props }) {
23
23
  const { spacing } = useTheme();
24
24
  offset ??= spacing[2];
25
25
  useImperativeHandle(popperRef, () => {
@@ -35,7 +35,6 @@ export function Popper({ ref, popperRef, anchorElement, container = document.bod
35
35
  const unmounted = useUnmounted();
36
36
  const openHolding = useRef(0);
37
37
  const hold = (open) => {
38
- console.log('hold', open);
39
38
  return open ? ++openHolding.current
40
39
  : openHolding.current > 0 ? --openHolding.current
41
40
  : openHolding.current;
@@ -102,14 +101,14 @@ export function Popper({ ref, popperRef, anchorElement, container = document.bod
102
101
  const getAnchorElement = () => {
103
102
  return anchorRef.current || (typeof syncAnchorElement.current === 'function' ? syncAnchorElement.current() : syncAnchorElement.current);
104
103
  };
105
- const containerRef = useSync((typeof container === 'function' ? container() : container) || document.body);
104
+ const containerEl = useContainer(container, effectContainer);
106
105
  const innerPopperRef = useRef(null);
107
106
  const [popperBounding, setPopperBounding] = useState();
108
107
  const [openNextFrame, setOpenNextFrame] = useDerivedState(!innerOpen.current, [innerOpen.current, contextMenuEvent.current]);
109
108
  const placeA = useRef(void 0);
110
109
  const placeB = useRef(void 0);
111
110
  const fitPosition = (options, beforeOpen) => {
112
- const containerRect = containerRef.current.getBoundingClientRect();
111
+ const containerRect = containerEl.current.getBoundingClientRect();
113
112
  const popperEl = innerPopperRef.current;
114
113
  let { offsetWidth: popperWidth, offsetHeight: popperHeight } = popperEl;
115
114
  let pA, pB;
@@ -185,7 +184,7 @@ export function Popper({ ref, popperRef, anchorElement, container = document.bod
185
184
  }
186
185
  popperEl.style.left = left + 'px';
187
186
  popperEl.style.top = top + 'px';
188
- return isElementVisibleCompletely(popperEl, containerRef.current === document.body ? void 0 : containerRef.current);
187
+ return isElementVisibleCompletely(popperEl, containerEl.current === document.body ? void 0 : containerEl.current);
189
188
  };
190
189
  }
191
190
  else {
@@ -256,7 +255,7 @@ export function Popper({ ref, popperRef, anchorElement, container = document.bod
256
255
  }
257
256
  popperEl.style.left = left + 'px';
258
257
  popperEl.style.top = top + 'px';
259
- return isElementVisibleCompletely(popperEl, containerRef.current === document.body ? void 0 : containerRef.current);
258
+ return isElementVisibleCompletely(popperEl, containerEl.current === document.body ? void 0 : containerEl.current);
260
259
  };
261
260
  }
262
261
  if (options?.forcePlacement) {
@@ -500,5 +499,5 @@ export function Popper({ ref, popperRef, anchorElement, container = document.bod
500
499
  transform: 'scale(1)'
501
500
  },
502
501
  ...props.style
503
- }, "data-open": innerOpen.current, "data-variant": variant, "data-place-a": placeA.current, "data-place-b": placeB.current, onTransitionEnd: onTransitionEnd, children: _jsx(PopperContext, { value: contextValue, children: content }) }) }), containerRef.current)] }));
502
+ }, "data-open": innerOpen.current, "data-variant": variant, "data-place-a": placeA.current, "data-place-b": placeB.current, onTransitionEnd: onTransitionEnd, children: _jsx(PopperContext, { value: contextValue, children: content }) }) }), containerEl.current)] }));
504
503
  }
@@ -7,7 +7,9 @@ import { css, keyframes } from '@emotion/react';
7
7
  import { Icon } from '../..';
8
8
  import { faCircleCheck } from '@fortawesome/free-solid-svg-icons/faCircleCheck';
9
9
  import { faCircleXmark } from '@fortawesome/free-solid-svg-icons/faCircleXmark';
10
- export const Progress = memo(({ showInfo = true, renderInfo, color = 'primary', status = 'default', variant = 'linear', gapDegree = 90, size = 60, indeterminate = false, barWidth = 4, strokeLinecap = variant === 'gauge' ? 'butt' : 'round', value = 0, ...props }) => {
10
+ export const Progress = memo(({ showInfo = true, renderInfo, color, status = 'default', variant = 'linear', gapDegree = 90, size = 60, indeterminate = false, barWidth = 4, strokeLinecap = variant === 'gauge' ? 'butt' : 'round', value = 0, ...props }) => {
11
+ const isColorSpecified = !!color;
12
+ color ??= 'primary';
11
13
  const { colors: { success, error } } = useTheme();
12
14
  const isSucceed = status === 'success' || (status !== 'error' && value === 100 && variant !== 'gauge');
13
15
  const renderInfoFn = () => {
@@ -52,7 +54,7 @@ export const Progress = memo(({ showInfo = true, renderInfo, color = 'primary',
52
54
  }
53
55
  return;
54
56
  }, [indeterminate, variant, strokeLinecap, size, barWidth]);
55
- return (_jsx("div", { ...props, css: useStyle({ color: color || 'primary', variant }), className: clsx(classes.root, props.className), "data-variant": variant, "data-indeterminate": indeterminate, "data-processing": value < 100 && status === 'processing', "data-success": isSucceed, "data-error": status === 'error', children: variant === 'linear'
57
+ return (_jsx("div", { ...props, css: useStyle({ color: color || 'primary', variant }), className: clsx(classes.root, props.className), "data-variant": variant, "data-indeterminate": indeterminate, "data-processing": value < 100 && status === 'processing', "data-success": isColorSpecified ? void 0 : isSucceed, "data-error": isColorSpecified ? void 0 : status === 'error', children: variant === 'linear'
56
58
  ? _jsxs(_Fragment, { children: [_jsx("div", { className: classes.track, style: {
57
59
  height: barWidth,
58
60
  ...props.style
@@ -24,11 +24,12 @@ export declare class SnackbarBaseMethods<P extends SnackbarBaseProps = SnackbarB
24
24
  error(content: ReactNode): Promise<void>;
25
25
  error(props: P): Promise<void>;
26
26
  }
27
- export declare const SnackbarBase: React.MemoExoticComponent<({ methods, useTo, max, container }: {
27
+ export declare const SnackbarBase: React.MemoExoticComponent<({ methods, useTo, max, container, effectContainer }: {
28
28
  methods: SnackbarBaseMethods;
29
29
  useTo: "message" | "notification";
30
30
  max?: number;
31
- container?: DefineElement;
31
+ container?: DefineElement<HTMLElement>;
32
+ effectContainer?: DefineElement<HTMLElement>;
32
33
  }) => React.ReactPortal>;
33
34
  interface SnackbarBaseItemProps extends Omit<SnackbarBaseProps, 'duration' | 'onAutoClose'> {
34
35
  id: string;
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  import { createElement as _createElement } from "@emotion/react";
3
3
  import { isValidElement, memo, useEffect, useRef, useState } from 'react';
4
4
  import { Collapse, Slide } from '../transitionBase';
5
- import { clsx, getEasyID, useColor } from '../../utils';
5
+ import { clsx, getEasyID, useColor, useContainer } from '../../utils';
6
6
  import { classes, style } from './snackbarBase.style';
7
7
  import { TransitionGroup } from 'react-transition-group';
8
8
  import { StatusIcon, statusMapToIconDefinition } from '../status';
@@ -33,7 +33,7 @@ const placementToIndex = {
33
33
  bottomRight: 5,
34
34
  rightBottom: 5
35
35
  };
36
- export const SnackbarBase = memo(({ methods, useTo, max = useTo === 'message' ? 5 : 4, container }) => {
36
+ export const SnackbarBase = memo(({ methods, useTo, max = useTo === 'message' ? 5 : 4, container, effectContainer }) => {
37
37
  const [stacks, setStacks] = useState([]);
38
38
  const timers = useRef([]);
39
39
  useEffect(() => () => {
@@ -81,10 +81,10 @@ export const SnackbarBase = memo(({ methods, useTo, max = useTo === 'message' ?
81
81
  methods.warning = defineMethod('warning');
82
82
  methods.error = defineMethod('error');
83
83
  const css = style();
84
- const containerEl = (typeof container === 'function' ? container() : container) || document.body;
84
+ const containerEl = useContainer(container, effectContainer);
85
85
  return createPortal(stacks.flatMap((stack, i) => stack
86
86
  ? _jsx(TransitionGroup, { css: css, className: classes.root, "data-place": i, "data-use-to": useTo, children: stack.map(p => _createElement(SnackbarBaseItem, { ...p, key: p.id })) }, i)
87
- : []), containerEl);
87
+ : []), containerEl.current);
88
88
  });
89
89
  /**
90
90
  * ----------------------------------------------------------------------
@@ -15,6 +15,7 @@ export declare function restoreThemeDefinition(theme: PartialTheme): ThemeDefini
15
15
  * 统一全局zIndex
16
16
  */
17
17
  export declare const zIndex: {
18
+ touchRipple: number;
18
19
  overlay: number;
19
20
  popper: number;
20
21
  dropdown: number;
@@ -91,6 +91,7 @@ export function restoreThemeDefinition(theme) {
91
91
  * 统一全局zIndex
92
92
  */
93
93
  export const zIndex = {
94
+ touchRipple: 900,
94
95
  overlay: 1000,
95
96
  popper: 1100,
96
97
  dropdown: 1200,
@@ -1 +1,2 @@
1
1
  export * from './touchRipple';
2
+ export * from './touchRipple';
@@ -1 +1,2 @@
1
1
  export * from './touchRipple';
2
+ export * from './touchRipple';
@@ -1,16 +1,8 @@
1
- import { ReactElement } from 'react';
2
- import { ColorPropsValue, DivProps } from '../../types';
3
- export interface TouchRippleProps extends Omit<DivProps, 'children'> {
1
+ import { ColorPropsValue, DefineElement, DivProps } from '../../types';
2
+ export interface TouchRippleOverlayProps extends DivProps {
4
3
  color?: ColorPropsValue;
5
- rippleProps?: DivProps;
6
- children?: ReactElement;
4
+ /** 容器元素,默认为该组件元素的父元素 */
5
+ container?: DefineElement<HTMLElement>;
6
+ effectContainer?: DefineElement<HTMLElement>;
7
7
  }
8
- export declare const TouchRipple: {
9
- (props: TouchRippleProps): ReactElement;
10
- Ripple: typeof Ripple;
11
- };
12
- interface RippleProps extends DivProps {
13
- color?: ColorPropsValue;
14
- }
15
- export declare const Ripple: import("react").MemoExoticComponent<({ ref, color, ...props }: RippleProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
16
- export {};
8
+ export declare const TouchRipple: import("react").MemoExoticComponent<({ color, container, effectContainer, ...props }: TouchRippleOverlayProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
@@ -1,54 +1,69 @@
1
1
  import { jsx as _jsx } from "@emotion/react/jsx-runtime";
2
- import { cloneElement, memo, useRef, useState, useLayoutEffect } from 'react';
2
+ import { memo, useEffect, useRef, useState } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { cloneRef, clsx, useContainer } from '../../utils';
3
5
  import { classes, useStyle } from './touchRipple.style';
4
- import { cloneRef, getEasyID } from '../../utils';
5
- export const TouchRipple = (({ ref, color, rippleProps, children, ...props }) => {
6
- const renderedRipple = (_jsx(Ripple, { ...rippleProps,
7
- // 有children属性时,ref传递给children
8
- ref: children ? ref : void 0 }));
9
- return children
10
- // 有children属性时,props传递给children,再追加Ripple组件
11
- ? cloneElement(children, { ...props, ref }, children.props.children, renderedRipple)
12
- : renderedRipple;
13
- });
14
- export const Ripple = memo(({ ref, color = 'primary', ...props }) => {
15
- const [ripples, setRipples] = useState([]);
16
- const rippleRef = useRef(null);
17
- useLayoutEffect(() => {
18
- const wrapper = rippleRef.current?.parentElement;
19
- if (wrapper) {
20
- const pointerDown = (e) => {
21
- setRipples(o => [
22
- ...o,
23
- {
24
- key: getEasyID('touch-ripple'),
25
- r: Math.sqrt(wrapper.clientWidth ** 2 + wrapper.clientHeight ** 2),
26
- left: e.offsetX,
27
- top: e.offsetY,
6
+ export const TouchRipple = memo(({ color = 'primary', container, effectContainer, ...props }) => {
7
+ const ref = useRef(null);
8
+ const [ripples, setRipples] = useState(new Map());
9
+ const incrementKey = useRef(0);
10
+ const containerEl = useContainer(container, effectContainer, null);
11
+ useEffect(() => {
12
+ const parentElement = containerEl.current ?? ref.current.parentElement;
13
+ if (parentElement) {
14
+ const pointerDown = ({ offsetX, offsetY }) => {
15
+ const maxWidth = Math.max(parentElement.clientWidth - offsetX, offsetX);
16
+ const maxHeight = Math.max(parentElement.clientHeight - offsetY, offsetY);
17
+ setRipples(o => {
18
+ const r = new Map(o);
19
+ const key = ++incrementKey.current;
20
+ r.set(key, {
21
+ key,
22
+ diameter: Math.sqrt(maxWidth ** 2 + maxHeight ** 2) * 2,
23
+ left: offsetX,
24
+ top: offsetY,
28
25
  leaving: false
29
- }
30
- ]);
31
- wrapper.addEventListener('pointerup', leave);
32
- wrapper.addEventListener('pointerleave', leave);
26
+ });
27
+ return r;
28
+ });
29
+ parentElement.addEventListener('pointerup', leave);
30
+ parentElement.addEventListener('pointerleave', leave);
33
31
  };
34
32
  const leave = () => {
35
- setRipples(o => o.map(v => ({ ...v, leaving: true })));
33
+ setRipples(o => {
34
+ const r = new Map(o);
35
+ r.forEach(v => v.leaving = true);
36
+ return r;
37
+ });
36
38
  removeLeaveListener();
37
39
  };
38
- wrapper.addEventListener('pointerdown', pointerDown);
39
40
  const removeLeaveListener = () => {
40
- wrapper.removeEventListener('pointerup', leave);
41
- wrapper.removeEventListener('pointerleave', leave);
41
+ parentElement.removeEventListener('pointerup', leave);
42
+ parentElement.removeEventListener('pointerleave', leave);
42
43
  };
44
+ parentElement.addEventListener('pointerdown', pointerDown);
43
45
  return () => {
44
- wrapper.removeEventListener('pointerdown', pointerDown);
46
+ parentElement.removeEventListener('pointerdown', pointerDown);
45
47
  removeLeaveListener();
46
48
  };
47
49
  }
48
- return;
49
- }, []);
50
- const onTransitionEnd = (key) => {
51
- setRipples(o => o.filter(v => v.key !== key));
50
+ }, [containerEl.current]);
51
+ const leftHandler = (key) => {
52
+ setRipples(o => {
53
+ const r = new Map(o);
54
+ r.delete(key);
55
+ if (!r.size) {
56
+ incrementKey.current = 0;
57
+ }
58
+ return r;
59
+ });
52
60
  };
53
- return (_jsx("div", { ...props, ref: cloneRef(ref, rippleRef), css: useStyle({ color: color || 'primary' }), className: classes.root, children: ripples.map(({ key, r, left, top, leaving }) => _jsx("div", { className: classes.ripple, style: { width: r * 2, left, top }, "data-leaving": leaving, onTransitionEnd: () => onTransitionEnd(key) }, key)) }));
61
+ const children = (_jsx("div", { ...props, ref: cloneRef(ref, props.ref), css: useStyle({ color }), className: clsx(classes.root, props.className), children: ripples.values().toArray().map(({ key, diameter, left, top, leaving }) => _jsx("div", { className: classes.ripple, style: {
62
+ width: diameter,
63
+ height: diameter,
64
+ left, top
65
+ }, "data-leaving": leaving, onTransitionEnd: () => leftHandler(key) }, key)) }));
66
+ return containerEl.current
67
+ ? createPortal(children, containerEl.current)
68
+ : children;
54
69
  });