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.
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
+ }