@canlooks/can-ui 0.0.39 → 0.0.41
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/dist/cjs/components/descriptions/descriptionItem.js +3 -3
- package/dist/cjs/components/descriptions/descriptions.js +5 -5
- package/dist/cjs/components/slidableActions/slidableActionsAction.js +1 -1
- package/dist/cjs/components/waterfall/waterfall.d.ts +3 -4
- package/dist/cjs/components/waterfall/waterfall.js +31 -23
- package/dist/cjs/components/waterfall/waterfall.style.js +2 -14
- package/dist/cjs/components/waterfall/waterfallItem.d.ts +7 -0
- package/dist/cjs/components/waterfall/waterfallItem.js +38 -0
- package/dist/cjs/utils/style.d.ts +2 -1
- package/dist/cjs/utils/style.js +11 -5
- package/dist/esm/components/descriptions/descriptionItem.js +3 -3
- package/dist/esm/components/descriptions/descriptions.js +5 -5
- package/dist/esm/components/slidableActions/slidableActionsAction.js +1 -1
- package/dist/esm/components/waterfall/waterfall.d.ts +3 -4
- package/dist/esm/components/waterfall/waterfall.js +31 -24
- package/dist/esm/components/waterfall/waterfall.style.js +2 -14
- package/dist/esm/components/waterfall/waterfallItem.d.ts +7 -0
- package/dist/esm/components/waterfall/waterfallItem.js +34 -0
- package/dist/esm/utils/style.d.ts +2 -1
- package/dist/esm/utils/style.js +12 -6
- package/package.json +1 -1
|
@@ -19,13 +19,13 @@ size, labelWidth, colon, labelPlacement, disableMargin, disablePadding, span = {
|
|
|
19
19
|
labelPlacement ??= context.labelPlacement ?? 'left';
|
|
20
20
|
disableMargin ??= context.disableMargin;
|
|
21
21
|
disablePadding ??= context.disablePadding;
|
|
22
|
-
const spanNum = (0, utils_1.useResponsiveValue)(span);
|
|
22
|
+
const spanNum = (0, utils_1.useResponsiveValue)(span, variant === 'grid');
|
|
23
23
|
return variant === 'grid'
|
|
24
24
|
? (0, jsx_runtime_1.jsxs)(grid_1.GridItem, { ...props, css: descriptions_style_1.gridItemStyle, className: (0, utils_1.clsx)(descriptions_style_1.classes.item, props.className), span: span, "data-size": size, "data-label-placement": labelPlacement, "data-disable-margin": disableMargin, children: [!!label &&
|
|
25
25
|
(0, jsx_runtime_1.jsxs)("div", { className: descriptions_style_1.classes.label, style: { width: labelWidth }, children: [label, !!colon && (labelPlacement === 'left' || labelPlacement === 'right') &&
|
|
26
26
|
(0, jsx_runtime_1.jsx)("div", { className: descriptions_style_1.classes.colon, children: colon })] }), (0, jsx_runtime_1.jsx)("div", { className: descriptions_style_1.classes.content, children: content ?? props.children })] })
|
|
27
27
|
: labelPlacement === 'top'
|
|
28
|
-
? (0, jsx_runtime_1.jsx)("td", { className: descriptions_style_1.classes.vertical, colSpan: spanNum, children: (0, jsx_runtime_1.jsxs)("div", { className: descriptions_style_1.classes.verticalColWrap, children: [(0, jsx_runtime_1.jsx)("div", { className: `${descriptions_style_1.classes.col} ${descriptions_style_1.classes.labelCol}`, "data-size": size, children: label }), (0, jsx_runtime_1.jsx)("div", { className: `${descriptions_style_1.classes.col} ${descriptions_style_1.classes.contentCol}`, "data-size": size, "data-disable-padding": disablePadding, children: content ?? props.children })] }) })
|
|
28
|
+
? (0, jsx_runtime_1.jsx)("td", { className: descriptions_style_1.classes.vertical, colSpan: spanNum.current, children: (0, jsx_runtime_1.jsxs)("div", { className: descriptions_style_1.classes.verticalColWrap, children: [(0, jsx_runtime_1.jsx)("div", { className: `${descriptions_style_1.classes.col} ${descriptions_style_1.classes.labelCol}`, "data-size": size, children: label }), (0, jsx_runtime_1.jsx)("div", { className: `${descriptions_style_1.classes.col} ${descriptions_style_1.classes.contentCol}`, "data-size": size, "data-disable-padding": disablePadding, children: content ?? props.children })] }) })
|
|
29
29
|
: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [!!label &&
|
|
30
|
-
(0, jsx_runtime_1.jsx)("td", { className: `${descriptions_style_1.classes.col} ${descriptions_style_1.classes.labelCol}`, "data-size": size, children: label }), (0, jsx_runtime_1.jsx)("td", { className: `${descriptions_style_1.classes.col} ${descriptions_style_1.classes.contentCol}`, colSpan: spanNum * 2 - 1, "data-size": size, "data-disable-padding": disablePadding, children: content ?? props.children })] });
|
|
30
|
+
(0, jsx_runtime_1.jsx)("td", { className: `${descriptions_style_1.classes.col} ${descriptions_style_1.classes.labelCol}`, "data-size": size, children: label }), (0, jsx_runtime_1.jsx)("td", { className: `${descriptions_style_1.classes.col} ${descriptions_style_1.classes.contentCol}`, colSpan: spanNum.current * 2 - 1, "data-size": size, "data-disable-padding": disablePadding, children: content ?? props.children })] });
|
|
31
31
|
});
|
|
@@ -27,17 +27,17 @@ exports.Descriptions = (0, react_2.memo)(({ size, labelWidth, colon = ':', label
|
|
|
27
27
|
// 最后一项沾满剩余行空间
|
|
28
28
|
flex: i === items.length - 1 ? 1 : void 0, ...itemProps, key: itemProps.key ?? i })) || props.children;
|
|
29
29
|
};
|
|
30
|
-
const columnCountNum = (0, utils_1.useResponsiveValue)(columnCount);
|
|
30
|
+
const columnCountNum = (0, utils_1.useResponsiveValue)(columnCount, variant === 'grid');
|
|
31
31
|
const renderTableItems = () => {
|
|
32
32
|
const actualItems = items || react_2.Children.map(props.children, c => (0, react_2.isValidElement)(c) ? c.props : c);
|
|
33
33
|
if (actualItems?.length) {
|
|
34
34
|
const rows = [];
|
|
35
35
|
for (let i = 0, { length } = actualItems; i < length; i++) {
|
|
36
|
-
const cols = rows[Math.floor(i / columnCountNum)] ||= [];
|
|
36
|
+
const cols = rows[Math.floor(i / columnCountNum.current)] ||= [];
|
|
37
37
|
const itemProps = actualItems[i];
|
|
38
|
-
cols.push((0, react_1.createElement)(ItemComponent
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
cols.push((0, react_1.createElement)(ItemComponent, { ...itemProps, key: itemProps.key ?? i,
|
|
39
|
+
// 最后一项沾满剩余行空间
|
|
40
|
+
span: i === actualItems.length - 1 ? columnCountNum.current - i % columnCountNum.current : itemProps.span, className: (0, utils_1.clsx)(descriptions_style_1.classes.col, itemProps) }));
|
|
41
41
|
}
|
|
42
42
|
return rows.map((r, i) => (0, jsx_runtime_1.jsx)("tr", { children: r }, i));
|
|
43
43
|
}
|
|
@@ -35,5 +35,5 @@ exports.SlidableActionsAction = (0, react_1.memo)(({ color = 'default', label, i
|
|
|
35
35
|
return ((0, jsx_runtime_1.jsx)("div", { ...props, className: slidableActions_style_1.classes.actionItem, style: {
|
|
36
36
|
translate: `${currentTranslate}px 0`,
|
|
37
37
|
backgroundColor
|
|
38
|
-
}, children: (0, jsx_runtime_1.jsx)(button_1.Button, { ...buttonProps, ref: (0, utils_1.cloneRef)(buttonProps?.ref, innerButtonRef), className: (0, utils_1.clsx)(slidableActions_style_1.classes.actionItemWrap, buttonProps?.className), prefix: icon, variant: "plain", color: "
|
|
38
|
+
}, children: (0, jsx_runtime_1.jsx)(button_1.Button, { ...buttonProps, ref: (0, utils_1.cloneRef)(buttonProps?.ref, innerButtonRef), className: (0, utils_1.clsx)(slidableActions_style_1.classes.actionItemWrap, buttonProps?.className), prefix: icon, variant: "plain", color: "text.primary", children: label }) }));
|
|
39
39
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { ResponsiveProp } from '../../types';
|
|
2
|
-
|
|
3
|
-
export interface WaterfallProps extends Omit<TransportStyleProps, 'padding' | 'paddingLeft' | 'paddingRight' | 'paddingTop' | 'paddingBottom'> {
|
|
1
|
+
import { DivProps, ResponsiveProp } from '../../types';
|
|
2
|
+
export interface WaterfallProps extends DivProps {
|
|
4
3
|
/** 布局列数,默认为`{xs: 4}` */
|
|
5
4
|
columnCount?: ResponsiveProp;
|
|
6
5
|
gap?: ResponsiveProp;
|
|
7
6
|
columnGap?: ResponsiveProp;
|
|
8
7
|
rowGap?: ResponsiveProp;
|
|
9
8
|
}
|
|
10
|
-
export declare
|
|
9
|
+
export declare const Waterfall: ({ columnCount, gap, columnGap, rowGap, ...props }: WaterfallProps) => import("@emotion/react/jsx-runtime").JSX.Element;
|
|
@@ -1,39 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Waterfall =
|
|
3
|
+
exports.Waterfall = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const waterfall_style_1 = require("./waterfall.style");
|
|
7
|
+
const waterfallItem_1 = require("./waterfallItem");
|
|
7
8
|
const utils_1 = require("../../utils");
|
|
8
|
-
const
|
|
9
|
-
function Waterfall({ columnCount = { xs: 4 }, gap = { xs: 0 }, columnGap, rowGap, ...props }) {
|
|
9
|
+
const Waterfall = ({ columnCount = { xs: 4 }, gap = 0, columnGap, rowGap, ...props }) => {
|
|
10
10
|
columnCount = (0, utils_1.toResponsiveValue)(columnCount);
|
|
11
11
|
gap = (0, utils_1.toResponsiveValue)(gap);
|
|
12
12
|
columnGap = (0, utils_1.toResponsiveValue)(columnGap) ?? gap;
|
|
13
13
|
rowGap = (0, utils_1.toResponsiveValue)(rowGap) ?? gap;
|
|
14
|
-
const
|
|
15
|
-
const
|
|
14
|
+
const columnCountNum = (0, utils_1.useResponsiveValue)(columnCount);
|
|
15
|
+
const containerRef = (0, react_1.useRef)(null);
|
|
16
16
|
const elements = (0, react_1.useRef)([]);
|
|
17
17
|
elements.current = [];
|
|
18
18
|
const computeItemOrder = () => {
|
|
19
|
-
const heights = Array(
|
|
19
|
+
const heights = Array(columnCountNum.current).fill(0);
|
|
20
20
|
elements.current.forEach(el => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
el.style.order = order + '';
|
|
25
|
-
}
|
|
21
|
+
const order = heights.indexOf(Math.min(...heights));
|
|
22
|
+
heights[order] += el.offsetHeight;
|
|
23
|
+
el.style.order = order + '';
|
|
26
24
|
});
|
|
27
|
-
|
|
25
|
+
containerRef.current.style.height = Math.max(...heights) + 1 + 'px';
|
|
28
26
|
};
|
|
29
27
|
const resizeObserver = (0, react_1.useRef)(void 0);
|
|
30
28
|
resizeObserver.current ||= new ResizeObserver(computeItemOrder);
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
resizeObserver.current.observe(
|
|
35
|
-
}
|
|
36
|
-
};
|
|
29
|
+
const pendingItems = [];
|
|
30
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
31
|
+
Promise.all(pendingItems).then(() => {
|
|
32
|
+
elements.current.forEach(el => resizeObserver.current.observe(el));
|
|
33
|
+
});
|
|
34
|
+
});
|
|
37
35
|
const isInitialized = (0, react_1.useRef)(false);
|
|
38
36
|
(0, react_1.useEffect)(() => {
|
|
39
37
|
if (!isInitialized.current) {
|
|
@@ -41,9 +39,19 @@ function Waterfall({ columnCount = { xs: 4 }, gap = { xs: 0 }, columnGap, rowGap
|
|
|
41
39
|
return;
|
|
42
40
|
}
|
|
43
41
|
computeItemOrder();
|
|
44
|
-
}, [
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
}, [columnCountNum.current]);
|
|
43
|
+
(0, react_1.useEffect)(() => () => {
|
|
44
|
+
resizeObserver.current.disconnect();
|
|
45
|
+
}, []);
|
|
46
|
+
return ((0, jsx_runtime_1.jsx)("div", { ...props, ref: (0, utils_1.cloneRef)(containerRef, props.ref), css: (0, waterfall_style_1.useStyle)({ columnCount, columnGap, rowGap }), className: (0, utils_1.clsx)(waterfall_style_1.classes.root, props.className), children: react_1.Children.map(props.children, child => {
|
|
47
|
+
if (!(0, react_1.isValidElement)(child)) {
|
|
48
|
+
throw Error('Children of <Waterfall> must be element');
|
|
49
|
+
}
|
|
50
|
+
let onLoad;
|
|
51
|
+
pendingItems.push(new Promise(r => onLoad = r));
|
|
52
|
+
return ((0, jsx_runtime_1.jsx)(waterfallItem_1.WaterfallItem, { ref: r => {
|
|
53
|
+
r && elements.current.push(r);
|
|
54
|
+
}, child: child, onLoad: onLoad }));
|
|
48
55
|
}) }));
|
|
49
|
-
}
|
|
56
|
+
};
|
|
57
|
+
exports.Waterfall = Waterfall;
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.classes = void 0;
|
|
4
4
|
exports.useStyle = useStyle;
|
|
5
|
-
const react_1 = require("@emotion/react");
|
|
6
5
|
const utils_1 = require("../../utils");
|
|
7
|
-
|
|
6
|
+
const react_1 = require("@emotion/react");
|
|
7
|
+
exports.classes = (0, utils_1.defineClasses)('waterfall', [
|
|
8
8
|
'item'
|
|
9
9
|
]);
|
|
10
10
|
function useStyle({ columnCount, columnGap, rowGap }) {
|
|
@@ -19,17 +19,5 @@ function useStyle({ columnCount, columnGap, rowGap }) {
|
|
|
19
19
|
flex-direction: column;
|
|
20
20
|
flex-wrap: wrap;
|
|
21
21
|
column-gap: var(--waterfall-column-gap);
|
|
22
|
-
//row-gap: var(--waterfall-row-gap);
|
|
23
|
-
//overflow: hidden;
|
|
24
|
-
|
|
25
|
-
.${exports.classes.item} {
|
|
26
|
-
width: calc((100% - var(--waterfall-column-gap) * (var(--waterfall-columnCount) - 1)) / var(--waterfall-columnCount));
|
|
27
|
-
padding-bottom: var(--waterfall-row-gap);
|
|
28
|
-
|
|
29
|
-
> img {
|
|
30
|
-
width: 100%;
|
|
31
|
-
display: flex;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
22
|
`);
|
|
35
23
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ReactElement, Ref } from 'react';
|
|
2
|
+
export type WaterfallItemProps = {
|
|
3
|
+
ref: Ref<HTMLElement>;
|
|
4
|
+
onLoad(): void;
|
|
5
|
+
child: ReactElement<any>;
|
|
6
|
+
};
|
|
7
|
+
export declare const WaterfallItem: ({ ref, onLoad, child }: WaterfallItemProps) => ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WaterfallItem = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const waterfall_style_1 = require("./waterfall.style");
|
|
6
|
+
const utils_1 = require("../../utils");
|
|
7
|
+
const WaterfallItem = ({ ref, onLoad, child }) => {
|
|
8
|
+
const innerRef = (0, react_1.useRef)(null);
|
|
9
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
10
|
+
const el = innerRef.current;
|
|
11
|
+
if (!el) {
|
|
12
|
+
throw Error(`Children of <Waterfall> must expose 'ref' prop`);
|
|
13
|
+
}
|
|
14
|
+
const imgTags = el.querySelectorAll('img');
|
|
15
|
+
if (!imgTags.length) {
|
|
16
|
+
onLoad();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
Promise.all([...imgTags].map(img => {
|
|
20
|
+
if (!img.complete) {
|
|
21
|
+
return new Promise(resolve => {
|
|
22
|
+
img.addEventListener('load', resolve, { once: true });
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
})).then(() => onLoad());
|
|
26
|
+
});
|
|
27
|
+
const clonedRef = (0, react_1.useCallback)((0, utils_1.cloneRef)(child.props.ref, innerRef, ref), [child.props.ref]);
|
|
28
|
+
return (0, react_1.cloneElement)(child, {
|
|
29
|
+
ref: clonedRef,
|
|
30
|
+
className: (0, utils_1.clsx)(waterfall_style_1.classes.item, child.props.className),
|
|
31
|
+
style: {
|
|
32
|
+
width: 'calc((100% - var(--waterfall-column-gap) * (var(--waterfall-columnCount) - 1)) / var(--waterfall-columnCount))',
|
|
33
|
+
paddingBottom: 'var(--waterfall-row-gap)',
|
|
34
|
+
...child.props.style
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
exports.WaterfallItem = WaterfallItem;
|
|
@@ -84,8 +84,9 @@ export declare function toResponsiveValue<T = number>(prop: ResponsiveProp<T>):
|
|
|
84
84
|
/**
|
|
85
85
|
* 使用hooks监听响应式值的变化,通常用于css不能满足需求的情况
|
|
86
86
|
* @param prop
|
|
87
|
+
* @param disabled
|
|
87
88
|
*/
|
|
88
|
-
export declare function useResponsiveValue<T = number>(prop: ResponsiveProp<T
|
|
89
|
+
export declare function useResponsiveValue<T = number>(prop: ResponsiveProp<T>, disabled?: boolean): import("react").RefObject<NonNullable<T>>;
|
|
89
90
|
/**
|
|
90
91
|
* 使用状态对应的颜色
|
|
91
92
|
* @param status
|
package/dist/cjs/utils/style.js
CHANGED
|
@@ -18,6 +18,7 @@ const react_1 = require("react");
|
|
|
18
18
|
const theme_1 = require("../components/theme");
|
|
19
19
|
const utils_1 = require("./utils");
|
|
20
20
|
const color_1 = tslib_1.__importDefault(require("color"));
|
|
21
|
+
const hooks_1 = require("./hooks");
|
|
21
22
|
/**
|
|
22
23
|
* 为类名添加统一前缀,通常为内部使用
|
|
23
24
|
* @param prefixName
|
|
@@ -186,14 +187,16 @@ function toResponsiveValue(prop) {
|
|
|
186
187
|
/**
|
|
187
188
|
* 使用hooks监听响应式值的变化,通常用于css不能满足需求的情况
|
|
188
189
|
* @param prop
|
|
190
|
+
* @param disabled
|
|
189
191
|
*/
|
|
190
|
-
function useResponsiveValue(prop) {
|
|
192
|
+
function useResponsiveValue(prop, disabled = false) {
|
|
191
193
|
const responsiveObj = toResponsiveValue(prop);
|
|
192
194
|
const { breakpoints } = (0, theme_1.useTheme)();
|
|
195
|
+
const syncBreakpoints = (0, hooks_1.useSync)(breakpoints);
|
|
193
196
|
const fn = () => {
|
|
194
197
|
let maxBreakpoint = 'xs';
|
|
195
|
-
for (const k in
|
|
196
|
-
if (window.innerWidth <
|
|
198
|
+
for (const k in syncBreakpoints.current) {
|
|
199
|
+
if (window.innerWidth < syncBreakpoints.current[k]) {
|
|
197
200
|
break;
|
|
198
201
|
}
|
|
199
202
|
if (k in responsiveObj) {
|
|
@@ -202,8 +205,11 @@ function useResponsiveValue(prop) {
|
|
|
202
205
|
}
|
|
203
206
|
return responsiveObj[maxBreakpoint];
|
|
204
207
|
};
|
|
205
|
-
const [value, setValue] = (0,
|
|
208
|
+
const [value, setValue] = (0, hooks_1.useDerivedState)(fn, [breakpoints]);
|
|
206
209
|
(0, react_1.useEffect)(() => {
|
|
210
|
+
if (disabled) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
207
213
|
const resize = () => {
|
|
208
214
|
setValue(fn());
|
|
209
215
|
};
|
|
@@ -211,7 +217,7 @@ function useResponsiveValue(prop) {
|
|
|
211
217
|
return () => {
|
|
212
218
|
removeEventListener('resize', resize);
|
|
213
219
|
};
|
|
214
|
-
}, []);
|
|
220
|
+
}, [disabled]);
|
|
215
221
|
return value;
|
|
216
222
|
}
|
|
217
223
|
/**
|
|
@@ -16,13 +16,13 @@ size, labelWidth, colon, labelPlacement, disableMargin, disablePadding, span = {
|
|
|
16
16
|
labelPlacement ??= context.labelPlacement ?? 'left';
|
|
17
17
|
disableMargin ??= context.disableMargin;
|
|
18
18
|
disablePadding ??= context.disablePadding;
|
|
19
|
-
const spanNum = useResponsiveValue(span);
|
|
19
|
+
const spanNum = useResponsiveValue(span, variant === 'grid');
|
|
20
20
|
return variant === 'grid'
|
|
21
21
|
? _jsxs(GridItem, { ...props, css: gridItemStyle, className: clsx(classes.item, props.className), span: span, "data-size": size, "data-label-placement": labelPlacement, "data-disable-margin": disableMargin, children: [!!label &&
|
|
22
22
|
_jsxs("div", { className: classes.label, style: { width: labelWidth }, children: [label, !!colon && (labelPlacement === 'left' || labelPlacement === 'right') &&
|
|
23
23
|
_jsx("div", { className: classes.colon, children: colon })] }), _jsx("div", { className: classes.content, children: content ?? props.children })] })
|
|
24
24
|
: labelPlacement === 'top'
|
|
25
|
-
? _jsx("td", { className: classes.vertical, colSpan: spanNum, children: _jsxs("div", { className: classes.verticalColWrap, children: [_jsx("div", { className: `${classes.col} ${classes.labelCol}`, "data-size": size, children: label }), _jsx("div", { className: `${classes.col} ${classes.contentCol}`, "data-size": size, "data-disable-padding": disablePadding, children: content ?? props.children })] }) })
|
|
25
|
+
? _jsx("td", { className: classes.vertical, colSpan: spanNum.current, children: _jsxs("div", { className: classes.verticalColWrap, children: [_jsx("div", { className: `${classes.col} ${classes.labelCol}`, "data-size": size, children: label }), _jsx("div", { className: `${classes.col} ${classes.contentCol}`, "data-size": size, "data-disable-padding": disablePadding, children: content ?? props.children })] }) })
|
|
26
26
|
: _jsxs(_Fragment, { children: [!!label &&
|
|
27
|
-
_jsx("td", { className: `${classes.col} ${classes.labelCol}`, "data-size": size, children: label }), _jsx("td", { className: `${classes.col} ${classes.contentCol}`, colSpan: spanNum * 2 - 1, "data-size": size, "data-disable-padding": disablePadding, children: content ?? props.children })] });
|
|
27
|
+
_jsx("td", { className: `${classes.col} ${classes.labelCol}`, "data-size": size, children: label }), _jsx("td", { className: `${classes.col} ${classes.contentCol}`, colSpan: spanNum.current * 2 - 1, "data-size": size, "data-disable-padding": disablePadding, children: content ?? props.children })] });
|
|
28
28
|
});
|
|
@@ -23,17 +23,17 @@ export const Descriptions = memo(({ size, labelWidth, colon = ':', labelPlacemen
|
|
|
23
23
|
// 最后一项沾满剩余行空间
|
|
24
24
|
flex: i === items.length - 1 ? 1 : void 0, ...itemProps, key: itemProps.key ?? i })) || props.children;
|
|
25
25
|
};
|
|
26
|
-
const columnCountNum = useResponsiveValue(columnCount);
|
|
26
|
+
const columnCountNum = useResponsiveValue(columnCount, variant === 'grid');
|
|
27
27
|
const renderTableItems = () => {
|
|
28
28
|
const actualItems = items || Children.map(props.children, c => isValidElement(c) ? c.props : c);
|
|
29
29
|
if (actualItems?.length) {
|
|
30
30
|
const rows = [];
|
|
31
31
|
for (let i = 0, { length } = actualItems; i < length; i++) {
|
|
32
|
-
const cols = rows[Math.floor(i / columnCountNum)] ||= [];
|
|
32
|
+
const cols = rows[Math.floor(i / columnCountNum.current)] ||= [];
|
|
33
33
|
const itemProps = actualItems[i];
|
|
34
|
-
cols.push(_createElement(ItemComponent
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
cols.push(_createElement(ItemComponent, { ...itemProps, key: itemProps.key ?? i,
|
|
35
|
+
// 最后一项沾满剩余行空间
|
|
36
|
+
span: i === actualItems.length - 1 ? columnCountNum.current - i % columnCountNum.current : itemProps.span, className: clsx(classes.col, itemProps) }));
|
|
37
37
|
}
|
|
38
38
|
return rows.map((r, i) => _jsx("tr", { children: r }, i));
|
|
39
39
|
}
|
|
@@ -32,5 +32,5 @@ export const SlidableActionsAction = memo(({ color = 'default', label, icon, but
|
|
|
32
32
|
return (_jsx("div", { ...props, className: classes.actionItem, style: {
|
|
33
33
|
translate: `${currentTranslate}px 0`,
|
|
34
34
|
backgroundColor
|
|
35
|
-
}, children: _jsx(Button, { ...buttonProps, ref: cloneRef(buttonProps?.ref, innerButtonRef), className: clsx(classes.actionItemWrap, buttonProps?.className), prefix: icon, variant: "plain", color: "
|
|
35
|
+
}, children: _jsx(Button, { ...buttonProps, ref: cloneRef(buttonProps?.ref, innerButtonRef), className: clsx(classes.actionItemWrap, buttonProps?.className), prefix: icon, variant: "plain", color: "text.primary", children: label }) }));
|
|
36
36
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { ResponsiveProp } from '../../types';
|
|
2
|
-
|
|
3
|
-
export interface WaterfallProps extends Omit<TransportStyleProps, 'padding' | 'paddingLeft' | 'paddingRight' | 'paddingTop' | 'paddingBottom'> {
|
|
1
|
+
import { DivProps, ResponsiveProp } from '../../types';
|
|
2
|
+
export interface WaterfallProps extends DivProps {
|
|
4
3
|
/** 布局列数,默认为`{xs: 4}` */
|
|
5
4
|
columnCount?: ResponsiveProp;
|
|
6
5
|
gap?: ResponsiveProp;
|
|
7
6
|
columnGap?: ResponsiveProp;
|
|
8
7
|
rowGap?: ResponsiveProp;
|
|
9
8
|
}
|
|
10
|
-
export declare
|
|
9
|
+
export declare const Waterfall: ({ columnCount, gap, columnGap, rowGap, ...props }: WaterfallProps) => import("@emotion/react/jsx-runtime").JSX.Element;
|
|
@@ -1,36 +1,34 @@
|
|
|
1
1
|
import { jsx as _jsx } from "@emotion/react/jsx-runtime";
|
|
2
|
-
import { Children, isValidElement, useEffect, useRef } from 'react';
|
|
2
|
+
import { Children, isValidElement, useEffect, useLayoutEffect, useRef } from 'react';
|
|
3
3
|
import { classes, useStyle } from './waterfall.style';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
export
|
|
4
|
+
import { WaterfallItem } from './waterfallItem';
|
|
5
|
+
import { cloneRef, clsx, toResponsiveValue, useResponsiveValue } from '../../utils';
|
|
6
|
+
export const Waterfall = ({ columnCount = { xs: 4 }, gap = 0, columnGap, rowGap, ...props }) => {
|
|
7
7
|
columnCount = toResponsiveValue(columnCount);
|
|
8
8
|
gap = toResponsiveValue(gap);
|
|
9
9
|
columnGap = toResponsiveValue(columnGap) ?? gap;
|
|
10
10
|
rowGap = toResponsiveValue(rowGap) ?? gap;
|
|
11
|
-
const
|
|
12
|
-
const
|
|
11
|
+
const columnCountNum = useResponsiveValue(columnCount);
|
|
12
|
+
const containerRef = useRef(null);
|
|
13
13
|
const elements = useRef([]);
|
|
14
14
|
elements.current = [];
|
|
15
15
|
const computeItemOrder = () => {
|
|
16
|
-
const heights = Array(
|
|
16
|
+
const heights = Array(columnCountNum.current).fill(0);
|
|
17
17
|
elements.current.forEach(el => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
el.style.order = order + '';
|
|
22
|
-
}
|
|
18
|
+
const order = heights.indexOf(Math.min(...heights));
|
|
19
|
+
heights[order] += el.offsetHeight;
|
|
20
|
+
el.style.order = order + '';
|
|
23
21
|
});
|
|
24
|
-
|
|
22
|
+
containerRef.current.style.height = Math.max(...heights) + 1 + 'px';
|
|
25
23
|
};
|
|
26
24
|
const resizeObserver = useRef(void 0);
|
|
27
25
|
resizeObserver.current ||= new ResizeObserver(computeItemOrder);
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
resizeObserver.current.observe(
|
|
32
|
-
}
|
|
33
|
-
};
|
|
26
|
+
const pendingItems = [];
|
|
27
|
+
useLayoutEffect(() => {
|
|
28
|
+
Promise.all(pendingItems).then(() => {
|
|
29
|
+
elements.current.forEach(el => resizeObserver.current.observe(el));
|
|
30
|
+
});
|
|
31
|
+
});
|
|
34
32
|
const isInitialized = useRef(false);
|
|
35
33
|
useEffect(() => {
|
|
36
34
|
if (!isInitialized.current) {
|
|
@@ -38,9 +36,18 @@ export function Waterfall({ columnCount = { xs: 4 }, gap = { xs: 0 }, columnGap,
|
|
|
38
36
|
return;
|
|
39
37
|
}
|
|
40
38
|
computeItemOrder();
|
|
41
|
-
}, [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
}, [columnCountNum.current]);
|
|
40
|
+
useEffect(() => () => {
|
|
41
|
+
resizeObserver.current.disconnect();
|
|
42
|
+
}, []);
|
|
43
|
+
return (_jsx("div", { ...props, ref: cloneRef(containerRef, props.ref), css: useStyle({ columnCount, columnGap, rowGap }), className: clsx(classes.root, props.className), children: Children.map(props.children, child => {
|
|
44
|
+
if (!isValidElement(child)) {
|
|
45
|
+
throw Error('Children of <Waterfall> must be element');
|
|
46
|
+
}
|
|
47
|
+
let onLoad;
|
|
48
|
+
pendingItems.push(new Promise(r => onLoad = r));
|
|
49
|
+
return (_jsx(WaterfallItem, { ref: r => {
|
|
50
|
+
r && elements.current.push(r);
|
|
51
|
+
}, child: child, onLoad: onLoad }));
|
|
45
52
|
}) }));
|
|
46
|
-
}
|
|
53
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { defineClasses, responsiveVariables, useCss } from '../../utils';
|
|
1
2
|
import { css } from '@emotion/react';
|
|
2
|
-
|
|
3
|
-
export const classes = defineInnerClasses('waterfall', [
|
|
3
|
+
export const classes = defineClasses('waterfall', [
|
|
4
4
|
'item'
|
|
5
5
|
]);
|
|
6
6
|
export function useStyle({ columnCount, columnGap, rowGap }) {
|
|
@@ -15,17 +15,5 @@ export function useStyle({ columnCount, columnGap, rowGap }) {
|
|
|
15
15
|
flex-direction: column;
|
|
16
16
|
flex-wrap: wrap;
|
|
17
17
|
column-gap: var(--waterfall-column-gap);
|
|
18
|
-
//row-gap: var(--waterfall-row-gap);
|
|
19
|
-
//overflow: hidden;
|
|
20
|
-
|
|
21
|
-
.${classes.item} {
|
|
22
|
-
width: calc((100% - var(--waterfall-column-gap) * (var(--waterfall-columnCount) - 1)) / var(--waterfall-columnCount));
|
|
23
|
-
padding-bottom: var(--waterfall-row-gap);
|
|
24
|
-
|
|
25
|
-
> img {
|
|
26
|
-
width: 100%;
|
|
27
|
-
display: flex;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
18
|
`);
|
|
31
19
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ReactElement, Ref } from 'react';
|
|
2
|
+
export type WaterfallItemProps = {
|
|
3
|
+
ref: Ref<HTMLElement>;
|
|
4
|
+
onLoad(): void;
|
|
5
|
+
child: ReactElement<any>;
|
|
6
|
+
};
|
|
7
|
+
export declare const WaterfallItem: ({ ref, onLoad, child }: WaterfallItemProps) => ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { cloneElement, useCallback, useLayoutEffect, useRef } from 'react';
|
|
2
|
+
import { classes } from './waterfall.style';
|
|
3
|
+
import { cloneRef, clsx } from '../../utils';
|
|
4
|
+
export const WaterfallItem = ({ ref, onLoad, child }) => {
|
|
5
|
+
const innerRef = useRef(null);
|
|
6
|
+
useLayoutEffect(() => {
|
|
7
|
+
const el = innerRef.current;
|
|
8
|
+
if (!el) {
|
|
9
|
+
throw Error(`Children of <Waterfall> must expose 'ref' prop`);
|
|
10
|
+
}
|
|
11
|
+
const imgTags = el.querySelectorAll('img');
|
|
12
|
+
if (!imgTags.length) {
|
|
13
|
+
onLoad();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
Promise.all([...imgTags].map(img => {
|
|
17
|
+
if (!img.complete) {
|
|
18
|
+
return new Promise(resolve => {
|
|
19
|
+
img.addEventListener('load', resolve, { once: true });
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
})).then(() => onLoad());
|
|
23
|
+
});
|
|
24
|
+
const clonedRef = useCallback(cloneRef(child.props.ref, innerRef, ref), [child.props.ref]);
|
|
25
|
+
return cloneElement(child, {
|
|
26
|
+
ref: clonedRef,
|
|
27
|
+
className: clsx(classes.item, child.props.className),
|
|
28
|
+
style: {
|
|
29
|
+
width: 'calc((100% - var(--waterfall-column-gap) * (var(--waterfall-columnCount) - 1)) / var(--waterfall-columnCount))',
|
|
30
|
+
paddingBottom: 'var(--waterfall-row-gap)',
|
|
31
|
+
...child.props.style
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
};
|
|
@@ -84,8 +84,9 @@ export declare function toResponsiveValue<T = number>(prop: ResponsiveProp<T>):
|
|
|
84
84
|
/**
|
|
85
85
|
* 使用hooks监听响应式值的变化,通常用于css不能满足需求的情况
|
|
86
86
|
* @param prop
|
|
87
|
+
* @param disabled
|
|
87
88
|
*/
|
|
88
|
-
export declare function useResponsiveValue<T = number>(prop: ResponsiveProp<T
|
|
89
|
+
export declare function useResponsiveValue<T = number>(prop: ResponsiveProp<T>, disabled?: boolean): import("react").RefObject<NonNullable<T>>;
|
|
89
90
|
/**
|
|
90
91
|
* 使用状态对应的颜色
|
|
91
92
|
* @param status
|
package/dist/esm/utils/style.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { useEffect, useMemo
|
|
1
|
+
import { useEffect, useMemo } from 'react';
|
|
2
2
|
import { defaultBreakpoints, useTheme } from '../components/theme';
|
|
3
3
|
import { humpToSegmented, isUnset } from './utils';
|
|
4
4
|
import Color from 'color';
|
|
5
|
+
import { useDerivedState, useSync } from './hooks';
|
|
5
6
|
/**
|
|
6
7
|
* 为类名添加统一前缀,通常为内部使用
|
|
7
8
|
* @param prefixName
|
|
@@ -170,14 +171,16 @@ export function toResponsiveValue(prop) {
|
|
|
170
171
|
/**
|
|
171
172
|
* 使用hooks监听响应式值的变化,通常用于css不能满足需求的情况
|
|
172
173
|
* @param prop
|
|
174
|
+
* @param disabled
|
|
173
175
|
*/
|
|
174
|
-
export function useResponsiveValue(prop) {
|
|
176
|
+
export function useResponsiveValue(prop, disabled = false) {
|
|
175
177
|
const responsiveObj = toResponsiveValue(prop);
|
|
176
178
|
const { breakpoints } = useTheme();
|
|
179
|
+
const syncBreakpoints = useSync(breakpoints);
|
|
177
180
|
const fn = () => {
|
|
178
181
|
let maxBreakpoint = 'xs';
|
|
179
|
-
for (const k in
|
|
180
|
-
if (window.innerWidth <
|
|
182
|
+
for (const k in syncBreakpoints.current) {
|
|
183
|
+
if (window.innerWidth < syncBreakpoints.current[k]) {
|
|
181
184
|
break;
|
|
182
185
|
}
|
|
183
186
|
if (k in responsiveObj) {
|
|
@@ -186,8 +189,11 @@ export function useResponsiveValue(prop) {
|
|
|
186
189
|
}
|
|
187
190
|
return responsiveObj[maxBreakpoint];
|
|
188
191
|
};
|
|
189
|
-
const [value, setValue] =
|
|
192
|
+
const [value, setValue] = useDerivedState(fn, [breakpoints]);
|
|
190
193
|
useEffect(() => {
|
|
194
|
+
if (disabled) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
191
197
|
const resize = () => {
|
|
192
198
|
setValue(fn());
|
|
193
199
|
};
|
|
@@ -195,7 +201,7 @@ export function useResponsiveValue(prop) {
|
|
|
195
201
|
return () => {
|
|
196
202
|
removeEventListener('resize', resize);
|
|
197
203
|
};
|
|
198
|
-
}, []);
|
|
204
|
+
}, [disabled]);
|
|
199
205
|
return value;
|
|
200
206
|
}
|
|
201
207
|
/**
|