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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) 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/Scroll/index.tsx +6 -6
  24. package/src/packages/components/SortList/index.tsx +191 -0
  25. package/src/packages/components/SortList/sort-list.scss +11 -0
  26. package/src/packages/components/StackCard/index.tsx +260 -0
  27. package/src/packages/components/StackCard/stack-card.scss +28 -0
  28. package/src/packages/components/StackCardItem/index.tsx +23 -0
  29. package/src/packages/components/Table/standard/PlcOperation/PlcOperation.tsx +1 -1
  30. package/src/packages/components/Table/standard/PlcTree/RenderPlcTreeNode.tsx +2 -1
  31. package/src/packages/components/Table/table/body/row.tsx +1 -1
  32. package/src/packages/components/Table/table/use/useTableDraggier.row.tsx +1 -1
  33. package/src/packages/components/Table/table/utils/createTableHooks.ts +1 -1
  34. package/src/packages/components/Tree/RenderTreeNode.tsx +2 -1
  35. package/src/packages/components/Tree/index.tsx +2 -1
  36. package/src/packages/components/VirtualList/index.tsx +12 -3
  37. package/src/packages/components/VirtualList/useVirtualList.tsx +129 -86
  38. package/src/packages/components/VirtualList/virtual-list.scss +31 -17
  39. package/src/packages/components/VirtualTable/index.tsx +1 -1
  40. package/src/packages/entry.tsx +5 -1
  41. package/src/packages/uses/useDragHorizontalScroll.ts +82 -0
  42. package/src/packages/utils/ComponentUtils.ts +10 -0
  43. package/src/packages/utils/buildCycleIndexList.ts +31 -0
  44. package/src/packages/utils/getDeviceInfo.ts +44 -44
  45. package/src/packages/utils/getRectAutoFormat.ts +9 -0
  46. package/src/packages/utils/notNull.ts +9 -0
  47. package/src/pages/index/app.scss +1 -1
  48. package/src/pages/index/components/normal/DemoCarousel.tsx +178 -73
  49. package/src/pages/index/components/normal/DemoKeepAlive.tsx +25 -25
  50. package/src/pages/index/components/normal/DemoSortList.tsx +70 -0
  51. package/src/pages/index/components/normal/DemoStackCard.tsx +356 -0
  52. package/src/pages/index/components/normal/DemoVirtualList.tsx +89 -3
  53. package/src/pages/index/components/service/DemoImagePreviewer.tsx +185 -0
  54. package/src/pages/index/home/AppHome.tsx +18 -3
  55. package/src/pages/index/home/menus.tsx +3 -1
  56. package/src/packages/components/CarouselGroup/carousel.scss +0 -143
  57. package/src/packages/components/CarouselGroup/index.tsx +0 -274
@@ -0,0 +1,140 @@
1
+ import {computed, designComponent, iMouseEvent, PropType, useClasses} from "plain-design-composition";
2
+ import Tooltip from "../Tooltip";
3
+ import {iImagePreviewerOption} from "./image-previewer.utils";
4
+
5
+ export const ImagePreviewerButtonBar = designComponent({
6
+ name: 'image-previewer-button-bar',
7
+ props: {
8
+ button: { type: [Boolean, Object] as PropType<iImagePreviewerOption['button']> }
9
+ },
10
+ emits: {
11
+ onZoomIn: () => true,
12
+ onZoomOut: () => true,
13
+ onAnticlockwise: () => true,
14
+ onClockwise: () => true,
15
+ onReset: () => true,
16
+ onClose: () => true,
17
+ },
18
+ setup({ props, event: { emit } }) {
19
+
20
+ const classes = useClasses(() => [
21
+ 'image-previewer-button-bar'
22
+ ]);
23
+
24
+ const buttonAvailable = computed((): Exclude<iImagePreviewerOption['button'], boolean | undefined> => {
25
+ if (props.button == null || props.button == true) {
26
+ return {
27
+ zoomIn: true,
28
+ zoomOut: true,
29
+ clockwise: true,
30
+ anticlockwise: true,
31
+ reset: true,
32
+ close: true,
33
+ };
34
+ }
35
+ if (props.button === false) {
36
+ return {
37
+ zoomIn: false,
38
+ zoomOut: false,
39
+ clockwise: false,
40
+ anticlockwise: false,
41
+ reset: false,
42
+ close: false,
43
+ };
44
+ }
45
+ return {
46
+ zoomIn: props.button.zoomIn != false,
47
+ zoomOut: props.button.zoomOut != false,
48
+ clockwise: props.button.clockwise != false,
49
+ anticlockwise: props.button.anticlockwise != false,
50
+ reset: props.button.reset != false,
51
+ close: props.button.close != false,
52
+ };
53
+ });
54
+
55
+ const buttons = [
56
+ buttonAvailable.value.zoomIn && {
57
+ tip: '放大(滚轮上滑)', icon: () => (
58
+ <svg width="1em" height="1em" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" fill="none" className="pi-zoom-in" strokeWidth="2" strokeLinecap="butt" strokeLinejoin="miter" style={{ verticalAlign: "baseline" }}>
59
+ <path d="M32.6066 32.6066C35.3211 29.8921 37 26.1421 37 22C37 13.7157 30.2843 7 22 7C13.7157 7 7 13.7157 7 22C7 30.2843 13.7157 37 22 37C26.1421 37 29.8921 35.3211 32.6066 32.6066ZM32.6066 32.6066L41.5 41.5M29 22H15M22 29V15"></path>
60
+ </svg>
61
+ ), handler: (e: iMouseEvent) => {
62
+ e.stopPropagation();
63
+ emit.onZoomIn();
64
+ }
65
+ },
66
+ buttonAvailable.value.zoomOut && {
67
+ tip: '缩小(滚轮下滑)', icon: () => (
68
+ <svg width="1em" height="1em" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" fill="none" className="pi-zoom-out" strokeWidth="2" strokeLinecap="butt" strokeLinejoin="miter" style={{ verticalAlign: "baseline" }}>
69
+ <path d="M32.6066 32.6066C35.3211 29.8921 37 26.1421 37 22C37 13.7157 30.2843 7 22 7C13.7157 7 7 13.7157 7 22C7 30.2843 13.7157 37 22 37C26.1421 37 29.8921 35.3211 32.6066 32.6066ZM32.6066 32.6066L41.5 41.5M29 22H15"></path>
70
+ </svg>
71
+ ), handler: (e: iMouseEvent) => {
72
+ e.stopPropagation();
73
+ emit.onZoomOut();
74
+ }
75
+ },
76
+ buttonAvailable.value.anticlockwise && {
77
+ tip: '逆时针旋转', icon: () => (
78
+ <svg width="1em" height="1em" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" fill="none" className="pi-rotate-left" strokeWidth="2" strokeLinecap="butt" strokeLinejoin="miter" style={{ verticalAlign: "baseline" }}>
79
+ <path d="M10 22C10 21.4477 10.4477 21 11 21H31C31.5523 21 32 21.4477 32 22V38C32 38.5523 31.5523 39 31 39H11C10.4477 39 10 38.5523 10 38V22Z"></path>
80
+ <path d="M23 11H34C37.3137 11 40 13.6863 40 17V23"></path>
81
+ <path d="M22.5 12.8933L19.5873 11L22.5 9.10672L22.5 12.8933Z"></path>
82
+ </svg>
83
+ ), handler: (e: iMouseEvent) => {
84
+ e.stopPropagation();
85
+ emit.onAnticlockwise();
86
+ }
87
+ },
88
+ buttonAvailable.value.clockwise && {
89
+ tip: '顺时针旋转', icon: () => (
90
+ <svg width="1em" height="1em" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" fill="none" className="pi-rotate-right" strokeWidth="2" strokeLinecap="butt" strokeLinejoin="miter" style={{ verticalAlign: "baseline" }}>
91
+ <path d="M38 22C38 21.4477 37.5523 21 37 21H17C16.4477 21 16 21.4477 16 22V38C16 38.5523 16.4477 39 17 39H37C37.5523 39 38 38.5523 38 38V22Z"></path>
92
+ <path d="M25 11H14C10.6863 11 8 13.6863 8 17V23"></path>
93
+ <path d="M25.5 12.8933L28.4127 11L25.5 9.10672L25.5 12.8933Z"></path>
94
+ </svg>
95
+ ), handler: (e: iMouseEvent) => {
96
+ e.stopPropagation();
97
+ emit.onClockwise();
98
+ }
99
+ },
100
+ buttonAvailable.value.reset && {
101
+ tip: '重置', icon: () => (
102
+ <svg width="1em" height="1em" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" fill="none" className="pi-sync" strokeWidth="2" strokeLinecap="butt" strokeLinejoin="miter" style={{ verticalAlign: "baseline" }}>
103
+ <path d="M33.1927 11.9799L34.607 10.5657L36.0212 9.15145H33.1927V11.9799Z" fill="currentColor" stroke="none" strokeWidth="none"></path>
104
+ <path d="M14.8115 36.018L13.3973 37.4322L11.9831 38.8464H14.8115V36.018Z" fill="currentColor" stroke="none" strokeWidth="none"></path>
105
+ <path d="M34.607 10.5657L36.0212 9.15145H33.1927V11.9799L34.607 10.5657ZM34.607 10.5657L36.0212 11.9799C42.6601 18.6188 42.6601 29.3826 36.0212 36.0215C33.4881 38.5545 30.3546 40.1211 27.0788 40.7212M13.3973 37.4322L11.9831 38.8464H14.8115V36.018L13.3973 37.4322ZM13.3973 37.4322L11.9831 36.018C5.34418 29.379 5.34418 18.6152 11.9831 11.9763C14.5161 9.44329 17.6497 7.87672 20.9255 7.27661"></path>
106
+ </svg>
107
+ ), handler: (e: iMouseEvent) => {
108
+ e.stopPropagation();
109
+ emit.onReset();
110
+ }
111
+ },
112
+ buttonAvailable.value.close && {
113
+ tip: '关闭(ESC按键/双击图片)', icon: () => (
114
+ <svg width="1em" height="1em" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" fill="none" className="pi-close" strokeWidth="2" strokeLinecap="butt" strokeLinejoin="miter" style={{ verticalAlign: "baseline" }}>
115
+ <path d="M9.85742 9.85791L23.9996 24M23.9996 24L38.1417 38.1422M23.9996 24L38.1417 9.85791M23.9996 24L9.85742 38.1422"></path>
116
+ </svg>
117
+ ), handler: (e: iMouseEvent) => {
118
+ e.stopPropagation();
119
+ emit.onClose();
120
+ }
121
+ },
122
+ ].filter(Boolean);
123
+
124
+ const onDoubleClickStopPropagation = (e: iMouseEvent) => {e.stopPropagation();};
125
+
126
+ return () => (
127
+ buttons.length && (
128
+ <div className={classes.value}>
129
+ {buttons.map((btn) => (
130
+ !!btn && typeof btn != "boolean" && !!btn.icon() && <Tooltip key={btn.tip} message={btn.tip} placement="bottom">
131
+ <div onClick={btn.handler} onDoubleClick={onDoubleClickStopPropagation} className="image-previewer-button">
132
+ {btn.icon()}
133
+ </div>
134
+ </Tooltip>
135
+ ))}
136
+ </div>
137
+ )
138
+ );
139
+ },
140
+ });
@@ -0,0 +1,54 @@
1
+ import {designComponent, iHTMLImageElement, iMouseEvent, PropType, reactive, useRefs, useStyles} from "plain-design-composition";
2
+ import {delay} from "plain-utils/utils/delay";
3
+
4
+ /**
5
+ * img自动判断自己是应该宽度沾满还是高度沾满
6
+ * @author 韦胜健
7
+ * @date 2024/1/5 15:47
8
+ */
9
+ export const ImagePreviewerCarouselImage = designComponent({
10
+ props: {
11
+ src: { type: String, required: true },
12
+ direction: { type: String as PropType<'horizontal' | 'vertical'> },
13
+ clientRatio: { type: Number, required: true },
14
+ },
15
+ inheritPropsType: iHTMLImageElement,
16
+ emits: {
17
+ onReady: () => true,
18
+ },
19
+ setup({ props, event: { emit } }) {
20
+
21
+ const { refs, onRef } = useRefs({ img: iHTMLImageElement });
22
+
23
+ const state = reactive({
24
+ direction: props.direction as null | undefined | 'horizontal' | 'vertical'
25
+ });
26
+
27
+ const styles = useStyles(style => {
28
+ if (!state.direction) {style.opacity = "0";}
29
+ });
30
+
31
+ const onLoad = async () => {
32
+ if (!state.direction) {
33
+ const { height, width } = refs.img!;
34
+ const imageRatio = width / height;
35
+ state.direction = imageRatio > props.clientRatio ? 'horizontal' : 'vertical';
36
+ await delay();
37
+ }
38
+ emit.onReady();
39
+ };
40
+
41
+ const onError = async () => {emit.onReady();};
42
+
43
+ /**
44
+ * 阻止点击冒泡,避免触发image previewer的双击关闭动作
45
+ * @author 韦胜健
46
+ * @date 2024/1/8 10:05
47
+ */
48
+ const preventDefaultDraggier = (e: iMouseEvent) => {e.preventDefault();};
49
+
50
+ return () => (
51
+ <img ref={onRef.img} style={styles.value} src={props.src} data-direction={state.direction} onLoad={onLoad} onError={onError} onDragStart={preventDefaultDraggier}/>
52
+ );
53
+ },
54
+ });
@@ -0,0 +1,202 @@
1
+ import {computed, designComponent, iHTMLDivElement, iMouseEvent, onBeforeUnmount, PropType, reactive, useClasses, useModel, useRefs, useStyles} from "plain-design-composition";
2
+ import {notNull} from "../../utils/notNull";
3
+ import {delay} from "plain-utils/utils/delay";
4
+ import {Icon} from "../Icon";
5
+ import {iImagePreviewerOption} from "./image-previewer.utils";
6
+ import {PreviewerLoading} from "./PreviewerLoading";
7
+ import {VirtualList} from "../VirtualList";
8
+ import {useDragHorizontalScroll} from "../../uses/useDragHorizontalScroll";
9
+
10
+ /**
11
+ * 画廊组件
12
+ * @author 韦胜健
13
+ * @date 2024/1/8 10:13
14
+ */
15
+ export const ImagePreviewerGallery = designComponent({
16
+ name: 'image-gallery',
17
+ props: {
18
+ modelValue: { type: Number },
19
+ option: { type: Object as PropType<iImagePreviewerOption>, required: true }
20
+ },
21
+ inheritPropsType: iHTMLDivElement,
22
+ emits: {
23
+ onUpdateModelValue: (val?: number) => true,
24
+ },
25
+ setup({ props, event: { emit } }) {
26
+
27
+ const { refs, onRef } = useRefs({ virtual: VirtualList });
28
+
29
+ const model = useModel(() => notNull(props.modelValue, 0), emit.onUpdateModelValue, { onChange: () => {handler.adjustScrollLeft();} });
30
+
31
+ const state = reactive({
32
+ /*是否显示滚动按钮*/
33
+ showScroller: false,
34
+
35
+ readyMap: {} as Record<string, boolean | undefined>,
36
+ });
37
+
38
+ const classes = useClasses(() => [
39
+ 'image-previewer-component-gallery',
40
+ {
41
+ 'image-previewer-component-gallery-show-scroller': state.showScroller
42
+ }
43
+ ]);
44
+
45
+ const utils = {
46
+ getScrollInfo: () => {
47
+ const { offsetWidth, scrollWidth, scrollLeft } = refs.virtual!.refs.scroll!.refs.wrapper!;
48
+ return { wrapperWidth: offsetWidth, scrollWidth, scrollLeft };
49
+ },
50
+ scrollLeft: (left: number, duration: number) => {
51
+ refs.virtual!.refs.scroll?.methods.scrollLeft(left, duration);
52
+ },
53
+ };
54
+
55
+ const handler = {
56
+
57
+ /**
58
+ * 根据选中的元素位置自动调整滚动距离,使得选中的元素居中展示
59
+ * @author 韦胜健
60
+ * @date 2024/1/5 17:53
61
+ */
62
+ adjustScrollLeft: async (duration = 300) => {
63
+ await delay();
64
+ const { wrapperWidth } = utils.getScrollInfo();
65
+ let scrollLeft = itemRect.value.width * model.value - Math.ceil(itemRect.value.width / 2) - Math.ceil(wrapperWidth / 2);
66
+ if (scrollLeft < 0) {scrollLeft = 0;}
67
+ utils.scrollLeft(scrollLeft, duration);
68
+ },
69
+ /**
70
+ * 图片加载完毕时,自动判断是否需要显示滚动按钮
71
+ * @author 韦胜健
72
+ * @date 2024/1/5 17:53
73
+ */
74
+ onImageLoad: async (thumbUrl: string) => {
75
+ state.readyMap = { ...state.readyMap, [thumbUrl]: true };
76
+ await delay();
77
+ const { wrapperWidth, scrollWidth } = utils.getScrollInfo();
78
+ const showScroller = scrollWidth > wrapperWidth;
79
+ if (state.showScroller != showScroller) {
80
+ state.showScroller = showScroller;
81
+ await handler.adjustScrollLeft(0);
82
+ }
83
+ },
84
+ /**
85
+ * 点击gallery item的时候更新绑定值,并且调整滚动位置
86
+ * @author 韦胜健
87
+ * @date 2024/1/5 17:54
88
+ */
89
+ onClickGalleryItem: async (index: number) => {
90
+ model.value = index;
91
+ },
92
+ /**
93
+ * 滚动到上一页
94
+ * @author 韦胜健
95
+ * @date 2024/1/5 17:54
96
+ */
97
+ scrollPrev: (e: iMouseEvent) => {
98
+ e.stopPropagation();
99
+ const { wrapperWidth, scrollLeft } = utils.getScrollInfo();
100
+ utils.scrollLeft(Math.ceil(scrollLeft - wrapperWidth / 2), 300);
101
+ },
102
+ /**
103
+ * 滚动到下一页
104
+ * @author 韦胜健
105
+ * @date 2024/1/5 17:54
106
+ */
107
+ scrollNext: (e: iMouseEvent) => {
108
+ e.stopPropagation();
109
+ const { wrapperWidth, scrollLeft } = utils.getScrollInfo();
110
+ utils.scrollLeft(Math.ceil(scrollLeft + wrapperWidth / 2), 300);
111
+ },
112
+ /**
113
+ * 双击滚动按钮的时候阻止事件冒泡,避免影响导致关闭预览
114
+ * @author 韦胜健
115
+ * @date 2024/1/5 17:54
116
+ */
117
+ onDoubleClickGallery: (e: iMouseEvent) => {
118
+ e.stopPropagation();
119
+ },
120
+ /**
121
+ * 拖拽图片的时候阻止默认行为,避免下载图片
122
+ * @author 韦胜健
123
+ * @date 2024/1/5 17:55
124
+ */
125
+ preventDragImage: (e: iMouseEvent) => {
126
+ e.preventDefault();
127
+ },
128
+ ...(() => {
129
+ let clickIndex: number | null = null;
130
+ let clickClientX: number | null = null;
131
+ const onMousedownItem = (e: iMouseEvent, index: number) => {
132
+ clickIndex = index;
133
+ clickClientX = e.clientX;
134
+ };
135
+ const onMouseupItem = (e: iMouseEvent, index: number) => {
136
+ if (index !== clickIndex || clickIndex == null || clickClientX == null) {return;}
137
+ if (Math.abs(e.clientX - clickClientX) > 10) {
138
+ /*距离过长,为拖拽而不是点击*/
139
+ return;
140
+ }
141
+ handler.onClickGalleryItem(index);
142
+ };
143
+
144
+ return { onMousedownItem, onMouseupItem };
145
+ })()
146
+ };
147
+
148
+ const itemRect = computed(() => {
149
+ const height = props.option.galleryHeight;
150
+ const width = Math.ceil(1920 / 1080 * height);
151
+ return { height, width };
152
+ });
153
+
154
+ const itemStyles = useStyles(style => {
155
+ style.height = itemRect.value.height + 'px';
156
+ style.width = itemRect.value.width + 'px';
157
+ });
158
+
159
+ onBeforeUnmount(useDragHorizontalScroll(() => refs.virtual?.refs.scroll?.refs.wrapper));
160
+
161
+ return () => (
162
+ <div className={classes.value} onDoubleClick={handler.onDoubleClickGallery}>
163
+ {state.showScroller && (
164
+ <div className="image-previewer-component-gallery-scroller">
165
+ <div className="image-previewer-component-gallery-scroller-prev" onClick={handler.scrollPrev}>
166
+ <Icon icon="pi-left"/>
167
+ </div>
168
+ <div className="image-previewer-component-gallery-scroller-next" onClick={handler.scrollNext}>
169
+ <Icon icon="pi-right"/>
170
+ </div>
171
+ </div>
172
+ )}
173
+ <div className="image-previewer-component-gallery-container">
174
+ <VirtualList
175
+ ref={onRef.virtual}
176
+ data={props.option.urls}
177
+ horizontal
178
+ size={itemRect.value.width}
179
+ v-slots={{
180
+ default: ({ index, vIndex, item, vid }) => (
181
+ <div
182
+ data-vid={vid}
183
+ data-idx={index}
184
+ key={vIndex}
185
+ style={itemStyles.value}
186
+ className="image-previewer-component-gallery-item"
187
+ onMouseDown={(e) => handler.onMousedownItem(e, index)}
188
+ onMouseUp={(e) => handler.onMouseupItem(e, index)}
189
+ data-active={String(model.value == index)}
190
+ >
191
+ <img src={item.thumbUrl} onMouseDown={handler.preventDragImage} onLoad={() => handler.onImageLoad(item.thumbUrl)} onError={() => handler.onImageLoad(item.thumbUrl)}/>
192
+ {/*{<PreviewerLoading/>}*/}
193
+ {state.readyMap[item.thumbUrl] !== true && <PreviewerLoading/>}
194
+ </div>
195
+ ),
196
+ }}
197
+ />
198
+ </div>
199
+ </div>
200
+ );
201
+ },
202
+ });
@@ -0,0 +1,26 @@
1
+ import {designComponent} from "plain-design-composition";
2
+ import './previewer-loading.scss';
3
+
4
+ export const PreviewerLoading = designComponent({
5
+ name: 'previewer-loading',
6
+ setup() {
7
+ return () => (
8
+ <div className="previewer-loading">
9
+ <div className="plain-loading-tag">
10
+ <div className="plain-loading-inner"></div>
11
+ <div className="plain-loading-inner"></div>
12
+ <div className="plain-loading-inner"></div>
13
+ <div className="plain-loading-inner"></div>
14
+ <div className="plain-loading-inner"></div>
15
+ <div className="plain-loading-inner"></div>
16
+ <div className="plain-loading-inner"></div>
17
+ <div className="plain-loading-inner"></div>
18
+ <div className="plain-loading-inner"></div>
19
+ <div className="plain-loading-inner"></div>
20
+ <div className="plain-loading-inner"></div>
21
+ <div className="plain-loading-inner"></div>
22
+ </div>
23
+ </div>
24
+ );
25
+ },
26
+ });
@@ -0,0 +1,244 @@
1
+ .image-previewer-component {
2
+ position: relative;
3
+ height: 100%;
4
+ width: 100%;
5
+ margin: 0 !important;
6
+ padding: 0 !important;
7
+ user-select: none;
8
+
9
+ .image-previewer-component-mask {
10
+ position: absolute;
11
+ inset: 0;
12
+ z-index: 1;
13
+ opacity: 1;
14
+ transition: opacity 300ms linear;
15
+ content: '';
16
+ }
17
+
18
+ @include comp(carousel) {
19
+ position: relative;
20
+ z-index: 2;
21
+ box-sizing: border-box;
22
+
23
+ .carousel-item-inner {
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ }
28
+
29
+ .carousel-indicator, .carousel-switch-button-prev, .carousel-switch-button-next, img {
30
+ pointer-events: auto;
31
+ }
32
+ .carousel-indicator {
33
+ transition: none;
34
+ bottom: -12px;
35
+ }
36
+ }
37
+
38
+ img {
39
+ display: inline-block;
40
+ object-fit: contain;
41
+
42
+ &[data-direction=horizontal] {
43
+ width: 100%;
44
+ }
45
+
46
+ &[data-direction=vertical] {
47
+ height: 100%;
48
+ }
49
+ }
50
+
51
+ &.image-previewer-component-waiting {
52
+ .image-previewer-component-mask, .image-previewer-component-gallery {
53
+ opacity: 0;
54
+ }
55
+ }
56
+
57
+ .image-previewer-component-gallery {
58
+ position: relative;
59
+ z-index: 2;
60
+ width: 100%;
61
+ transition: opacity 300ms linear;
62
+ user-select: none;
63
+
64
+ .image-previewer-component-gallery-container {
65
+ overflow: hidden;
66
+ height: 100%;
67
+ width: 100%;
68
+ }
69
+
70
+ .image-previewer-component-gallery-item {
71
+ display: inline-block;
72
+ height: 100%;
73
+ padding: 2px 1px;
74
+ cursor: pointer;
75
+ box-sizing: border-box;
76
+ position: relative;
77
+ background-color: #DDDDDD;
78
+
79
+ img {
80
+ height: 100%;
81
+ width: 100%;
82
+ object-fit: cover;
83
+ object-position: center;
84
+ position: relative;
85
+ z-index: 2;
86
+ }
87
+
88
+ &[data-active=true] {
89
+ &:before {
90
+ position: absolute;
91
+ inset: 0 -1px;
92
+ content: '';
93
+ background-color: gold;
94
+ z-index: 1;
95
+ }
96
+ }
97
+
98
+ &:first-child {
99
+ padding-left: 2px;
100
+
101
+ &[data-active=true] {
102
+ &:before {
103
+ top: 0;
104
+ left: 0;
105
+ right: -1px;
106
+ bottom: 0;
107
+ }
108
+ }
109
+ }
110
+
111
+ &:last-child {
112
+ padding-right: 2px;
113
+
114
+ &[data-active=true] {
115
+ &:before {
116
+ top: 0;
117
+ right: 0;
118
+ left: -1px;
119
+ bottom: 0;
120
+ }
121
+ }
122
+ }
123
+ }
124
+
125
+ .image-previewer-component-gallery-scroller {
126
+ position: absolute;
127
+ inset: 0;
128
+ pointer-events: none;
129
+ display: flex;
130
+ align-items: stretch;
131
+ justify-content: space-between;
132
+ z-index: 3;
133
+
134
+ .image-previewer-component-gallery-scroller-prev, .image-previewer-component-gallery-scroller-next {
135
+ display: flex;
136
+ align-items: center;
137
+ justify-content: center;
138
+ width: 50px;
139
+ color: white;
140
+ font-size: 20px;
141
+ pointer-events: auto;
142
+ cursor: pointer;
143
+ position: relative;
144
+
145
+ &:before {
146
+ position: absolute;
147
+ inset: 0;
148
+ content: '';
149
+ opacity: 0.5;
150
+ transition: opacity 300ms ease;
151
+ z-index: 1;
152
+ }
153
+
154
+ @include comp(icon) {
155
+ position: relative;
156
+ z-index: 2;
157
+ }
158
+ }
159
+
160
+ .image-previewer-component-gallery-scroller-prev {
161
+ &:before {
162
+ background: linear-gradient(to right, black, transparent);
163
+ }
164
+
165
+ &:hover {
166
+ &:before {
167
+ opacity: 1;
168
+ }
169
+ }
170
+ }
171
+
172
+ .image-previewer-component-gallery-scroller-next {
173
+ &:before {
174
+ background: linear-gradient(to left, black, transparent);
175
+ }
176
+
177
+ &:hover {
178
+ &:before {
179
+ opacity: 1;
180
+ }
181
+ }
182
+ }
183
+ }
184
+
185
+ &.image-previewer-component-gallery-show-scroller {
186
+ justify-content: flex-start;
187
+ }
188
+
189
+ &:not(.image-previewer-component-gallery-show-scroller) {
190
+ .scroll-wrapper {
191
+ text-align: center;
192
+ }
193
+ }
194
+
195
+ .previewer-loading {
196
+ position: absolute;
197
+ inset: 0;
198
+ display: flex;
199
+ align-items: center;
200
+ justify-content: center;
201
+ width: 100%;
202
+ height: 100%;
203
+ color: white;
204
+ font-size: 16px;
205
+ z-index: 3;
206
+ background-color: black;
207
+ }
208
+ }
209
+
210
+ .image-previewer-button-bar {
211
+ position: absolute;
212
+ top: 0;
213
+ left: 0;
214
+ right: 0;
215
+ pointer-events: none;
216
+ display: flex;
217
+ align-items: center;
218
+ justify-content: center;
219
+ z-index: 3;
220
+ padding: 16px;
221
+
222
+ .image-previewer-button {
223
+ pointer-events: auto;
224
+ color: white;
225
+ height: 50px;
226
+ width: 50px;
227
+ font-size: 28px;
228
+ background-color: rgba(black, 0.2);
229
+ display: flex;
230
+ align-items: center;
231
+ justify-content: center;
232
+ cursor: pointer;
233
+ transition: background-color ease 300ms;
234
+
235
+ & + .image-previewer-button {
236
+ margin-left: 1px;
237
+ }
238
+
239
+ &:hover {
240
+ background-color: rgba(black, 0.3);
241
+ }
242
+ }
243
+ }
244
+ }