@antscorp/antsomi-ui 1.3.5-beta.261 → 1.3.5-beta.263

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 (27) hide show
  1. package/es/components/common/ConfigProvider/GlobalStyle.js +5 -0
  2. package/es/components/molecules/ImageEditor/ImageEditor.d.ts +18 -0
  3. package/es/components/molecules/ImageEditor/ImageEditor.js +774 -0
  4. package/es/components/molecules/ImageEditor/index.d.ts +1 -7
  5. package/es/components/molecules/ImageEditor/index.js +1 -555
  6. package/es/components/molecules/ImageEditor/reducer.d.ts +1 -1
  7. package/es/components/molecules/ImageEditor/styled.d.ts +4 -3
  8. package/es/components/molecules/ImageEditor/styled.js +12 -6
  9. package/es/components/molecules/ImageResizeTuiEditor/ImageResizeTuiEditor.d.ts +12 -0
  10. package/es/components/molecules/ImageResizeTuiEditor/ImageResizeTuiEditor.js +73 -0
  11. package/es/components/molecules/ImageResizeTuiEditor/index.d.ts +1 -0
  12. package/es/components/molecules/ImageResizeTuiEditor/index.js +1 -0
  13. package/es/components/molecules/ImageResizeTuiEditor/types.d.ts +5 -0
  14. package/es/components/molecules/ImageResizeTuiEditor/types.js +1 -0
  15. package/es/components/molecules/TemplateSaveAs/TemplateSaveAs.d.ts +4 -0
  16. package/es/components/molecules/TemplateSaveAs/TemplateSaveAs.js +5 -3
  17. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/BigImage.d.ts +2 -0
  18. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/BigImage.js +12 -6
  19. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/ImageSlider.d.ts +5 -0
  20. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/ImageSlider.js +92 -8
  21. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/styled.js +70 -5
  22. package/es/components/molecules/TemplateSaveAs/styled.js +22 -0
  23. package/es/components/molecules/index.d.ts +2 -0
  24. package/es/components/molecules/index.js +1 -0
  25. package/es/providers/ConfigProvider/GlobalStyle.js +5 -0
  26. package/es/test.js +4 -4
  27. package/package.json +2 -1
@@ -0,0 +1,73 @@
1
+ import React, { useEffect, useImperativeHandle, useRef } from 'react';
2
+ import { fabric } from 'fabric';
3
+ const ImageResizeTuiEditor = React.forwardRef(({ className, imageUrl, width, height, defaultValue, hideAction }, ref) => {
4
+ const loadRef = useRef(false);
5
+ const fabricCanvasRef = useRef(null);
6
+ const canvasRef = useRef(null);
7
+ const resetScaleImage = img => {
8
+ const widthRatio = width / img.width;
9
+ const heightRatio = height / img.height;
10
+ img.set({ left: 0, top: 0 }).scale(Math.min(widthRatio, heightRatio));
11
+ img.set({ left: (width - img.oCoords.br.x) / 2, top: (height - img.oCoords.br.y) / 2 });
12
+ img.set({
13
+ borderColor: '#00a1ff',
14
+ cornerColor: '#fff',
15
+ cornerSize: 10,
16
+ cornerStrokeColor: '#00a1ff',
17
+ // transparentCorners: true,
18
+ });
19
+ };
20
+ const loadImage = url => {
21
+ fabric.Image.fromURL(url, img => {
22
+ var _a;
23
+ resetScaleImage(img);
24
+ (_a = fabricCanvasRef.current) === null || _a === void 0 ? void 0 : _a.add(img);
25
+ }, {
26
+ crossOrigin: '',
27
+ });
28
+ };
29
+ const changeImage = url => {
30
+ var _a;
31
+ (_a = fabricCanvasRef.current) === null || _a === void 0 ? void 0 : _a.forEachObject(obj => {
32
+ var _a;
33
+ (_a = fabricCanvasRef.current) === null || _a === void 0 ? void 0 : _a.remove(obj);
34
+ });
35
+ loadImage(url);
36
+ };
37
+ useImperativeHandle(ref, () => ({
38
+ getBase64(options) {
39
+ var _a;
40
+ const dataURL = (_a = fabricCanvasRef.current) === null || _a === void 0 ? void 0 : _a.toDataURL(Object.assign({ format: 'png', quality: 1 }, options));
41
+ return dataURL;
42
+ },
43
+ replaceImageWithUrl(imageUrl) {
44
+ changeImage(imageUrl);
45
+ },
46
+ getCurrentState() {
47
+ return fabricCanvasRef.current;
48
+ },
49
+ }), []);
50
+ useEffect(() => {
51
+ if (loadRef.current) {
52
+ changeImage(imageUrl);
53
+ }
54
+ loadRef.current = true;
55
+ fabricCanvasRef.current = new fabric.Canvas('tui-image-editor', {
56
+ width,
57
+ height,
58
+ });
59
+ fabric.Object.prototype.transparentCorners = false;
60
+ if (imageUrl) {
61
+ loadImage(imageUrl);
62
+ }
63
+ else if (defaultValue) {
64
+ defaultValue.forEachObject(obj => {
65
+ var _a;
66
+ (_a = fabricCanvasRef.current) === null || _a === void 0 ? void 0 : _a.add(obj);
67
+ });
68
+ }
69
+ }, [imageUrl]);
70
+ return (React.createElement("div", { className: className },
71
+ React.createElement("canvas", { ref: canvasRef, id: "tui-image-editor", style: { width, height } })));
72
+ });
73
+ export { ImageResizeTuiEditor };
@@ -0,0 +1 @@
1
+ export { ImageResizeTuiEditor } from './ImageResizeTuiEditor';
@@ -0,0 +1 @@
1
+ export { ImageResizeTuiEditor } from './ImageResizeTuiEditor';
@@ -0,0 +1,5 @@
1
+ export type ImageResizeHandle = {
2
+ getBase64: (options?: any) => string | undefined;
3
+ replaceImageWithUrl: (imageUrl: string) => void;
4
+ getCurrentState: () => any;
5
+ };
@@ -76,6 +76,10 @@ export interface TemplateSaveAsProps {
76
76
  form?: FormInstance<FormValue>;
77
77
  value?: TemplateValueOptions;
78
78
  onChange?: (value: Partial<TemplateValueOptions>, errors?: any[]) => void;
79
+ onSaveThumbnail?: (data: {
80
+ thumbnails: (string | undefined)[];
81
+ thumbnailChange: number;
82
+ }) => void;
79
83
  onEvent?: (value: Partial<TemplateValueOptions>) => void;
80
84
  }
81
85
  export declare const TemplateSaveAs: React.FC<TemplateSaveAsProps>;
@@ -27,12 +27,12 @@ export const TemplateSaveAs = props => {
27
27
  var _a;
28
28
  const { className, shareAccess, saveOptions, imageReview, isLoadingCategories, categories, omitCategories, templateNames: templateNameList, templateNamesOptions, descriptionOptions,
29
29
  // form,
30
- form: formProps, value, onChange, onEvent, } = props;
30
+ form: formProps, value, onChange, onEvent, onSaveThumbnail, } = props;
31
31
  const [internalForm] = Form.useForm();
32
32
  const form = formProps || internalForm;
33
33
  const { show: isShowShareAccess } = shareAccess, shareAccessProps = __rest(shareAccess, ["show"]);
34
34
  const { label: imageReviewLabel } = imageReview, restImageReviewProps = __rest(imageReview, ["label"]);
35
- console.log('🚀 ~ restImageReviewProps:', restImageReviewProps);
35
+ // console.log('🚀 ~ restImageReviewProps:', restImageReviewProps);
36
36
  const { isLoading, label: templateLabel, defaultNewTemplateName = `Untitled Media Template#${dayjs().format('YYYY-MM-DD HH:mm:ss')}`, selectPlaceholder = 'Please select an item', placeholder = 'Enter your media template name', validateName, onSearch, onNamePopupScroll, onScrollToBottom, } = templateNamesOptions || {};
37
37
  const { label: descriptionLabel, placeholder: descriptionPlaceholder } = descriptionOptions || {};
38
38
  const { saveNewText = 'Save as a new media template', saveExistText = 'Save as an existing media template', saveNewValue = 'save-new', saveExistValue = 'save-exist', } = saveOptions || {};
@@ -213,7 +213,9 @@ export const TemplateSaveAs = props => {
213
213
  React.createElement(ImageSlider, Object.assign({ defaultThumbnail: defaultThumbnailValue, onSelectDefault: value => {
214
214
  form.setFieldValue('defaultThumbnail', value);
215
215
  handleChangeValue({ defaultThumbnail: value });
216
- } }, restImageReviewProps))),
216
+ },
217
+ // onSelectDefault={value => handleChangeValue({ defaultThumbnail: value })}
218
+ onSaveThumbnail: data => onSaveThumbnail === null || onSaveThumbnail === void 0 ? void 0 : onSaveThumbnail(data) }, restImageReviewProps))),
217
219
  isLoadingCategories ? (React.createElement(Flex, { className: "field-container" },
218
220
  React.createElement(Text, { className: "field-title" }, "Categories"),
219
221
  React.createElement(Space, { style: {
@@ -7,6 +7,8 @@ interface BigImageProps {
7
7
  imageFit?: React.CSSProperties['objectFit'];
8
8
  index: number;
9
9
  onClickDefaultButton?: (index: number) => void;
10
+ onClickEdit?: (index: number) => void;
11
+ onClickUpload?: (index: number) => void;
10
12
  }
11
13
  export declare const BigImage: React.FC<BigImageProps>;
12
14
  export {};
@@ -1,10 +1,10 @@
1
1
  import React, { useMemo } from 'react';
2
- import { Image } from 'antd';
3
- import { Button } from '@antscorp/antsomi-ui/es/components';
2
+ import { ConfigProvider, Image, Tooltip } from 'antd';
3
+ import { Button, Flex, Checkbox } from '@antscorp/antsomi-ui/es/components';
4
4
  import Icon from '@antscorp/icons';
5
5
  import { checkShowSkeletonBaseUrl, getUrlNoCache } from '@antscorp/antsomi-ui/es/utils';
6
6
  export const BigImage = React.memo(props => {
7
- const { url, isDefaultThumbnail, isHideDefaultButton, index, showSkeleton, imageFit, onClickDefaultButton, } = props;
7
+ const { url, isDefaultThumbnail, isHideDefaultButton, index, showSkeleton, imageFit, onClickDefaultButton, onClickEdit, onClickUpload, } = props;
8
8
  const currentTime = useMemo(() => new Date(), []);
9
9
  const timeGenerated = Math.floor(currentTime.getTime() / 1000 - (currentTime.getTime() % 3)) * 1000;
10
10
  const urlNoCache = getUrlNoCache(url, timeGenerated);
@@ -13,7 +13,13 @@ export const BigImage = React.memo(props => {
13
13
  url ? (React.createElement(Image, { preview: false, width: "100%", height: "100%", src: urlNoCache, style: { objectFit: imageFit }, onError: e => {
14
14
  e.currentTarget.style.display = 'none';
15
15
  } })) : null,
16
- isHideDefaultButton ? null : (React.createElement(Button, { className: "set-default-button", onClick: () => onClickDefaultButton && onClickDefaultButton(index) },
17
- isDefaultThumbnail ? React.createElement(Icon, { type: "icon-ants-check", style: { fontSize: '12px' } }) : null,
18
- isDefaultThumbnail ? 'Default thumbnail' : 'Set as default'))));
16
+ isHideDefaultButton || !isDefaultThumbnail ? null : (React.createElement(ConfigProvider, { theme: {
17
+ components: { Checkbox: { borderRadiusSM: 1000 }, Tooltip: { borderRadius: 10 } },
18
+ } },
19
+ React.createElement(Tooltip, { title: "Default thumbnail", zIndex: 5000 },
20
+ React.createElement(Checkbox, { checked: true, className: "default-checkbox" })))),
21
+ React.createElement(Flex, { className: "set-default-button", gap: 8 },
22
+ isHideDefaultButton || isDefaultThumbnail ? null : (React.createElement(Button, { onClick: () => onClickDefaultButton && onClickDefaultButton(index) }, "Set as default")),
23
+ React.createElement(Button, { icon: React.createElement(Icon, { type: "icon-ants-pencil" }), size: "middle", style: { fontSize: '14px' }, onClick: () => onClickEdit === null || onClickEdit === void 0 ? void 0 : onClickEdit(index) }),
24
+ React.createElement(Button, { icon: React.createElement(Icon, { type: "icon-ants-file-upload" }), size: "middle", style: { fontSize: '14px' }, onClick: () => onClickUpload === null || onClickUpload === void 0 ? void 0 : onClickUpload(index) }))));
19
25
  });
@@ -11,11 +11,16 @@ export interface ImageSliderProps {
11
11
  imageWidth?: number;
12
12
  imageHeight?: number;
13
13
  infinity?: boolean;
14
+ useFabric?: boolean;
14
15
  thumbnailFit?: React.CSSProperties['objectFit'];
15
16
  /**
16
17
  * Default thumbnail - order of default thumbnail in thumbnails array
17
18
  */
18
19
  defaultThumbnail?: number;
19
20
  onSelectDefault?: (imgIndex: number) => void;
21
+ onSaveThumbnail?: (data: {
22
+ thumbnails: (string | undefined)[];
23
+ thumbnailChange: number;
24
+ }) => void;
20
25
  }
21
26
  export declare const ImageSlider: React.FC<ImageSliderProps>;
@@ -2,22 +2,30 @@
2
2
  import React, { useState, useRef, useMemo, useCallback, useEffect } from 'react';
3
3
  import Icon from '@antscorp/icons';
4
4
  // Components
5
- import { Flex, Spin } from '@antscorp/antsomi-ui/es/components';
5
+ import { Button, Flex, ImageResize, message, Spin, Typography, ImageResizeTuiEditor, } from '@antscorp/antsomi-ui/es/components';
6
6
  // Styles
7
7
  import { ImageSliderStyled } from './styled';
8
8
  import { SmallImage } from './SmallImage';
9
9
  import { BigImage } from './BigImage';
10
+ import { useDropFile } from '@antscorp/antsomi-ui/es/hooks';
11
+ import { checkShowSkeletonBaseUrl, getUrlNoCache } from '@antscorp/antsomi-ui/es/utils';
12
+ // Image size limit to 10MB
13
+ const SIZE_LIMIT = 10 * 1024 * 1024;
10
14
  const ButtonSlider = React.memo(({ direction, type, onClick }) => (React.createElement("div", { className: type === 'slider'
11
15
  ? `slider-button slider-button--${direction}`
12
16
  : `change-preview-button change-preview-button--${direction}`, onClick: onClick },
13
17
  React.createElement(Icon, { type: `icon-ants-angle-${direction}` }))));
14
18
  export const ImageSlider = props => {
15
- const { thumbnails, isLoading, className, skeleton, previewNavigation, slidesPerView = 3, hideThumbnailsList, hideDefaultButton, imageWidth = 330, imageHeight = 230, infinity = true, defaultThumbnail, thumbnailFit, onSelectDefault, } = props;
19
+ const { thumbnails, isLoading, className, skeleton, previewNavigation, slidesPerView = 3, hideThumbnailsList, hideDefaultButton, imageWidth = 330, imageHeight = 230, infinity = true, defaultThumbnail, thumbnailFit, onSelectDefault, onSaveThumbnail, useFabric = false, } = props;
16
20
  const sliderContainerRef = useRef(null);
17
21
  const thumbnailSelectedRef = useRef(null);
22
+ const imageResizeRef = useRef(null);
18
23
  const smallImageWidth = useMemo(() => imageWidth / slidesPerView - (10 * (slidesPerView - 1)) / slidesPerView, [imageWidth, slidesPerView]);
19
24
  const [selectedThumbnail, setSelectedThumbnail] = useState(0);
20
25
  const [defaultThumbnailInternal, setDefaultThumbnailInternal] = useState(defaultThumbnail || 0);
26
+ const [editingThumbnail, setEditingThumbnail] = useState();
27
+ const [uploadThumbnail, setUploadThumbnail] = useState();
28
+ const [latestCanvas, setLatestCanvas] = useState();
21
29
  // Effects
22
30
  useEffect(() => {
23
31
  setDefaultThumbnailInternal(defaultThumbnail || 0);
@@ -33,16 +41,17 @@ export const ImageSlider = props => {
33
41
  behavior: 'smooth',
34
42
  });
35
43
  }, [imageWidth, smallImageWidth]);
44
+ const thumbnailsQuantity = thumbnails.length;
36
45
  const handleNextThumbnail = useCallback(() => {
37
46
  setSelectedThumbnail(prev => {
38
- const newValue = prev === thumbnails.length - 1 ? 0 : prev + 1;
47
+ const newValue = prev === thumbnailsQuantity - 1 ? 0 : prev + 1;
39
48
  handleScroll(newValue);
40
49
  return newValue;
41
50
  });
42
51
  }, [thumbnails, handleScroll]);
43
52
  const handlePrevThumbnail = useCallback(() => {
44
53
  setSelectedThumbnail(prev => {
45
- const newValue = prev === 0 ? thumbnails.length - 1 : prev - 1;
54
+ const newValue = prev === 0 ? thumbnailsQuantity - 1 : prev - 1;
46
55
  handleScroll(newValue);
47
56
  return newValue;
48
57
  });
@@ -58,13 +67,88 @@ export const ImageSlider = props => {
58
67
  onSelectDefault(index);
59
68
  }
60
69
  }, [onSelectDefault]);
70
+ const handleSaveThumbnail = () => {
71
+ var _a;
72
+ const newThumbnail = [...thumbnails];
73
+ // NOTE: https://konvajs.org/docs/data_and_serialization/High-Quality-Export.html
74
+ newThumbnail[selectedThumbnail] = (_a = imageResizeRef.current) === null || _a === void 0 ? void 0 : _a.getBase64({ pixelRatio: 2.5 });
75
+ onSaveThumbnail === null || onSaveThumbnail === void 0 ? void 0 : onSaveThumbnail({ thumbnails: newThumbnail, thumbnailChange: selectedThumbnail });
76
+ setLatestCanvas(prev => {
77
+ var _a;
78
+ return (Object.assign(Object.assign({}, prev), { [selectedThumbnail]: (_a = imageResizeRef.current) === null || _a === void 0 ? void 0 : _a.getCurrentState() }));
79
+ });
80
+ setEditingThumbnail(undefined);
81
+ };
82
+ const fileRef = useRef(null);
83
+ const onImportImageClick = useCallback(() => {
84
+ var _a;
85
+ (_a = fileRef === null || fileRef === void 0 ? void 0 : fileRef.current) === null || _a === void 0 ? void 0 : _a.click();
86
+ }, []);
87
+ const onImportImageSelect = (e) => {
88
+ var _a, _b, _c;
89
+ if ((_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0]) {
90
+ if (((_b = e.target.files) === null || _b === void 0 ? void 0 : _b[0].size) > SIZE_LIMIT) {
91
+ return message.error('File size too big');
92
+ }
93
+ (_c = imageResizeRef.current) === null || _c === void 0 ? void 0 : _c.replaceImageWithUrl(URL.createObjectURL(e.target.files[0]));
94
+ setUploadThumbnail(undefined);
95
+ }
96
+ e.target.files = null;
97
+ };
98
+ useDropFile('.image-upload-zone', e => {
99
+ var _a, _b, _c, _d;
100
+ if (!((_a = e === null || e === void 0 ? void 0 : e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files[0]))
101
+ return;
102
+ if (((_b = e === null || e === void 0 ? void 0 : e.dataTransfer) === null || _b === void 0 ? void 0 : _b.files[0].size) > SIZE_LIMIT) {
103
+ return message.error('File size too big');
104
+ }
105
+ (_c = imageResizeRef.current) === null || _c === void 0 ? void 0 : _c.replaceImageWithUrl(URL.createObjectURL((_d = e === null || e === void 0 ? void 0 : e.dataTransfer) === null || _d === void 0 ? void 0 : _d.files[0]));
106
+ setUploadThumbnail(undefined);
107
+ });
108
+ const currentTime = useMemo(() => new Date(), []);
109
+ const timeGenerated = Math.floor(currentTime.getTime() / 1000 - (currentTime.getTime() % 3)) * 1000;
110
+ const currentEditing = useMemo(() => editingThumbnail !== null && editingThumbnail !== void 0 ? editingThumbnail : uploadThumbnail, [editingThumbnail, uploadThumbnail]);
111
+ const imageResizeProps = {
112
+ className: 'image-resize-wrapper',
113
+ width: imageWidth,
114
+ height: imageHeight,
115
+ ref: imageResizeRef,
116
+ hideAction: true,
117
+ imageUrl:
118
+ // latestCanvas && isEditPrevious
119
+ (latestCanvas === null || latestCanvas === void 0 ? void 0 : latestCanvas[currentEditing])
120
+ ? undefined
121
+ : getUrlNoCache(thumbnails[currentEditing], timeGenerated),
122
+ defaultValue: latestCanvas === null || latestCanvas === void 0 ? void 0 : latestCanvas[currentEditing],
123
+ };
124
+ const ImageResizeComponent = useFabric ? ImageResizeTuiEditor : ImageResize;
125
+ const showSkeletonMemo = skeleton !== undefined
126
+ ? skeleton
127
+ : checkShowSkeletonBaseUrl(getUrlNoCache(thumbnails[currentEditing], timeGenerated));
61
128
  return (React.createElement(ImageSliderStyled, { className: className || '', "$skeleton": skeleton, "$imageWidth": imageWidth, "$smallImageWidth": smallImageWidth, "$imageHeight": imageHeight, vertical: true, gap: 10 },
62
- React.createElement(Flex, { className: "thumbnail-preview-container", ref: thumbnailSelectedRef }, isLoading ? (React.createElement(Spin, { spinning: true })) : (thumbnails.map((url, index) => (React.createElement(BigImage, { key: `image-big_${url}_${index * 2}`, url: url, index: index, showSkeleton: skeleton, isDefaultThumbnail: defaultThumbnailInternal === index, isHideDefaultButton: hideDefaultButton || hideThumbnailsList || thumbnails.length <= 1, imageFit: thumbnailFit, onClickDefaultButton: handleClickDefault }))))),
63
- hideThumbnailsList || thumbnails.length <= 1 ? null : (React.createElement(Flex, { gap: 10, className: "thumbnail-slider-container", ref: sliderContainerRef, style: { justifyContent: thumbnails.length < slidesPerView ? 'center' : 'flex-start' } }, isLoading ? (React.createElement(Spin, { spinning: true })) : (thumbnails.map((url, index) => (React.createElement(SmallImage, { imageFit: thumbnailFit, key: `${url}_${index * 2}`, showSkeleton: skeleton, isSelected: index === selectedThumbnail, url: url, index: index, onClick: handleSelectThumbnail })))))),
129
+ typeof editingThumbnail === 'number' || typeof uploadThumbnail === 'number' ? (React.createElement(Flex, { vertical: true, style: { zIndex: 25 }, className: "edit-thumbnail-container" },
130
+ React.createElement(ImageResizeComponent, Object.assign({}, imageResizeProps)),
131
+ typeof uploadThumbnail !== 'number' ? null : (React.createElement(Flex, { className: `image-upload-zone ${!showSkeletonMemo ? 'hide-skeleton' : ''}` },
132
+ React.createElement(Icon, { type: "icon-ants-upload-fill", style: { fontSize: '40px' } }),
133
+ React.createElement(Flex, { vertical: true, align: "flex-start" },
134
+ React.createElement(Typography.Text, { style: { fontSize: 16, marginBottom: '10px' } }, "Drag & Drop file here"),
135
+ React.createElement("input", { type: "file", ref: fileRef, onChange: onImportImageSelect, style: { display: 'none' }, accept: "image/*" }),
136
+ React.createElement(Button, { onClick: onImportImageClick }, "Browse Image"),
137
+ React.createElement(Typography.Text, { style: { marginTop: '5px' } }, "File type: .jpg, .png. File size: under 10MB")))),
138
+ React.createElement(Flex, { justify: "center", align: "center", gap: 8, className: "image-resize-action" },
139
+ React.createElement(Button, { onClick: handleSaveThumbnail, type: "primary", disabled: uploadThumbnail !== undefined }, "Save"),
140
+ React.createElement(Button, { onClick: () => {
141
+ setEditingThumbnail(undefined);
142
+ setUploadThumbnail(undefined);
143
+ } }, "Cancel")))) : (React.createElement(Flex, { className: "thumbnail-preview-container", ref: thumbnailSelectedRef }, isLoading ? (React.createElement(Spin, { spinning: true })) : (thumbnails.map((url, index) => (React.createElement(BigImage, { key: `image-big_${url}_${index * 2}`, url: url, index: index, showSkeleton: skeleton, isDefaultThumbnail: defaultThumbnailInternal === index, isHideDefaultButton: hideDefaultButton || hideThumbnailsList || thumbnailsQuantity <= 1, imageFit: thumbnailFit, onClickDefaultButton: handleClickDefault, onClickEdit: index => setEditingThumbnail(index), onClickUpload: index => {
144
+ setEditingThumbnail(index);
145
+ setUploadThumbnail(index);
146
+ } })))))),
147
+ hideThumbnailsList || thumbnailsQuantity <= 1 ? null : (React.createElement(Flex, { gap: 10, className: "thumbnail-slider-container", ref: sliderContainerRef, style: { justifyContent: thumbnailsQuantity < slidesPerView ? 'center' : 'flex-start' } }, isLoading ? (React.createElement(Spin, { spinning: true })) : (thumbnails.map((url, index) => (React.createElement(SmallImage, { imageFit: thumbnailFit, key: `${url}_${index * 2}`, showSkeleton: skeleton, isSelected: index === selectedThumbnail, url: url, index: index, onClick: handleSelectThumbnail })))))),
64
148
  previewNavigation && !isLoading ? (React.createElement(React.Fragment, null,
65
149
  React.createElement(ButtonSlider, { direction: "left", type: "preview", onClick: handlePrevThumbnail }),
66
150
  React.createElement(ButtonSlider, { direction: "right", type: "preview", onClick: handleNextThumbnail }))) : null,
67
- hideThumbnailsList || isLoading || thumbnails.length <= 2 ? null : (React.createElement(React.Fragment, null,
151
+ hideThumbnailsList || isLoading || thumbnailsQuantity <= 2 ? null : (React.createElement(React.Fragment, null,
68
152
  (!infinity && selectedThumbnail !== 0) || infinity ? (React.createElement(ButtonSlider, { direction: "left", type: "slider", onClick: handlePrevThumbnail })) : null,
69
- (!infinity && selectedThumbnail !== thumbnails.length - 1) || infinity ? (React.createElement(ButtonSlider, { direction: "right", type: "slider", onClick: handleNextThumbnail })) : null))));
153
+ (!infinity && selectedThumbnail !== thumbnailsQuantity - 1) || infinity ? (React.createElement(ButtonSlider, { direction: "right", type: "slider", onClick: handleNextThumbnail })) : null))));
70
154
  };
@@ -1,4 +1,4 @@
1
- var _a, _b;
1
+ var _a, _b, _c, _d, _e, _f;
2
2
  // Libraries
3
3
  import styled, { css } from 'styled-components';
4
4
  import { Flex } from '@antscorp/antsomi-ui/es/components';
@@ -32,6 +32,60 @@ export const ImageSliderStyled = styled(Flex) `
32
32
  position: relative;
33
33
  margin-top: 6px;
34
34
 
35
+ .edit-thumbnail-container {
36
+ position: relative;
37
+ }
38
+
39
+ .image-resize-action {
40
+ margin-top: 20px;
41
+ margin-bottom: 40px;
42
+ }
43
+
44
+ .image-resize-wrapper {
45
+ background: ${props => props.$skeleton ? `url(${SkeletonBg}) no-repeat center center` : 'unset'};
46
+
47
+ background-size: 90% 90%;
48
+ }
49
+
50
+ .image-resize-wrapper,
51
+ .image-upload-zone {
52
+ border: 1px solid ${(_a = THEME.token) === null || _a === void 0 ? void 0 : _a.blue1_1};
53
+ border-radius: 5px;
54
+ margin-top: 0;
55
+ overflow: hidden;
56
+ }
57
+
58
+ &:has(.image-upload-zone) #image-editor {
59
+ display: none;
60
+ }
61
+
62
+ .image-upload-zone {
63
+ justify-content: center;
64
+ align-items: center;
65
+ gap: 20px;
66
+
67
+ position: absolute;
68
+ top: 0;
69
+ left: 0;
70
+ width: ${props => `${props.$imageWidth}px`};
71
+ height: ${props => `${props.$imageHeight}px`};
72
+ background: ${(_b = THEME.token) === null || _b === void 0 ? void 0 : _b.colorBgSkeleton};
73
+
74
+ & > i {
75
+ color: ${(_c = THEME.token) === null || _c === void 0 ? void 0 : _c.bw8};
76
+ }
77
+
78
+ & > div > span:last-child {
79
+ color: ${(_d = THEME.token) === null || _d === void 0 ? void 0 : _d.bw7};
80
+ }
81
+
82
+ &:not(.hide-skeleton) {
83
+ background: ${props => props.$skeleton ? `url(${SkeletonBg}) no-repeat center center` : 'unset'};
84
+
85
+ background-size: 90% 90%;
86
+ }
87
+ }
88
+
35
89
  .change-preview-button {
36
90
  ${centerBlock}
37
91
  position: absolute;
@@ -125,7 +179,7 @@ export const ImageSliderStyled = styled(Flex) `
125
179
  }
126
180
  }
127
181
 
128
- &:has(> .thumbnail-preview-container + .thumbnail-slider-container) {
182
+ &:has(> .thumbnail-preview-container) {
129
183
  .image-container--big::before {
130
184
  content: '';
131
185
  position: absolute;
@@ -148,8 +202,8 @@ export const ImageSliderStyled = styled(Flex) `
148
202
  &--small {
149
203
  position: relative;
150
204
  box-sizing: border-box;
151
- background: ${(_a = THEME.token) === null || _a === void 0 ? void 0 : _a.colorBgSkeleton};
152
- border: 1px solid ${(_b = THEME.token) === null || _b === void 0 ? void 0 : _b.blue1_1};
205
+ background: ${(_e = THEME.token) === null || _e === void 0 ? void 0 : _e.colorBgSkeleton};
206
+ border: 1px solid ${(_f = THEME.token) === null || _f === void 0 ? void 0 : _f.blue1_1};
153
207
  border-radius: 5px;
154
208
 
155
209
  ${centerBlock}
@@ -196,6 +250,15 @@ export const ImageSliderStyled = styled(Flex) `
196
250
  }
197
251
  }
198
252
 
253
+ .default-checkbox {
254
+ position: absolute;
255
+ top: 10px;
256
+ left: 10px;
257
+ opacity: 0;
258
+ z-index: 3;
259
+ transition: opacity 150ms ease-in-out;
260
+ }
261
+
199
262
  .set-default-button {
200
263
  position: absolute;
201
264
  top: 50%;
@@ -205,8 +268,10 @@ export const ImageSliderStyled = styled(Flex) `
205
268
  opacity: 0;
206
269
  transition: opacity 150ms ease-in-out;
207
270
  }
271
+
208
272
  .image-container--big:hover {
209
- .set-default-button {
273
+ .set-default-button,
274
+ .default-checkbox {
210
275
  opacity: 1;
211
276
  }
212
277
  }
@@ -8,6 +8,20 @@ export const TemplateSaveAsStyled = styled(Flex) `
8
8
  /* max-width: 1177px; */
9
9
  height: 100%;
10
10
 
11
+ position: relative;
12
+
13
+ &:has(canvas),
14
+ &:has(.image-upload-zone) {
15
+ &:after {
16
+ content: '';
17
+ position: absolute;
18
+ inset: 0;
19
+ background-color: #fff;
20
+ opacity: 0.5;
21
+ z-index: 20;
22
+ }
23
+ }
24
+
11
25
  .save-options-container {
12
26
  padding: 15px 0;
13
27
  margin-bottom: 20px;
@@ -124,3 +138,11 @@ export const TemplateSaveAsStyled = styled(Flex) `
124
138
  }
125
139
  }
126
140
  `;
141
+ // export const FormStyled = styled(Form)`
142
+ // position: relative;
143
+ // &::after {
144
+ // position: absolute;
145
+ // inset: 0;
146
+ // background-color: rgba(255, 255, 255, 0.5);
147
+ // }
148
+ // `;
@@ -18,6 +18,7 @@ export { InputSearch } from './InputSearch';
18
18
  export { UploadImage } from './UploadImage';
19
19
  export { IconSelection } from './IconSelection';
20
20
  export { ImageEditor as ImageResize } from './ImageEditor';
21
+ export { ImageResizeTuiEditor } from './ImageResizeTuiEditor';
21
22
  export { IconSelectionRenderer } from './IconSelection/components/Icon';
22
23
  export { AlignSetting } from './AlignSetting';
23
24
  export { EdgeSetting } from './EdgeSetting';
@@ -62,3 +63,4 @@ export type { TemplateValueOptions } from './TemplateSaveAs';
62
63
  export type { SelectProps as SelectV2Props } from './SelectV2';
63
64
  export type { InputNumberProps as InputNumberWithLabelProps } from './InputNumber';
64
65
  export type { ModalSelectProps } from './ModalSelect';
66
+ export type { ImageResizeHandle } from './ImageEditor';
@@ -18,6 +18,7 @@ export { InputSearch } from './InputSearch';
18
18
  export { UploadImage } from './UploadImage';
19
19
  export { IconSelection } from './IconSelection';
20
20
  export { ImageEditor as ImageResize } from './ImageEditor';
21
+ export { ImageResizeTuiEditor } from './ImageResizeTuiEditor';
21
22
  export { IconSelectionRenderer } from './IconSelection/components/Icon';
22
23
  export { AlignSetting } from './AlignSetting';
23
24
  export { EdgeSetting } from './EdgeSetting';
@@ -114,6 +114,11 @@ export const GlobalStyle = () => {
114
114
  height: 36px !important;
115
115
  }
116
116
 
117
+ &.antsomi-btn-icon-only.antsomi-btn-default {
118
+ width: 30px !important;
119
+ height: 30px !important;
120
+ }
121
+
117
122
  &.antsomi-btn-icon-only.antsomi-btn-sm {
118
123
  /* Important to override the above code before */
119
124
  width: 24px !important;
package/es/test.js CHANGED
@@ -19,7 +19,6 @@ import { GET_LIST_TYPE, OBJECT_TYPES, PUBLIC_LEVEL } from './constants';
19
19
  import axios from 'axios';
20
20
  import { get } from 'lodash';
21
21
  import { MENU_PERMISSION } from './components/molecules/ShareAccess/constants';
22
- import { QueryClientProviderAntsomiUI, queryClientAntsomiUI } from './queries';
23
22
  import { ConfigProvider } from './providers';
24
23
  const SHARE_ACCESS_DEFAULT_VALUE = {
25
24
  ownerId: 1600085510,
@@ -206,6 +205,7 @@ export const App = () => {
206
205
  };
207
206
  const container = document.getElementById('root');
208
207
  const root = createRoot(container);
209
- root.render(React.createElement(QueryClientProviderAntsomiUI, { client: queryClientAntsomiUI },
210
- React.createElement(ConfigProvider, { locale: "en" },
211
- React.createElement(App, null))));
208
+ root.render(
209
+ // <QueryClientProviderAntsomiUI client={queryClientAntsomiUI}>
210
+ React.createElement(ConfigProvider, { locale: "en" },
211
+ React.createElement(App, null)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antscorp/antsomi-ui",
3
- "version": "1.3.5-beta.261",
3
+ "version": "1.3.5-beta.263",
4
4
  "description": "An enterprise-class UI design language and React UI library.",
5
5
  "sideEffects": [
6
6
  "dist/*",
@@ -85,6 +85,7 @@
85
85
  "currency-formatter": "1.5.9",
86
86
  "d3-interpolate": "^3.0.1",
87
87
  "dayjs": "^1.11.10",
88
+ "fabric": "^5.3.0",
88
89
  "font-awesome": "4.7.0",
89
90
  "highlight.js": "^11.8.0",
90
91
  "html-entities": "^2.0.2",