@canlooks/can-ui 0.0.112 → 0.0.114

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.
@@ -7,7 +7,7 @@ const utils_1 = require("../../utils");
7
7
  const theme_1 = require("../theme");
8
8
  const transitionBase_1 = require("../transitionBase");
9
9
  const icon_1 = require("../icon");
10
- const faCaretRight_1 = require("@fortawesome/free-solid-svg-icons/faCaretRight");
10
+ const free_solid_svg_icons_1 = require("@fortawesome/free-solid-svg-icons");
11
11
  function Accordion({ size, title, prefix, suffix, expandIcon, defaultExpanded = false, expanded, onExpandedChange, readOnly, disabled, ...props }) {
12
12
  const theme = (0, theme_1.useTheme)();
13
13
  size ??= theme.size;
@@ -17,7 +17,7 @@ function Accordion({ size, title, prefix, suffix, expandIcon, defaultExpanded =
17
17
  };
18
18
  const renderExpandIcon = () => {
19
19
  if (!expandIcon) {
20
- return (0, jsx_runtime_1.jsx)(icon_1.Icon, { icon: faCaretRight_1.faCaretRight, className: accordion_style_1.classes.expandIcon });
20
+ return (0, jsx_runtime_1.jsx)(icon_1.Icon, { icon: free_solid_svg_icons_1.faCaretRight, className: accordion_style_1.classes.expandIcon });
21
21
  }
22
22
  if (typeof expandIcon === 'function') {
23
23
  return expandIcon(innerExpanded.current);
@@ -27,12 +27,12 @@ exports.App = (({ theme, ...props }) => {
27
27
  return ((0, jsx_runtime_1.jsx)(globalEventDelegation_1.GlobalEventDelegation, { children: (0, jsx_runtime_1.jsx)(theme_1.ThemeProvider, { theme: theme, children: (0, jsx_runtime_1.jsx)(InnerApp, { ...props }) }) }));
28
28
  });
29
29
  function InnerApp({ component: Component = 'div', theme, children, fill = true, ...props }) {
30
- const appValue = (0, react_1.useMemo)(() => ({
30
+ const appValue = (0, utils_1.useExternalClass)(() => ({
31
31
  dialog: exports.App.dialog = new appDialog_1.AppDialogMethods(),
32
32
  message: exports.App.message = new appMessage_1.AppMessageMethods(),
33
33
  notification: exports.App.notification = new appNotification_1.AppNotificationMethods(),
34
34
  actionSheet: exports.App.actionSheet = new appActionSheet_1.AppActionSheetMethods()
35
- }), []);
35
+ }));
36
36
  return ((0, jsx_runtime_1.jsxs)(AppContext, { value: appValue, children: [Component
37
37
  ? (0, jsx_runtime_1.jsx)(Component, { ...props, css: [
38
38
  app_style_1.style,
@@ -37,7 +37,7 @@ export declare function ClickAway({ ref, container, eventType, onClickAway, disa
37
37
  title: string;
38
38
  translate: "yes" | "no";
39
39
  radioGroup: string;
40
- role: "article" | "button" | "dialog" | "figure" | "form" | "img" | "link" | "main" | "menu" | "menuitem" | "option" | "search" | "table" | "switch" | "status" | (string & {}) | "none" | "checkbox" | "listbox" | "radio" | "region" | "cell" | "grid" | "row" | "listitem" | "menubar" | "progressbar" | "separator" | "tab" | "tabpanel" | "toolbar" | "tooltip" | "treeitem" | "scrollbar" | "alert" | "alertdialog" | "application" | "banner" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "directory" | "document" | "feed" | "gridcell" | "group" | "heading" | "list" | "log" | "marquee" | "math" | "menuitemcheckbox" | "menuitemradio" | "navigation" | "note" | "presentation" | "radiogroup" | "rowgroup" | "rowheader" | "searchbox" | "slider" | "spinbutton" | "tablist" | "term" | "textbox" | "timer" | "tree" | "treegrid";
40
+ role: "article" | "button" | "dialog" | "figure" | "form" | "img" | "link" | "main" | "menu" | "menuitem" | "option" | "search" | "table" | "switch" | "status" | (string & {}) | "none" | "checkbox" | "listbox" | "radio" | "region" | "cell" | "grid" | "row" | "math" | "listitem" | "menubar" | "progressbar" | "separator" | "tab" | "tabpanel" | "toolbar" | "tooltip" | "treeitem" | "scrollbar" | "alert" | "alertdialog" | "application" | "banner" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "directory" | "document" | "feed" | "gridcell" | "group" | "heading" | "list" | "log" | "marquee" | "menuitemcheckbox" | "menuitemradio" | "navigation" | "note" | "presentation" | "radiogroup" | "rowgroup" | "rowheader" | "searchbox" | "slider" | "spinbutton" | "tablist" | "term" | "textbox" | "timer" | "tree" | "treegrid";
41
41
  about: string;
42
42
  content: string;
43
43
  datatype: string;
@@ -60,7 +60,7 @@ export declare function ClickAway({ ref, container, eventType, onClickAway, disa
60
60
  results: number;
61
61
  security: string;
62
62
  unselectable: "off" | "on";
63
- popover: "" | "auto" | "manual";
63
+ popover: "" | "auto" | "manual" | "hint";
64
64
  popoverTargetAction: "hide" | "show" | "toggle";
65
65
  popoverTarget: string;
66
66
  inert: boolean;
@@ -70,7 +70,7 @@ export declare function ClickAway({ ref, container, eventType, onClickAway, disa
70
70
  part: string;
71
71
  "aria-activedescendant": string;
72
72
  "aria-atomic": boolean | "false" | "true";
73
- "aria-autocomplete": "both" | "none" | "inline" | "list";
73
+ "aria-autocomplete": "none" | "both" | "inline" | "list";
74
74
  "aria-braillelabel": string;
75
75
  "aria-brailleroledescription": string;
76
76
  "aria-busy": boolean | "false" | "true";
@@ -1,6 +1,8 @@
1
1
  import { FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
2
2
  import { ColorPropsValue } from '../../types';
3
- export interface IconProps extends Omit<FontAwesomeIconProps, 'color'> {
3
+ import { IconDefinition } from '@fortawesome/free-brands-svg-icons';
4
+ export interface IconProps extends Omit<FontAwesomeIconProps, 'color' | 'icon'> {
4
5
  color?: ColorPropsValue;
6
+ icon: FontAwesomeIconProps['icon'] | IconDefinition;
5
7
  }
6
8
  export declare function Icon({ color, ...props }: IconProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -24,4 +24,4 @@ export interface OverlayBaseProps extends DivProps {
24
24
  removeFocusOnOpen?: boolean;
25
25
  }
26
26
  export declare const overlayBaseTransitionDuration = 300;
27
- export declare function OverlayBase({ container, effectContainer, 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 | null;
@@ -37,7 +37,7 @@ function OverlayBase({ container, effectContainer, forceRender, open, onMaskClic
37
37
  onClosed?.();
38
38
  forceRender === false && setShouldRender(false);
39
39
  };
40
- return shouldRender.current && (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsxs)("div", { ...props, css: overlayBase_style_1.style, className: (0, utils_1.clsx)(overlayBase_style_1.classes.root, props.className), "data-open": open, "data-custom-container": containerEl.current !== document.body, children: [(0, jsx_runtime_1.jsx)(transitionBase_1.Fade, { timeout: exports.overlayBaseTransitionDuration, ...(0, utils_1.mergeComponentProps)(maskProps, {
40
+ return shouldRender.current && containerEl.current && (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsxs)("div", { ...props, css: overlayBase_style_1.style, className: (0, utils_1.clsx)(overlayBase_style_1.classes.root, props.className), "data-open": open, "data-custom-container": containerEl.current !== document.body, children: [(0, jsx_runtime_1.jsx)(transitionBase_1.Fade, { timeout: exports.overlayBaseTransitionDuration, ...(0, utils_1.mergeComponentProps)(maskProps, {
41
41
  in: open,
42
42
  className: overlayBase_style_1.classes.mask,
43
43
  onClick,
@@ -22,7 +22,7 @@ const getAttemptOrder = (placement) => {
22
22
  }
23
23
  return order;
24
24
  };
25
- function Popper({ ref, popperRef, anchorElement, container = document.body, effectContainer, content, offset, trigger = 'hover', clickToClose, placement = 'top', variant = 'zoom', sizeAdaptable = variant === 'collapse', mouseEnterDelay = 150, mouseLeaveDelay = 150, defaultOpen = false, open, onOpenChange, onOpenChangeEnd, disabled, autoClose = false, forceRender, children, ...props }) {
25
+ function Popper({ ref, popperRef, anchorElement, container, effectContainer, content, offset, trigger = 'hover', clickToClose, placement = 'top', variant = 'zoom', sizeAdaptable = variant === 'collapse', mouseEnterDelay = 150, mouseLeaveDelay = 150, defaultOpen = false, open, onOpenChange, onOpenChangeEnd, disabled, autoClose = false, forceRender, children, ...props }) {
26
26
  const { spacing } = (0, theme_1.useTheme)();
27
27
  offset ??= spacing[2];
28
28
  (0, react_1.useImperativeHandle)(popperRef, () => {
@@ -537,7 +537,7 @@ function Popper({ ref, popperRef, anchorElement, container = document.body, effe
537
537
  ? (0, react_1.cloneElement)(children, {
538
538
  ref: childRef
539
539
  })
540
- : children, renderedOnce.current && (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)(clickAway_1.ClickAway, { disabled: !clickable && !enterable && !contextMenuable,
540
+ : children, renderedOnce.current && containerEl.current && (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)(clickAway_1.ClickAway, { disabled: !clickable && !enterable && !contextMenuable,
541
541
  // 右键菜单点击anchor需要关闭弹框
542
542
  targets: () => contextMenuEvent.current ? void 0 : getAnchorElement(), onClickAway: onClickAway, children: (0, jsx_runtime_1.jsx)("div", { ...props, ref: innerPopperRef, css: popper_style_1.style, className: (0, utils_1.clsx)(popper_style_1.classes.root, props.className), style: {
543
543
  ...popperBounding,
@@ -30,7 +30,7 @@ export declare const SnackbarBase: React.MemoExoticComponent<({ methods, useTo,
30
30
  max?: number;
31
31
  container?: DefineElement<HTMLElement>;
32
32
  effectContainer?: DefineElement<HTMLElement>;
33
- }) => React.ReactPortal>;
33
+ }) => React.ReactPortal | null>;
34
34
  interface SnackbarBaseItemProps extends Omit<SnackbarBaseProps, 'duration' | 'onAutoClose'> {
35
35
  id: string;
36
36
  type: keyof SnackbarBaseMethods;
@@ -86,7 +86,7 @@ exports.SnackbarBase = (0, react_2.memo)(({ methods, useTo, max = useTo === 'mes
86
86
  methods.error = defineMethod('error');
87
87
  const css = (0, snackbarBase_style_1.style)();
88
88
  const containerEl = (0, utils_1.useContainer)(container, effectContainer);
89
- return (0, react_dom_1.createPortal)(stacks.flatMap((stack, i) => stack
89
+ return containerEl.current && (0, react_dom_1.createPortal)(stacks.flatMap((stack, i) => stack
90
90
  ? (0, jsx_runtime_1.jsx)(react_transition_group_1.TransitionGroup, { css: css, className: snackbarBase_style_1.classes.root, "data-place": i, "data-use-to": useTo, children: stack.map(p => (0, react_1.createElement)(exports.SnackbarBaseItem, { ...p, key: p.id })) }, i)
91
91
  : []), containerEl.current);
92
92
  });
@@ -1,16 +1,16 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { DivProps, Status as IStatus } from '../../types';
3
- import { FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
3
+ import { IconProps } from '../icon';
4
4
  export type StatusType = IStatus | 'confirm' | 'unknown';
5
5
  export declare const statusMapToIconDefinition: {
6
- info: import("@fortawesome/fontawesome-common-types").IconDefinition;
7
- success: import("@fortawesome/fontawesome-common-types").IconDefinition;
8
- warning: import("@fortawesome/fontawesome-common-types").IconDefinition;
9
- error: import("@fortawesome/fontawesome-common-types").IconDefinition;
10
- confirm: import("@fortawesome/fontawesome-common-types").IconDefinition;
11
- unknown: import("@fortawesome/fontawesome-common-types").IconDefinition;
6
+ info: import("@fortawesome/free-solid-svg-icons").IconDefinition;
7
+ success: import("@fortawesome/free-solid-svg-icons").IconDefinition;
8
+ warning: import("@fortawesome/free-solid-svg-icons").IconDefinition;
9
+ error: import("@fortawesome/free-solid-svg-icons").IconDefinition;
10
+ confirm: import("@fortawesome/free-solid-svg-icons").IconDefinition;
11
+ unknown: import("@fortawesome/free-solid-svg-icons").IconDefinition;
12
12
  };
13
- export interface StatusIconProps extends Partial<FontAwesomeIconProps> {
13
+ export interface StatusIconProps extends Partial<IconProps> {
14
14
  status?: StatusType;
15
15
  }
16
16
  export declare const StatusIcon: import("react").MemoExoticComponent<({ status, ...props }: StatusIconProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
@@ -22,6 +22,6 @@ export interface StatusProps extends DivProps {
22
22
  /** 是否播放动画,默认为false */
23
23
  animation?: boolean;
24
24
  /** {@link variant}为`icon`时生效,传递给`<StatusIcon/>`组件 */
25
- iconProps?: Partial<FontAwesomeIconProps>;
25
+ iconProps?: Partial<IconProps>;
26
26
  }
27
27
  export declare const Status: import("react").MemoExoticComponent<({ status, variant, label, animation, iconProps, ...props }: StatusProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
@@ -5,19 +5,15 @@ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const status_style_1 = require("./status.style");
7
7
  const utils_1 = require("../../utils");
8
- const faCircleInfo_1 = require("@fortawesome/free-solid-svg-icons/faCircleInfo");
9
- const faCircleCheck_1 = require("@fortawesome/free-solid-svg-icons/faCircleCheck");
10
- const faCircleExclamation_1 = require("@fortawesome/free-solid-svg-icons/faCircleExclamation");
11
- const faCircleXmark_1 = require("@fortawesome/free-solid-svg-icons/faCircleXmark");
12
- const faCircleQuestion_1 = require("@fortawesome/free-solid-svg-icons/faCircleQuestion");
13
- const react_fontawesome_1 = require("@fortawesome/react-fontawesome");
8
+ const free_solid_svg_icons_1 = require("@fortawesome/free-solid-svg-icons");
9
+ const icon_1 = require("../icon");
14
10
  exports.statusMapToIconDefinition = {
15
- info: faCircleInfo_1.faCircleInfo,
16
- success: faCircleCheck_1.faCircleCheck,
17
- warning: faCircleExclamation_1.faCircleExclamation,
18
- error: faCircleXmark_1.faCircleXmark,
19
- confirm: faCircleQuestion_1.faCircleQuestion,
20
- unknown: faCircleQuestion_1.faCircleQuestion
11
+ info: free_solid_svg_icons_1.faCircleInfo,
12
+ success: free_solid_svg_icons_1.faCircleCheck,
13
+ warning: free_solid_svg_icons_1.faCircleExclamation,
14
+ error: free_solid_svg_icons_1.faCircleXmark,
15
+ confirm: free_solid_svg_icons_1.faCircleQuestion,
16
+ unknown: free_solid_svg_icons_1.faCircleQuestion
21
17
  };
22
18
  exports.StatusIcon = (0, react_1.memo)(({ status = 'unknown', ...props }) => {
23
19
  const statusColor = (0, utils_1.useStatusColor)(status);
@@ -30,7 +26,7 @@ exports.StatusIcon = (0, react_1.memo)(({ status = 'unknown', ...props }) => {
30
26
  ...props.style
31
27
  }), [statusColor, props.style])
32
28
  };
33
- return (0, jsx_runtime_1.jsx)(react_fontawesome_1.FontAwesomeIcon, { ...iconProps });
29
+ return (0, jsx_runtime_1.jsx)(icon_1.Icon, { ...iconProps });
34
30
  });
35
31
  const defaultLabel = {
36
32
  unknown: '未知',
@@ -55,4 +55,8 @@ export declare function useLoading<A extends any[], R>(fn: (...args: A) => R | P
55
55
  * @param effectContainer
56
56
  * @param defaultContainer 默认为`document.body`
57
57
  */
58
- export declare function useContainer<T extends HTMLElement | null>(container?: DefineElement<T>, effectContainer?: DefineElement<T>, defaultContainer?: T): RefObject<T>;
58
+ export declare function useContainer<T extends HTMLElement | null>(container?: DefineElement<T>, effectContainer?: DefineElement<T>, defaultContainer?: DefineElement<T>): RefObject<T | null>;
59
+ /**
60
+ * 使用外部类,该方法可避免`StrictMode`下,React渲染行为与外部类实例生命周期不同步的问题
61
+ */
62
+ export declare function useExternalClass<T>(setup: () => T, cleanup?: (instance: T) => void): T;
@@ -9,6 +9,7 @@ exports.useUnmounted = useUnmounted;
9
9
  exports.useControlled = useControlled;
10
10
  exports.useLoading = useLoading;
11
11
  exports.useContainer = useContainer;
12
+ exports.useExternalClass = useExternalClass;
12
13
  const react_1 = require("react");
13
14
  const utils_1 = require("./utils");
14
15
  /**
@@ -130,18 +131,36 @@ function useLoading(fn, referredLoading = false) {
130
131
  * @param effectContainer
131
132
  * @param defaultContainer 默认为`document.body`
132
133
  */
133
- function useContainer(container, effectContainer, defaultContainer = document.body) {
134
+ function useContainer(container, effectContainer, defaultContainer) {
134
135
  const [containerEl, setContainerEl] = useDerivedState(prev => {
135
136
  if (container) {
136
137
  return typeof container === 'function' ? container() : container;
137
138
  }
138
- return prev || defaultContainer;
139
- }, [container, defaultContainer]);
139
+ return prev || null;
140
+ }, [container]);
140
141
  (0, react_1.useEffect)(() => {
141
- if (effectContainer) {
142
- const el = typeof effectContainer === 'function' ? effectContainer() : effectContainer;
142
+ const _container = effectContainer || defaultContainer || document.body;
143
+ if (_container) {
144
+ const el = typeof _container === 'function' ? _container() : _container;
143
145
  setContainerEl(el);
144
146
  }
145
- }, []);
147
+ }, [effectContainer, defaultContainer]);
146
148
  return containerEl;
147
149
  }
150
+ /**
151
+ * 使用外部类,该方法可避免`StrictMode`下,React渲染行为与外部类实例生命周期不同步的问题
152
+ */
153
+ function useExternalClass(setup, cleanup) {
154
+ const mountTimes = (0, react_1.useRef)(0);
155
+ const prevInstance = (0, react_1.useRef)(void 0);
156
+ const [instance] = (0, react_1.useState)(() => {
157
+ if (!mountTimes.current++) {
158
+ prevInstance.current = setup();
159
+ }
160
+ return prevInstance.current;
161
+ });
162
+ (0, react_1.useEffect)(() => () => {
163
+ !--mountTimes.current && cleanup?.(instance);
164
+ }, []);
165
+ return instance;
166
+ }
@@ -4,7 +4,7 @@ import { clsx, useControlled } from '../../utils';
4
4
  import { useTheme } from '../theme';
5
5
  import { Collapse } from '../transitionBase';
6
6
  import { Icon } from '../icon';
7
- import { faCaretRight } from '@fortawesome/free-solid-svg-icons/faCaretRight';
7
+ import { faCaretRight } from '@fortawesome/free-solid-svg-icons';
8
8
  export function Accordion({ size, title, prefix, suffix, expandIcon, defaultExpanded = false, expanded, onExpandedChange, readOnly, disabled, ...props }) {
9
9
  const theme = useTheme();
10
10
  size ??= theme.size;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
- import { createContext, useContext, useMemo } from 'react';
3
- import { clsx, defineCss } from '../../utils';
2
+ import { createContext, useContext } from 'react';
3
+ import { clsx, defineCss, useExternalClass } from '../../utils';
4
4
  import { classes, style } from './app.style';
5
5
  import { ThemeProvider } from '../theme';
6
6
  import { AppDialog, AppDialogMethods } from './appDialog';
@@ -22,12 +22,12 @@ export const App = (({ theme, ...props }) => {
22
22
  return (_jsx(GlobalEventDelegation, { children: _jsx(ThemeProvider, { theme: theme, children: _jsx(InnerApp, { ...props }) }) }));
23
23
  });
24
24
  export function InnerApp({ component: Component = 'div', theme, children, fill = true, ...props }) {
25
- const appValue = useMemo(() => ({
25
+ const appValue = useExternalClass(() => ({
26
26
  dialog: App.dialog = new AppDialogMethods(),
27
27
  message: App.message = new AppMessageMethods(),
28
28
  notification: App.notification = new AppNotificationMethods(),
29
29
  actionSheet: App.actionSheet = new AppActionSheetMethods()
30
- }), []);
30
+ }));
31
31
  return (_jsxs(AppContext, { value: appValue, children: [Component
32
32
  ? _jsx(Component, { ...props, css: [
33
33
  style,
@@ -37,7 +37,7 @@ export declare function ClickAway({ ref, container, eventType, onClickAway, disa
37
37
  title: string;
38
38
  translate: "yes" | "no";
39
39
  radioGroup: string;
40
- role: "article" | "button" | "dialog" | "figure" | "form" | "img" | "link" | "main" | "menu" | "menuitem" | "option" | "search" | "table" | "switch" | "status" | (string & {}) | "none" | "checkbox" | "listbox" | "radio" | "region" | "cell" | "grid" | "row" | "listitem" | "menubar" | "progressbar" | "separator" | "tab" | "tabpanel" | "toolbar" | "tooltip" | "treeitem" | "scrollbar" | "alert" | "alertdialog" | "application" | "banner" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "directory" | "document" | "feed" | "gridcell" | "group" | "heading" | "list" | "log" | "marquee" | "math" | "menuitemcheckbox" | "menuitemradio" | "navigation" | "note" | "presentation" | "radiogroup" | "rowgroup" | "rowheader" | "searchbox" | "slider" | "spinbutton" | "tablist" | "term" | "textbox" | "timer" | "tree" | "treegrid";
40
+ role: "article" | "button" | "dialog" | "figure" | "form" | "img" | "link" | "main" | "menu" | "menuitem" | "option" | "search" | "table" | "switch" | "status" | (string & {}) | "none" | "checkbox" | "listbox" | "radio" | "region" | "cell" | "grid" | "row" | "math" | "listitem" | "menubar" | "progressbar" | "separator" | "tab" | "tabpanel" | "toolbar" | "tooltip" | "treeitem" | "scrollbar" | "alert" | "alertdialog" | "application" | "banner" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "directory" | "document" | "feed" | "gridcell" | "group" | "heading" | "list" | "log" | "marquee" | "menuitemcheckbox" | "menuitemradio" | "navigation" | "note" | "presentation" | "radiogroup" | "rowgroup" | "rowheader" | "searchbox" | "slider" | "spinbutton" | "tablist" | "term" | "textbox" | "timer" | "tree" | "treegrid";
41
41
  about: string;
42
42
  content: string;
43
43
  datatype: string;
@@ -60,7 +60,7 @@ export declare function ClickAway({ ref, container, eventType, onClickAway, disa
60
60
  results: number;
61
61
  security: string;
62
62
  unselectable: "off" | "on";
63
- popover: "" | "auto" | "manual";
63
+ popover: "" | "auto" | "manual" | "hint";
64
64
  popoverTargetAction: "hide" | "show" | "toggle";
65
65
  popoverTarget: string;
66
66
  inert: boolean;
@@ -70,7 +70,7 @@ export declare function ClickAway({ ref, container, eventType, onClickAway, disa
70
70
  part: string;
71
71
  "aria-activedescendant": string;
72
72
  "aria-atomic": boolean | "false" | "true";
73
- "aria-autocomplete": "both" | "none" | "inline" | "list";
73
+ "aria-autocomplete": "none" | "both" | "inline" | "list";
74
74
  "aria-braillelabel": string;
75
75
  "aria-brailleroledescription": string;
76
76
  "aria-busy": boolean | "false" | "true";
@@ -1,6 +1,8 @@
1
1
  import { FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
2
2
  import { ColorPropsValue } from '../../types';
3
- export interface IconProps extends Omit<FontAwesomeIconProps, 'color'> {
3
+ import { IconDefinition } from '@fortawesome/free-brands-svg-icons';
4
+ export interface IconProps extends Omit<FontAwesomeIconProps, 'color' | 'icon'> {
4
5
  color?: ColorPropsValue;
6
+ icon: FontAwesomeIconProps['icon'] | IconDefinition;
5
7
  }
6
8
  export declare function Icon({ color, ...props }: IconProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -24,4 +24,4 @@ export interface OverlayBaseProps extends DivProps {
24
24
  removeFocusOnOpen?: boolean;
25
25
  }
26
26
  export declare const overlayBaseTransitionDuration = 300;
27
- export declare function OverlayBase({ container, effectContainer, 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 | null;
@@ -33,7 +33,7 @@ export function OverlayBase({ container, effectContainer, forceRender, open, onM
33
33
  onClosed?.();
34
34
  forceRender === false && setShouldRender(false);
35
35
  };
36
- 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, ...mergeComponentProps(maskProps, {
36
+ return shouldRender.current && containerEl.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, ...mergeComponentProps(maskProps, {
37
37
  in: open,
38
38
  className: classes.mask,
39
39
  onClick,
@@ -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, effectContainer, content, offset, trigger = 'hover', clickToClose, placement = 'top', variant = 'zoom', sizeAdaptable = variant === 'collapse', mouseEnterDelay = 150, mouseLeaveDelay = 150, defaultOpen = false, open, onOpenChange, onOpenChangeEnd, disabled, autoClose = false, forceRender, children, ...props }) {
22
+ export function Popper({ ref, popperRef, anchorElement, container, effectContainer, content, offset, trigger = 'hover', clickToClose, placement = 'top', variant = 'zoom', sizeAdaptable = variant === 'collapse', mouseEnterDelay = 150, 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, () => {
@@ -534,7 +534,7 @@ export function Popper({ ref, popperRef, anchorElement, container = document.bod
534
534
  ? cloneElement(children, {
535
535
  ref: childRef
536
536
  })
537
- : children, renderedOnce.current && createPortal(_jsx(ClickAway, { disabled: !clickable && !enterable && !contextMenuable,
537
+ : children, renderedOnce.current && containerEl.current && createPortal(_jsx(ClickAway, { disabled: !clickable && !enterable && !contextMenuable,
538
538
  // 右键菜单点击anchor需要关闭弹框
539
539
  targets: () => contextMenuEvent.current ? void 0 : getAnchorElement(), onClickAway: onClickAway, children: _jsx("div", { ...props, ref: innerPopperRef, css: style, className: clsx(classes.root, props.className), style: {
540
540
  ...popperBounding,
@@ -30,7 +30,7 @@ export declare const SnackbarBase: React.MemoExoticComponent<({ methods, useTo,
30
30
  max?: number;
31
31
  container?: DefineElement<HTMLElement>;
32
32
  effectContainer?: DefineElement<HTMLElement>;
33
- }) => React.ReactPortal>;
33
+ }) => React.ReactPortal | null>;
34
34
  interface SnackbarBaseItemProps extends Omit<SnackbarBaseProps, 'duration' | 'onAutoClose'> {
35
35
  id: string;
36
36
  type: keyof SnackbarBaseMethods;
@@ -82,7 +82,7 @@ export const SnackbarBase = memo(({ methods, useTo, max = useTo === 'message' ?
82
82
  methods.error = defineMethod('error');
83
83
  const css = style();
84
84
  const containerEl = useContainer(container, effectContainer);
85
- return createPortal(stacks.flatMap((stack, i) => stack
85
+ return containerEl.current && 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
87
  : []), containerEl.current);
88
88
  });
@@ -1,16 +1,16 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { DivProps, Status as IStatus } from '../../types';
3
- import { FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
3
+ import { IconProps } from '../icon';
4
4
  export type StatusType = IStatus | 'confirm' | 'unknown';
5
5
  export declare const statusMapToIconDefinition: {
6
- info: import("@fortawesome/fontawesome-common-types").IconDefinition;
7
- success: import("@fortawesome/fontawesome-common-types").IconDefinition;
8
- warning: import("@fortawesome/fontawesome-common-types").IconDefinition;
9
- error: import("@fortawesome/fontawesome-common-types").IconDefinition;
10
- confirm: import("@fortawesome/fontawesome-common-types").IconDefinition;
11
- unknown: import("@fortawesome/fontawesome-common-types").IconDefinition;
6
+ info: import("@fortawesome/free-solid-svg-icons").IconDefinition;
7
+ success: import("@fortawesome/free-solid-svg-icons").IconDefinition;
8
+ warning: import("@fortawesome/free-solid-svg-icons").IconDefinition;
9
+ error: import("@fortawesome/free-solid-svg-icons").IconDefinition;
10
+ confirm: import("@fortawesome/free-solid-svg-icons").IconDefinition;
11
+ unknown: import("@fortawesome/free-solid-svg-icons").IconDefinition;
12
12
  };
13
- export interface StatusIconProps extends Partial<FontAwesomeIconProps> {
13
+ export interface StatusIconProps extends Partial<IconProps> {
14
14
  status?: StatusType;
15
15
  }
16
16
  export declare const StatusIcon: import("react").MemoExoticComponent<({ status, ...props }: StatusIconProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
@@ -22,6 +22,6 @@ export interface StatusProps extends DivProps {
22
22
  /** 是否播放动画,默认为false */
23
23
  animation?: boolean;
24
24
  /** {@link variant}为`icon`时生效,传递给`<StatusIcon/>`组件 */
25
- iconProps?: Partial<FontAwesomeIconProps>;
25
+ iconProps?: Partial<IconProps>;
26
26
  }
27
27
  export declare const Status: import("react").MemoExoticComponent<({ status, variant, label, animation, iconProps, ...props }: StatusProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
@@ -2,12 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  import { memo, useMemo } from 'react';
3
3
  import { classes, style } from './status.style';
4
4
  import { clsx, useStatusColor } from '../../utils';
5
- import { faCircleInfo } from '@fortawesome/free-solid-svg-icons/faCircleInfo';
6
- import { faCircleCheck } from '@fortawesome/free-solid-svg-icons/faCircleCheck';
7
- import { faCircleExclamation } from '@fortawesome/free-solid-svg-icons/faCircleExclamation';
8
- import { faCircleXmark } from '@fortawesome/free-solid-svg-icons/faCircleXmark';
9
- import { faCircleQuestion } from '@fortawesome/free-solid-svg-icons/faCircleQuestion';
10
- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
5
+ import { faCircleInfo, faCircleCheck, faCircleExclamation, faCircleXmark, faCircleQuestion } from '@fortawesome/free-solid-svg-icons';
6
+ import { Icon } from '../icon';
11
7
  export const statusMapToIconDefinition = {
12
8
  info: faCircleInfo,
13
9
  success: faCircleCheck,
@@ -27,7 +23,7 @@ export const StatusIcon = memo(({ status = 'unknown', ...props }) => {
27
23
  ...props.style
28
24
  }), [statusColor, props.style])
29
25
  };
30
- return _jsx(FontAwesomeIcon, { ...iconProps });
26
+ return _jsx(Icon, { ...iconProps });
31
27
  });
32
28
  const defaultLabel = {
33
29
  unknown: '未知',
@@ -55,4 +55,8 @@ export declare function useLoading<A extends any[], R>(fn: (...args: A) => R | P
55
55
  * @param effectContainer
56
56
  * @param defaultContainer 默认为`document.body`
57
57
  */
58
- export declare function useContainer<T extends HTMLElement | null>(container?: DefineElement<T>, effectContainer?: DefineElement<T>, defaultContainer?: T): RefObject<T>;
58
+ export declare function useContainer<T extends HTMLElement | null>(container?: DefineElement<T>, effectContainer?: DefineElement<T>, defaultContainer?: DefineElement<T>): RefObject<T | null>;
59
+ /**
60
+ * 使用外部类,该方法可避免`StrictMode`下,React渲染行为与外部类实例生命周期不同步的问题
61
+ */
62
+ export declare function useExternalClass<T>(setup: () => T, cleanup?: (instance: T) => void): T;
@@ -119,18 +119,36 @@ export function useLoading(fn, referredLoading = false) {
119
119
  * @param effectContainer
120
120
  * @param defaultContainer 默认为`document.body`
121
121
  */
122
- export function useContainer(container, effectContainer, defaultContainer = document.body) {
122
+ export function useContainer(container, effectContainer, defaultContainer) {
123
123
  const [containerEl, setContainerEl] = useDerivedState(prev => {
124
124
  if (container) {
125
125
  return typeof container === 'function' ? container() : container;
126
126
  }
127
- return prev || defaultContainer;
128
- }, [container, defaultContainer]);
127
+ return prev || null;
128
+ }, [container]);
129
129
  useEffect(() => {
130
- if (effectContainer) {
131
- const el = typeof effectContainer === 'function' ? effectContainer() : effectContainer;
130
+ const _container = effectContainer || defaultContainer || document.body;
131
+ if (_container) {
132
+ const el = typeof _container === 'function' ? _container() : _container;
132
133
  setContainerEl(el);
133
134
  }
134
- }, []);
135
+ }, [effectContainer, defaultContainer]);
135
136
  return containerEl;
136
137
  }
138
+ /**
139
+ * 使用外部类,该方法可避免`StrictMode`下,React渲染行为与外部类实例生命周期不同步的问题
140
+ */
141
+ export function useExternalClass(setup, cleanup) {
142
+ const mountTimes = useRef(0);
143
+ const prevInstance = useRef(void 0);
144
+ const [instance] = useState(() => {
145
+ if (!mountTimes.current++) {
146
+ prevInstance.current = setup();
147
+ }
148
+ return prevInstance.current;
149
+ });
150
+ useEffect(() => () => {
151
+ !--mountTimes.current && cleanup?.(instance);
152
+ }, []);
153
+ return instance;
154
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canlooks/can-ui",
3
- "version": "0.0.112",
3
+ "version": "0.0.114",
4
4
  "author": "C.CanLiang <canlooks@gmail.com>",
5
5
  "description": "My ui framework",
6
6
  "license": "MIT",
@@ -51,35 +51,35 @@
51
51
  "@dnd-kit/core": "^6.3.1",
52
52
  "@dnd-kit/sortable": "^10.0.0",
53
53
  "@emotion/react": "^11.14.0",
54
- "@fortawesome/free-brands-svg-icons": "^6.7.2",
55
- "@fortawesome/free-regular-svg-icons": "^6.7.2",
56
- "@fortawesome/free-solid-svg-icons": "^6.7.2",
57
- "@fortawesome/react-fontawesome": "^0.2.2",
58
- "color": "^5.0.0",
59
- "dayjs": "^1.11.13",
54
+ "@fortawesome/free-brands-svg-icons": "^7.1.0",
55
+ "@fortawesome/free-regular-svg-icons": "^7.1.0",
56
+ "@fortawesome/free-solid-svg-icons": "^7.1.0",
57
+ "@fortawesome/react-fontawesome": "^3.1.1",
58
+ "color": "^5.0.3",
59
+ "dayjs": "^1.11.19",
60
60
  "react-transition-group": "^4.4.5",
61
61
  "tslib": "^2.8.1"
62
62
  },
63
63
  "devDependencies": {
64
- "@ant-design/icons": "^6.0.0",
65
- "@canlooks/react-router": "^1.0.11",
66
- "@canlooks/reactive": "^4.2.5",
67
- "@emotion/styled": "^11.14.0",
64
+ "@ant-design/icons": "^6.1.0",
65
+ "@canlooks/react-router": "^1.1.0",
66
+ "@canlooks/reactive": "^4.7.10",
67
+ "@emotion/styled": "^11.14.1",
68
68
  "@mdi/js": "^7.4.47",
69
69
  "@mdi/react": "^1.6.1",
70
- "@mui/icons-material": "^7.1.2",
71
- "@types/node": "^24.0.3",
72
- "@types/react": "^19.1.8",
73
- "@types/react-dom": "^19.1.6",
70
+ "@mui/icons-material": "^7.3.6",
71
+ "@types/node": "^25.0.2",
72
+ "@types/react": "^19.2.7",
73
+ "@types/react-dom": "^19.2.3",
74
74
  "@types/react-syntax-highlighter": "^15.5.13",
75
75
  "@types/react-transition-group": "^4.4.12",
76
- "mime": "^4.0.7",
77
- "react": "^19.1.0",
78
- "react-dom": "^19.1.0",
76
+ "mime": "^4.1.0",
77
+ "react": "^19.2.3",
78
+ "react-dom": "^19.2.3",
79
79
  "react-markdown": "^10.1.0",
80
- "react-syntax-highlighter": "^15.6.1",
80
+ "react-syntax-highlighter": "^16.1.0",
81
81
  "remark-gfm": "^4.0.1",
82
- "typescript": "^5.8.3",
83
- "vite": "^6.3.5"
82
+ "typescript": "^5.9.3",
83
+ "vite": "^7.3.0"
84
84
  }
85
85
  }