@ioca/react 1.5.23 → 1.5.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/es/components/popup/popup.js +5 -1
- package/lib/es/components/tabs/async-content.js +36 -0
- package/lib/es/components/tabs/helper.js +16 -2
- package/lib/es/components/tabs/tabs.js +12 -3
- package/lib/index.js +63 -5
- package/lib/types/components/tabs/type.d.ts +5 -2
- package/package.json +1 -1
|
@@ -459,7 +459,11 @@ function Popup(props) {
|
|
|
459
459
|
if (!triggerEl || !contentEl)
|
|
460
460
|
return;
|
|
461
461
|
const tar = e.target;
|
|
462
|
-
if (
|
|
462
|
+
if (contentEl.contains(tar))
|
|
463
|
+
return;
|
|
464
|
+
if (triggerEl.contains(tar) && latestRef.current.trigger !== "contextmenu")
|
|
465
|
+
return;
|
|
466
|
+
if (triggerEl.contains(tar) && e.button !== 0)
|
|
463
467
|
return;
|
|
464
468
|
doHide();
|
|
465
469
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
const AsyncContent = (props) => {
|
|
5
|
+
const { load, loader } = props;
|
|
6
|
+
const [state, setState] = useState({ status: "loading" });
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
let cancelled = false;
|
|
9
|
+
setState({ status: "loading" });
|
|
10
|
+
load()
|
|
11
|
+
.then((module) => {
|
|
12
|
+
if (!cancelled) {
|
|
13
|
+
setState({ status: "loaded", Component: module.default });
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
.catch((error) => {
|
|
17
|
+
if (!cancelled) {
|
|
18
|
+
setState({ status: "error", error });
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
return () => {
|
|
22
|
+
cancelled = true;
|
|
23
|
+
};
|
|
24
|
+
}, [load]);
|
|
25
|
+
switch (state.status) {
|
|
26
|
+
case "loaded":
|
|
27
|
+
return jsx(state.Component, {});
|
|
28
|
+
case "error":
|
|
29
|
+
return null;
|
|
30
|
+
case "loading":
|
|
31
|
+
default:
|
|
32
|
+
return loader ?? null;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { AsyncContent as default };
|
|
@@ -21,11 +21,17 @@ const isSameTabs = (prev, next) => prev.length === next.length &&
|
|
|
21
21
|
const getParsedTabs = (items, children) => {
|
|
22
22
|
const contents = new Map();
|
|
23
23
|
if (!items) {
|
|
24
|
+
const lazyLoaders = new Map();
|
|
24
25
|
const tabs = Children.map(children, (node, i) => {
|
|
25
26
|
const { key, props: nodeProps } = node;
|
|
26
27
|
const { title, children: tabChildren, content, keepDOM, closable, } = nodeProps;
|
|
27
28
|
const tabKey = String(key ?? i);
|
|
28
|
-
|
|
29
|
+
if (typeof content === "function") {
|
|
30
|
+
lazyLoaders.set(tabKey, { load: content });
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
contents.set(tabKey, tabChildren ?? content);
|
|
34
|
+
}
|
|
29
35
|
return {
|
|
30
36
|
key: tabKey,
|
|
31
37
|
title,
|
|
@@ -36,16 +42,23 @@ const getParsedTabs = (items, children) => {
|
|
|
36
42
|
return {
|
|
37
43
|
tabs,
|
|
38
44
|
contents,
|
|
45
|
+
lazyLoaders,
|
|
39
46
|
keys: new Set(tabs.map((tab) => String(tab.key))),
|
|
40
47
|
};
|
|
41
48
|
}
|
|
49
|
+
const lazyLoaders = new Map();
|
|
42
50
|
const tabs = items.map((item, i) => {
|
|
43
51
|
if (["string", "number"].includes(typeof item)) {
|
|
44
52
|
const key = String(item);
|
|
45
53
|
return { key, title: item };
|
|
46
54
|
}
|
|
47
55
|
const key = String(item.key ?? i);
|
|
48
|
-
|
|
56
|
+
if (typeof item.content === "function") {
|
|
57
|
+
lazyLoaders.set(key, { load: item.content });
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
contents.set(key, item.content);
|
|
61
|
+
}
|
|
49
62
|
const { content, ...rest } = item;
|
|
50
63
|
return {
|
|
51
64
|
...rest,
|
|
@@ -55,6 +68,7 @@ const getParsedTabs = (items, children) => {
|
|
|
55
68
|
return {
|
|
56
69
|
tabs,
|
|
57
70
|
contents,
|
|
71
|
+
lazyLoaders,
|
|
58
72
|
keys: new Set(tabs.map((tab) => String(tab.key))),
|
|
59
73
|
};
|
|
60
74
|
};
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import { useRef, useState, useMemo, useEffect, useImperativeHandle } from 'react';
|
|
4
4
|
import { useIntersectionObserver, useSize } from '../../js/hooks.js';
|
|
5
|
+
import AsyncContent from './async-content.js';
|
|
5
6
|
import TabsContents from './contents.js';
|
|
6
7
|
import { defaultRenderMore, getParsedTabs, isSameTabs, emptyBarStyle } from './helper.js';
|
|
7
8
|
import Item from './item.js';
|
|
8
9
|
import TabsNavs from './navs.js';
|
|
9
10
|
|
|
10
11
|
const Tabs = ((props) => {
|
|
11
|
-
const { ref, active, tabs: items, type = "default", prepend, append, children, className, vertical, toggable, navsJustify = "start", navsClass, bar = true, hideMore, barClass, renderMore = defaultRenderMore, onTabChange, ...rest } = props;
|
|
12
|
+
const { ref, active, tabs: items, type = "default", prepend, append, children, className, vertical, toggable, loader, navsJustify = "start", navsClass, bar = true, hideMore, barClass, renderMore = defaultRenderMore, onTabChange, ...rest } = props;
|
|
12
13
|
const navRefs = useRef([]);
|
|
13
14
|
const navsRef = useRef(null);
|
|
14
15
|
const contentsRef = useRef(new Map());
|
|
@@ -34,6 +35,9 @@ const Tabs = ((props) => {
|
|
|
34
35
|
const nextContents = new Map(parsedTabs.contents);
|
|
35
36
|
const sourceTabs = parsedTabs.tabs;
|
|
36
37
|
const sourceKeys = parsedTabs.keys;
|
|
38
|
+
parsedTabs.lazyLoaders.forEach((lazyLoader, key) => {
|
|
39
|
+
nextContents.set(key, jsx(AsyncContent, { load: lazyLoader.load, loader: loader }));
|
|
40
|
+
});
|
|
37
41
|
hiddenSourceKeysRef.current.forEach((key) => {
|
|
38
42
|
if (!sourceKeys.has(key)) {
|
|
39
43
|
hiddenSourceKeysRef.current.delete(key);
|
|
@@ -60,7 +64,12 @@ const Tabs = ((props) => {
|
|
|
60
64
|
open(currentTabs[i].key ?? `${i}`);
|
|
61
65
|
return;
|
|
62
66
|
}
|
|
63
|
-
|
|
67
|
+
if (typeof tab.content === "function") {
|
|
68
|
+
contentsRef.current.set(tkey, jsx(AsyncContent, { load: tab.content, loader: loader }));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
contentsRef.current.set(tkey, tab.content);
|
|
72
|
+
}
|
|
64
73
|
const { content, ...rest } = tab;
|
|
65
74
|
setTabs((ts) => {
|
|
66
75
|
const nextTabs = [...ts];
|
package/lib/index.js
CHANGED
|
@@ -2305,7 +2305,11 @@ function Popup(props) {
|
|
|
2305
2305
|
if (!triggerEl || !contentEl)
|
|
2306
2306
|
return;
|
|
2307
2307
|
const tar = e.target;
|
|
2308
|
-
if (
|
|
2308
|
+
if (contentEl.contains(tar))
|
|
2309
|
+
return;
|
|
2310
|
+
if (triggerEl.contains(tar) && latestRef.current.trigger !== "contextmenu")
|
|
2311
|
+
return;
|
|
2312
|
+
if (triggerEl.contains(tar) && e.button !== 0)
|
|
2309
2313
|
return;
|
|
2310
2314
|
doHide();
|
|
2311
2315
|
};
|
|
@@ -5942,6 +5946,38 @@ const Swiper = ((props) => {
|
|
|
5942
5946
|
});
|
|
5943
5947
|
Swiper.Item = Item$1;
|
|
5944
5948
|
|
|
5949
|
+
const AsyncContent = (props) => {
|
|
5950
|
+
const { load, loader } = props;
|
|
5951
|
+
const [state, setState] = useState({ status: "loading" });
|
|
5952
|
+
useEffect(() => {
|
|
5953
|
+
let cancelled = false;
|
|
5954
|
+
setState({ status: "loading" });
|
|
5955
|
+
load()
|
|
5956
|
+
.then((module) => {
|
|
5957
|
+
if (!cancelled) {
|
|
5958
|
+
setState({ status: "loaded", Component: module.default });
|
|
5959
|
+
}
|
|
5960
|
+
})
|
|
5961
|
+
.catch((error) => {
|
|
5962
|
+
if (!cancelled) {
|
|
5963
|
+
setState({ status: "error", error });
|
|
5964
|
+
}
|
|
5965
|
+
});
|
|
5966
|
+
return () => {
|
|
5967
|
+
cancelled = true;
|
|
5968
|
+
};
|
|
5969
|
+
}, [load]);
|
|
5970
|
+
switch (state.status) {
|
|
5971
|
+
case "loaded":
|
|
5972
|
+
return jsx(state.Component, {});
|
|
5973
|
+
case "error":
|
|
5974
|
+
return null;
|
|
5975
|
+
case "loading":
|
|
5976
|
+
default:
|
|
5977
|
+
return loader ?? null;
|
|
5978
|
+
}
|
|
5979
|
+
};
|
|
5980
|
+
|
|
5945
5981
|
const TabsContents = (props) => {
|
|
5946
5982
|
const { tabs, activeKey, cachedTabKeySet, getContent } = props;
|
|
5947
5983
|
return (jsx("div", { className: "i-tab-contents", children: tabs.map((tab, i) => {
|
|
@@ -5973,11 +6009,17 @@ const isSameTabs = (prev, next) => prev.length === next.length &&
|
|
|
5973
6009
|
const getParsedTabs = (items, children) => {
|
|
5974
6010
|
const contents = new Map();
|
|
5975
6011
|
if (!items) {
|
|
6012
|
+
const lazyLoaders = new Map();
|
|
5976
6013
|
const tabs = Children.map(children, (node, i) => {
|
|
5977
6014
|
const { key, props: nodeProps } = node;
|
|
5978
6015
|
const { title, children: tabChildren, content, keepDOM, closable, } = nodeProps;
|
|
5979
6016
|
const tabKey = String(key ?? i);
|
|
5980
|
-
|
|
6017
|
+
if (typeof content === "function") {
|
|
6018
|
+
lazyLoaders.set(tabKey, { load: content });
|
|
6019
|
+
}
|
|
6020
|
+
else {
|
|
6021
|
+
contents.set(tabKey, tabChildren ?? content);
|
|
6022
|
+
}
|
|
5981
6023
|
return {
|
|
5982
6024
|
key: tabKey,
|
|
5983
6025
|
title,
|
|
@@ -5988,16 +6030,23 @@ const getParsedTabs = (items, children) => {
|
|
|
5988
6030
|
return {
|
|
5989
6031
|
tabs,
|
|
5990
6032
|
contents,
|
|
6033
|
+
lazyLoaders,
|
|
5991
6034
|
keys: new Set(tabs.map((tab) => String(tab.key))),
|
|
5992
6035
|
};
|
|
5993
6036
|
}
|
|
6037
|
+
const lazyLoaders = new Map();
|
|
5994
6038
|
const tabs = items.map((item, i) => {
|
|
5995
6039
|
if (["string", "number"].includes(typeof item)) {
|
|
5996
6040
|
const key = String(item);
|
|
5997
6041
|
return { key, title: item };
|
|
5998
6042
|
}
|
|
5999
6043
|
const key = String(item.key ?? i);
|
|
6000
|
-
|
|
6044
|
+
if (typeof item.content === "function") {
|
|
6045
|
+
lazyLoaders.set(key, { load: item.content });
|
|
6046
|
+
}
|
|
6047
|
+
else {
|
|
6048
|
+
contents.set(key, item.content);
|
|
6049
|
+
}
|
|
6001
6050
|
const { content, ...rest } = item;
|
|
6002
6051
|
return {
|
|
6003
6052
|
...rest,
|
|
@@ -6007,6 +6056,7 @@ const getParsedTabs = (items, children) => {
|
|
|
6007
6056
|
return {
|
|
6008
6057
|
tabs,
|
|
6009
6058
|
contents,
|
|
6059
|
+
lazyLoaders,
|
|
6010
6060
|
keys: new Set(tabs.map((tab) => String(tab.key))),
|
|
6011
6061
|
};
|
|
6012
6062
|
};
|
|
@@ -6038,7 +6088,7 @@ const TabsNavs = (props) => {
|
|
|
6038
6088
|
var TabsNavs$1 = memo(TabsNavs);
|
|
6039
6089
|
|
|
6040
6090
|
const Tabs = ((props) => {
|
|
6041
|
-
const { ref, active, tabs: items, type = "default", prepend, append, children, className, vertical, toggable, navsJustify = "start", navsClass, bar = true, hideMore, barClass, renderMore = defaultRenderMore, onTabChange, ...rest } = props;
|
|
6091
|
+
const { ref, active, tabs: items, type = "default", prepend, append, children, className, vertical, toggable, loader, navsJustify = "start", navsClass, bar = true, hideMore, barClass, renderMore = defaultRenderMore, onTabChange, ...rest } = props;
|
|
6042
6092
|
const navRefs = useRef([]);
|
|
6043
6093
|
const navsRef = useRef(null);
|
|
6044
6094
|
const contentsRef = useRef(new Map());
|
|
@@ -6064,6 +6114,9 @@ const Tabs = ((props) => {
|
|
|
6064
6114
|
const nextContents = new Map(parsedTabs.contents);
|
|
6065
6115
|
const sourceTabs = parsedTabs.tabs;
|
|
6066
6116
|
const sourceKeys = parsedTabs.keys;
|
|
6117
|
+
parsedTabs.lazyLoaders.forEach((lazyLoader, key) => {
|
|
6118
|
+
nextContents.set(key, jsx(AsyncContent, { load: lazyLoader.load, loader: loader }));
|
|
6119
|
+
});
|
|
6067
6120
|
hiddenSourceKeysRef.current.forEach((key) => {
|
|
6068
6121
|
if (!sourceKeys.has(key)) {
|
|
6069
6122
|
hiddenSourceKeysRef.current.delete(key);
|
|
@@ -6090,7 +6143,12 @@ const Tabs = ((props) => {
|
|
|
6090
6143
|
open(currentTabs[i].key ?? `${i}`);
|
|
6091
6144
|
return;
|
|
6092
6145
|
}
|
|
6093
|
-
|
|
6146
|
+
if (typeof tab.content === "function") {
|
|
6147
|
+
contentsRef.current.set(tkey, jsx(AsyncContent, { load: tab.content, loader: loader }));
|
|
6148
|
+
}
|
|
6149
|
+
else {
|
|
6150
|
+
contentsRef.current.set(tkey, tab.content);
|
|
6151
|
+
}
|
|
6094
6152
|
const { content, ...rest } = tab;
|
|
6095
6153
|
setTabs((ts) => {
|
|
6096
6154
|
const nextTabs = [...ts];
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { ForwardRefExoticComponent, Ref, ReactNode, RefObject, CSSProperties } from 'react';
|
|
1
|
+
import { ForwardRefExoticComponent, Ref, ReactNode, ComponentType, RefObject, CSSProperties } from 'react';
|
|
2
2
|
import Item from './item.js';
|
|
3
3
|
|
|
4
4
|
interface ITabItem {
|
|
5
5
|
key?: string;
|
|
6
6
|
title?: ReactNode;
|
|
7
|
-
content?: ReactNode
|
|
7
|
+
content?: ReactNode | (() => Promise<{
|
|
8
|
+
default: ComponentType<any>;
|
|
9
|
+
}>);
|
|
8
10
|
closable?: boolean;
|
|
9
11
|
keepDOM?: boolean;
|
|
10
12
|
intersecting?: boolean;
|
|
@@ -28,6 +30,7 @@ interface ITabs {
|
|
|
28
30
|
children?: ReactNode;
|
|
29
31
|
style?: CSSProperties;
|
|
30
32
|
renderMore?: (moreTabs: ITabItem[]) => ReactNode;
|
|
33
|
+
loader?: ReactNode;
|
|
31
34
|
onTabChange?: (to?: string, from?: string) => void;
|
|
32
35
|
}
|
|
33
36
|
interface RefTabs {
|