deepsea-components 3.1.1 → 3.2.0-beta.20240606182955

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.
@@ -68,8 +68,10 @@ export interface FlowProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, "chil
68
68
  transitionDuration?: number;
69
69
  /** 变化的回调函数 */
70
70
  onSizeChange?: (sizeData: FlowSizeData) => void;
71
+ /** 宽度 */
72
+ width?: number;
71
73
  }
72
74
  export declare function getGapRange(gap?: undefined | number | "auto" | (number | "auto")[]): [number, number | "auto"];
73
75
  export declare function getGapCountAndSize(width: number, itemWidth: number, minGap: number, maxGap: number | "auto"): [number, number];
74
76
  /** 自适应浮动组件 */
75
- export declare function Flow<T>(props: FlowProps<T>): import("react/jsx-runtime").JSX.Element;
77
+ export declare function Flow<T>(props: FlowProps<T>): import("react/jsx-runtime").JSX.Element | null;
@@ -47,15 +47,13 @@ function getGapCountAndSize(width, itemWidth, minGap, maxGap) {
47
47
  return [count, maxGap];
48
48
  return [count, averageGap];
49
49
  }
50
- function Flow(props) {
51
- let { itemWidth, itemHeight, columnGap, rowGap, maxRows, data, render, keyExactor, className, style, wrapperClassName, wrapperStyle, throttle, transitionDuration, onSizeChange, containerClassName, containerStyle, gap = 0, ...rest } = props;
50
+ function RealFlow(props) {
51
+ let { itemWidth, itemHeight, columnGap, rowGap, maxRows, data, render, keyExactor, className, style, wrapperClassName, wrapperStyle, throttle, transitionDuration, onSizeChange, containerClassName, containerStyle, gap = 0, width, ...rest } = props;
52
52
  rowGap ??= gap;
53
53
  columnGap ??= gap;
54
54
  const [minColumnGap, maxColumnGap] = getGapRange(columnGap);
55
- const [width, setWidth] = (0, import_react.useState)(0);
56
55
  const [columnCount, setColumnCount] = (0, import_react.useState)(1);
57
56
  const [columnGapSize, setColumnGapSize] = (0, import_react.useState)(minColumnGap);
58
- const [showItems, setShowItems] = (0, import_react.useState)(false);
59
57
  const ele = (0, import_react.useRef)(null);
60
58
  const contentRows = Math.ceil(data.length / columnCount);
61
59
  const contentShownRows = typeof maxRows === "number" ? Math.min(contentRows, maxRows) : contentRows;
@@ -73,29 +71,20 @@ function Flow(props) {
73
71
  return false;
74
72
  return index >= maxRows * columnCount;
75
73
  }
74
+ function task() {
75
+ const [newColumnCount, newColumnGapSize] = getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap);
76
+ setColumnCount(newColumnCount);
77
+ setColumnGapSize(newColumnGapSize);
78
+ }
76
79
  (0, import_react.useEffect)(() => {
77
- let timeout;
78
- const observer = new ResizeObserver((entries) => {
79
- clearTimeout(timeout);
80
- function task() {
81
- const { width: width2 } = entries[0].contentRect;
82
- const [newColumnCount, newColumnGapSize] = getGapCountAndSize(width2, itemWidth, minColumnGap, maxColumnGap);
83
- setShowItems(true);
84
- setWidth(width2);
85
- setColumnCount(newColumnCount);
86
- setColumnGapSize(newColumnGapSize);
87
- }
88
- if (throttle === 0) {
89
- task();
90
- } else {
91
- timeout = window.setTimeout(task, throttle || 200);
92
- }
93
- });
94
- observer.observe(ele.current);
95
- return () => {
96
- observer.disconnect();
97
- };
98
- }, [itemWidth, throttle, columnGap]);
80
+ task();
81
+ }, []);
82
+ (0, import_react.useEffect)(() => {
83
+ if (throttle === 0)
84
+ return task();
85
+ const timeout = setTimeout(task, throttle || 200);
86
+ return () => clearTimeout(timeout);
87
+ }, [width, itemWidth, throttle, columnGap]);
99
88
  (0, import_react.useEffect)(() => {
100
89
  onSizeChange?.({ width, height, itemWidth, itemHeight, columnGap: columnGapSize, columnCount, rowGap, rowCount: contentShownRows, overflow: data.length > contentShownRows * columnCount, itemCount: data.length, maxRows: maxRows ?? null });
101
90
  }, [width, height, columnGapSize, columnCount, rowGap, contentShownRows, data.length, itemWidth, itemHeight, maxRows]);
@@ -114,20 +103,20 @@ function Flow(props) {
114
103
  style: (0, import_utils.transformCSSVariable)({ height: (0, import_utils.px)(height) }, style),
115
104
  ...rest
116
105
  },
117
- showItems && data.map((item, index, arr) => /* @__PURE__ */ React.createElement(
106
+ data.map((item, index, arr) => /* @__PURE__ */ React.createElement(
118
107
  "div",
119
108
  {
120
109
  key: keyExactor ? keyExactor(item, index, arr) : index,
121
110
  className: (0, import_deepsea_tools.clsx)(
122
111
  import_css.css`
123
- position: absolute;
124
- width: var(--width);
125
- height: var(--height);
126
- transition: var(--transition);
127
- left: 0;
128
- top: 0;
129
- transform: translate(var(--left), var(--top));
130
- `,
112
+ position: absolute;
113
+ width: var(--width);
114
+ height: var(--height);
115
+ transition: var(--transition);
116
+ left: 0;
117
+ top: 0;
118
+ transform: translate(var(--left), var(--top));
119
+ `,
131
120
  wrapperClassName
132
121
  ),
133
122
  style: (0, import_utils.transformCSSVariable)(
@@ -146,10 +135,10 @@ function Flow(props) {
146
135
  {
147
136
  className: (0, import_deepsea_tools.clsx)(
148
137
  import_css.css`
149
- width: 100%;
150
- height: 100%;
151
- display: var(--display);
152
- `,
138
+ width: 100%;
139
+ height: 100%;
140
+ display: var(--display);
141
+ `,
153
142
  containerClassName
154
143
  ),
155
144
  style: (0, import_utils.transformCSSVariable)({ display: getHidden(index) ? "none" : "block" }, containerStyle)
@@ -159,6 +148,12 @@ function Flow(props) {
159
148
  ))
160
149
  );
161
150
  }
151
+ function Flow(props) {
152
+ const { width, data } = props;
153
+ if (!width || data.length === 0)
154
+ return null;
155
+ return /* @__PURE__ */ React.createElement(RealFlow, { ...props, width });
156
+ }
162
157
  // Annotate the CommonJS export names for ESM import in node:
163
158
  0 && (module.exports = {
164
159
  Flow,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/Flow.tsx"],
4
- "sourcesContent": ["\"use client\"\r\n\r\nimport { css } from \"@emotion/css\"\r\nimport { clsx } from \"deepsea-tools\"\r\nimport { CSSProperties, HTMLAttributes, Key, ReactNode, useEffect, useRef, useState } from \"react\"\r\nimport { px, transformCSSVariable } from \"../utils\"\r\n\r\nexport interface FlowSizeData {\r\n /** 容器宽度 */\r\n width: number\r\n /** 容器高度 */\r\n height: number\r\n /** 元素宽度 */\r\n itemWidth: number\r\n /** 元素高度 */\r\n itemHeight: number\r\n /** 列间距 */\r\n columnGap: number\r\n /** 列数 */\r\n columnCount: number\r\n /** 行间距 */\r\n rowGap: number\r\n /** 行数 */\r\n rowCount: number\r\n /** 元素格数 */\r\n itemCount: number\r\n /** 最大行数 */\r\n maxRows: number | null\r\n /** 是否有元素被隐藏 */\r\n overflow: boolean\r\n}\r\n\r\nexport interface FlowProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\r\n /** 元素宽度 */\r\n itemWidth: number\r\n /** 元素高度 */\r\n itemHeight: number\r\n /**\r\n * 列间距\r\n * 1. 如果是数字,表示列间距是固定的\r\n * 2. 如果是 auto,表示会在尽可能放进更多列的情况下,列间距是平均的\r\n * 2. 如果是数组,表示列间距是区间的,第一个元素是最小值,第二个元素是最大值\r\n */\r\n columnGap?: number | \"auto\" | [number | \"auto\", number | \"auto\"]\r\n /** 行间距 */\r\n rowGap?: number\r\n gap?: number\r\n /** 最大行数 */\r\n maxRows?: number | null\r\n /** 源数据 */\r\n data: T[]\r\n /** 渲染 */\r\n render: (item: T, index: number, arr: T[]) => ReactNode\r\n /** key释放器,默认为 index */\r\n keyExactor?: (item: T, index: number, arr: T[]) => Key\r\n /**\r\n * 渲染的元素由两层容器包裹,外层容器类名\r\n */\r\n wrapperClassName?: string\r\n /**\r\n * 渲染的元素由两层容器包裹,外层容器样式\r\n */\r\n wrapperStyle?: CSSProperties\r\n /** \r\n * 渲染的元素由两层容器包裹,内层容器类名\r\n */\r\n containerClassName?: string\r\n /**\r\n * 渲染的元素由两层容器包裹,内层容器样式\r\n */\r\n containerStyle?: CSSProperties\r\n /** 节流时间,单位毫秒,默认200ms,传入 0 不节流 */\r\n throttle?: number\r\n /** 动画时间,单位毫秒,默认400ms,传入 0 不展示动画 */\r\n transitionDuration?: number\r\n /** 变化的回调函数 */\r\n onSizeChange?: (sizeData: FlowSizeData) => void\r\n}\r\n\r\nexport function getGapRange(gap?: undefined | number | \"auto\" | (number | \"auto\")[]): [number, number | \"auto\"] {\r\n if (typeof gap === \"number\") return [gap, gap]\r\n if (Array.isArray(gap)) return [typeof gap[0] === \"number\" ? gap[0] : 0, gap[1]]\r\n return [0, \"auto\"]\r\n}\r\n\r\nexport function getGapCountAndSize(width: number, itemWidth: number, minGap: number, maxGap: number | \"auto\"): [number, number] {\r\n const count = Math.floor((width + minGap) / (itemWidth + minGap)) || 1\r\n if (count === 1) return [count, 0]\r\n const averageGap = (width - itemWidth * count) / (count - 1)\r\n if (averageGap < minGap) return [count, minGap]\r\n if (maxGap !== \"auto\" && averageGap > maxGap) return [count, maxGap]\r\n return [count, averageGap]\r\n}\r\n\r\ninterface Position {\r\n left: number\r\n top: number\r\n}\r\n\r\n/** 自适应浮动组件 */\r\nexport function Flow<T>(props: FlowProps<T>) {\r\n let { itemWidth, itemHeight, columnGap, rowGap, maxRows, data, render, keyExactor, className, style, wrapperClassName, wrapperStyle, throttle, transitionDuration, onSizeChange, containerClassName, containerStyle, gap = 0, ...rest } = props\r\n rowGap ??= gap\r\n columnGap ??= gap\r\n const [minColumnGap, maxColumnGap] = getGapRange(columnGap)\r\n const [width, setWidth] = useState(0)\r\n const [columnCount, setColumnCount] = useState(1)\r\n const [columnGapSize, setColumnGapSize] = useState(minColumnGap)\r\n const [showItems, setShowItems] = useState(false)\r\n const ele = useRef<HTMLDivElement>(null)\r\n const contentRows = Math.ceil(data.length / columnCount)\r\n const contentShownRows = typeof maxRows === \"number\" ? Math.min(contentRows, maxRows) : contentRows\r\n const height = contentShownRows > 0 ? contentShownRows * (itemHeight + rowGap) - rowGap : 0\r\n\r\n function getPosition(index: number): Position {\r\n const y = Math.floor(index / columnCount)\r\n const x = index - y * columnCount\r\n return {\r\n left: x * (itemWidth + columnGapSize),\r\n top: y * (itemHeight + rowGap!)\r\n }\r\n }\r\n\r\n function getHidden(index: number) {\r\n if (typeof maxRows !== \"number\") return false\r\n return index >= maxRows * columnCount\r\n }\r\n\r\n useEffect(() => {\r\n let timeout: number\r\n const observer = new ResizeObserver(entries => {\r\n clearTimeout(timeout)\r\n function task() {\r\n const { width } = entries[0].contentRect\r\n const [newColumnCount, newColumnGapSize] = getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap)\r\n setShowItems(true)\r\n setWidth(width)\r\n setColumnCount(newColumnCount)\r\n setColumnGapSize(newColumnGapSize)\r\n }\r\n if (throttle === 0) {\r\n task()\r\n } else {\r\n timeout = window.setTimeout(task, throttle || 200)\r\n }\r\n })\r\n observer.observe(ele.current!)\r\n\r\n return () => {\r\n observer.disconnect()\r\n }\r\n }, [itemWidth, throttle, columnGap])\r\n\r\n useEffect(() => {\r\n onSizeChange?.({ width, height, itemWidth, itemHeight, columnGap: columnGapSize, columnCount, rowGap: rowGap!, rowCount: contentShownRows, overflow: data.length > contentShownRows * columnCount, itemCount: data.length, maxRows: maxRows ?? null })\r\n }, [width, height, columnGapSize, columnCount, rowGap, contentShownRows, data.length, itemWidth, itemHeight, maxRows])\r\n\r\n return (\r\n <div\r\n ref={ele}\r\n className={clsx(\r\n css`\r\n position: relative;\r\n height: var(--height);\r\n overflow: hidden;\r\n `,\r\n className\r\n )}\r\n style={transformCSSVariable({ height: px(height) }, style)}\r\n {...rest}>\r\n {showItems &&\r\n data.map((item, index, arr) => (\r\n <div\r\n key={keyExactor ? keyExactor(item, index, arr) : index}\r\n className={clsx(\r\n css`\r\n position: absolute;\r\n width: var(--width);\r\n height: var(--height);\r\n transition: var(--transition);\r\n left: 0;\r\n top: 0;\r\n transform: translate(var(--left), var(--top));\r\n `,\r\n wrapperClassName\r\n )}\r\n style={transformCSSVariable(\r\n {\r\n width: px(itemWidth),\r\n height: px(itemHeight),\r\n transition: transitionDuration === 0 ? \"none\" : `all ${transitionDuration || 400}ms`,\r\n left: px(getPosition(index).left),\r\n top: px(getPosition(index).top)\r\n },\r\n wrapperStyle\r\n )}>\r\n <div\r\n className={clsx(\r\n css`\r\n width: 100%;\r\n height: 100%;\r\n display: var(--display);\r\n `,\r\n containerClassName\r\n )}\r\n style={transformCSSVariable({ display: getHidden(index) ? \"none\" : \"block\" }, containerStyle)}>\r\n {render(item, index, arr)}\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n )\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": ["width"]
4
+ "sourcesContent": ["\"use client\"\r\n\r\nimport { css } from \"@emotion/css\"\r\nimport { clsx } from \"deepsea-tools\"\r\nimport { CSSProperties, HTMLAttributes, Key, ReactNode, useEffect, useRef, useState } from \"react\"\r\nimport { px, transformCSSVariable } from \"../utils\"\r\n\r\nexport interface FlowSizeData {\r\n /** 容器宽度 */\r\n width: number\r\n /** 容器高度 */\r\n height: number\r\n /** 元素宽度 */\r\n itemWidth: number\r\n /** 元素高度 */\r\n itemHeight: number\r\n /** 列间距 */\r\n columnGap: number\r\n /** 列数 */\r\n columnCount: number\r\n /** 行间距 */\r\n rowGap: number\r\n /** 行数 */\r\n rowCount: number\r\n /** 元素格数 */\r\n itemCount: number\r\n /** 最大行数 */\r\n maxRows: number | null\r\n /** 是否有元素被隐藏 */\r\n overflow: boolean\r\n}\r\n\r\nexport interface FlowProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\r\n /** 元素宽度 */\r\n itemWidth: number\r\n /** 元素高度 */\r\n itemHeight: number\r\n /**\r\n * 列间距\r\n * 1. 如果是数字,表示列间距是固定的\r\n * 2. 如果是 auto,表示会在尽可能放进更多列的情况下,列间距是平均的\r\n * 2. 如果是数组,表示列间距是区间的,第一个元素是最小值,第二个元素是最大值\r\n */\r\n columnGap?: number | \"auto\" | [number | \"auto\", number | \"auto\"]\r\n /** 行间距 */\r\n rowGap?: number\r\n gap?: number\r\n /** 最大行数 */\r\n maxRows?: number | null\r\n /** 源数据 */\r\n data: T[]\r\n /** 渲染 */\r\n render: (item: T, index: number, arr: T[]) => ReactNode\r\n /** key释放器,默认为 index */\r\n keyExactor?: (item: T, index: number, arr: T[]) => Key\r\n /**\r\n * 渲染的元素由两层容器包裹,外层容器类名\r\n */\r\n wrapperClassName?: string\r\n /**\r\n * 渲染的元素由两层容器包裹,外层容器样式\r\n */\r\n wrapperStyle?: CSSProperties\r\n /**\r\n * 渲染的元素由两层容器包裹,内层容器类名\r\n */\r\n containerClassName?: string\r\n /**\r\n * 渲染的元素由两层容器包裹,内层容器样式\r\n */\r\n containerStyle?: CSSProperties\r\n /** 节流时间,单位毫秒,默认200ms,传入 0 不节流 */\r\n throttle?: number\r\n /** 动画时间,单位毫秒,默认400ms,传入 0 不展示动画 */\r\n transitionDuration?: number\r\n /** 变化的回调函数 */\r\n onSizeChange?: (sizeData: FlowSizeData) => void\r\n /** 宽度 */\r\n width?: number\r\n}\r\n\r\nexport function getGapRange(gap?: undefined | number | \"auto\" | (number | \"auto\")[]): [number, number | \"auto\"] {\r\n if (typeof gap === \"number\") return [gap, gap]\r\n if (Array.isArray(gap)) return [typeof gap[0] === \"number\" ? gap[0] : 0, gap[1]]\r\n return [0, \"auto\"]\r\n}\r\n\r\nexport function getGapCountAndSize(width: number, itemWidth: number, minGap: number, maxGap: number | \"auto\"): [number, number] {\r\n const count = Math.floor((width + minGap) / (itemWidth + minGap)) || 1\r\n if (count === 1) return [count, 0]\r\n const averageGap = (width - itemWidth * count) / (count - 1)\r\n if (averageGap < minGap) return [count, minGap]\r\n if (maxGap !== \"auto\" && averageGap > maxGap) return [count, maxGap]\r\n return [count, averageGap]\r\n}\r\n\r\ninterface Position {\r\n left: number\r\n top: number\r\n}\r\n\r\nfunction RealFlow<T>(props: FlowProps<T> & { width: number }) {\r\n let { itemWidth, itemHeight, columnGap, rowGap, maxRows, data, render, keyExactor, className, style, wrapperClassName, wrapperStyle, throttle, transitionDuration, onSizeChange, containerClassName, containerStyle, gap = 0, width, ...rest } = props\r\n rowGap ??= gap\r\n columnGap ??= gap\r\n const [minColumnGap, maxColumnGap] = getGapRange(columnGap)\r\n const [columnCount, setColumnCount] = useState(1)\r\n const [columnGapSize, setColumnGapSize] = useState(minColumnGap)\r\n\r\n const ele = useRef<HTMLDivElement>(null)\r\n const contentRows = Math.ceil(data.length / columnCount)\r\n const contentShownRows = typeof maxRows === \"number\" ? Math.min(contentRows, maxRows) : contentRows\r\n const height = contentShownRows > 0 ? contentShownRows * (itemHeight + rowGap) - rowGap : 0\r\n\r\n function getPosition(index: number): Position {\r\n const y = Math.floor(index / columnCount)\r\n const x = index - y * columnCount\r\n return {\r\n left: x * (itemWidth + columnGapSize),\r\n top: y * (itemHeight + rowGap!)\r\n }\r\n }\r\n\r\n function getHidden(index: number) {\r\n if (typeof maxRows !== \"number\") return false\r\n return index >= maxRows * columnCount\r\n }\r\n\r\n function task() {\r\n const [newColumnCount, newColumnGapSize] = getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap)\r\n setColumnCount(newColumnCount)\r\n setColumnGapSize(newColumnGapSize)\r\n }\r\n\r\n useEffect(() => {\r\n task()\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (throttle === 0) return task()\r\n const timeout = setTimeout(task, throttle || 200)\r\n return () => clearTimeout(timeout)\r\n }, [width, itemWidth, throttle, columnGap])\r\n\r\n useEffect(() => {\r\n onSizeChange?.({ width, height, itemWidth, itemHeight, columnGap: columnGapSize, columnCount, rowGap: rowGap!, rowCount: contentShownRows, overflow: data.length > contentShownRows * columnCount, itemCount: data.length, maxRows: maxRows ?? null })\r\n }, [width, height, columnGapSize, columnCount, rowGap, contentShownRows, data.length, itemWidth, itemHeight, maxRows])\r\n\r\n return (\r\n <div\r\n ref={ele}\r\n className={clsx(\r\n css`\r\n position: relative;\r\n height: var(--height);\r\n overflow: hidden;\r\n `,\r\n className\r\n )}\r\n style={transformCSSVariable({ height: px(height) }, style)}\r\n {...rest}>\r\n {data.map((item, index, arr) => (\r\n <div\r\n key={keyExactor ? keyExactor(item, index, arr) : index}\r\n className={clsx(\r\n css`\r\n position: absolute;\r\n width: var(--width);\r\n height: var(--height);\r\n transition: var(--transition);\r\n left: 0;\r\n top: 0;\r\n transform: translate(var(--left), var(--top));\r\n `,\r\n wrapperClassName\r\n )}\r\n style={transformCSSVariable(\r\n {\r\n width: px(itemWidth),\r\n height: px(itemHeight),\r\n transition: transitionDuration === 0 ? \"none\" : `all ${transitionDuration || 400}ms`,\r\n left: px(getPosition(index).left),\r\n top: px(getPosition(index).top)\r\n },\r\n wrapperStyle\r\n )}>\r\n <div\r\n className={clsx(\r\n css`\r\n width: 100%;\r\n height: 100%;\r\n display: var(--display);\r\n `,\r\n containerClassName\r\n )}\r\n style={transformCSSVariable({ display: getHidden(index) ? \"none\" : \"block\" }, containerStyle)}>\r\n {render(item, index, arr)}\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n )\r\n}\r\n\r\n/** 自适应浮动组件 */\r\nexport function Flow<T>(props: FlowProps<T>) {\r\n const { width, data } = props\r\n if (!width || data.length === 0) return null\r\n return <RealFlow {...props} width={width} />\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": []
7
7
  }
@@ -68,8 +68,10 @@ export interface FlowProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, "chil
68
68
  transitionDuration?: number;
69
69
  /** 变化的回调函数 */
70
70
  onSizeChange?: (sizeData: FlowSizeData) => void;
71
+ /** 宽度 */
72
+ width?: number;
71
73
  }
72
74
  export declare function getGapRange(gap?: undefined | number | "auto" | (number | "auto")[]): [number, number | "auto"];
73
75
  export declare function getGapCountAndSize(width: number, itemWidth: number, minGap: number, maxGap: number | "auto"): [number, number];
74
76
  /** 自适应浮动组件 */
75
- export declare function Flow<T>(props: FlowProps<T>): import("react/jsx-runtime").JSX.Element;
77
+ export declare function Flow<T>(props: FlowProps<T>): import("react/jsx-runtime").JSX.Element | null;
@@ -18,8 +18,7 @@ export function getGapCountAndSize(width, itemWidth, minGap, maxGap) {
18
18
  if (maxGap !== "auto" && averageGap > maxGap) return [count, maxGap];
19
19
  return [count, averageGap];
20
20
  }
21
- /** 自适应浮动组件 */
22
- export function Flow(props) {
21
+ function RealFlow(props) {
23
22
  let {
24
23
  itemWidth,
25
24
  itemHeight,
@@ -39,15 +38,14 @@ export function Flow(props) {
39
38
  containerClassName,
40
39
  containerStyle,
41
40
  gap = 0,
41
+ width,
42
42
  ...rest
43
43
  } = props;
44
44
  rowGap ??= gap;
45
45
  columnGap ??= gap;
46
46
  const [minColumnGap, maxColumnGap] = getGapRange(columnGap);
47
- const [width, setWidth] = useState(0);
48
47
  const [columnCount, setColumnCount] = useState(1);
49
48
  const [columnGapSize, setColumnGapSize] = useState(minColumnGap);
50
- const [showItems, setShowItems] = useState(false);
51
49
  const ele = useRef(null);
52
50
  const contentRows = Math.ceil(data.length / columnCount);
53
51
  const contentShownRows = typeof maxRows === "number" ? Math.min(contentRows, maxRows) : contentRows;
@@ -64,31 +62,19 @@ export function Flow(props) {
64
62
  if (typeof maxRows !== "number") return false;
65
63
  return index >= maxRows * columnCount;
66
64
  }
65
+ function task() {
66
+ const [newColumnCount, newColumnGapSize] = getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap);
67
+ setColumnCount(newColumnCount);
68
+ setColumnGapSize(newColumnGapSize);
69
+ }
67
70
  useEffect(() => {
68
- let timeout;
69
- const observer = new ResizeObserver(entries => {
70
- clearTimeout(timeout);
71
- function task() {
72
- const {
73
- width
74
- } = entries[0].contentRect;
75
- const [newColumnCount, newColumnGapSize] = getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap);
76
- setShowItems(true);
77
- setWidth(width);
78
- setColumnCount(newColumnCount);
79
- setColumnGapSize(newColumnGapSize);
80
- }
81
- if (throttle === 0) {
82
- task();
83
- } else {
84
- timeout = window.setTimeout(task, throttle || 200);
85
- }
86
- });
87
- observer.observe(ele.current);
88
- return () => {
89
- observer.disconnect();
90
- };
91
- }, [itemWidth, throttle, columnGap]);
71
+ task();
72
+ }, []);
73
+ useEffect(() => {
74
+ if (throttle === 0) return task();
75
+ const timeout = setTimeout(task, throttle || 200);
76
+ return () => clearTimeout(timeout);
77
+ }, [width, itemWidth, throttle, columnGap]);
92
78
  useEffect(() => {
93
79
  onSizeChange?.({
94
80
  width,
@@ -115,16 +101,16 @@ export function Flow(props) {
115
101
  height: px(height)
116
102
  }, style),
117
103
  ...rest,
118
- children: showItems && data.map((item, index, arr) => /*#__PURE__*/_jsx("div", {
104
+ children: data.map((item, index, arr) => /*#__PURE__*/_jsx("div", {
119
105
  className: clsx(css`
120
- position: absolute;
121
- width: var(--width);
122
- height: var(--height);
123
- transition: var(--transition);
124
- left: 0;
125
- top: 0;
126
- transform: translate(var(--left), var(--top));
127
- `, wrapperClassName),
106
+ position: absolute;
107
+ width: var(--width);
108
+ height: var(--height);
109
+ transition: var(--transition);
110
+ left: 0;
111
+ top: 0;
112
+ transform: translate(var(--left), var(--top));
113
+ `, wrapperClassName),
128
114
  style: transformCSSVariable({
129
115
  width: px(itemWidth),
130
116
  height: px(itemHeight),
@@ -134,10 +120,10 @@ export function Flow(props) {
134
120
  }, wrapperStyle),
135
121
  children: /*#__PURE__*/_jsx("div", {
136
122
  className: clsx(css`
137
- width: 100%;
138
- height: 100%;
139
- display: var(--display);
140
- `, containerClassName),
123
+ width: 100%;
124
+ height: 100%;
125
+ display: var(--display);
126
+ `, containerClassName),
141
127
  style: transformCSSVariable({
142
128
  display: getHidden(index) ? "none" : "block"
143
129
  }, containerStyle),
@@ -146,4 +132,17 @@ export function Flow(props) {
146
132
  }, keyExactor ? keyExactor(item, index, arr) : index))
147
133
  });
148
134
  }
135
+
136
+ /** 自适应浮动组件 */
137
+ export function Flow(props) {
138
+ const {
139
+ width,
140
+ data
141
+ } = props;
142
+ if (!width || data.length === 0) return null;
143
+ return /*#__PURE__*/_jsx(RealFlow, {
144
+ ...props,
145
+ width: width
146
+ });
147
+ }
149
148
  //# sourceMappingURL=Flow.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["css","clsx","useEffect","useRef","useState","px","transformCSSVariable","jsx","_jsx","getGapRange","gap","Array","isArray","getGapCountAndSize","width","itemWidth","minGap","maxGap","count","Math","floor","averageGap","Flow","props","itemHeight","columnGap","rowGap","maxRows","data","render","keyExactor","className","style","wrapperClassName","wrapperStyle","throttle","transitionDuration","onSizeChange","containerClassName","containerStyle","rest","minColumnGap","maxColumnGap","setWidth","columnCount","setColumnCount","columnGapSize","setColumnGapSize","showItems","setShowItems","ele","contentRows","ceil","length","contentShownRows","min","height","getPosition","index","y","x","left","top","getHidden","timeout","observer","ResizeObserver","entries","clearTimeout","task","contentRect","newColumnCount","newColumnGapSize","window","setTimeout","observe","current","disconnect","rowCount","overflow","itemCount","ref","children","map","item","arr","transition","display"],"sources":["../../../src/components/Flow.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { css } from \"@emotion/css\"\r\nimport { clsx } from \"deepsea-tools\"\r\nimport { CSSProperties, HTMLAttributes, Key, ReactNode, useEffect, useRef, useState } from \"react\"\r\nimport { px, transformCSSVariable } from \"../utils\"\r\n\r\nexport interface FlowSizeData {\r\n /** 容器宽度 */\r\n width: number\r\n /** 容器高度 */\r\n height: number\r\n /** 元素宽度 */\r\n itemWidth: number\r\n /** 元素高度 */\r\n itemHeight: number\r\n /** 列间距 */\r\n columnGap: number\r\n /** 列数 */\r\n columnCount: number\r\n /** 行间距 */\r\n rowGap: number\r\n /** 行数 */\r\n rowCount: number\r\n /** 元素格数 */\r\n itemCount: number\r\n /** 最大行数 */\r\n maxRows: number | null\r\n /** 是否有元素被隐藏 */\r\n overflow: boolean\r\n}\r\n\r\nexport interface FlowProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\r\n /** 元素宽度 */\r\n itemWidth: number\r\n /** 元素高度 */\r\n itemHeight: number\r\n /**\r\n * 列间距\r\n * 1. 如果是数字,表示列间距是固定的\r\n * 2. 如果是 auto,表示会在尽可能放进更多列的情况下,列间距是平均的\r\n * 2. 如果是数组,表示列间距是区间的,第一个元素是最小值,第二个元素是最大值\r\n */\r\n columnGap?: number | \"auto\" | [number | \"auto\", number | \"auto\"]\r\n /** 行间距 */\r\n rowGap?: number\r\n gap?: number\r\n /** 最大行数 */\r\n maxRows?: number | null\r\n /** 源数据 */\r\n data: T[]\r\n /** 渲染 */\r\n render: (item: T, index: number, arr: T[]) => ReactNode\r\n /** key释放器,默认为 index */\r\n keyExactor?: (item: T, index: number, arr: T[]) => Key\r\n /**\r\n * 渲染的元素由两层容器包裹,外层容器类名\r\n */\r\n wrapperClassName?: string\r\n /**\r\n * 渲染的元素由两层容器包裹,外层容器样式\r\n */\r\n wrapperStyle?: CSSProperties\r\n /** \r\n * 渲染的元素由两层容器包裹,内层容器类名\r\n */\r\n containerClassName?: string\r\n /**\r\n * 渲染的元素由两层容器包裹,内层容器样式\r\n */\r\n containerStyle?: CSSProperties\r\n /** 节流时间,单位毫秒,默认200ms,传入 0 不节流 */\r\n throttle?: number\r\n /** 动画时间,单位毫秒,默认400ms,传入 0 不展示动画 */\r\n transitionDuration?: number\r\n /** 变化的回调函数 */\r\n onSizeChange?: (sizeData: FlowSizeData) => void\r\n}\r\n\r\nexport function getGapRange(gap?: undefined | number | \"auto\" | (number | \"auto\")[]): [number, number | \"auto\"] {\r\n if (typeof gap === \"number\") return [gap, gap]\r\n if (Array.isArray(gap)) return [typeof gap[0] === \"number\" ? gap[0] : 0, gap[1]]\r\n return [0, \"auto\"]\r\n}\r\n\r\nexport function getGapCountAndSize(width: number, itemWidth: number, minGap: number, maxGap: number | \"auto\"): [number, number] {\r\n const count = Math.floor((width + minGap) / (itemWidth + minGap)) || 1\r\n if (count === 1) return [count, 0]\r\n const averageGap = (width - itemWidth * count) / (count - 1)\r\n if (averageGap < minGap) return [count, minGap]\r\n if (maxGap !== \"auto\" && averageGap > maxGap) return [count, maxGap]\r\n return [count, averageGap]\r\n}\r\n\r\ninterface Position {\r\n left: number\r\n top: number\r\n}\r\n\r\n/** 自适应浮动组件 */\r\nexport function Flow<T>(props: FlowProps<T>) {\r\n let { itemWidth, itemHeight, columnGap, rowGap, maxRows, data, render, keyExactor, className, style, wrapperClassName, wrapperStyle, throttle, transitionDuration, onSizeChange, containerClassName, containerStyle, gap = 0, ...rest } = props\r\n rowGap ??= gap\r\n columnGap ??= gap\r\n const [minColumnGap, maxColumnGap] = getGapRange(columnGap)\r\n const [width, setWidth] = useState(0)\r\n const [columnCount, setColumnCount] = useState(1)\r\n const [columnGapSize, setColumnGapSize] = useState(minColumnGap)\r\n const [showItems, setShowItems] = useState(false)\r\n const ele = useRef<HTMLDivElement>(null)\r\n const contentRows = Math.ceil(data.length / columnCount)\r\n const contentShownRows = typeof maxRows === \"number\" ? Math.min(contentRows, maxRows) : contentRows\r\n const height = contentShownRows > 0 ? contentShownRows * (itemHeight + rowGap) - rowGap : 0\r\n\r\n function getPosition(index: number): Position {\r\n const y = Math.floor(index / columnCount)\r\n const x = index - y * columnCount\r\n return {\r\n left: x * (itemWidth + columnGapSize),\r\n top: y * (itemHeight + rowGap!)\r\n }\r\n }\r\n\r\n function getHidden(index: number) {\r\n if (typeof maxRows !== \"number\") return false\r\n return index >= maxRows * columnCount\r\n }\r\n\r\n useEffect(() => {\r\n let timeout: number\r\n const observer = new ResizeObserver(entries => {\r\n clearTimeout(timeout)\r\n function task() {\r\n const { width } = entries[0].contentRect\r\n const [newColumnCount, newColumnGapSize] = getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap)\r\n setShowItems(true)\r\n setWidth(width)\r\n setColumnCount(newColumnCount)\r\n setColumnGapSize(newColumnGapSize)\r\n }\r\n if (throttle === 0) {\r\n task()\r\n } else {\r\n timeout = window.setTimeout(task, throttle || 200)\r\n }\r\n })\r\n observer.observe(ele.current!)\r\n\r\n return () => {\r\n observer.disconnect()\r\n }\r\n }, [itemWidth, throttle, columnGap])\r\n\r\n useEffect(() => {\r\n onSizeChange?.({ width, height, itemWidth, itemHeight, columnGap: columnGapSize, columnCount, rowGap: rowGap!, rowCount: contentShownRows, overflow: data.length > contentShownRows * columnCount, itemCount: data.length, maxRows: maxRows ?? null })\r\n }, [width, height, columnGapSize, columnCount, rowGap, contentShownRows, data.length, itemWidth, itemHeight, maxRows])\r\n\r\n return (\r\n <div\r\n ref={ele}\r\n className={clsx(\r\n css`\r\n position: relative;\r\n height: var(--height);\r\n overflow: hidden;\r\n `,\r\n className\r\n )}\r\n style={transformCSSVariable({ height: px(height) }, style)}\r\n {...rest}>\r\n {showItems &&\r\n data.map((item, index, arr) => (\r\n <div\r\n key={keyExactor ? keyExactor(item, index, arr) : index}\r\n className={clsx(\r\n css`\r\n position: absolute;\r\n width: var(--width);\r\n height: var(--height);\r\n transition: var(--transition);\r\n left: 0;\r\n top: 0;\r\n transform: translate(var(--left), var(--top));\r\n `,\r\n wrapperClassName\r\n )}\r\n style={transformCSSVariable(\r\n {\r\n width: px(itemWidth),\r\n height: px(itemHeight),\r\n transition: transitionDuration === 0 ? \"none\" : `all ${transitionDuration || 400}ms`,\r\n left: px(getPosition(index).left),\r\n top: px(getPosition(index).top)\r\n },\r\n wrapperStyle\r\n )}>\r\n <div\r\n className={clsx(\r\n css`\r\n width: 100%;\r\n height: 100%;\r\n display: var(--display);\r\n `,\r\n containerClassName\r\n )}\r\n style={transformCSSVariable({ display: getHidden(index) ? \"none\" : \"block\" }, containerStyle)}>\r\n {render(item, index, arr)}\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n )\r\n}\r\n"],"mappings":"AAAA,YAAY;;AAEZ,SAASA,GAAG,QAAQ,cAAc;AAClC,SAASC,IAAI,QAAQ,eAAe;AACpC,SAAwDC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AAClG,SAASC,EAAE,EAAEC,oBAAoB;AAAkB,SAAAC,GAAA,IAAAC,IAAA;AA0EnD,OAAO,SAASC,WAAWA,CAACC,GAAuD,EAA6B;EAC5G,IAAI,OAAOA,GAAG,KAAK,QAAQ,EAAE,OAAO,CAACA,GAAG,EAAEA,GAAG,CAAC;EAC9C,IAAIC,KAAK,CAACC,OAAO,CAACF,GAAG,CAAC,EAAE,OAAO,CAAC,OAAOA,GAAG,CAAC,CAAC,CAAC,KAAK,QAAQ,GAAGA,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAEA,GAAG,CAAC,CAAC,CAAC,CAAC;EAChF,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC;AACtB;AAEA,OAAO,SAASG,kBAAkBA,CAACC,KAAa,EAAEC,SAAiB,EAAEC,MAAc,EAAEC,MAAuB,EAAoB;EAC5H,MAAMC,KAAK,GAAGC,IAAI,CAACC,KAAK,CAAC,CAACN,KAAK,GAAGE,MAAM,KAAKD,SAAS,GAAGC,MAAM,CAAC,CAAC,IAAI,CAAC;EACtE,IAAIE,KAAK,KAAK,CAAC,EAAE,OAAO,CAACA,KAAK,EAAE,CAAC,CAAC;EAClC,MAAMG,UAAU,GAAG,CAACP,KAAK,GAAGC,SAAS,GAAGG,KAAK,KAAKA,KAAK,GAAG,CAAC,CAAC;EAC5D,IAAIG,UAAU,GAAGL,MAAM,EAAE,OAAO,CAACE,KAAK,EAAEF,MAAM,CAAC;EAC/C,IAAIC,MAAM,KAAK,MAAM,IAAII,UAAU,GAAGJ,MAAM,EAAE,OAAO,CAACC,KAAK,EAAED,MAAM,CAAC;EACpE,OAAO,CAACC,KAAK,EAAEG,UAAU,CAAC;AAC9B;AAOA;AACA,OAAO,SAASC,IAAIA,CAAIC,KAAmB,EAAE;EACzC,IAAI;IAAER,SAAS;IAAES,UAAU;IAAEC,SAAS;IAAEC,MAAM;IAAEC,OAAO;IAAEC,IAAI;IAAEC,MAAM;IAAEC,UAAU;IAAEC,SAAS;IAAEC,KAAK;IAAEC,gBAAgB;IAAEC,YAAY;IAAEC,QAAQ;IAAEC,kBAAkB;IAAEC,YAAY;IAAEC,kBAAkB;IAAEC,cAAc;IAAE7B,GAAG,GAAG,CAAC;IAAE,GAAG8B;EAAK,CAAC,GAAGjB,KAAK;EAC/OG,MAAM,KAAKhB,GAAG;EACde,SAAS,KAAKf,GAAG;EACjB,MAAM,CAAC+B,YAAY,EAAEC,YAAY,CAAC,GAAGjC,WAAW,CAACgB,SAAS,CAAC;EAC3D,MAAM,CAACX,KAAK,EAAE6B,QAAQ,CAAC,GAAGvC,QAAQ,CAAC,CAAC,CAAC;EACrC,MAAM,CAACwC,WAAW,EAAEC,cAAc,CAAC,GAAGzC,QAAQ,CAAC,CAAC,CAAC;EACjD,MAAM,CAAC0C,aAAa,EAAEC,gBAAgB,CAAC,GAAG3C,QAAQ,CAACqC,YAAY,CAAC;EAChE,MAAM,CAACO,SAAS,EAAEC,YAAY,CAAC,GAAG7C,QAAQ,CAAC,KAAK,CAAC;EACjD,MAAM8C,GAAG,GAAG/C,MAAM,CAAiB,IAAI,CAAC;EACxC,MAAMgD,WAAW,GAAGhC,IAAI,CAACiC,IAAI,CAACxB,IAAI,CAACyB,MAAM,GAAGT,WAAW,CAAC;EACxD,MAAMU,gBAAgB,GAAG,OAAO3B,OAAO,KAAK,QAAQ,GAAGR,IAAI,CAACoC,GAAG,CAACJ,WAAW,EAAExB,OAAO,CAAC,GAAGwB,WAAW;EACnG,MAAMK,MAAM,GAAGF,gBAAgB,GAAG,CAAC,GAAGA,gBAAgB,IAAI9B,UAAU,GAAGE,MAAM,CAAC,GAAGA,MAAM,GAAG,CAAC;EAE3F,SAAS+B,WAAWA,CAACC,KAAa,EAAY;IAC1C,MAAMC,CAAC,GAAGxC,IAAI,CAACC,KAAK,CAACsC,KAAK,GAAGd,WAAW,CAAC;IACzC,MAAMgB,CAAC,GAAGF,KAAK,GAAGC,CAAC,GAAGf,WAAW;IACjC,OAAO;MACHiB,IAAI,EAAED,CAAC,IAAI7C,SAAS,GAAG+B,aAAa,CAAC;MACrCgB,GAAG,EAAEH,CAAC,IAAInC,UAAU,GAAGE,MAAO;IAClC,CAAC;EACL;EAEA,SAASqC,SAASA,CAACL,KAAa,EAAE;IAC9B,IAAI,OAAO/B,OAAO,KAAK,QAAQ,EAAE,OAAO,KAAK;IAC7C,OAAO+B,KAAK,IAAI/B,OAAO,GAAGiB,WAAW;EACzC;EAEA1C,SAAS,CAAC,MAAM;IACZ,IAAI8D,OAAe;IACnB,MAAMC,QAAQ,GAAG,IAAIC,cAAc,CAACC,OAAO,IAAI;MAC3CC,YAAY,CAACJ,OAAO,CAAC;MACrB,SAASK,IAAIA,CAAA,EAAG;QACZ,MAAM;UAAEvD;QAAM,CAAC,GAAGqD,OAAO,CAAC,CAAC,CAAC,CAACG,WAAW;QACxC,MAAM,CAACC,cAAc,EAAEC,gBAAgB,CAAC,GAAG3D,kBAAkB,CAACC,KAAK,EAAEC,SAAS,EAAE0B,YAAY,EAAEC,YAAY,CAAC;QAC3GO,YAAY,CAAC,IAAI,CAAC;QAClBN,QAAQ,CAAC7B,KAAK,CAAC;QACf+B,cAAc,CAAC0B,cAAc,CAAC;QAC9BxB,gBAAgB,CAACyB,gBAAgB,CAAC;MACtC;MACA,IAAIrC,QAAQ,KAAK,CAAC,EAAE;QAChBkC,IAAI,CAAC,CAAC;MACV,CAAC,MAAM;QACHL,OAAO,GAAGS,MAAM,CAACC,UAAU,CAACL,IAAI,EAAElC,QAAQ,IAAI,GAAG,CAAC;MACtD;IACJ,CAAC,CAAC;IACF8B,QAAQ,CAACU,OAAO,CAACzB,GAAG,CAAC0B,OAAQ,CAAC;IAE9B,OAAO,MAAM;MACTX,QAAQ,CAACY,UAAU,CAAC,CAAC;IACzB,CAAC;EACL,CAAC,EAAE,CAAC9D,SAAS,EAAEoB,QAAQ,EAAEV,SAAS,CAAC,CAAC;EAEpCvB,SAAS,CAAC,MAAM;IACZmC,YAAY,GAAG;MAAEvB,KAAK;MAAE0C,MAAM;MAAEzC,SAAS;MAAES,UAAU;MAAEC,SAAS,EAAEqB,aAAa;MAAEF,WAAW;MAAElB,MAAM,EAAEA,MAAO;MAAEoD,QAAQ,EAAExB,gBAAgB;MAAEyB,QAAQ,EAAEnD,IAAI,CAACyB,MAAM,GAAGC,gBAAgB,GAAGV,WAAW;MAAEoC,SAAS,EAAEpD,IAAI,CAACyB,MAAM;MAAE1B,OAAO,EAAEA,OAAO,IAAI;IAAK,CAAC,CAAC;EAC1P,CAAC,EAAE,CAACb,KAAK,EAAE0C,MAAM,EAAEV,aAAa,EAAEF,WAAW,EAAElB,MAAM,EAAE4B,gBAAgB,EAAE1B,IAAI,CAACyB,MAAM,EAAEtC,SAAS,EAAES,UAAU,EAAEG,OAAO,CAAC,CAAC;EAEtH,oBACInB,IAAA;IACIyE,GAAG,EAAE/B,GAAI;IACTnB,SAAS,EAAE9B,IAAI,CACXD,GAAI;AACpB;AACA;AACA;AACA,iBAAiB,EACD+B,SACJ,CAAE;IACFC,KAAK,EAAE1B,oBAAoB,CAAC;MAAEkD,MAAM,EAAEnD,EAAE,CAACmD,MAAM;IAAE,CAAC,EAAExB,KAAK,CAAE;IAAA,GACvDQ,IAAI;IAAA0C,QAAA,EACPlC,SAAS,IACNpB,IAAI,CAACuD,GAAG,CAAC,CAACC,IAAI,EAAE1B,KAAK,EAAE2B,GAAG,kBACtB7E,IAAA;MAEIuB,SAAS,EAAE9B,IAAI,CACXD,GAAI;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B,EACDiC,gBACJ,CAAE;MACFD,KAAK,EAAE1B,oBAAoB,CACvB;QACIQ,KAAK,EAAET,EAAE,CAACU,SAAS,CAAC;QACpByC,MAAM,EAAEnD,EAAE,CAACmB,UAAU,CAAC;QACtB8D,UAAU,EAAElD,kBAAkB,KAAK,CAAC,GAAG,MAAM,GAAI,OAAMA,kBAAkB,IAAI,GAAI,IAAG;QACpFyB,IAAI,EAAExD,EAAE,CAACoD,WAAW,CAACC,KAAK,CAAC,CAACG,IAAI,CAAC;QACjCC,GAAG,EAAEzD,EAAE,CAACoD,WAAW,CAACC,KAAK,CAAC,CAACI,GAAG;MAClC,CAAC,EACD5B,YACJ,CAAE;MAAAgD,QAAA,eACF1E,IAAA;QACIuB,SAAS,EAAE9B,IAAI,CACXD,GAAI;AACpC;AACA;AACA;AACA,iCAAiC,EACDsC,kBACJ,CAAE;QACFN,KAAK,EAAE1B,oBAAoB,CAAC;UAAEiF,OAAO,EAAExB,SAAS,CAACL,KAAK,CAAC,GAAG,MAAM,GAAG;QAAQ,CAAC,EAAEnB,cAAc,CAAE;QAAA2C,QAAA,EAC7FrD,MAAM,CAACuD,IAAI,EAAE1B,KAAK,EAAE2B,GAAG;MAAC,CACxB;IAAC,GAlCDvD,UAAU,GAAGA,UAAU,CAACsD,IAAI,EAAE1B,KAAK,EAAE2B,GAAG,CAAC,GAAG3B,KAmChD,CACR;EAAC,CACL,CAAC;AAEd"}
1
+ {"version":3,"names":["css","clsx","useEffect","useRef","useState","px","transformCSSVariable","jsx","_jsx","getGapRange","gap","Array","isArray","getGapCountAndSize","width","itemWidth","minGap","maxGap","count","Math","floor","averageGap","RealFlow","props","itemHeight","columnGap","rowGap","maxRows","data","render","keyExactor","className","style","wrapperClassName","wrapperStyle","throttle","transitionDuration","onSizeChange","containerClassName","containerStyle","rest","minColumnGap","maxColumnGap","columnCount","setColumnCount","columnGapSize","setColumnGapSize","ele","contentRows","ceil","length","contentShownRows","min","height","getPosition","index","y","x","left","top","getHidden","task","newColumnCount","newColumnGapSize","timeout","setTimeout","clearTimeout","rowCount","overflow","itemCount","ref","children","map","item","arr","transition","display","Flow"],"sources":["../../../src/components/Flow.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { css } from \"@emotion/css\"\r\nimport { clsx } from \"deepsea-tools\"\r\nimport { CSSProperties, HTMLAttributes, Key, ReactNode, useEffect, useRef, useState } from \"react\"\r\nimport { px, transformCSSVariable } from \"../utils\"\r\n\r\nexport interface FlowSizeData {\r\n /** 容器宽度 */\r\n width: number\r\n /** 容器高度 */\r\n height: number\r\n /** 元素宽度 */\r\n itemWidth: number\r\n /** 元素高度 */\r\n itemHeight: number\r\n /** 列间距 */\r\n columnGap: number\r\n /** 列数 */\r\n columnCount: number\r\n /** 行间距 */\r\n rowGap: number\r\n /** 行数 */\r\n rowCount: number\r\n /** 元素格数 */\r\n itemCount: number\r\n /** 最大行数 */\r\n maxRows: number | null\r\n /** 是否有元素被隐藏 */\r\n overflow: boolean\r\n}\r\n\r\nexport interface FlowProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\r\n /** 元素宽度 */\r\n itemWidth: number\r\n /** 元素高度 */\r\n itemHeight: number\r\n /**\r\n * 列间距\r\n * 1. 如果是数字,表示列间距是固定的\r\n * 2. 如果是 auto,表示会在尽可能放进更多列的情况下,列间距是平均的\r\n * 2. 如果是数组,表示列间距是区间的,第一个元素是最小值,第二个元素是最大值\r\n */\r\n columnGap?: number | \"auto\" | [number | \"auto\", number | \"auto\"]\r\n /** 行间距 */\r\n rowGap?: number\r\n gap?: number\r\n /** 最大行数 */\r\n maxRows?: number | null\r\n /** 源数据 */\r\n data: T[]\r\n /** 渲染 */\r\n render: (item: T, index: number, arr: T[]) => ReactNode\r\n /** key释放器,默认为 index */\r\n keyExactor?: (item: T, index: number, arr: T[]) => Key\r\n /**\r\n * 渲染的元素由两层容器包裹,外层容器类名\r\n */\r\n wrapperClassName?: string\r\n /**\r\n * 渲染的元素由两层容器包裹,外层容器样式\r\n */\r\n wrapperStyle?: CSSProperties\r\n /**\r\n * 渲染的元素由两层容器包裹,内层容器类名\r\n */\r\n containerClassName?: string\r\n /**\r\n * 渲染的元素由两层容器包裹,内层容器样式\r\n */\r\n containerStyle?: CSSProperties\r\n /** 节流时间,单位毫秒,默认200ms,传入 0 不节流 */\r\n throttle?: number\r\n /** 动画时间,单位毫秒,默认400ms,传入 0 不展示动画 */\r\n transitionDuration?: number\r\n /** 变化的回调函数 */\r\n onSizeChange?: (sizeData: FlowSizeData) => void\r\n /** 宽度 */\r\n width?: number\r\n}\r\n\r\nexport function getGapRange(gap?: undefined | number | \"auto\" | (number | \"auto\")[]): [number, number | \"auto\"] {\r\n if (typeof gap === \"number\") return [gap, gap]\r\n if (Array.isArray(gap)) return [typeof gap[0] === \"number\" ? gap[0] : 0, gap[1]]\r\n return [0, \"auto\"]\r\n}\r\n\r\nexport function getGapCountAndSize(width: number, itemWidth: number, minGap: number, maxGap: number | \"auto\"): [number, number] {\r\n const count = Math.floor((width + minGap) / (itemWidth + minGap)) || 1\r\n if (count === 1) return [count, 0]\r\n const averageGap = (width - itemWidth * count) / (count - 1)\r\n if (averageGap < minGap) return [count, minGap]\r\n if (maxGap !== \"auto\" && averageGap > maxGap) return [count, maxGap]\r\n return [count, averageGap]\r\n}\r\n\r\ninterface Position {\r\n left: number\r\n top: number\r\n}\r\n\r\nfunction RealFlow<T>(props: FlowProps<T> & { width: number }) {\r\n let { itemWidth, itemHeight, columnGap, rowGap, maxRows, data, render, keyExactor, className, style, wrapperClassName, wrapperStyle, throttle, transitionDuration, onSizeChange, containerClassName, containerStyle, gap = 0, width, ...rest } = props\r\n rowGap ??= gap\r\n columnGap ??= gap\r\n const [minColumnGap, maxColumnGap] = getGapRange(columnGap)\r\n const [columnCount, setColumnCount] = useState(1)\r\n const [columnGapSize, setColumnGapSize] = useState(minColumnGap)\r\n\r\n const ele = useRef<HTMLDivElement>(null)\r\n const contentRows = Math.ceil(data.length / columnCount)\r\n const contentShownRows = typeof maxRows === \"number\" ? Math.min(contentRows, maxRows) : contentRows\r\n const height = contentShownRows > 0 ? contentShownRows * (itemHeight + rowGap) - rowGap : 0\r\n\r\n function getPosition(index: number): Position {\r\n const y = Math.floor(index / columnCount)\r\n const x = index - y * columnCount\r\n return {\r\n left: x * (itemWidth + columnGapSize),\r\n top: y * (itemHeight + rowGap!)\r\n }\r\n }\r\n\r\n function getHidden(index: number) {\r\n if (typeof maxRows !== \"number\") return false\r\n return index >= maxRows * columnCount\r\n }\r\n\r\n function task() {\r\n const [newColumnCount, newColumnGapSize] = getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap)\r\n setColumnCount(newColumnCount)\r\n setColumnGapSize(newColumnGapSize)\r\n }\r\n\r\n useEffect(() => {\r\n task()\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (throttle === 0) return task()\r\n const timeout = setTimeout(task, throttle || 200)\r\n return () => clearTimeout(timeout)\r\n }, [width, itemWidth, throttle, columnGap])\r\n\r\n useEffect(() => {\r\n onSizeChange?.({ width, height, itemWidth, itemHeight, columnGap: columnGapSize, columnCount, rowGap: rowGap!, rowCount: contentShownRows, overflow: data.length > contentShownRows * columnCount, itemCount: data.length, maxRows: maxRows ?? null })\r\n }, [width, height, columnGapSize, columnCount, rowGap, contentShownRows, data.length, itemWidth, itemHeight, maxRows])\r\n\r\n return (\r\n <div\r\n ref={ele}\r\n className={clsx(\r\n css`\r\n position: relative;\r\n height: var(--height);\r\n overflow: hidden;\r\n `,\r\n className\r\n )}\r\n style={transformCSSVariable({ height: px(height) }, style)}\r\n {...rest}>\r\n {data.map((item, index, arr) => (\r\n <div\r\n key={keyExactor ? keyExactor(item, index, arr) : index}\r\n className={clsx(\r\n css`\r\n position: absolute;\r\n width: var(--width);\r\n height: var(--height);\r\n transition: var(--transition);\r\n left: 0;\r\n top: 0;\r\n transform: translate(var(--left), var(--top));\r\n `,\r\n wrapperClassName\r\n )}\r\n style={transformCSSVariable(\r\n {\r\n width: px(itemWidth),\r\n height: px(itemHeight),\r\n transition: transitionDuration === 0 ? \"none\" : `all ${transitionDuration || 400}ms`,\r\n left: px(getPosition(index).left),\r\n top: px(getPosition(index).top)\r\n },\r\n wrapperStyle\r\n )}>\r\n <div\r\n className={clsx(\r\n css`\r\n width: 100%;\r\n height: 100%;\r\n display: var(--display);\r\n `,\r\n containerClassName\r\n )}\r\n style={transformCSSVariable({ display: getHidden(index) ? \"none\" : \"block\" }, containerStyle)}>\r\n {render(item, index, arr)}\r\n </div>\r\n </div>\r\n ))}\r\n </div>\r\n )\r\n}\r\n\r\n/** 自适应浮动组件 */\r\nexport function Flow<T>(props: FlowProps<T>) {\r\n const { width, data } = props\r\n if (!width || data.length === 0) return null\r\n return <RealFlow {...props} width={width} />\r\n}\r\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepsea-components",
3
- "version": "3.1.1",
3
+ "version": "3.2.0-beta.20240606182955",
4
4
  "description": "格数科技自用组件库",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -45,4 +45,4 @@
45
45
  "peerDependencies": {
46
46
  "react": "^18.3.1"
47
47
  }
48
- }
48
+ }
@@ -61,7 +61,7 @@ export interface FlowProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, "chil
61
61
  * 渲染的元素由两层容器包裹,外层容器样式
62
62
  */
63
63
  wrapperStyle?: CSSProperties
64
- /**
64
+ /**
65
65
  * 渲染的元素由两层容器包裹,内层容器类名
66
66
  */
67
67
  containerClassName?: string
@@ -75,6 +75,8 @@ export interface FlowProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, "chil
75
75
  transitionDuration?: number
76
76
  /** 变化的回调函数 */
77
77
  onSizeChange?: (sizeData: FlowSizeData) => void
78
+ /** 宽度 */
79
+ width?: number
78
80
  }
79
81
 
80
82
  export function getGapRange(gap?: undefined | number | "auto" | (number | "auto")[]): [number, number | "auto"] {
@@ -97,16 +99,14 @@ interface Position {
97
99
  top: number
98
100
  }
99
101
 
100
- /** 自适应浮动组件 */
101
- export function Flow<T>(props: FlowProps<T>) {
102
- let { itemWidth, itemHeight, columnGap, rowGap, maxRows, data, render, keyExactor, className, style, wrapperClassName, wrapperStyle, throttle, transitionDuration, onSizeChange, containerClassName, containerStyle, gap = 0, ...rest } = props
102
+ function RealFlow<T>(props: FlowProps<T> & { width: number }) {
103
+ let { itemWidth, itemHeight, columnGap, rowGap, maxRows, data, render, keyExactor, className, style, wrapperClassName, wrapperStyle, throttle, transitionDuration, onSizeChange, containerClassName, containerStyle, gap = 0, width, ...rest } = props
103
104
  rowGap ??= gap
104
105
  columnGap ??= gap
105
106
  const [minColumnGap, maxColumnGap] = getGapRange(columnGap)
106
- const [width, setWidth] = useState(0)
107
107
  const [columnCount, setColumnCount] = useState(1)
108
108
  const [columnGapSize, setColumnGapSize] = useState(minColumnGap)
109
- const [showItems, setShowItems] = useState(false)
109
+
110
110
  const ele = useRef<HTMLDivElement>(null)
111
111
  const contentRows = Math.ceil(data.length / columnCount)
112
112
  const contentShownRows = typeof maxRows === "number" ? Math.min(contentRows, maxRows) : contentRows
@@ -126,30 +126,21 @@ export function Flow<T>(props: FlowProps<T>) {
126
126
  return index >= maxRows * columnCount
127
127
  }
128
128
 
129
+ function task() {
130
+ const [newColumnCount, newColumnGapSize] = getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap)
131
+ setColumnCount(newColumnCount)
132
+ setColumnGapSize(newColumnGapSize)
133
+ }
134
+
129
135
  useEffect(() => {
130
- let timeout: number
131
- const observer = new ResizeObserver(entries => {
132
- clearTimeout(timeout)
133
- function task() {
134
- const { width } = entries[0].contentRect
135
- const [newColumnCount, newColumnGapSize] = getGapCountAndSize(width, itemWidth, minColumnGap, maxColumnGap)
136
- setShowItems(true)
137
- setWidth(width)
138
- setColumnCount(newColumnCount)
139
- setColumnGapSize(newColumnGapSize)
140
- }
141
- if (throttle === 0) {
142
- task()
143
- } else {
144
- timeout = window.setTimeout(task, throttle || 200)
145
- }
146
- })
147
- observer.observe(ele.current!)
148
-
149
- return () => {
150
- observer.disconnect()
151
- }
152
- }, [itemWidth, throttle, columnGap])
136
+ task()
137
+ }, [])
138
+
139
+ useEffect(() => {
140
+ if (throttle === 0) return task()
141
+ const timeout = setTimeout(task, throttle || 200)
142
+ return () => clearTimeout(timeout)
143
+ }, [width, itemWidth, throttle, columnGap])
153
144
 
154
145
  useEffect(() => {
155
146
  onSizeChange?.({ width, height, itemWidth, itemHeight, columnGap: columnGapSize, columnCount, rowGap: rowGap!, rowCount: contentShownRows, overflow: data.length > contentShownRows * columnCount, itemCount: data.length, maxRows: maxRows ?? null })
@@ -168,46 +159,52 @@ export function Flow<T>(props: FlowProps<T>) {
168
159
  )}
169
160
  style={transformCSSVariable({ height: px(height) }, style)}
170
161
  {...rest}>
171
- {showItems &&
172
- data.map((item, index, arr) => (
162
+ {data.map((item, index, arr) => (
163
+ <div
164
+ key={keyExactor ? keyExactor(item, index, arr) : index}
165
+ className={clsx(
166
+ css`
167
+ position: absolute;
168
+ width: var(--width);
169
+ height: var(--height);
170
+ transition: var(--transition);
171
+ left: 0;
172
+ top: 0;
173
+ transform: translate(var(--left), var(--top));
174
+ `,
175
+ wrapperClassName
176
+ )}
177
+ style={transformCSSVariable(
178
+ {
179
+ width: px(itemWidth),
180
+ height: px(itemHeight),
181
+ transition: transitionDuration === 0 ? "none" : `all ${transitionDuration || 400}ms`,
182
+ left: px(getPosition(index).left),
183
+ top: px(getPosition(index).top)
184
+ },
185
+ wrapperStyle
186
+ )}>
173
187
  <div
174
- key={keyExactor ? keyExactor(item, index, arr) : index}
175
188
  className={clsx(
176
189
  css`
177
- position: absolute;
178
- width: var(--width);
179
- height: var(--height);
180
- transition: var(--transition);
181
- left: 0;
182
- top: 0;
183
- transform: translate(var(--left), var(--top));
190
+ width: 100%;
191
+ height: 100%;
192
+ display: var(--display);
184
193
  `,
185
- wrapperClassName
194
+ containerClassName
186
195
  )}
187
- style={transformCSSVariable(
188
- {
189
- width: px(itemWidth),
190
- height: px(itemHeight),
191
- transition: transitionDuration === 0 ? "none" : `all ${transitionDuration || 400}ms`,
192
- left: px(getPosition(index).left),
193
- top: px(getPosition(index).top)
194
- },
195
- wrapperStyle
196
- )}>
197
- <div
198
- className={clsx(
199
- css`
200
- width: 100%;
201
- height: 100%;
202
- display: var(--display);
203
- `,
204
- containerClassName
205
- )}
206
- style={transformCSSVariable({ display: getHidden(index) ? "none" : "block" }, containerStyle)}>
207
- {render(item, index, arr)}
208
- </div>
196
+ style={transformCSSVariable({ display: getHidden(index) ? "none" : "block" }, containerStyle)}>
197
+ {render(item, index, arr)}
209
198
  </div>
210
- ))}
199
+ </div>
200
+ ))}
211
201
  </div>
212
202
  )
213
203
  }
204
+
205
+ /** 自适应浮动组件 */
206
+ export function Flow<T>(props: FlowProps<T>) {
207
+ const { width, data } = props
208
+ if (!width || data.length === 0) return null
209
+ return <RealFlow {...props} width={width} />
210
+ }