react-public-components 1.1.16 → 1.1.18
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/README.md +112 -4
- package/dist/index.cjs +343 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +55 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +79 -2
- package/dist/index.d.ts +79 -2
- package/dist/index.js +341 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
封装 react 常用的组件,欢迎更多同学提出大众化普遍存在的业务场景。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
本仓库包含四个独立的 React 组件:
|
|
6
6
|
|
|
7
7
|
1. **CollapseBox** — 可折叠的内容容器组件
|
|
8
8
|
2. **Splitter** — 可拖拽调整、可折叠的分屏面板组件
|
|
9
9
|
3. **DisabledBox** — 禁用态包装容器组件(带锁图标及拦截事件)
|
|
10
|
+
4. **Masonry** — 瀑布流布局组件(一比一复刻 Ant Design V6 规范)
|
|
10
11
|
|
|
11
12
|
---
|
|
12
13
|
|
|
@@ -198,7 +199,108 @@ export default function Demo() {
|
|
|
198
199
|
|
|
199
200
|
---
|
|
200
201
|
|
|
201
|
-
##
|
|
202
|
+
## 四、Masonry 瀑布流组件
|
|
203
|
+
|
|
204
|
+
### 简介
|
|
205
|
+
|
|
206
|
+
`Masonry` 是一个符合 Ant Design V6 规范的瀑布流布局组件。支持固定或响应式列数配置(`columns`)、水平垂直间距配置(`gutter`)、持续监听子项尺寸变化(`fresh`)、自定义语义化结构样式/类名(`styles`/`classNames`)以及列排序回调(`onLayoutChange`)。
|
|
207
|
+
|
|
208
|
+
### 引入方式
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
import { Masonry } from 'react-public-components';
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Masonry Props
|
|
215
|
+
|
|
216
|
+
| 参数 | 说明 | 类型 | 默认值 |
|
|
217
|
+
| ---------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------- |
|
|
218
|
+
| `classNames` | 自定义内部语义化结构 class,支持对象或函数 | `Record<'root' \| 'item', string> \| ((info: { props }) => Record<'root' \| 'item', string>)` | `-` |
|
|
219
|
+
| `columns` | 列数,固定数字或响应式配置 | `number \| { xs?: number; sm?: number; md?: number; lg?: number; xl?: number; xxl?: number }` | `3` |
|
|
220
|
+
| `fresh` | 是否持续监听子项尺寸变化 | `boolean` | `false` |
|
|
221
|
+
| `gutter` | 间距,固定数字、响应式配置或水平垂直间距配置 | `Gap \| [Gap, Gap]` | `0` |
|
|
222
|
+
| `items` | 瀑布流数据项 | `MasonryItem[]` | `-` |
|
|
223
|
+
| `itemRender` | 自定义数据项渲染函数 | `(item: MasonryItem) => ReactNode` | `-` |
|
|
224
|
+
| `styles` | 语义化结构 style,支持对象和函数形式 | `Record<'root' \| 'item', CSSProperties> \| ((info: { props }) => Record<'root' \| 'item', CSSProperties>)` | `-` |
|
|
225
|
+
| `onLayoutChange` | 列排序计算完成回调 | `(layout: { key: React.Key; column: number }[]) => void` | `-` |
|
|
226
|
+
|
|
227
|
+
### MasonryItem 属性
|
|
228
|
+
|
|
229
|
+
| 参数 | 说明 | 类型 | 默认值 |
|
|
230
|
+
| ---------- | ------------------------------------------------ | ------------------ | ------ |
|
|
231
|
+
| `children` | 自定义展示内容,相对 `itemRender` 具有更高优先级 | `ReactNode` | `-` |
|
|
232
|
+
| `column` | 自定义指定放置列(0-indexed) | `number` | `-` |
|
|
233
|
+
| `data` | 自定义存储数据 | `T` | `-` |
|
|
234
|
+
| `height` | 高度(手指定时优先使用) | `number` | `-` |
|
|
235
|
+
| `key` | 唯一标识 | `string \| number` | `-` |
|
|
236
|
+
|
|
237
|
+
### 基础用法
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
import { Masonry } from 'react-public-components';
|
|
241
|
+
|
|
242
|
+
export default function Demo() {
|
|
243
|
+
return (
|
|
244
|
+
<Masonry
|
|
245
|
+
columns={{ xs: 1, sm: 2, md: 3, lg: 4 }}
|
|
246
|
+
gutter={[16, 16]}
|
|
247
|
+
fresh={true}
|
|
248
|
+
items={[
|
|
249
|
+
{ key: '1', height: 120, children: <div>卡片 1</div> },
|
|
250
|
+
{ key: '2', height: 180, children: <div>卡片 2</div> },
|
|
251
|
+
{ key: '3', height: 150, children: <div>卡片 3</div> },
|
|
252
|
+
]}
|
|
253
|
+
/>
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## 五、BorderBeam 边框流光组件
|
|
261
|
+
|
|
262
|
+
### 简介
|
|
263
|
+
|
|
264
|
+
`BorderBeam` 是一个给任意容器边框添加持续流动高亮效果的组件。使用现代 CSS Mask 遮罩与 CSS Motion Path 动画,支持单色与多点渐变色配置、多条流光均匀分布、流光尺寸与线宽调节,以及贴合自定义宿主容器。
|
|
265
|
+
|
|
266
|
+
### 引入方式
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
import { BorderBeam } from 'react-public-components';
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### API
|
|
273
|
+
|
|
274
|
+
| 参数 | 说明 | 类型 | 默认值 | 版本 | 全局配置 |
|
|
275
|
+
| ----------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ------ | ----- | -------- |
|
|
276
|
+
| `children` | 装饰内容 | `ReactNode` | `-` | 6.4.0 | × |
|
|
277
|
+
| `color` | 流光颜色配置,支持单色字符串或渐变停靠点数组。`percent` 使用 `0 ~ 100` 的输入区间,组件会在内部为尾部透明过渡预留空间 | `string \| { color: string; percent: number }[]` | `-` | 6.4.0 | × |
|
|
278
|
+
| `count` | 流光数量 | `number` | `1` | 6.6.0 | × |
|
|
279
|
+
| `duration` | 流光完成一圈动画的时间,单位秒 | `number` | `6` | 6.5.0 | × |
|
|
280
|
+
| `lineWidth` | 流光线宽,数字类型按像素处理 | `number \| string` | `1px` | 6.5.0 | × |
|
|
281
|
+
| `outset` | 流光层相对容器边缘的外扩距离,遇到裁剪容器时可设为 `0` | `number \| string` | `-` | 6.4.0 | × |
|
|
282
|
+
| `size` | 流光可见段的尺寸,数字类型按像素处理 | `number \| string` | `100` | 6.5.0 | × |
|
|
283
|
+
|
|
284
|
+
### 基础用法
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
import { BorderBeam } from 'react-public-components';
|
|
288
|
+
|
|
289
|
+
export default function Demo() {
|
|
290
|
+
return (
|
|
291
|
+
<BorderBeam size={100} duration={6} color="#1677ff">
|
|
292
|
+
<div style={{ padding: 24, borderRadius: 12, border: '1px solid #eee' }}>
|
|
293
|
+
<h3>Workspace overview</h3>
|
|
294
|
+
<p>Review task status, deployment health, and recent automation activity in one panel.</p>
|
|
295
|
+
</div>
|
|
296
|
+
</BorderBeam>
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## 六、目录结构
|
|
202
304
|
|
|
203
305
|
```
|
|
204
306
|
.
|
|
@@ -207,14 +309,20 @@ export default function Demo() {
|
|
|
207
309
|
│ └── index.less
|
|
208
310
|
├── Splitter/
|
|
209
311
|
│ └── index.tsx
|
|
210
|
-
|
|
312
|
+
├── DisabledBox/
|
|
313
|
+
│ ├── index.tsx
|
|
314
|
+
│ └── index.less
|
|
315
|
+
├── Masonry/
|
|
316
|
+
│ ├── index.tsx
|
|
317
|
+
│ └── index.less
|
|
318
|
+
└── BorderBeam/
|
|
211
319
|
├── index.tsx
|
|
212
320
|
└── index.less
|
|
213
321
|
```
|
|
214
322
|
|
|
215
323
|
---
|
|
216
324
|
|
|
217
|
-
##
|
|
325
|
+
## 七、发布到 npm
|
|
218
326
|
|
|
219
327
|
### 1. 前置准备
|
|
220
328
|
|
package/dist/index.cjs
CHANGED
|
@@ -30,8 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
BorderBeam: () => BorderBeam_default,
|
|
33
34
|
CollapseBox: () => CollapseBox_default,
|
|
34
35
|
DisabledBox: () => DisabledBox_default,
|
|
36
|
+
Masonry: () => Masonry_default,
|
|
35
37
|
Splitter: () => Splitter_default
|
|
36
38
|
});
|
|
37
39
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -865,10 +867,351 @@ var DisabledBox = (props) => {
|
|
|
865
867
|
);
|
|
866
868
|
};
|
|
867
869
|
var DisabledBox_default = DisabledBox;
|
|
870
|
+
|
|
871
|
+
// Masonry/index.tsx
|
|
872
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
873
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
874
|
+
var BREAKPOINT_ORDER = ["xs", "sm", "md", "lg", "xl", "xxl"];
|
|
875
|
+
function getBreakpoint(width) {
|
|
876
|
+
if (width >= 1600) return "xxl";
|
|
877
|
+
if (width >= 1200) return "xl";
|
|
878
|
+
if (width >= 992) return "lg";
|
|
879
|
+
if (width >= 768) return "md";
|
|
880
|
+
if (width >= 576) return "sm";
|
|
881
|
+
return "xs";
|
|
882
|
+
}
|
|
883
|
+
function resolveResponsiveValue(value, currentBp, defaultValue) {
|
|
884
|
+
if (value === void 0 || value === null) return defaultValue;
|
|
885
|
+
if (typeof value === "object") {
|
|
886
|
+
const obj = value;
|
|
887
|
+
if (obj[currentBp] !== void 0) return obj[currentBp];
|
|
888
|
+
const currentIdx = BREAKPOINT_ORDER.indexOf(currentBp);
|
|
889
|
+
for (let i = currentIdx - 1; i >= 0; i--) {
|
|
890
|
+
const bp = BREAKPOINT_ORDER[i];
|
|
891
|
+
if (obj[bp] !== void 0) return obj[bp];
|
|
892
|
+
}
|
|
893
|
+
for (let i = currentIdx + 1; i < BREAKPOINT_ORDER.length; i++) {
|
|
894
|
+
const bp = BREAKPOINT_ORDER[i];
|
|
895
|
+
if (obj[bp] !== void 0) return obj[bp];
|
|
896
|
+
}
|
|
897
|
+
return defaultValue;
|
|
898
|
+
}
|
|
899
|
+
return value;
|
|
900
|
+
}
|
|
901
|
+
function resolveGutter(gutter, currentBp) {
|
|
902
|
+
if (!gutter) return [0, 0];
|
|
903
|
+
if (Array.isArray(gutter)) {
|
|
904
|
+
const h = resolveResponsiveValue(gutter[0], currentBp, 0);
|
|
905
|
+
const v = resolveResponsiveValue(gutter[1], currentBp, 0);
|
|
906
|
+
return [h, v];
|
|
907
|
+
}
|
|
908
|
+
const g = resolveResponsiveValue(gutter, currentBp, 0);
|
|
909
|
+
return [g, g];
|
|
910
|
+
}
|
|
911
|
+
var Masonry = (props) => {
|
|
912
|
+
const {
|
|
913
|
+
classNames,
|
|
914
|
+
columns = 3,
|
|
915
|
+
fresh = false,
|
|
916
|
+
gutter = 0,
|
|
917
|
+
items,
|
|
918
|
+
itemRender,
|
|
919
|
+
styles,
|
|
920
|
+
onLayoutChange,
|
|
921
|
+
className,
|
|
922
|
+
style,
|
|
923
|
+
children
|
|
924
|
+
} = props;
|
|
925
|
+
const rootRef = (0, import_react3.useRef)(null);
|
|
926
|
+
const [containerWidth, setContainerWidth] = (0, import_react3.useState)(0);
|
|
927
|
+
const [measuredHeights, setMeasuredHeights] = (0, import_react3.useState)({});
|
|
928
|
+
const itemRefs = (0, import_react3.useRef)(/* @__PURE__ */ new Map());
|
|
929
|
+
const normalizedItems = (0, import_react3.useMemo)(() => {
|
|
930
|
+
if (items) return items;
|
|
931
|
+
if (!children) return [];
|
|
932
|
+
return import_react3.default.Children.toArray(children).map((child, index) => {
|
|
933
|
+
var _a;
|
|
934
|
+
if (import_react3.default.isValidElement(child)) {
|
|
935
|
+
const key = (_a = child.key) != null ? _a : `masonry-item-${index}`;
|
|
936
|
+
return {
|
|
937
|
+
key,
|
|
938
|
+
children: child
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
return {
|
|
942
|
+
key: `masonry-item-${index}`,
|
|
943
|
+
children: child
|
|
944
|
+
};
|
|
945
|
+
});
|
|
946
|
+
}, [items, children]);
|
|
947
|
+
const currentBreakpoint = (0, import_react3.useMemo)(() => getBreakpoint(containerWidth), [containerWidth]);
|
|
948
|
+
const resolvedColumns = (0, import_react3.useMemo)(() => {
|
|
949
|
+
const count = resolveResponsiveValue(columns, currentBreakpoint, 3);
|
|
950
|
+
return Math.max(1, Math.floor(count));
|
|
951
|
+
}, [columns, currentBreakpoint]);
|
|
952
|
+
const [horizontalGap, verticalGap] = (0, import_react3.useMemo)(
|
|
953
|
+
() => resolveGutter(gutter, currentBreakpoint),
|
|
954
|
+
[gutter, currentBreakpoint]
|
|
955
|
+
);
|
|
956
|
+
(0, import_react3.useEffect)(() => {
|
|
957
|
+
if (!rootRef.current) return;
|
|
958
|
+
const observer = new ResizeObserver((entries) => {
|
|
959
|
+
for (const entry of entries) {
|
|
960
|
+
const width = entry.contentRect.width;
|
|
961
|
+
if (width > 0) {
|
|
962
|
+
setContainerWidth(width);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
observer.observe(rootRef.current);
|
|
967
|
+
return () => observer.disconnect();
|
|
968
|
+
}, []);
|
|
969
|
+
const measureItems = (0, import_react3.useCallback)(() => {
|
|
970
|
+
let hasChange = false;
|
|
971
|
+
const newHeights = {};
|
|
972
|
+
itemRefs.current.forEach((el, key) => {
|
|
973
|
+
if (el) {
|
|
974
|
+
const strKey = String(key);
|
|
975
|
+
const h = el.offsetHeight;
|
|
976
|
+
if (h > 0) {
|
|
977
|
+
newHeights[strKey] = h;
|
|
978
|
+
if (measuredHeights[strKey] !== h) {
|
|
979
|
+
hasChange = true;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
});
|
|
984
|
+
if (hasChange) {
|
|
985
|
+
setMeasuredHeights((prev) => ({ ...prev, ...newHeights }));
|
|
986
|
+
}
|
|
987
|
+
}, [measuredHeights]);
|
|
988
|
+
(0, import_react3.useLayoutEffect)(() => {
|
|
989
|
+
const handle = requestAnimationFrame(() => {
|
|
990
|
+
measureItems();
|
|
991
|
+
});
|
|
992
|
+
return () => cancelAnimationFrame(handle);
|
|
993
|
+
}, [measureItems]);
|
|
994
|
+
(0, import_react3.useEffect)(() => {
|
|
995
|
+
if (!fresh) return;
|
|
996
|
+
const observer = new ResizeObserver(() => {
|
|
997
|
+
measureItems();
|
|
998
|
+
});
|
|
999
|
+
itemRefs.current.forEach((el) => {
|
|
1000
|
+
if (el) observer.observe(el);
|
|
1001
|
+
});
|
|
1002
|
+
return () => observer.disconnect();
|
|
1003
|
+
}, [fresh, measureItems, normalizedItems]);
|
|
1004
|
+
const columnWidth = (0, import_react3.useMemo)(() => {
|
|
1005
|
+
if (containerWidth <= 0) return 0;
|
|
1006
|
+
const totalGap = (resolvedColumns - 1) * horizontalGap;
|
|
1007
|
+
return Math.max(0, (containerWidth - totalGap) / resolvedColumns);
|
|
1008
|
+
}, [containerWidth, resolvedColumns, horizontalGap]);
|
|
1009
|
+
const { layoutItems, containerHeight, layoutChangeData } = (0, import_react3.useMemo)(() => {
|
|
1010
|
+
const colHeights = new Array(resolvedColumns).fill(0);
|
|
1011
|
+
const changeData = [];
|
|
1012
|
+
const computedList = normalizedItems.map((item) => {
|
|
1013
|
+
var _a, _b;
|
|
1014
|
+
const h = (_b = (_a = item.height) != null ? _a : measuredHeights[String(item.key)]) != null ? _b : 0;
|
|
1015
|
+
let targetCol = 0;
|
|
1016
|
+
if (typeof item.column === "number" && item.column >= 0 && item.column < resolvedColumns) {
|
|
1017
|
+
targetCol = Math.floor(item.column);
|
|
1018
|
+
} else {
|
|
1019
|
+
let minH = colHeights[0];
|
|
1020
|
+
for (let i = 1; i < resolvedColumns; i++) {
|
|
1021
|
+
if (colHeights[i] < minH) {
|
|
1022
|
+
minH = colHeights[i];
|
|
1023
|
+
targetCol = i;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
const left = targetCol * (columnWidth + horizontalGap);
|
|
1028
|
+
const top = colHeights[targetCol];
|
|
1029
|
+
colHeights[targetCol] += h + (h > 0 ? verticalGap : 0);
|
|
1030
|
+
changeData.push({ key: item.key, column: targetCol });
|
|
1031
|
+
return {
|
|
1032
|
+
item,
|
|
1033
|
+
left,
|
|
1034
|
+
top,
|
|
1035
|
+
width: columnWidth,
|
|
1036
|
+
height: h,
|
|
1037
|
+
column: targetCol
|
|
1038
|
+
};
|
|
1039
|
+
});
|
|
1040
|
+
const totalH = Math.max(0, ...colHeights);
|
|
1041
|
+
return {
|
|
1042
|
+
layoutItems: computedList,
|
|
1043
|
+
containerHeight: totalH,
|
|
1044
|
+
layoutChangeData: changeData
|
|
1045
|
+
};
|
|
1046
|
+
}, [normalizedItems, resolvedColumns, horizontalGap, verticalGap, columnWidth, measuredHeights]);
|
|
1047
|
+
const prevLayoutRef = (0, import_react3.useRef)("");
|
|
1048
|
+
(0, import_react3.useEffect)(() => {
|
|
1049
|
+
const layoutKey = JSON.stringify(layoutChangeData);
|
|
1050
|
+
if (layoutKey !== prevLayoutRef.current) {
|
|
1051
|
+
prevLayoutRef.current = layoutKey;
|
|
1052
|
+
onLayoutChange == null ? void 0 : onLayoutChange(layoutChangeData);
|
|
1053
|
+
}
|
|
1054
|
+
}, [layoutChangeData, onLayoutChange]);
|
|
1055
|
+
const semanticClassNames = (0, import_react3.useMemo)(() => {
|
|
1056
|
+
var _a;
|
|
1057
|
+
if (typeof classNames === "function") {
|
|
1058
|
+
return (_a = classNames({ props })) != null ? _a : {};
|
|
1059
|
+
}
|
|
1060
|
+
return classNames != null ? classNames : {};
|
|
1061
|
+
}, [classNames, props]);
|
|
1062
|
+
const semanticStyles = (0, import_react3.useMemo)(() => {
|
|
1063
|
+
var _a;
|
|
1064
|
+
if (typeof styles === "function") {
|
|
1065
|
+
return (_a = styles({ props })) != null ? _a : {};
|
|
1066
|
+
}
|
|
1067
|
+
return styles != null ? styles : {};
|
|
1068
|
+
}, [styles, props]);
|
|
1069
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1070
|
+
"div",
|
|
1071
|
+
{
|
|
1072
|
+
ref: rootRef,
|
|
1073
|
+
className: ["masonry_root", semanticClassNames.root, className].filter(Boolean).join(" "),
|
|
1074
|
+
style: {
|
|
1075
|
+
minHeight: containerHeight > 0 ? containerHeight : void 0,
|
|
1076
|
+
height: containerHeight > 0 ? containerHeight : void 0,
|
|
1077
|
+
...semanticStyles.root,
|
|
1078
|
+
...style
|
|
1079
|
+
},
|
|
1080
|
+
children: layoutItems.map(({ item, left, top, width, height }) => {
|
|
1081
|
+
var _a;
|
|
1082
|
+
const content = (_a = item.children) != null ? _a : itemRender == null ? void 0 : itemRender(item);
|
|
1083
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1084
|
+
"div",
|
|
1085
|
+
{
|
|
1086
|
+
ref: (node) => {
|
|
1087
|
+
if (node) {
|
|
1088
|
+
itemRefs.current.set(item.key, node);
|
|
1089
|
+
} else {
|
|
1090
|
+
itemRefs.current.delete(item.key);
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
className: ["masonry_item", semanticClassNames.item].filter(Boolean).join(" "),
|
|
1094
|
+
style: {
|
|
1095
|
+
width: containerWidth > 0 ? width : "100%",
|
|
1096
|
+
height: height > 0 ? height : void 0,
|
|
1097
|
+
transform: containerWidth > 0 ? `translate3d(${left}px, ${top}px, 0)` : void 0,
|
|
1098
|
+
opacity: containerWidth > 0 ? 1 : 0,
|
|
1099
|
+
...semanticStyles.item
|
|
1100
|
+
},
|
|
1101
|
+
onLoad: measureItems,
|
|
1102
|
+
children: content
|
|
1103
|
+
},
|
|
1104
|
+
item.key
|
|
1105
|
+
);
|
|
1106
|
+
})
|
|
1107
|
+
}
|
|
1108
|
+
);
|
|
1109
|
+
};
|
|
1110
|
+
var Masonry_default = Masonry;
|
|
1111
|
+
|
|
1112
|
+
// BorderBeam/index.tsx
|
|
1113
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1114
|
+
var formatSizeUnit = (value, defaultValue) => {
|
|
1115
|
+
if (value === void 0 || value === null) {
|
|
1116
|
+
return defaultValue;
|
|
1117
|
+
}
|
|
1118
|
+
if (typeof value === "number") {
|
|
1119
|
+
return `${value}px`;
|
|
1120
|
+
}
|
|
1121
|
+
return value;
|
|
1122
|
+
};
|
|
1123
|
+
var buildGradientString = (color) => {
|
|
1124
|
+
if (!color) {
|
|
1125
|
+
return "linear-gradient(to left, #1677ff 0%, transparent 100%)";
|
|
1126
|
+
}
|
|
1127
|
+
if (typeof color === "string") {
|
|
1128
|
+
return `linear-gradient(to left, ${color} 0%, transparent 100%)`;
|
|
1129
|
+
}
|
|
1130
|
+
if (Array.isArray(color)) {
|
|
1131
|
+
if (color.length === 0) {
|
|
1132
|
+
return "linear-gradient(to left, #1677ff 0%, transparent 100%)";
|
|
1133
|
+
}
|
|
1134
|
+
const sorted = [...color].sort((a, b) => a.percent - b.percent);
|
|
1135
|
+
const mappedStops = sorted.map((stop) => {
|
|
1136
|
+
const mappedPercent = Math.min(Math.max(stop.percent / 100 * 80, 0), 80);
|
|
1137
|
+
return `${stop.color} ${mappedPercent.toFixed(2)}%`;
|
|
1138
|
+
});
|
|
1139
|
+
return `linear-gradient(to left, ${mappedStops.join(", ")}, transparent 100%)`;
|
|
1140
|
+
}
|
|
1141
|
+
return "linear-gradient(to left, #1677ff 0%, transparent 100%)";
|
|
1142
|
+
};
|
|
1143
|
+
var BorderBeam = (props) => {
|
|
1144
|
+
const {
|
|
1145
|
+
children,
|
|
1146
|
+
color,
|
|
1147
|
+
count = 1,
|
|
1148
|
+
duration = 6,
|
|
1149
|
+
lineWidth = "1px",
|
|
1150
|
+
outset = "0px",
|
|
1151
|
+
size = 100,
|
|
1152
|
+
className,
|
|
1153
|
+
style,
|
|
1154
|
+
...restProps
|
|
1155
|
+
} = props;
|
|
1156
|
+
const formattedLineWidth = formatSizeUnit(lineWidth, "1px");
|
|
1157
|
+
const formattedOutset = formatSizeUnit(outset, "0px");
|
|
1158
|
+
const formattedSize = formatSizeUnit(size, "100px");
|
|
1159
|
+
const gradientCss = buildGradientString(color);
|
|
1160
|
+
const maskStyle = {
|
|
1161
|
+
"--border-beam-line-width": formattedLineWidth,
|
|
1162
|
+
"--border-beam-outset": formattedOutset,
|
|
1163
|
+
"--border-beam-size": formattedSize,
|
|
1164
|
+
"--border-beam-duration": `${duration}s`,
|
|
1165
|
+
"--border-beam-gradient": gradientCss
|
|
1166
|
+
};
|
|
1167
|
+
const beamCount = Math.max(1, count);
|
|
1168
|
+
const beams = Array.from({ length: beamCount }).map((_, index) => {
|
|
1169
|
+
const delaySeconds = -(duration * index / beamCount);
|
|
1170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1171
|
+
"div",
|
|
1172
|
+
{
|
|
1173
|
+
className: "react-public-border-beam-item",
|
|
1174
|
+
style: {
|
|
1175
|
+
animationDelay: `${delaySeconds}s`
|
|
1176
|
+
}
|
|
1177
|
+
},
|
|
1178
|
+
index
|
|
1179
|
+
);
|
|
1180
|
+
});
|
|
1181
|
+
if (children !== void 0) {
|
|
1182
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
1183
|
+
"div",
|
|
1184
|
+
{
|
|
1185
|
+
className: `react-public-border-beam-container ${className || ""}`.trim(),
|
|
1186
|
+
style,
|
|
1187
|
+
...restProps,
|
|
1188
|
+
children: [
|
|
1189
|
+
children,
|
|
1190
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "react-public-border-beam-mask", style: maskStyle, children: beams })
|
|
1191
|
+
]
|
|
1192
|
+
}
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1196
|
+
"div",
|
|
1197
|
+
{
|
|
1198
|
+
className: `react-public-border-beam-mask ${className || ""}`.trim(),
|
|
1199
|
+
style: {
|
|
1200
|
+
...maskStyle,
|
|
1201
|
+
...style
|
|
1202
|
+
},
|
|
1203
|
+
...restProps,
|
|
1204
|
+
children: beams
|
|
1205
|
+
}
|
|
1206
|
+
);
|
|
1207
|
+
};
|
|
1208
|
+
var BorderBeam_default = BorderBeam;
|
|
868
1209
|
// Annotate the CommonJS export names for ESM import in node:
|
|
869
1210
|
0 && (module.exports = {
|
|
1211
|
+
BorderBeam,
|
|
870
1212
|
CollapseBox,
|
|
871
1213
|
DisabledBox,
|
|
1214
|
+
Masonry,
|
|
872
1215
|
Splitter
|
|
873
1216
|
});
|
|
874
1217
|
//# sourceMappingURL=index.cjs.map
|