@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.
@@ -459,7 +459,11 @@ function Popup(props) {
459
459
  if (!triggerEl || !contentEl)
460
460
  return;
461
461
  const tar = e.target;
462
- if (triggerEl.contains(tar) || contentEl.contains(tar))
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
- contents.set(tabKey, tabChildren ?? content);
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
- contents.set(key, item.content);
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 { jsxs, jsx } from 'react/jsx-runtime';
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
- contentsRef.current.set(tkey, tab.content);
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 (triggerEl.contains(tar) || contentEl.contains(tar))
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
- contents.set(tabKey, tabChildren ?? content);
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
- contents.set(key, item.content);
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
- contentsRef.current.set(tkey, tab.content);
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 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ioca/react",
3
- "version": "1.5.23",
3
+ "version": "1.5.25",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite",