plain-design 1.0.0-beta.30 → 1.0.0-beta.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. package/dist/plain-design.commonjs.min.js +3 -3
  2. package/dist/plain-design.min.css +11 -6
  3. package/dist/plain-design.min.js +3 -3
  4. package/dist/report.html +2 -2
  5. package/package.json +3 -3
  6. package/src/packages/components/$previewer/ImagePreviewerFixedContainer.tsx +107 -0
  7. package/src/packages/components/$previewer/image-previewer-fixed-container.scss +18 -0
  8. package/src/packages/components/$previewer/index.tsx +52 -0
  9. package/src/packages/components/Application/service/useApplicationService.tsx +2 -0
  10. package/src/packages/components/Carousel/carousel.scss +391 -0
  11. package/src/packages/components/Carousel/index.tsx +569 -22
  12. package/src/packages/components/CarouselItem/index.tsx +77 -0
  13. package/src/packages/components/ImagePreviewer/ImagePreviewer.tsx +572 -0
  14. package/src/packages/components/ImagePreviewer/ImagePreviewerButtonBar.tsx +140 -0
  15. package/src/packages/components/ImagePreviewer/ImagePreviewerCarouselImage.tsx +54 -0
  16. package/src/packages/components/ImagePreviewer/ImagePreviewerGallery.tsx +202 -0
  17. package/src/packages/components/ImagePreviewer/PreviewerLoading.tsx +26 -0
  18. package/src/packages/components/ImagePreviewer/image-previewer.scss +244 -0
  19. package/src/packages/components/ImagePreviewer/image-previewer.utils.tsx +135 -0
  20. package/src/packages/components/ImagePreviewer/index.tsx +5 -0
  21. package/src/packages/components/ImagePreviewer/previewer-loading.scss +52 -0
  22. package/src/packages/components/Input/useMultipleInput.tsx +2 -79
  23. package/src/packages/components/InputNumber/NumberResize.tsx +14 -1
  24. package/src/packages/components/InputNumber/input-number.utils.tsx +7 -5
  25. package/src/packages/components/InputNumber/useInputNumber.public.tsx +25 -6
  26. package/src/packages/components/Scroll/index.tsx +6 -6
  27. package/src/packages/components/SortList/index.tsx +191 -0
  28. package/src/packages/components/SortList/sort-list.scss +11 -0
  29. package/src/packages/components/StackCard/index.tsx +260 -0
  30. package/src/packages/components/StackCard/stack-card.scss +28 -0
  31. package/src/packages/components/StackCardItem/index.tsx +23 -0
  32. package/src/packages/components/Table/standard/PlcOperation/PlcOperation.tsx +1 -1
  33. package/src/packages/components/Table/standard/PlcTree/RenderPlcTreeNode.tsx +2 -1
  34. package/src/packages/components/Table/table/body/row.tsx +1 -1
  35. package/src/packages/components/Table/table/use/useTableDraggier.row.tsx +1 -1
  36. package/src/packages/components/Table/table/utils/createTableHooks.ts +1 -1
  37. package/src/packages/components/Tree/RenderTreeNode.tsx +2 -1
  38. package/src/packages/components/Tree/index.tsx +2 -1
  39. package/src/packages/components/VirtualList/index.tsx +12 -3
  40. package/src/packages/components/VirtualList/useVirtualList.tsx +129 -86
  41. package/src/packages/components/VirtualList/virtual-list.scss +31 -17
  42. package/src/packages/components/VirtualTable/index.tsx +1 -1
  43. package/src/packages/entry.tsx +5 -1
  44. package/src/packages/uses/useDragHorizontalScroll.ts +82 -0
  45. package/src/packages/utils/ComponentUtils.ts +10 -0
  46. package/src/packages/utils/buildCycleIndexList.ts +31 -0
  47. package/src/packages/utils/getDeviceInfo.ts +44 -44
  48. package/src/packages/utils/getRectAutoFormat.ts +9 -0
  49. package/src/packages/utils/notNull.ts +9 -0
  50. package/src/pages/index/app.scss +1 -1
  51. package/src/pages/index/components/normal/DemoCarousel.tsx +178 -73
  52. package/src/pages/index/components/normal/DemoKeepAlive.tsx +25 -25
  53. package/src/pages/index/components/normal/DemoNumber.tsx +4 -1
  54. package/src/pages/index/components/normal/DemoSortList.tsx +70 -0
  55. package/src/pages/index/components/normal/DemoStackCard.tsx +356 -0
  56. package/src/pages/index/components/normal/DemoVirtualList.tsx +89 -3
  57. package/src/pages/index/components/service/DemoImagePreviewer.tsx +185 -0
  58. package/src/pages/index/home/AppHome.tsx +18 -3
  59. package/src/pages/index/home/menus.tsx +3 -1
  60. package/src/packages/components/CarouselGroup/carousel.scss +0 -143
  61. package/src/packages/components/CarouselGroup/index.tsx +0 -274
@@ -1,44 +1,591 @@
1
- import {createCounter} from "plain-utils/utils/createCounter";
2
- import {computed, designComponent, getComponentCls, reactive, useClasses, useRefs, useStyles} from "plain-design-composition";
3
- import {CarouselCollector} from "../CarouselGroup";
4
-
5
- const counter = createCounter('carousel');
1
+ import {computed, CSSProperties, designComponent, getComponentCls, iHTMLDivElement, iMouseEvent, isReact, iTouchEvent, onBeforeUnmount, PropType, reactive, StyleProperties, useClasses, useModel, useRefs, useStyles,} from 'plain-design-composition';
2
+ import './carousel.scss';
3
+ import CarouselItem, {iCarouselItemMeta} from '../CarouselItem';
4
+ import {createCounter} from 'plain-utils/utils/createCounter';
5
+ import {Icon} from '../Icon';
6
+ import {useWatchAutoClear} from '../../utils/watchEffectAutoClear';
7
+ import {findReactElement} from '../../utils/findReactElement';
8
+ import {addElementListener} from 'plain-utils/dom/addElementListener';
9
+ import {createEffects} from "plain-utils/utils/createEffects";
10
+ import {unit} from "plain-utils/string/unit";
11
+ import {doNothing} from "../../utils/doNothing";
12
+ import {delay} from "plain-utils/utils/delay";
13
+ import {Tooltip} from "../Tooltip";
14
+ import {buildCycleIndexList} from "../../utils/buildCycleIndexList";
15
+ import {ComponentUtils} from "../../utils/ComponentUtils";
6
16
 
7
17
  export const Carousel = designComponent({
8
- name: 'carousel-item',
18
+ name: 'carousel',
19
+ provideRefer: true,
9
20
  props: {
10
- val: { type: [String, Number] },
21
+ modelValue: { type: [String, Number] }, // 双向绑定值
22
+ vertical: { type: Boolean }, // 纵向轮播
23
+ card: { type: Boolean }, // 卡片形式切换
24
+ noIndicator: { type: Boolean }, // 禁用指示器
25
+ indicatorStyle: { type: String as PropType<'line' | 'dot' | 'text'>, default: 'line' }, // 指示器类型
26
+ switchButton: { type: Boolean, default: true }, // 显示切换按钮
27
+ largeSwitchButton: { type: Boolean }, // 使用大型的切换按钮
28
+ autoPlay: { type: [Boolean, Number] as PropType<number | boolean>, default: true }, // 自动播放
29
+ height: { type: [String, Number] }, // 固定高度
30
+ disableSwiper: { type: Boolean }, // 禁用拂动切换
31
+ indicatorTrigger: { type: String as PropType<'click' | 'hover'>, default: 'click' }, // 指示器的触发类型,click点击,hover鼠标悬浮
32
+ alignItems: { type: String as PropType<CSSProperties['alignItems']>, default: 'center' }, // 每个子元素的对其方式
33
+ fullHeight: { type: Boolean }, // 适配容器高度,开启这个特性会限制每个子元素的高度为容器高度
34
+ prevSwitchButtonTip: { type: String }, // 上一页按钮提示文本
35
+ nextSwitchButtonTip: { type: String }, // 下一页按钮提示文本
36
+ },
37
+ emits: {
38
+ onUpdateModelValue: (val?: string | number) => true
39
+ },
40
+ scopeSlots: {
41
+ indicator: (scope: {
42
+ total: number;
43
+ activeIndex: number;
44
+ prevIndex: number;
45
+ nextIndex: number;
46
+ }) => {}
11
47
  },
12
- inheritPropsType: HTMLDivElement,
13
- slots: ['default'],
14
- setup({ props, slots }) {
48
+ slots: ['default', 'cover'],
49
+ setup({ props, event: { emit }, slots, scopeSlots }) {
50
+
51
+ const { refs, onRef } = useRefs({ el: iHTMLDivElement });
52
+
53
+ const id = nextCarouselId();
15
54
 
16
- const { refs, onRef } = useRefs({
17
- el: HTMLDivElement,
55
+ const model = useModel(() => props.modelValue, emit.onUpdateModelValue, {
56
+ onChange: async (newVal, oldVal) => {
57
+ methods.show(newVal, oldVal, false);
58
+ }
18
59
  });
19
- const carousel = CarouselCollector.child({ sort: () => refs.el! });
20
- const itemVal = computed(() => props.val == null ? counter() : props.val);
21
- const styles = useStyles(() => carousel.utils.getItemStyles(itemVal.value) as any);
60
+
61
+ const direction = computed(() =>
62
+ /*方向,是横向还是纵向*/
63
+ props.vertical ? ('vertical' as const) : ('horizontal' as const)
64
+ );
22
65
 
23
66
  const classes = useClasses(() => [
24
67
  getComponentCls('carousel'),
25
- { 'carousel-animating': carousel.utils.isAnimating(itemVal.value), }
68
+ `carousel-${direction.value}`,
69
+ {
70
+ 'carousel-card': props.card,
71
+ 'carousel-disable-swiper': props.disableSwiper,
72
+ 'carousel-touching': !!touchHandler.touchState.touching,
73
+ 'carousel-full-height': !!props.fullHeight,
74
+ 'carousel-fixed-height': !!props.height,
75
+ 'carousel-large-switch-button': !!props.largeSwitchButton
76
+ }
26
77
  ]);
27
78
 
79
+ const styles = useStyles((style) => {
80
+ if (!!props.height) {
81
+ style.height = unit(props.height);
82
+ }
83
+ });
84
+
85
+ const state = reactive({
86
+ /*临时绑定值,不直接使用modelValue,这个值与baseLeft,baseLeftCount对应,同时变化*/
87
+ tempValue: model.value,
88
+ });
89
+
90
+ const utils = {
91
+ /**
92
+ * 获取container item的style
93
+ * @author 韦胜健
94
+ * @date 2023/4/27 23:13
95
+ */
96
+ getItemStyles(itemMeta: iCarouselItemMeta) {
97
+ const style = {} as StyleProperties;
98
+ let base = -itemMeta.props.index; // 令item偏移到第一个item的位置
99
+
100
+ if (itemMeta.props.distance < 0) {
101
+ base--;
102
+ } else if (itemMeta.props.distance > 0) {
103
+ base++;
104
+ }
105
+
106
+ const isMoving = Math.abs(itemMeta.props.distance) <= 1;
107
+
108
+ /*实际偏移位置*/
109
+ style.transform = props.vertical
110
+ ? `translate3d(0,calc(${base * 100}% + ${!isMoving ? 0 : (touchHandler.touchState.touching?.moveTop || 0)}px),0)`
111
+ : `translate3d(calc(${base * 100}% + ${!isMoving ? 0 : (touchHandler.touchState.touching?.moveLeft || 0)}px),0,0)`;
112
+
113
+ /*既不是prev,也不是next以及active的item不显示,但是占用空间,以实现自动撑开高度的效果*/
114
+ if (Math.abs(itemMeta.props.distance) > 1) {
115
+ style.opacity = '0';
116
+ style.transition = 'none';
117
+ style.pointerEvents = 'none';
118
+ }
119
+ if (touchHandler.touchState.touching) {
120
+ style.transition = 'none';
121
+ }
122
+
123
+ if (itemMeta.props.distance != 0) {
124
+ /*如果一个元素从循环列表的一端跑到另一端,则禁用过度动画*/
125
+ if (!!tempState.prev && !!tempState.curr) {
126
+
127
+ /*上一次在循环列表的左边还是右边*/
128
+ const prevPos: 'left' | 'right' | null = ((() => {
129
+ if (itemMeta.props.index === tempState.prev!.current) {return null;}
130
+ const prevCurrIndex = tempState.prev!.cycleIndexList.indexOf(tempState.prev!.current);
131
+ const prevItemIndex = tempState.prev!.cycleIndexList.indexOf(itemMeta.props.index);
132
+ return prevCurrIndex > prevItemIndex ? 'left' : 'right';
133
+ })());
134
+
135
+ /*这一次在循环列表的左边还是右边*/
136
+ const nextPos: 'left' | 'right' | null = ((() => {
137
+ if (itemMeta.props.index === tempState.curr!.current) {return null;}
138
+ const nextCurrIndex = tempState.curr!.cycleIndexList.indexOf(tempState.curr!.current);
139
+ const nextItemIndex = tempState.curr!.cycleIndexList.indexOf(itemMeta.props.index);
140
+ return nextCurrIndex > nextItemIndex ? 'left' : 'right';
141
+ })());
142
+
143
+ /*两次渲染的左右位置不同的话,则禁用过度动画*/
144
+ if (!!prevPos && !!nextPos && prevPos !== nextPos) {
145
+ style.transition = 'none';
146
+ }
147
+ }
148
+ }
149
+
150
+ style.zIndex = itemProps.length - Math.abs(itemMeta.props.distance);
151
+ return style;
152
+ }
153
+ };
154
+
155
+ const touchHandler = (() => {
156
+ let touchState = reactive({
157
+ /*拖拽开始时x定位*/
158
+ startX: null as null | number,
159
+ /*拖拽开始时y定位*/
160
+ startY: null as null | number,
161
+ /*拖拽的状态,拖拽开始时偏移大于5个px开始计算*/
162
+ touching: null as null | {
163
+ /*拖拽开始时container的left偏移量*/
164
+ startLeft: number;
165
+ /*拖拽 过程中container的left偏移量*/
166
+ moveLeft: number;
167
+ /*拖拽开始时container的top偏移量*/
168
+ startTop: number;
169
+ /*拖拽 过程中container的top偏移量*/
170
+ moveTop: number;
171
+ }
172
+ });
173
+
174
+ /**
175
+ * 拖拽开始
176
+ * @author 韦胜健
177
+ * @date 2023/4/27 23:17
178
+ */
179
+ const touchstart = (e: TouchEvent | MouseEvent) => {
180
+
181
+ e.preventDefault();
182
+ e.stopPropagation();
183
+
184
+ const { effects: draggierEffects } = createEffects();
185
+
186
+ if (props.vertical) {
187
+ touchHandler.touchState.startY = 'touches' in e ? e.touches[0].clientY : e.clientY;
188
+ } else {
189
+ touchHandler.touchState.startX = 'touches' in e ? e.touches[0].clientX : e.clientX;
190
+ }
191
+
192
+ /**
193
+ * 拖拽移动
194
+ * @author 韦胜健
195
+ * @date 2023/4/27 23:17
196
+ */
197
+ const touchmove = (e: TouchEvent | MouseEvent) => {
198
+ if (props.disableSwiper) {
199
+ return;
200
+ }
201
+ if (props.vertical) {
202
+ const durY = ('touches' in e ? e.touches[0].clientY : e.clientY) - touchHandler.touchState.startY!;
203
+ if (!touchState.touching) {
204
+ if (Math.abs(durY) > 5) {
205
+ touchState.touching = {
206
+ startLeft: 0,
207
+ moveLeft: 0,
208
+ startTop: 0,
209
+ moveTop: 0,
210
+ };
211
+ draggierEffects.push(touchend);
212
+ }
213
+ }
214
+ if (touchState.touching) {
215
+ touchState.touching.moveTop = touchState.touching.startTop + durY;
216
+ }
217
+ } else {
218
+ const durX = ('touches' in e ? e.touches[0].clientX : e.clientX) - touchHandler.touchState.startX!;
219
+ if (!touchState.touching) {
220
+ if (Math.abs(durX) > 5) {
221
+ touchState.touching = {
222
+ startLeft: 0,
223
+ moveLeft: 0,
224
+ startTop: 0,
225
+ moveTop: 0,
226
+ };
227
+ draggierEffects.push(touchend);
228
+ }
229
+ }
230
+ if (touchState.touching) {
231
+ touchState.touching.moveLeft = touchState.touching.startLeft + durX;
232
+ }
233
+ }
234
+ };
235
+
236
+ /**
237
+ * 拖拽结束
238
+ * @author 韦胜健
239
+ * @date 2023/4/27 23:17
240
+ */
241
+ const touchend = async (e: iTouchEvent | iMouseEvent) => {
242
+ if (!touchState.touching) {
243
+ return;
244
+ }
245
+ let dur = props.vertical
246
+ ? touchState.touching.moveTop - touchState.touching.startTop!
247
+ : touchState.touching.moveLeft - touchState.touching.startLeft!;
248
+ const info = await ComponentUtils.getElInfo(`#${id}`);
249
+ const duration = props.vertical ? info.height / 4 : info.width / 4;
250
+
251
+ let activeIndex = itemProps!.findIndex((i) => i == state.tempValue);
252
+ if (activeIndex === -1) {
253
+ activeIndex = 0;
254
+ }
255
+ if (itemProps.length <= 1) {
256
+ /**
257
+ * 轮播节点少于等于1个,不做切换
258
+ * @author 韦胜健
259
+ * @date 2024/1/4 10:57
260
+ */
261
+ dur = 0;
262
+ } else {
263
+ /**
264
+ * 当轮播节点数量少于或者等于2时,
265
+ * 如果是第一个节点后移,不做切换
266
+ * 如果是最后一个节点前移,不做切换
267
+ * @author 韦胜健
268
+ * @date 2024/1/4 10:56
269
+ */
270
+ if (itemProps.length <= 2) {
271
+ if (dur < 0 && activeIndex === itemProps.length - 1) {
272
+ dur = 0;
273
+ } else if (dur > 0 && activeIndex === 0) {
274
+ dur = 0;
275
+ }
276
+ }
277
+ }
278
+ if (dur > duration) {
279
+ /*上一张*/
280
+ activeIndex--;
281
+ } else if (dur < -duration) {
282
+ /*下一张*/
283
+ activeIndex++;
284
+ }
285
+ if (activeIndex < 0) {
286
+ activeIndex = itemProps!.length - 1;
287
+ }
288
+ if (activeIndex >= itemProps!.length) {
289
+ activeIndex = 0;
290
+ }
291
+ state.tempValue = itemProps![activeIndex];
292
+ model.value = state.tempValue;
293
+
294
+ reset();
295
+ };
296
+
297
+ draggierEffects.push(addElementListener(document.body, 'mousemove', touchmove));
298
+ draggierEffects.push(addElementListener(document.body, 'touchmove', touchmove));
299
+
300
+ draggierEffects.push(addElementListener(document.body, 'mouseup', draggierEffects.clear));
301
+ draggierEffects.push(addElementListener(document.body, 'touchend', draggierEffects.clear));
302
+ };
303
+
304
+ const reset = () => {
305
+ /*重置拖拽状态*/
306
+ touchState.startX = null;
307
+ touchState.startY = null;
308
+ touchState.touching = null;
309
+ };
310
+
311
+ return { touchstart, touchState, reset };
312
+ })();
313
+
314
+ let itemProps = [] as any[];
315
+
316
+ const play = (() => {
317
+ let timer: any = null;
318
+ const start = () => {
319
+ if (!!timer) {
320
+ return;
321
+ }
322
+ timer = setInterval(
323
+ () => {
324
+ methods.next();
325
+ },
326
+ typeof props.autoPlay === 'boolean' ? 3000 : props.autoPlay
327
+ );
328
+ };
329
+
330
+ const stop = () => {
331
+ if (!!timer) {
332
+ clearInterval(timer);
333
+ timer = null;
334
+ }
335
+ };
336
+
337
+ return { start, stop };
338
+ })();
339
+
340
+ const methods = {
341
+ /**
342
+ * 切换到上一张
343
+ * @author 韦胜健
344
+ * @date 2023/4/28 16:21
345
+ */
346
+ prev: async (): Promise<void> => {
347
+ /*当前只有一个元素,不做处理*/
348
+ if (itemProps.length < 2) {return;}
349
+
350
+ if (!itemProps) {
351
+ return;
352
+ }
353
+ let activeIndex = itemProps.findIndex((i) => i === state.tempValue);
354
+ if (activeIndex === -1) {
355
+ activeIndex = 0;
356
+ }
357
+
358
+ /*当前只有两个元素,并且已经是第一个元素了,点击prev的时候转为next*/
359
+ if (activeIndex === 0 && itemProps.length === 2) {
360
+ return methods.next();
361
+ }
362
+ let prevIndex = activeIndex == 0 ? itemProps.length - 1 : activeIndex - 1;
363
+
364
+ state.tempValue = itemProps[prevIndex];
365
+ model.value = state.tempValue;
366
+
367
+ if (props.autoPlay) {
368
+ methods.stop();
369
+ methods.start();
370
+ }
371
+ },
372
+ /**
373
+ * 切换到下一张
374
+ * @author 韦胜健
375
+ * @date 2023/4/28 16:21
376
+ */
377
+ next: async () => {
378
+ /*当前只有一个元素,不做处理*/
379
+ if (itemProps.length < 2) {return;}
380
+ if (!itemProps) {
381
+ return;
382
+ }
383
+ let activeIndex = itemProps.findIndex((i) => i === state.tempValue);
384
+ if (activeIndex === -1) {
385
+ activeIndex = 0;
386
+ }
387
+
388
+ /*当前只有两个元素,并且已经是最后一个元素了,点击next的时候转为prev*/
389
+ if (activeIndex === itemProps.length - 1 && itemProps.length === 2) {
390
+ return methods.prev();
391
+ }
392
+ let nextIndex = activeIndex == itemProps.length - 1 ? 0 : activeIndex + 1;
393
+
394
+ state.tempValue = itemProps[nextIndex];
395
+ model.value = state.tempValue;
396
+
397
+ if (props.autoPlay) {
398
+ methods.stop();
399
+ methods.start();
400
+ }
401
+ },
402
+ ...play,
403
+ show: async (newVal: any, oldVal: any, autoEmit = true) => {
404
+ if (autoEmit && newVal === oldVal) {
405
+ return;
406
+ }
407
+ /*更新tempValue*/
408
+ state.tempValue = newVal;
409
+ if (autoEmit) {
410
+ model.value = state.tempValue;
411
+ }
412
+ if (!!props.autoPlay) {
413
+ methods.stop();
414
+ methods.start();
415
+ }
416
+ },
417
+ };
418
+
419
+ const handler = {
420
+ onDoubleClickSwitchButton: (e: iMouseEvent) => {
421
+ e.stopPropagation();
422
+ }
423
+ };
424
+
425
+ useWatchAutoClear(
426
+ /*拖拽过程中禁用自动播放*/
427
+ () => props.autoPlay && !touchHandler.touchState.touching,
428
+ (autoPlay) => {
429
+ if (!!autoPlay) {
430
+ methods.start();
431
+ }
432
+ return () => {
433
+ methods.stop();
434
+ };
435
+ }
436
+ );
437
+
438
+ const { effects: listenerEffects } = createEffects();
439
+ useWatchAutoClear(() => props.disableSwiper, disableSwiper => {
440
+ listenerEffects.clear();
441
+ if (disableSwiper) {
442
+ touchHandler.reset();
443
+ return doNothing;
444
+ }
445
+ delay().then(() => {
446
+ listenerEffects.push(addElementListener(refs.el!, 'touchstart', touchHandler.touchstart, { passive: false }));
447
+ listenerEffects.push(addElementListener(refs.el!, 'mousedown', touchHandler.touchstart, { passive: false }));
448
+ });
449
+ return listenerEffects.clear;
450
+ });
451
+
452
+ onBeforeUnmount(() => {
453
+ play.stop();
454
+ listenerEffects.clear();
455
+ });
456
+
457
+ let tempState = {
458
+ /*上一次渲染的循环列表数据*/
459
+ prev: null as null | {
460
+ current: number,
461
+ cycleIndexList: number[],
462
+ },
463
+ /*下一次渲染的循环列表数据*/
464
+ curr: null as null | {
465
+ current: number,
466
+ cycleIndexList: number[],
467
+ }
468
+ };
469
+
28
470
  return {
29
- refer: reactive({
30
- itemVal,
471
+ refer: {
472
+ utils,
473
+ methods,
31
474
  refs,
32
- }),
475
+ },
33
476
  render: () => {
477
+ const content = slots.default() as any;
478
+
479
+ const items: any[] = !content
480
+ ? []
481
+ : findReactElement(content, (i: any) => i.type?.name === CarouselItem.name) || [];
482
+
483
+ itemProps = items.map((i, index) => i.props?.val == null ? index : i.props?.val);
484
+
485
+ const total = items.length;
486
+ const activeIndex = !state.tempValue
487
+ ? 0
488
+ : itemProps.findIndex((i) => i === state.tempValue);
489
+
490
+ const { index2distance, cycleIndexList, currentIndexInCycle } = buildCycleIndexList({ length: itemProps.length, current: activeIndex });
491
+ const prevIndex = cycleIndexList[currentIndexInCycle] - 1;
492
+ const nextIndex = cycleIndexList[currentIndexInCycle] + 1;
493
+
494
+ if (!tempState.curr || tempState.curr.current !== activeIndex) {
495
+ tempState.prev = tempState.curr;
496
+ tempState.curr = {
497
+ current: activeIndex,
498
+ cycleIndexList: cycleIndexList,
499
+ };
500
+ }
501
+
34
502
  return (
35
- <div className={classes.value} ref={onRef.el} style={styles.value}>
36
- {slots.default()}
503
+ <div
504
+ id={id}
505
+ className={classes.value}
506
+ style={styles.value}
507
+ ref={onRef.el}
508
+ >
509
+ <div className="carousel-container">
510
+ {items.map((Item: any, index: number) => {
511
+ const ItemComp = isReact ? Item.type : Item;
512
+ return (
513
+ <ItemComp
514
+ {...Item.props}
515
+ index={index}
516
+ distance={index2distance[index]}
517
+ alignItems={props.alignItems}
518
+ key={index}
519
+ />
520
+ );
521
+ })}
522
+ </div>
523
+ {!props.noIndicator &&
524
+ scopeSlots.indicator(
525
+ { total, activeIndex, prevIndex, nextIndex },
526
+ (() => {
527
+ return (
528
+ <div
529
+ className={`carousel-indicator carousel-indicator-style-${props.indicatorStyle}`} style={{ zIndex: itemProps.length + 2 }}>
530
+ {(() => {
531
+ if (props.indicatorStyle === 'text') {
532
+ return `${activeIndex + 1} / ${total}`;
533
+ } else {
534
+ return itemProps.map((_, index) => (
535
+ <div
536
+ key={index}
537
+ {...props.indicatorTrigger === 'click' ?
538
+ { onClick: () => methods.show(itemProps[index], model.value) } :
539
+ { onMouseEnter: () => methods.show(itemProps[index], model.value) }}
540
+ className={`carousel-indicator-item ${
541
+ index === activeIndex
542
+ ? 'carousel-indicator-item-active'
543
+ : index === prevIndex
544
+ ? 'carousel-indicator-item-prev'
545
+ : index === nextIndex
546
+ ? 'carousel-indicator-item-next'
547
+ : ''
548
+ }`}
549
+ />
550
+ ));
551
+ }
552
+ })()}
553
+ </div>
554
+ );
555
+ })()
556
+ )}
557
+ {props.switchButton && (
558
+ <div className="carousel-switch-button" style={{ zIndex: itemProps.length + 2 }}>
559
+ {(() => {
560
+ const prevButton = (
561
+ <div className="carousel-switch-button-prev" onClick={methods.prev} onDoubleClick={handler.onDoubleClickSwitchButton}>
562
+ <Icon icon={props.vertical ? 'pi-up' : 'pi-left'}/>
563
+ </div>
564
+ );
565
+ return !!props.prevSwitchButtonTip ? <Tooltip message={props.prevSwitchButtonTip} placement="bottom-start">{prevButton}</Tooltip> : prevButton;
566
+ })()}
567
+ {(() => {
568
+ const nextButton = (
569
+ <div className="carousel-switch-button-next" onClick={methods.next} onDoubleClick={handler.onDoubleClickSwitchButton}>
570
+ <Icon icon={props.vertical ? 'pi-down' : 'pi-right'}/>
571
+ </div>
572
+ );
573
+ return !!props.nextSwitchButtonTip ? <Tooltip message={props.nextSwitchButtonTip} placement="bottom-end">{nextButton}</Tooltip> : nextButton;
574
+ })()}
575
+ </div>
576
+ )}
577
+ {slots.cover.isExist() && (
578
+ <div className="carousel-cover" style={{ zIndex: itemProps.length + 2 }}>
579
+ {slots.cover()}
580
+ </div>
581
+ )}
37
582
  </div>
38
583
  );
39
584
  }
40
585
  };
41
- },
586
+ }
42
587
  });
43
588
 
589
+ const nextCarouselId = createCounter('carousel');
590
+
44
591
  export default Carousel;
@@ -0,0 +1,77 @@
1
+ import {cacheComputed, designComponent, getComponentCls, iHTMLDivElement, onBeforeUnmount, onMounted, useClasses, useRefs} from 'plain-design-composition';
2
+ import {Carousel} from '../Carousel';
3
+ import {createEffects} from "plain-utils/utils/createEffects";
4
+ import {addElementListener} from "plain-utils/dom/addElementListener";
5
+ import {PreviewerLoading} from "../ImagePreviewer/PreviewerLoading";
6
+
7
+ export const CarouselItem = designComponent({
8
+ name: 'carousel-item',
9
+ props: {
10
+ val: { type: [String, Number] },
11
+ distance: { type: Number },
12
+ index: { type: Number },
13
+ alignItems: { type: String },
14
+ loading: { type: Boolean },
15
+ },
16
+ inheritPropsType: iHTMLDivElement,
17
+ emits: {
18
+ onMousedownInner: (e: MouseEvent) => true,
19
+ onTouchstartInner: (e: TouchEvent) => true,
20
+ },
21
+ slots: ['default'],
22
+ setup({ props: _props, slots, event: { emit } }) {
23
+
24
+ const { refs, onRef } = useRefs({ inner: iHTMLDivElement });
25
+
26
+ const carousel = Carousel.use.inject();
27
+
28
+ const props = _props as iCarouselItemMeta['props'];
29
+
30
+ const classes = useClasses(() => [
31
+ getComponentCls('carousel-item'),
32
+ {
33
+ 'carousel-active': props.distance === 0,
34
+ 'carousel-prev': props.distance === -1,
35
+ 'carousel-next': props.distance === 1
36
+ }
37
+ ]);
38
+
39
+ const styles = cacheComputed(
40
+ () => {
41
+ const style = carousel.utils.getItemStyles({ props });
42
+ style.alignItems = props.alignItems;
43
+ return style;
44
+ },
45
+ (newValue, oldValue) => JSON.stringify(newValue) !== JSON.stringify(oldValue)
46
+ );
47
+
48
+ const { effects: setupEffects } = createEffects();
49
+
50
+ onMounted(() => {
51
+ setupEffects.push(addElementListener(refs.inner!, 'mousedown', e => emit.onMousedownInner(e), { passive: false }));
52
+ setupEffects.push(addElementListener(refs.inner!, 'touchstart', e => emit.onTouchstartInner(e), { passive: false }));
53
+ });
54
+
55
+ onBeforeUnmount(setupEffects.clear);
56
+
57
+ return () => (
58
+ <div style={styles.value} className={classes.value}>
59
+ <div className="carousel-item-inner" ref={onRef.inner}>{slots.default()}</div>
60
+ {/*<PreviewerLoading/>*/}
61
+ {!!props.loading && <PreviewerLoading/>}
62
+ </div>
63
+ );
64
+ }
65
+ });
66
+
67
+ export default CarouselItem;
68
+
69
+ export interface iCarouselItemMeta {
70
+ props: {
71
+ val?: string;
72
+ index: number;
73
+ distance: number,
74
+ alignItems: string,
75
+ loading?: boolean
76
+ };
77
+ }