plain-design 1.0.0-beta.30 → 1.0.0-beta.32
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/plain-design.commonjs.min.js +3 -3
- package/dist/plain-design.min.css +11 -6
- package/dist/plain-design.min.js +3 -3
- package/dist/report.html +2 -2
- package/package.json +3 -3
- package/src/packages/components/$previewer/ImagePreviewerFixedContainer.tsx +107 -0
- package/src/packages/components/$previewer/image-previewer-fixed-container.scss +18 -0
- package/src/packages/components/$previewer/index.tsx +52 -0
- package/src/packages/components/Application/service/useApplicationService.tsx +2 -0
- package/src/packages/components/Carousel/carousel.scss +391 -0
- package/src/packages/components/Carousel/index.tsx +569 -22
- package/src/packages/components/CarouselItem/index.tsx +77 -0
- package/src/packages/components/ImagePreviewer/ImagePreviewer.tsx +572 -0
- package/src/packages/components/ImagePreviewer/ImagePreviewerButtonBar.tsx +140 -0
- package/src/packages/components/ImagePreviewer/ImagePreviewerCarouselImage.tsx +54 -0
- package/src/packages/components/ImagePreviewer/ImagePreviewerGallery.tsx +202 -0
- package/src/packages/components/ImagePreviewer/PreviewerLoading.tsx +26 -0
- package/src/packages/components/ImagePreviewer/image-previewer.scss +244 -0
- package/src/packages/components/ImagePreviewer/image-previewer.utils.tsx +135 -0
- package/src/packages/components/ImagePreviewer/index.tsx +5 -0
- package/src/packages/components/ImagePreviewer/previewer-loading.scss +52 -0
- package/src/packages/components/Input/useMultipleInput.tsx +2 -79
- package/src/packages/components/InputNumber/NumberResize.tsx +14 -1
- package/src/packages/components/InputNumber/input-number.utils.tsx +7 -5
- package/src/packages/components/InputNumber/useInputNumber.public.tsx +25 -6
- package/src/packages/components/Scroll/index.tsx +6 -6
- package/src/packages/components/SortList/index.tsx +191 -0
- package/src/packages/components/SortList/sort-list.scss +11 -0
- package/src/packages/components/StackCard/index.tsx +260 -0
- package/src/packages/components/StackCard/stack-card.scss +28 -0
- package/src/packages/components/StackCardItem/index.tsx +23 -0
- package/src/packages/components/Table/standard/PlcOperation/PlcOperation.tsx +1 -1
- package/src/packages/components/Table/standard/PlcTree/RenderPlcTreeNode.tsx +2 -1
- package/src/packages/components/Table/table/body/row.tsx +1 -1
- package/src/packages/components/Table/table/use/useTableDraggier.row.tsx +1 -1
- package/src/packages/components/Table/table/utils/createTableHooks.ts +1 -1
- package/src/packages/components/Tree/RenderTreeNode.tsx +2 -1
- package/src/packages/components/Tree/index.tsx +2 -1
- package/src/packages/components/VirtualList/index.tsx +12 -3
- package/src/packages/components/VirtualList/useVirtualList.tsx +129 -86
- package/src/packages/components/VirtualList/virtual-list.scss +31 -17
- package/src/packages/components/VirtualTable/index.tsx +1 -1
- package/src/packages/entry.tsx +5 -1
- package/src/packages/uses/useDragHorizontalScroll.ts +82 -0
- package/src/packages/utils/ComponentUtils.ts +10 -0
- package/src/packages/utils/buildCycleIndexList.ts +31 -0
- package/src/packages/utils/getDeviceInfo.ts +44 -44
- package/src/packages/utils/getRectAutoFormat.ts +9 -0
- package/src/packages/utils/notNull.ts +9 -0
- package/src/pages/index/app.scss +1 -1
- package/src/pages/index/components/normal/DemoCarousel.tsx +178 -73
- package/src/pages/index/components/normal/DemoKeepAlive.tsx +25 -25
- package/src/pages/index/components/normal/DemoNumber.tsx +4 -1
- package/src/pages/index/components/normal/DemoSortList.tsx +70 -0
- package/src/pages/index/components/normal/DemoStackCard.tsx +356 -0
- package/src/pages/index/components/normal/DemoVirtualList.tsx +89 -3
- package/src/pages/index/components/service/DemoImagePreviewer.tsx +185 -0
- package/src/pages/index/home/AppHome.tsx +18 -3
- package/src/pages/index/home/menus.tsx +3 -1
- package/src/packages/components/CarouselGroup/carousel.scss +0 -143
- package/src/packages/components/CarouselGroup/index.tsx +0 -274
@@ -0,0 +1,135 @@
|
|
1
|
+
import {PartialFields} from "../../utils/type";
|
2
|
+
import {createCounter, createHooks} from "plain-design-composition";
|
3
|
+
import {notNull} from "../../utils/notNull";
|
4
|
+
|
5
|
+
export const ImagePreviewerConstants = {
|
6
|
+
/*画廊高度,默认70px*/
|
7
|
+
DEFAULT_GALLERY_HEIGHT: 70,
|
8
|
+
/*画廊与大图之间的距离,默认24px*/
|
9
|
+
DEFAULT_SEPARATOR_HEIGHT: 0,
|
10
|
+
};
|
11
|
+
|
12
|
+
export interface iImagePreviewerOptionPartialFields {
|
13
|
+
imageElement?: null | HTMLImageElement, // 点击的图片原始dom对象,如果有传这个属性对象的话会有一个显示放大动画
|
14
|
+
galleryHeight: number, // 底部画廊的高度
|
15
|
+
separatorHeight: number, // 底部画廊距离图片显示区域的距离
|
16
|
+
autoHeight: boolean, // 自动高度,默认是true。这样设置之后图片会撑满宽度,高度自动;关闭的时候会设置高度100%,图片宽度自动
|
17
|
+
mask: boolean, // 显示背部遮罩
|
18
|
+
button?: boolean | { // 顶部按钮栏控制,button为false则禁用所有按钮;为对象则单独禁用某个按钮
|
19
|
+
zoomIn?: boolean, // 放大按钮
|
20
|
+
zoomOut?: boolean, // 缩小按钮
|
21
|
+
clockwise?: boolean, // 顺时针旋转按钮
|
22
|
+
anticlockwise?: boolean, // 逆时针旋转按钮
|
23
|
+
reset?: boolean, // 重置按钮
|
24
|
+
close?: boolean, // 关闭按钮
|
25
|
+
},
|
26
|
+
swipeButton?: boolean // 左右切换按钮控制,swipeButton为false则禁用前后按钮
|
27
|
+
gallery?: boolean, // 底部画廊控制,为false则禁用底部画廊
|
28
|
+
globalKeyboardEvent?: boolean // 监听全局的键盘事件,默认不监听全局键盘按键事件,而是等鼠标移入的时候才监听
|
29
|
+
maskColor?: string, // 遮罩颜色
|
30
|
+
disableZoomOnWheel?: boolean, // 禁用滚轮缩放
|
31
|
+
/*---------------------------------------以下为不可配置属性-------------------------------------------*/
|
32
|
+
id: string, // option唯一标识
|
33
|
+
oldSourceImageOpacity?: string // 原始的img对象的opacity属性值
|
34
|
+
}
|
35
|
+
|
36
|
+
export interface iImagePreviewerOption extends iImagePreviewerOptionPartialFields {
|
37
|
+
current: number; // 当前显示的元素索引
|
38
|
+
urls: { url: string, thumbUrl: string }[]; // 所有展示的图片,url为大图地址,thumbUrl为底部画廊图片预览地址
|
39
|
+
}
|
40
|
+
|
41
|
+
export type iImagePreviewerParamOption = string | string[] | iImagePreviewerOption['urls'] | Omit<PartialFields<iImagePreviewerOption, keyof iImagePreviewerOptionPartialFields>, 'urls'> & { urls: string[] | iImagePreviewerOption['urls'] }
|
42
|
+
|
43
|
+
export const ImagePreviewerHooks = {
|
44
|
+
/*PreviewerComponent挂载完毕事件*/
|
45
|
+
onImagePreviewerReady: createHooks<(data: { option: iImagePreviewerOption }) => void>()
|
46
|
+
};
|
47
|
+
|
48
|
+
const nextOptionId = createCounter('image_previewer');
|
49
|
+
|
50
|
+
export function createImagePreviewerOption(
|
51
|
+
param: iImagePreviewerParamOption,
|
52
|
+
imageElement?: HTMLImageElement,
|
53
|
+
defaultParam?: Partial<iImagePreviewerOption>
|
54
|
+
): iImagePreviewerOption {
|
55
|
+
if (typeof param === "string") {
|
56
|
+
return {
|
57
|
+
id: nextOptionId(),
|
58
|
+
current: 0,
|
59
|
+
imageElement,
|
60
|
+
autoHeight: true,
|
61
|
+
mask: false,
|
62
|
+
urls: [{ url: param, thumbUrl: param }],
|
63
|
+
galleryHeight: ImagePreviewerConstants.DEFAULT_GALLERY_HEIGHT,
|
64
|
+
separatorHeight: ImagePreviewerConstants.DEFAULT_SEPARATOR_HEIGHT,
|
65
|
+
...defaultParam,
|
66
|
+
};
|
67
|
+
}
|
68
|
+
if (Array.isArray(param)) {
|
69
|
+
return {
|
70
|
+
id: nextOptionId(),
|
71
|
+
current: 0,
|
72
|
+
imageElement,
|
73
|
+
autoHeight: true,
|
74
|
+
mask: false,
|
75
|
+
urls: param.map(p => typeof p === "string" ? { url: p, thumbUrl: p } : p),
|
76
|
+
galleryHeight: ImagePreviewerConstants.DEFAULT_GALLERY_HEIGHT,
|
77
|
+
separatorHeight: ImagePreviewerConstants.DEFAULT_SEPARATOR_HEIGHT,
|
78
|
+
...defaultParam,
|
79
|
+
};
|
80
|
+
}
|
81
|
+
if (!!imageElement) {
|
82
|
+
param.imageElement = imageElement;
|
83
|
+
}
|
84
|
+
return {
|
85
|
+
autoHeight: true,
|
86
|
+
mask: false,
|
87
|
+
galleryHeight: notNull(param.galleryHeight, ImagePreviewerConstants.DEFAULT_GALLERY_HEIGHT),
|
88
|
+
separatorHeight: notNull(param.separatorHeight, ImagePreviewerConstants.DEFAULT_SEPARATOR_HEIGHT),
|
89
|
+
...defaultParam,
|
90
|
+
...param,
|
91
|
+
id: nextOptionId(),
|
92
|
+
urls: param.urls.map(p => typeof p === "string" ? { url: p, thumbUrl: p } : p),
|
93
|
+
};
|
94
|
+
}
|
95
|
+
|
96
|
+
/**
|
97
|
+
* 获取imageElement在containerElement容器中居中铺满的位置信息
|
98
|
+
* @author 韦胜健
|
99
|
+
* @date 2024/1/10 18:50
|
100
|
+
*/
|
101
|
+
export const getCenterRect = (
|
102
|
+
{
|
103
|
+
imageElement, containerElement
|
104
|
+
}: {
|
105
|
+
imageElement: HTMLDivElement,
|
106
|
+
containerElement: HTMLDivElement | { containerRatio: number, containerHeight: number, containerWidth: number },
|
107
|
+
}
|
108
|
+
) => {
|
109
|
+
const imageRatio = Number((imageElement.offsetWidth / imageElement.offsetHeight).toFixed(2));
|
110
|
+
const { containerRatio, containerHeight, containerWidth } = 'tagName' in containerElement ? (() => {
|
111
|
+
const containerRatio = Number((containerElement.offsetWidth / containerElement.offsetHeight).toFixed(2));
|
112
|
+
return {
|
113
|
+
containerRatio,
|
114
|
+
containerHeight: containerElement.offsetHeight,
|
115
|
+
containerWidth: containerElement.offsetWidth,
|
116
|
+
};
|
117
|
+
})() : containerElement;
|
118
|
+
|
119
|
+
|
120
|
+
if (imageRatio > containerRatio) {
|
121
|
+
/*宽度更宽,固定宽度为屏幕宽度缩放*/
|
122
|
+
const left = 0;
|
123
|
+
const width = containerWidth;
|
124
|
+
const height = Number((imageElement.offsetHeight / imageElement.offsetWidth * width).toFixed(0));
|
125
|
+
const top = Number(((containerHeight - height) / 2).toFixed(0));
|
126
|
+
return { top, left, width, height };
|
127
|
+
} else {
|
128
|
+
/*高度更高,固定高度将宽度缩放*/
|
129
|
+
const top = 0;
|
130
|
+
const height = containerHeight;
|
131
|
+
const width = Number((imageElement.offsetWidth / imageElement.offsetHeight * height).toFixed(0));
|
132
|
+
const left = Number(((containerWidth - width) / 2).toFixed(0));
|
133
|
+
return { top, left, width, height };
|
134
|
+
}
|
135
|
+
};
|
@@ -0,0 +1,52 @@
|
|
1
|
+
.previewer-loading {
|
2
|
+
|
3
|
+
$size: 1em;
|
4
|
+
|
5
|
+
height: $size;
|
6
|
+
width: $size;
|
7
|
+
|
8
|
+
.plain-loading-tag {
|
9
|
+
$centerRadius: (0.5*$size)/1.2;
|
10
|
+
$itemWidth: (0.35*$size)/1.2;
|
11
|
+
$itemHeight: (0.1*$size)/1.2;
|
12
|
+
$width: $centerRadius + $itemWidth * 2;
|
13
|
+
$height: $width;
|
14
|
+
|
15
|
+
width: $width;
|
16
|
+
height: $height;
|
17
|
+
position: relative;
|
18
|
+
display: block;
|
19
|
+
|
20
|
+
.plain-loading-inner {
|
21
|
+
background-color: currentColor;
|
22
|
+
display: inline-block;
|
23
|
+
width: $itemWidth;
|
24
|
+
height: $itemHeight;
|
25
|
+
margin-top: $itemHeight / 2 * -1;
|
26
|
+
margin-left: $centerRadius / 2;
|
27
|
+
top: 50%;
|
28
|
+
left: 50%;
|
29
|
+
position: absolute;
|
30
|
+
transform-origin: ($centerRadius / 2 * -1) ($itemHeight / 2);
|
31
|
+
@for $i from 1 through 12 {
|
32
|
+
&:nth-child(#{$i}) {
|
33
|
+
transform: rotate(($i - 1) * 30deg);
|
34
|
+
animation: plain-loading-tag 1s linear infinite #{-1 + $i / 12}s;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
@keyframes plain-loading-tag {
|
38
|
+
0% {
|
39
|
+
opacity: 1;
|
40
|
+
}
|
41
|
+
@for $i from 1 through 11 {
|
42
|
+
#{$i / 12 * 100}% {
|
43
|
+
opacity: 1 - $i / 12;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
100% {
|
47
|
+
opacity: 1;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
@@ -1,12 +1,12 @@
|
|
1
1
|
import {AutoWidthInput} from "../AutoWidthInput";
|
2
2
|
import {iInputCompositionData, inputScrollEnd} from "./input.utils";
|
3
3
|
import Icon from "../Icon";
|
4
|
-
import {iHTMLElement, useClasses, useModel, useRefs
|
4
|
+
import {iHTMLElement, useClasses, useModel, useRefs} from "plain-design-composition";
|
5
5
|
import {getKey, KEY} from "../KeyboardService";
|
6
6
|
import {delay} from "plain-utils/utils/delay";
|
7
7
|
import {createEffectiveHandler} from "../../utils/createEffectiveHandler";
|
8
8
|
import {createEffects} from "plain-utils/utils/createEffects";
|
9
|
-
import {
|
9
|
+
import {useDragHorizontalScroll} from "../../uses/useDragHorizontalScroll";
|
10
10
|
|
11
11
|
/**
|
12
12
|
* 渲染多值输入框
|
@@ -121,80 +121,3 @@ export const useMultipleInput = createEffectiveHandler(({ hooks, props, model, r
|
|
121
121
|
|
122
122
|
return effects.clear;
|
123
123
|
});
|
124
|
-
|
125
|
-
function useDragHorizontalScroll(getEl: () => HTMLElement | null | undefined) {
|
126
|
-
|
127
|
-
const staticState = {
|
128
|
-
isDragging: false,
|
129
|
-
el: null as null | undefined | HTMLElement,
|
130
|
-
start: {
|
131
|
-
x: 0,
|
132
|
-
left: 0,
|
133
|
-
width: 0,
|
134
|
-
},
|
135
|
-
move: {
|
136
|
-
x: 0
|
137
|
-
}
|
138
|
-
};
|
139
|
-
|
140
|
-
const { effects } = createEffects();
|
141
|
-
|
142
|
-
const handler = {
|
143
|
-
mousedown: (e: MouseEvent) => {
|
144
|
-
const { clientX } = ClientZoom.getClientPosition(e);
|
145
|
-
staticState.isDragging = false;
|
146
|
-
staticState.start = {
|
147
|
-
x: clientX,
|
148
|
-
left: staticState.el!.scrollLeft,
|
149
|
-
width: staticState.el!.scrollWidth,
|
150
|
-
};
|
151
|
-
document.documentElement.addEventListener('mousemove', handler.mousemove, true);
|
152
|
-
document.documentElement.addEventListener('mouseup', handler.mouseup, true);
|
153
|
-
},
|
154
|
-
mousemove: (e: MouseEvent) => {
|
155
|
-
const { clientX } = ClientZoom.getClientPosition(e);
|
156
|
-
staticState.move.x = clientX;
|
157
|
-
const durX = staticState.move.x - staticState.start.x;
|
158
|
-
if (!staticState.isDragging) {
|
159
|
-
if (Math.abs(durX) > 5) {
|
160
|
-
staticState.isDragging = true;
|
161
|
-
}
|
162
|
-
}
|
163
|
-
if (!staticState.isDragging) {
|
164
|
-
return;
|
165
|
-
}
|
166
|
-
staticState.el!.scrollLeft = staticState.start.left - durX;
|
167
|
-
},
|
168
|
-
mouseup: () => {
|
169
|
-
document.documentElement.removeEventListener('mousemove', handler.mousemove, true);
|
170
|
-
document.documentElement.removeEventListener('mouseup', handler.mouseup, true);
|
171
|
-
},
|
172
|
-
onWheel: (e: WheelEvent) => {
|
173
|
-
e.stopPropagation();
|
174
|
-
e.preventDefault();
|
175
|
-
const el = e.currentTarget as HTMLElement;
|
176
|
-
const delta = e.deltaX + e.deltaY;
|
177
|
-
el.scrollLeft += delta;
|
178
|
-
},
|
179
|
-
};
|
180
|
-
|
181
|
-
effects.push(watch(() => getEl(), el => {
|
182
|
-
if (!!staticState.el) {
|
183
|
-
staticState.el.removeEventListener('mousedown', handler.mousedown);
|
184
|
-
staticState.el.removeEventListener('wheel', handler.onWheel);
|
185
|
-
}
|
186
|
-
staticState.el = el;
|
187
|
-
if (!staticState.el) {return;}
|
188
|
-
staticState.el.addEventListener('mousedown', handler.mousedown);
|
189
|
-
staticState.el.addEventListener('wheel', handler.onWheel);
|
190
|
-
}));
|
191
|
-
|
192
|
-
effects.push(() => {
|
193
|
-
if (!!staticState.el) {
|
194
|
-
staticState.el.removeEventListener('mousedown', handler.mousedown);
|
195
|
-
staticState.el.removeEventListener('wheel', handler.onWheel);
|
196
|
-
}
|
197
|
-
});
|
198
|
-
|
199
|
-
return effects.clear;
|
200
|
-
}
|
@@ -3,6 +3,7 @@ import {Icon} from "../Icon";
|
|
3
3
|
import {createEffects} from "plain-utils/utils/createEffects";
|
4
4
|
import {addClass} from "plain-utils/dom/addClass";
|
5
5
|
import {ClientZoom} from "../ClientZoom";
|
6
|
+
import {roundFixed} from "plain-utils/utils/roundFixed";
|
6
7
|
|
7
8
|
export const NumberResize = designComponent({
|
8
9
|
name: "number-resize",
|
@@ -10,6 +11,9 @@ export const NumberResize = designComponent({
|
|
10
11
|
props: {
|
11
12
|
step: { type: Number, default: 1 },
|
12
13
|
value: { type: Number },
|
14
|
+
precision: { type: Number },
|
15
|
+
max: { type: Number },
|
16
|
+
min: { type: Number }
|
13
17
|
},
|
14
18
|
emits: {
|
15
19
|
onChange: (val: number) => true,
|
@@ -78,7 +82,16 @@ export const NumberResize = designComponent({
|
|
78
82
|
const durY = (clientY - staticState.startY);
|
79
83
|
const elMoveTop = staticState.startTop + durY;
|
80
84
|
staticState.el.style.transform = `translate3d(${staticState.startLeft}px,${elMoveTop}px,0)`;
|
81
|
-
|
85
|
+
let newValue = Math.ceil(staticState.startValue + (durY * -1) / unit) * props.step;
|
86
|
+
if (props.precision != null) {
|
87
|
+
newValue = roundFixed(newValue, props.precision)!;
|
88
|
+
}
|
89
|
+
if (props.max != null && newValue > props.max) {
|
90
|
+
newValue = props.max;
|
91
|
+
}
|
92
|
+
if (props.min != null && newValue < props.min) {
|
93
|
+
newValue = props.min;
|
94
|
+
}
|
82
95
|
event.emit.onChange(newValue);
|
83
96
|
// console.log(newValue);
|
84
97
|
},
|
@@ -12,13 +12,15 @@ export const InputNumberPropsOption = {
|
|
12
12
|
min: { type: [String, Number] }, // 最小值
|
13
13
|
max: { type: [String, Number] }, // 最大值
|
14
14
|
step: { type: [String, Number], default: 1 }, // 计数器步长
|
15
|
-
stepStrictly: { type: Boolean },
|
15
|
+
stepStrictly: { type: Boolean }, // 是否只能输入 step 的倍数
|
16
16
|
precision: { type: [Number, String] }, // 数值精度
|
17
17
|
button: { type: [String, Boolean] as PropType<boolean | typeof NumberButtonTypes.TYPE | null>, default: NumberButtonTypes.right },// 按钮模式 false, 'none','button','right'
|
18
|
-
availableUnits: { type: Array as PropType<string[]> },
|
19
|
-
defaultUnit: { type: String },
|
20
|
-
addIcon: { type: String },
|
21
|
-
subIcon: { type: String },
|
18
|
+
availableUnits: { type: Array as PropType<string[]> }, // 允许输入的数字单位
|
19
|
+
defaultUnit: { type: String }, // 默认的数字单位,当没有值的时候点击加减号默认给的单位
|
20
|
+
addIcon: { type: String }, // add按钮图标
|
21
|
+
subIcon: { type: String }, // sub按钮图标
|
22
|
+
requireUnit: { type: Boolean }, // 输入的值必须带单位,否则视为无效输入(不会触发change,并且失焦之后恢复上一次有效值)
|
23
|
+
isValueEffective: { type: Function as PropType<(val: string | number, unit?: string | null) => boolean> }, // 判断值是否有效,否则视为无效输入
|
22
24
|
|
23
25
|
/*---------------------------------------input-------------------------------------------*/
|
24
26
|
inputAttrs: { type: Object }, // input属性配置对象
|
@@ -41,18 +41,26 @@ export function useInputNumberPublic(param: iInputNumberCompositionParam) {
|
|
41
41
|
*/
|
42
42
|
getValueInfo: (val: any): iInputNumberValueInfo => {
|
43
43
|
if (!props.availableUnits || props.availableUnits.length === 0) {
|
44
|
-
|
44
|
+
|
45
|
+
/*---------------------------------------不允许带单位-------------------------------------------*/
|
46
|
+
|
45
47
|
if (val == null) return { val: undefined };
|
46
48
|
val = String(val).trim();
|
47
49
|
if (val === '') return { val: undefined };
|
48
50
|
val = Number(val);
|
49
51
|
if (isNaN(val)) {
|
50
52
|
return { val: NAN };
|
51
|
-
} else {
|
52
|
-
return { val: val };
|
53
53
|
}
|
54
|
+
if (!!props.isValueEffective && !props.isValueEffective(val)) {
|
55
|
+
return { val: NAN };
|
56
|
+
}
|
57
|
+
|
58
|
+
return { val: val };
|
59
|
+
|
54
60
|
} else {
|
55
|
-
|
61
|
+
|
62
|
+
/*---------------------------------------允许带单位-------------------------------------------*/
|
63
|
+
|
56
64
|
if (val == null) return { val: undefined, unit: props.defaultUnit };
|
57
65
|
if (typeof val === "string") {
|
58
66
|
val = val.trim();
|
@@ -69,9 +77,17 @@ export function useInputNumberPublic(param: iInputNumberCompositionParam) {
|
|
69
77
|
|
70
78
|
if (isNaN(num)) {
|
71
79
|
return { val: NAN, unit };
|
72
|
-
} else {
|
73
|
-
return { val: num, unit: !!unit ? unit : undefined };
|
74
80
|
}
|
81
|
+
|
82
|
+
if (!!props.requireUnit && !unit) {
|
83
|
+
return { val: NAN, unit };
|
84
|
+
}
|
85
|
+
|
86
|
+
if (!!props.isValueEffective && !props.isValueEffective(num, unit)) {
|
87
|
+
return { val: NAN, unit };
|
88
|
+
}
|
89
|
+
|
90
|
+
return { val: num, unit: !!unit ? unit : undefined };
|
75
91
|
}
|
76
92
|
}
|
77
93
|
}
|
@@ -334,6 +350,9 @@ export function useInputNumberPublic(param: iInputNumberCompositionParam) {
|
|
334
350
|
<NumberResize
|
335
351
|
value={effectiveInputValue.value?.val || 0}
|
336
352
|
step={numberState.step}
|
353
|
+
precision={numberState.precision}
|
354
|
+
max={numberState.max}
|
355
|
+
min={numberState.min}
|
337
356
|
onChange={handler.onResize}
|
338
357
|
onMouseDown={handler.onMousedownResize}
|
339
358
|
/>
|
@@ -78,9 +78,9 @@ export const Scroll = designComponent({
|
|
78
78
|
set isDragging(val: boolean) {
|
79
79
|
this._isDragging = val;
|
80
80
|
if (val) {
|
81
|
-
refs.host
|
81
|
+
refs.host?.setAttribute('is-dragging', '');
|
82
82
|
} else {
|
83
|
-
refs.host
|
83
|
+
refs.host?.removeAttribute('is-dragging');
|
84
84
|
}
|
85
85
|
},
|
86
86
|
};
|
@@ -215,9 +215,9 @@ export const Scroll = designComponent({
|
|
215
215
|
* @date 2020/12/15 10:16
|
216
216
|
*/
|
217
217
|
disableListTransition: (() => {
|
218
|
-
const disabledQueueAnimation = debounce(() => refs.host
|
218
|
+
const disabledQueueAnimation = debounce(() => refs.host?.removeAttribute('virtual-scrolling'), 300, true);
|
219
219
|
return () => {
|
220
|
-
refs.host
|
220
|
+
refs.host?.setAttribute('virtual-scrolling', '');
|
221
221
|
disabledQueueAnimation();
|
222
222
|
};
|
223
223
|
})(),
|
@@ -227,9 +227,9 @@ export const Scroll = designComponent({
|
|
227
227
|
* @date 2022.10.28 21:34
|
228
228
|
*/
|
229
229
|
disableInnerTransition: (() => {
|
230
|
-
const disabledQueueAnimation = debounce(() => refs.host
|
230
|
+
const disabledQueueAnimation = debounce(() => refs.host?.removeAttribute('disable-all-transition'), 300, true);
|
231
231
|
return () => {
|
232
|
-
refs.host
|
232
|
+
refs.host?.setAttribute('disable-all-transition', '');
|
233
233
|
disabledQueueAnimation();
|
234
234
|
};
|
235
235
|
})()
|
@@ -0,0 +1,191 @@
|
|
1
|
+
import {computed, CSSProperties, designComponent, getComponentCls, iHTMLDivElement, iMouseEvent, PropType, reactive, useClasses, useModel, useRefs} from "plain-design-composition";
|
2
|
+
import './sort-list.scss';
|
3
|
+
import {createEffects} from "plain-utils/utils/createEffects";
|
4
|
+
import {addWindowListener} from "plain-utils/dom/addWindowListener";
|
5
|
+
import {getRectAutoFormat} from "../../utils/getRectAutoFormat";
|
6
|
+
import {iElementRect} from "../../utils/getRowEl";
|
7
|
+
|
8
|
+
export const SortList = designComponent({
|
9
|
+
name: 'sort-list',
|
10
|
+
props: {
|
11
|
+
modelValue: { type: Array as PropType<any[]> },
|
12
|
+
col: { type: Number, default: 1 },
|
13
|
+
space: { type: Number, default: 0 },
|
14
|
+
},
|
15
|
+
emits: {
|
16
|
+
onUpdateModelValue: (val: any[]) => true,
|
17
|
+
onDragStart: (data: { item: any, index: number, e: iMouseEvent }) => true,
|
18
|
+
},
|
19
|
+
scopeSlots: {
|
20
|
+
default: (data: { item: any, index: number }) => true,
|
21
|
+
},
|
22
|
+
setup({ props, scopeSlots, event: { emit } }) {
|
23
|
+
|
24
|
+
const { refs, onRef } = useRefs({ el: iHTMLDivElement });
|
25
|
+
|
26
|
+
const model = useModel(() => props.modelValue || [], emit.onUpdateModelValue);
|
27
|
+
|
28
|
+
const isHorizontal = computed(() => props.col > 1);
|
29
|
+
|
30
|
+
const classes = useClasses(() => [
|
31
|
+
getComponentCls('sort-list'),
|
32
|
+
]);
|
33
|
+
|
34
|
+
const draggier = (() => {
|
35
|
+
|
36
|
+
const draggierState = reactive({
|
37
|
+
isDragging: false,
|
38
|
+
});
|
39
|
+
|
40
|
+
const mousedown = (e: iMouseEvent, item: any, index: number) => {
|
41
|
+
emit.onDragStart({ item, index, e });
|
42
|
+
|
43
|
+
const { effects: draggierEffects } = createEffects();
|
44
|
+
const staticState = {
|
45
|
+
start: {
|
46
|
+
x: e.clientX,
|
47
|
+
y: e.clientY,
|
48
|
+
left: 0,
|
49
|
+
top: 0,
|
50
|
+
},
|
51
|
+
siblingRects: (() => {
|
52
|
+
const sortItemElements = Array.from(refs.el!.querySelectorAll('.sort-item')) as HTMLElement[];
|
53
|
+
return sortItemElements.map((el, index) => {
|
54
|
+
return {
|
55
|
+
index,
|
56
|
+
rects: getRectAutoFormat(el)
|
57
|
+
};
|
58
|
+
});
|
59
|
+
})(),
|
60
|
+
dropData: null as null | {
|
61
|
+
itemRect: { index: number, rects: Omit<iElementRect, 'right' | 'bottom'> },
|
62
|
+
pos: 'prev' | 'next'
|
63
|
+
}
|
64
|
+
};
|
65
|
+
const sourceElement = (e.currentTarget as HTMLElement);
|
66
|
+
const sourceRect = getRectAutoFormat(sourceElement);
|
67
|
+
staticState.start.left = sourceRect.left;
|
68
|
+
staticState.start.top = sourceRect.top;
|
69
|
+
let shadowElement: HTMLElement | null = null;
|
70
|
+
let indicator: HTMLDivElement | null = null;
|
71
|
+
const indicatorSize = 2;
|
72
|
+
|
73
|
+
draggierEffects.push(addWindowListener('mouseup', draggierEffects.clear));
|
74
|
+
draggierEffects.push(addWindowListener('mousemove', (e) => {
|
75
|
+
const durX = e.clientX - staticState.start.x;
|
76
|
+
const durY = e.clientY - staticState.start.y;
|
77
|
+
|
78
|
+
if (!draggierState.isDragging) {
|
79
|
+
if (Math.abs(durX) > 5 || Math.abs(durY) > 5) {
|
80
|
+
draggierState.isDragging = true;
|
81
|
+
draggierEffects.push(() => {draggierState.isDragging = false;});
|
82
|
+
|
83
|
+
shadowElement = sourceElement.cloneNode(true) as HTMLElement;
|
84
|
+
shadowElement.style.boxSizing = 'border-box';
|
85
|
+
shadowElement.style.position = 'fixed';
|
86
|
+
shadowElement.style.top = sourceRect.top + 'px';
|
87
|
+
shadowElement.style.left = sourceRect.left + 'px';
|
88
|
+
shadowElement.style.height = sourceRect.height + 'px';
|
89
|
+
shadowElement.style.width = sourceRect.width + 'px';
|
90
|
+
shadowElement.style.opacity = '0.5';
|
91
|
+
shadowElement.style.zIndex = '2';
|
92
|
+
refs.el!.appendChild(shadowElement);
|
93
|
+
draggierEffects.push(() => {refs.el!.removeChild(shadowElement!);});
|
94
|
+
|
95
|
+
sourceElement.style.opacity = "0";
|
96
|
+
draggierEffects.push(() => sourceElement.style.opacity = "");
|
97
|
+
|
98
|
+
indicator = document.createElement('div') as HTMLDivElement;
|
99
|
+
indicator.style.position = 'fixed';
|
100
|
+
indicator.style.zIndex = '3';
|
101
|
+
refs.el!.appendChild(indicator);
|
102
|
+
draggierEffects.push(() => {refs.el!.removeChild(indicator!);});
|
103
|
+
|
104
|
+
draggierEffects.push(() => {
|
105
|
+
if (!staticState.dropData) {return;}
|
106
|
+
if (staticState.dropData.itemRect.index === index) {return;}
|
107
|
+
let currentIndex = index;
|
108
|
+
let targetIndex = staticState.dropData.itemRect.index + (staticState.dropData.pos === 'prev' ? 0 : 1);
|
109
|
+
const newData = [...model.value];
|
110
|
+
const removeData = newData.splice(currentIndex, 1);
|
111
|
+
newData.splice(targetIndex > currentIndex ? targetIndex - 1 : targetIndex, 0, ...removeData);
|
112
|
+
model.value = newData;
|
113
|
+
});
|
114
|
+
}
|
115
|
+
}
|
116
|
+
if (!draggierState.isDragging || !shadowElement || !indicator) {
|
117
|
+
return;
|
118
|
+
}
|
119
|
+
|
120
|
+
shadowElement.style.top = `${Math.ceil(staticState.start.top + durY)}px`;
|
121
|
+
shadowElement.style.left = `${Math.ceil(staticState.start.left + durX)}px`;
|
122
|
+
|
123
|
+
const matchItemRect = staticState.siblingRects.find(i => {
|
124
|
+
return e.clientY > i.rects.top && e.clientY < i.rects.top + i.rects.height && e.clientX > i.rects.left && e.clientX < i.rects.left + i.rects.width;
|
125
|
+
});
|
126
|
+
if (!matchItemRect) {
|
127
|
+
staticState.dropData = null;
|
128
|
+
indicator.style.display = 'none';
|
129
|
+
} else {
|
130
|
+
staticState.dropData = {
|
131
|
+
itemRect: matchItemRect,
|
132
|
+
pos: (() => {
|
133
|
+
if (isHorizontal.value) {
|
134
|
+
return e.clientX > matchItemRect.rects.left + matchItemRect.rects.width / 2 ? 'next' : 'prev';
|
135
|
+
} else {
|
136
|
+
return e.clientY > matchItemRect.rects.top + matchItemRect.rects.height / 2 ? 'next' : 'prev';
|
137
|
+
}
|
138
|
+
})()
|
139
|
+
};
|
140
|
+
indicator.style.display = 'block';
|
141
|
+
indicator.style.backgroundColor = 'black';
|
142
|
+
if (isHorizontal.value) {
|
143
|
+
indicator.style.top = matchItemRect.rects.top + 'px';
|
144
|
+
indicator.style.height = matchItemRect.rects.height + 'px';
|
145
|
+
indicator.style.left = matchItemRect.rects.left + (staticState.dropData.pos === 'prev' ? (-indicatorSize / 2 - props.space / 2) : (matchItemRect.rects.width + props.space / 2 - indicatorSize / 2)) + 'px';
|
146
|
+
indicator.style.width = indicatorSize + 'px';
|
147
|
+
} else {
|
148
|
+
indicator.style.left = matchItemRect.rects.left + 'px';
|
149
|
+
indicator.style.width = matchItemRect.rects.width + 'px';
|
150
|
+
indicator.style.top = matchItemRect.rects.top + (staticState.dropData.pos === 'prev' ? (-indicatorSize / 2 - props.space / 2) : (matchItemRect.rects.height + props.space / 2 - indicatorSize / 2)) + 'px';
|
151
|
+
indicator.style.height = indicatorSize + 'px';
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}));
|
155
|
+
};
|
156
|
+
|
157
|
+
return { mousedown };
|
158
|
+
})();
|
159
|
+
|
160
|
+
return () => (
|
161
|
+
<div
|
162
|
+
className={classes.value}
|
163
|
+
data-direction={isHorizontal.value ? 'horizontal' : 'vertical'}
|
164
|
+
ref={onRef.el}
|
165
|
+
>
|
166
|
+
{model.value.map((item, index) => {
|
167
|
+
const styles = {} as CSSProperties;
|
168
|
+
if (props.col !== 1) {
|
169
|
+
styles.width = `calc((100% - ${(props.col - 1) * props.space}px) / ${props.col})`;
|
170
|
+
if ((index + 1) % props.col !== 0) {
|
171
|
+
styles.marginRight = props.space + 'px';
|
172
|
+
}
|
173
|
+
} else {
|
174
|
+
styles.width = '100%';
|
175
|
+
}
|
176
|
+
styles.marginBottom = props.space + 'px';
|
177
|
+
return (
|
178
|
+
<div
|
179
|
+
className="sort-item"
|
180
|
+
style={styles}
|
181
|
+
key={index}
|
182
|
+
onMouseDown={e => draggier.mousedown(e, item, index)}
|
183
|
+
>
|
184
|
+
{scopeSlots.default({ item, index }, null)}
|
185
|
+
</div>
|
186
|
+
);
|
187
|
+
})}
|
188
|
+
</div>
|
189
|
+
);
|
190
|
+
},
|
191
|
+
});
|