@antscorp/antsomi-ui 1.4.4 → 1.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/components/common/ConfigProvider/GlobalStyle.js +4 -0
- package/es/components/molecules/DatePicker/components/AdvancedPicker/AdvancedPicker.js +1 -1
- package/es/components/molecules/DatePicker/components/AdvancedPicker/styled.d.ts +1 -0
- package/es/components/molecules/DatePicker/components/AdvancedPicker/styled.js +2 -1
- package/es/components/molecules/DatePicker/components/AdvancedPicker/utils.d.ts +12 -0
- package/es/components/molecules/DatePicker/components/AdvancedPicker/utils.js +27 -0
- package/es/components/molecules/DatePicker/components/AdvancedRangePicker/AdvancedRangePicker.d.ts +4 -0
- package/es/components/molecules/DatePicker/components/AdvancedRangePicker/AdvancedRangePicker.js +12 -3
- package/es/components/molecules/TemplateSaveAs/TemplateSaveAs.js +4 -1
- package/es/components/molecules/TemplateSaveAs/components/ImageSlider/BigImage.d.ts +2 -0
- package/es/components/molecules/TemplateSaveAs/components/ImageSlider/BigImage.js +8 -8
- package/es/components/molecules/TemplateSaveAs/components/ImageSlider/ImageSlider.d.ts +1 -0
- package/es/components/molecules/TemplateSaveAs/components/ImageSlider/ImageSlider.js +8 -4
- package/es/components/molecules/TemplateSaveAs/components/ImageSlider/SmallImage.d.ts +2 -0
- package/es/components/molecules/TemplateSaveAs/components/ImageSlider/SmallImage.js +8 -8
- package/es/components/molecules/TemplateSaveAs/components/ImageSlider/styled.js +9 -9
- package/es/components/molecules/TemplateSaveAs/styled.js +2 -1
- package/es/components/molecules/ThumbnailCard/ThumbnailCard.js +12 -4
- package/es/components/molecules/ThumbnailCard/types.d.ts +2 -1
- package/es/components/organism/PreviewTemplateModal/components/Information/styled.js +6 -1
- package/es/constants/theme.js +2 -1
- package/es/utils/common.d.ts +1 -1
- package/es/utils/common.js +14 -5
- package/es/utils/templateListing.d.ts +1 -0
- package/es/utils/templateListing.js +17 -0
- package/package.json +1 -1
|
@@ -407,7 +407,7 @@ export const AdvancedPicker = props => {
|
|
|
407
407
|
React.createElement(ErrorMessage, { errorMessage: errorMessage })),
|
|
408
408
|
renderDropdownFooter()),
|
|
409
409
|
React.createElement(Divider, null),
|
|
410
|
-
timeFormat && valueType !== 'HOUR' && valueType !== 'MINUTE' ? (React.createElement(TimeLabel, { "$width": timeFormat.length * 30 },
|
|
410
|
+
timeFormat && valueType !== 'HOUR' && valueType !== 'MINUTE' ? (React.createElement(TimeLabel, { "$width": timeFormat.length * 30, "$isRangePicker": operatorKey === 'between' },
|
|
411
411
|
['HH', 'HHmm', 'HHmmss'].includes(timeFormat) ? React.createElement("span", null, "Hours") : null,
|
|
412
412
|
['HHmm', 'HHmmss', 'mm'].includes(timeFormat) ? React.createElement("span", null, "Minutes") : null,
|
|
413
413
|
timeFormat === 'HHmmss' ? React.createElement("span", null, "Seconds") : null)) : null));
|
|
@@ -9,4 +9,5 @@ export declare const DatePickerFooter: import("styled-components").StyledCompone
|
|
|
9
9
|
export declare const CalendarIconWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
10
10
|
export declare const TimeLabel: import("styled-components").StyledComponent<"div", any, {
|
|
11
11
|
$width: number;
|
|
12
|
+
$isRangePicker: boolean;
|
|
12
13
|
}, never>;
|
|
@@ -101,7 +101,8 @@ export const CalendarIconWrapper = styled.div `
|
|
|
101
101
|
export const TimeLabel = styled.div `
|
|
102
102
|
position: absolute;
|
|
103
103
|
right: 0;
|
|
104
|
-
top: 120px;
|
|
104
|
+
/* top: 120px; */
|
|
105
|
+
top: ${props => (props.$isRangePicker ? '140px' : '120px')};
|
|
105
106
|
height: 39.1px;
|
|
106
107
|
width: ${props => `${props.$width}px`};
|
|
107
108
|
/* width: 180px; */
|
|
@@ -37,3 +37,15 @@ export declare const getFormatDisplay: (operatorKey?: TOperatorKey, type?: TAdva
|
|
|
37
37
|
formatDisplay: string;
|
|
38
38
|
timeFormatDisplay: string;
|
|
39
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* Returns the formatted display string based on the given type and value type.
|
|
42
|
+
*
|
|
43
|
+
* @param {TAdvancedType} [type] - The type indicating whether it's a start or end date.
|
|
44
|
+
* @param {ValueTypes} [valueType] - The value type specifying the date/time format.
|
|
45
|
+
* @returns {string} The formatted display string.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // returns ADVANCED_RANGE_PICKER_FORMAT.general
|
|
49
|
+
* getFormatDisplayFromValueType('anyType', 'YEAR_MONTH_DAY_SECOND');
|
|
50
|
+
*/
|
|
51
|
+
export declare const getFormatDisplayFromValueType: (type?: TAdvancedType, valueType?: ValueTypes) => string;
|
|
@@ -8,6 +8,7 @@ import utc from 'dayjs/plugin/utc';
|
|
|
8
8
|
import timezone from 'dayjs/plugin/timezone';
|
|
9
9
|
// Constants
|
|
10
10
|
import { DATE_TYPE_MAPPING, DEFAULT_DATE_FORMAT, MONTH_LABEL_SHORT, QUARTER_PLACEHOLDER, WEEK_PLACEHOLDER, } from './constants';
|
|
11
|
+
import { ADVANCED_RANGE_PICKER_FORMAT } from '../AdvancedRangePicker/constants';
|
|
11
12
|
dayjs.extend(isoWeek);
|
|
12
13
|
dayjs.extend(quarterOfYear);
|
|
13
14
|
dayjs.extend(utc);
|
|
@@ -209,3 +210,29 @@ export const getFormatDisplay = (operatorKey, type, valueType, formatInputDispla
|
|
|
209
210
|
}
|
|
210
211
|
return { formatDisplay: formatInputDisplay || formatDisplay, timeFormatDisplay };
|
|
211
212
|
};
|
|
213
|
+
/**
|
|
214
|
+
* Returns the formatted display string based on the given type and value type.
|
|
215
|
+
*
|
|
216
|
+
* @param {TAdvancedType} [type] - The type indicating whether it's a start or end date.
|
|
217
|
+
* @param {ValueTypes} [valueType] - The value type specifying the date/time format.
|
|
218
|
+
* @returns {string} The formatted display string.
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* // returns ADVANCED_RANGE_PICKER_FORMAT.general
|
|
222
|
+
* getFormatDisplayFromValueType('anyType', 'YEAR_MONTH_DAY_SECOND');
|
|
223
|
+
*/
|
|
224
|
+
export const getFormatDisplayFromValueType = (type, valueType) => {
|
|
225
|
+
switch (valueType) {
|
|
226
|
+
case 'YEAR_MONTH_DAY_HOUR':
|
|
227
|
+
return type === 'startDate' ? 'YYYY-MM-DD HH:00:00' : 'YYYY-MM-DD HH:59:59';
|
|
228
|
+
case 'YEAR_MONTH_DAY_MINUTE':
|
|
229
|
+
return type === 'startDate' ? 'YYYY-MM-DD HH:mm:00' : 'YYYY-MM-DD HH:mm:59';
|
|
230
|
+
case 'YEAR_MONTH_DAY_SECOND':
|
|
231
|
+
return ADVANCED_RANGE_PICKER_FORMAT.general;
|
|
232
|
+
case 'YEAR_MONTH_DAY':
|
|
233
|
+
default:
|
|
234
|
+
return type === 'startDate'
|
|
235
|
+
? ADVANCED_RANGE_PICKER_FORMAT.startDate
|
|
236
|
+
: ADVANCED_RANGE_PICKER_FORMAT.endDate;
|
|
237
|
+
}
|
|
238
|
+
};
|
package/es/components/molecules/DatePicker/components/AdvancedRangePicker/AdvancedRangePicker.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ import { TDateConfig, TOnChangePayload, TTimeRange } from './types';
|
|
|
4
4
|
export interface AdvancedRangePickerProps {
|
|
5
5
|
className?: string;
|
|
6
6
|
valueType?: ValueTypes;
|
|
7
|
+
/**
|
|
8
|
+
* If true => auto generate time format from valueType props; else use hard config
|
|
9
|
+
*/
|
|
10
|
+
useFormatMapping?: boolean;
|
|
7
11
|
disabled?: boolean;
|
|
8
12
|
showCalculationTypeCondition?: TShowCalculationTypeCondition;
|
|
9
13
|
startDateConfig?: TDateConfig;
|
package/es/components/molecules/DatePicker/components/AdvancedRangePicker/AdvancedRangePicker.js
CHANGED
|
@@ -15,11 +15,12 @@ import { handleError } from '@antscorp/antsomi-ui/es/utils';
|
|
|
15
15
|
import { translations } from '@antscorp/antsomi-ui/es/locales/translations';
|
|
16
16
|
// Instance
|
|
17
17
|
import i18nInstance from '@antscorp/antsomi-ui/es/locales/i18n';
|
|
18
|
+
import { getFormatDisplayFromValueType } from '../AdvancedPicker/utils';
|
|
18
19
|
const PATH = '@antscorp/antsomi-ui/es/components/molecules/DatePicker/components/AdvancedRangePicker/AdvancedRangePicker.tsx';
|
|
19
20
|
export const AdvancedRangePicker = props => {
|
|
20
21
|
const { t } = i18nInstance;
|
|
21
22
|
// Props
|
|
22
|
-
const { className, valueType, timeRange, errorMessage, showLabel, startDateConfig, endDateConfig, showTime, showCalculationTypeCondition, disabled, timezone, separator, inputStyle, isViewMode, onChange, } = props;
|
|
23
|
+
const { className, valueType, useFormatMapping, timeRange, errorMessage, showLabel, startDateConfig, endDateConfig, showTime, showCalculationTypeCondition, disabled, timezone, separator, inputStyle, isViewMode, onChange, } = props;
|
|
23
24
|
const [timeRangeState, setTimeRange] = useState(timeRange);
|
|
24
25
|
useDeepCompareEffect(() => {
|
|
25
26
|
if (typeof onChange === 'function') {
|
|
@@ -55,9 +56,17 @@ export const AdvancedRangePicker = props => {
|
|
|
55
56
|
}
|
|
56
57
|
};
|
|
57
58
|
return (React.createElement(Space, { size: 20, align: "end", className: className || '' },
|
|
58
|
-
React.createElement(AdvancedPicker, { valueType: valueType, disabled: disabled, label: showLabel ? t(translations.datePicker.startDate) || '' : '', date: timeRange.startDate.date, option: omit(timeRange.startDate, 'date'), operatorKey: "between", type: "startDate", format:
|
|
59
|
+
React.createElement(AdvancedPicker, { valueType: valueType, disabled: disabled, label: showLabel ? t(translations.datePicker.startDate) || '' : '', date: timeRange.startDate.date, option: omit(timeRange.startDate, 'date'), operatorKey: "between", type: "startDate", format: useFormatMapping
|
|
60
|
+
? getFormatDisplayFromValueType('startDate', valueType)
|
|
61
|
+
: ADVANCED_RANGE_PICKER_FORMAT.startDate,
|
|
62
|
+
// format={ADVANCED_RANGE_PICKER_FORMAT.startDate}
|
|
63
|
+
errorMessage: errorMessage, disableAfterDate: timeRange.endDate.date, showTime: showTime, calculationTypeKeysShow: startDateConfig === null || startDateConfig === void 0 ? void 0 : startDateConfig.calculationTypeKeysShow, showCalculationTypeCondition: showCalculationTypeCondition, timezone: timezone, onUpdatedNewDate: ({ date }) => onUpdateTimeRange('startDate', { date }, 'system'), onApply: ({ date, option }) => onUpdateTimeRange('startDate', Object.assign({ date }, option), 'user'), inputStyle: inputStyle, isViewMode: isViewMode }),
|
|
59
64
|
separator || null,
|
|
60
|
-
React.createElement(AdvancedPicker, { valueType: valueType, disabled: disabled, label: showLabel ? t(translations.datePicker.endDate) || '' : '', date: timeRange.endDate.date, option: omit(timeRange.endDate, 'date'), operatorKey: "between", type: "endDate", format:
|
|
65
|
+
React.createElement(AdvancedPicker, { valueType: valueType, disabled: disabled, label: showLabel ? t(translations.datePicker.endDate) || '' : '', date: timeRange.endDate.date, option: omit(timeRange.endDate, 'date'), operatorKey: "between", type: "endDate", format: useFormatMapping
|
|
66
|
+
? getFormatDisplayFromValueType('endDate', valueType)
|
|
67
|
+
: ADVANCED_RANGE_PICKER_FORMAT.endDate,
|
|
68
|
+
// format={ADVANCED_RANGE_PICKER_FORMAT.endDate}
|
|
69
|
+
errorMessage: errorMessage, showTime: showTime, calculationTypeKeysShow: endDateConfig === null || endDateConfig === void 0 ? void 0 : endDateConfig.calculationTypeKeysShow, showCalculationTypeCondition: showCalculationTypeCondition, timezone: timezone, onUpdatedNewDate: ({ date }) => onUpdateTimeRange('endDate', { date }, 'system'), onApply: ({ date, option }) => onUpdateTimeRange('endDate', Object.assign({ date }, option), 'user'), inputStyle: inputStyle, isViewMode: isViewMode })));
|
|
61
70
|
};
|
|
62
71
|
AdvancedRangePicker.defaultProps = {
|
|
63
72
|
timeRange: {
|
|
@@ -32,6 +32,7 @@ export const TemplateSaveAs = props => {
|
|
|
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
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 || {};
|
|
36
37
|
const { label: descriptionLabel, placeholder: descriptionPlaceholder } = descriptionOptions || {};
|
|
37
38
|
const { saveNewText = 'Save as a new media template', saveExistText = 'Save as an existing media template', saveNewValue = 'save-new', saveExistValue = 'save-exist', } = saveOptions || {};
|
|
@@ -50,6 +51,8 @@ export const TemplateSaveAs = props => {
|
|
|
50
51
|
};
|
|
51
52
|
const [searchValue, setSearchValue] = useState('');
|
|
52
53
|
const searchValueDebounce = useDebounce(searchValue, 1000);
|
|
54
|
+
// Watches
|
|
55
|
+
const defaultThumbnailValue = Form.useWatch('defaultThumbnail', form);
|
|
53
56
|
// Effects
|
|
54
57
|
useEffect(() => {
|
|
55
58
|
if (searchValueDebounce && onSearch)
|
|
@@ -207,7 +210,7 @@ export const TemplateSaveAs = props => {
|
|
|
207
210
|
React.createElement(Form.Item, { name: "description", label: descriptionLabel || 'Description' },
|
|
208
211
|
React.createElement(Input, { placeholder: descriptionPlaceholder || 'Describe your media template', maxLength: 400, onBlur: e => handleChangeValue({ description: e.target.value }) })),
|
|
209
212
|
React.createElement(Form.Item, { name: "defaultThumbnail", shouldUpdate: true, required: true, label: imageReviewLabel || 'Thumbnail template' },
|
|
210
|
-
React.createElement(ImageSlider, Object.assign({ defaultThumbnail:
|
|
213
|
+
React.createElement(ImageSlider, Object.assign({ defaultThumbnail: defaultThumbnailValue, onSelectDefault: value => {
|
|
211
214
|
form.setFieldValue('defaultThumbnail', value);
|
|
212
215
|
handleChangeValue({ defaultThumbnail: value });
|
|
213
216
|
} }, restImageReviewProps))),
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
interface BigImageProps {
|
|
3
3
|
url?: string;
|
|
4
|
+
showSkeleton?: boolean;
|
|
4
5
|
isDefaultThumbnail?: boolean;
|
|
5
6
|
isHideDefaultButton?: boolean;
|
|
7
|
+
imageFit?: React.CSSProperties['objectFit'];
|
|
6
8
|
index: number;
|
|
7
9
|
onClickDefaultButton?: (index: number) => void;
|
|
8
10
|
}
|
|
@@ -2,17 +2,17 @@ import React, { useMemo } from 'react';
|
|
|
2
2
|
import { Image } from 'antd';
|
|
3
3
|
import { Button } from '@antscorp/antsomi-ui/es/components';
|
|
4
4
|
import Icon from '@antscorp/icons';
|
|
5
|
+
import { checkShowSkeletonBaseUrl, getUrlNoCache } from '@antscorp/antsomi-ui/es/utils';
|
|
5
6
|
export const BigImage = React.memo(props => {
|
|
6
|
-
const { url, isDefaultThumbnail, isHideDefaultButton, index, onClickDefaultButton } = props;
|
|
7
|
+
const { url, isDefaultThumbnail, isHideDefaultButton, index, showSkeleton, imageFit, onClickDefaultButton, } = props;
|
|
7
8
|
const currentTime = useMemo(() => new Date(), []);
|
|
8
9
|
const timeGenerated = Math.floor(currentTime.getTime() / 1000 - (currentTime.getTime() % 3)) * 1000;
|
|
9
|
-
const urlNoCache = url
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
url ? (React.createElement(Image, { preview: false, width: "80%", height: "96%", src: urlNoCache })) : null,
|
|
10
|
+
const urlNoCache = getUrlNoCache(url, timeGenerated);
|
|
11
|
+
const showSkeletonMemo = showSkeleton !== undefined ? showSkeleton : checkShowSkeletonBaseUrl(urlNoCache);
|
|
12
|
+
return (React.createElement("div", { className: `image-container--big ${!showSkeletonMemo ? 'hide-skeleton' : ''}` },
|
|
13
|
+
url ? (React.createElement(Image, { preview: false, width: "100%", height: "100%", src: urlNoCache, style: { objectFit: imageFit }, onError: e => {
|
|
14
|
+
e.currentTarget.style.display = 'none';
|
|
15
|
+
} })) : null,
|
|
16
16
|
isHideDefaultButton ? null : (React.createElement(Button, { className: "set-default-button", onClick: () => onClickDefaultButton && onClickDefaultButton(index) },
|
|
17
17
|
isDefaultThumbnail ? React.createElement(Icon, { type: "icon-ants-check", style: { fontSize: '12px' } }) : null,
|
|
18
18
|
isDefaultThumbnail ? 'Default thumbnail' : 'Set as default'))));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Libraries
|
|
2
|
-
import React, { useState, useRef, useMemo, useCallback } from 'react';
|
|
2
|
+
import React, { useState, useRef, useMemo, useCallback, useEffect } from 'react';
|
|
3
3
|
import Icon from '@antscorp/icons';
|
|
4
4
|
// Components
|
|
5
5
|
import { Flex, Spin } from '@antscorp/antsomi-ui/es/components';
|
|
@@ -12,12 +12,16 @@ const ButtonSlider = React.memo(({ direction, type, onClick }) => (React.createE
|
|
|
12
12
|
: `change-preview-button change-preview-button--${direction}`, onClick: onClick },
|
|
13
13
|
React.createElement(Icon, { type: `icon-ants-angle-${direction}` }))));
|
|
14
14
|
export const ImageSlider = props => {
|
|
15
|
-
const { thumbnails, isLoading, className, skeleton, previewNavigation, slidesPerView = 3, hideThumbnailsList, hideDefaultButton, imageWidth = 330, imageHeight = 230, infinity = true, defaultThumbnail, onSelectDefault, } = props;
|
|
15
|
+
const { thumbnails, isLoading, className, skeleton, previewNavigation, slidesPerView = 3, hideThumbnailsList, hideDefaultButton, imageWidth = 330, imageHeight = 230, infinity = true, defaultThumbnail, thumbnailFit, onSelectDefault, } = props;
|
|
16
16
|
const sliderContainerRef = useRef(null);
|
|
17
17
|
const thumbnailSelectedRef = useRef(null);
|
|
18
18
|
const smallImageWidth = useMemo(() => imageWidth / slidesPerView - (10 * (slidesPerView - 1)) / slidesPerView, [imageWidth, slidesPerView]);
|
|
19
19
|
const [selectedThumbnail, setSelectedThumbnail] = useState(0);
|
|
20
20
|
const [defaultThumbnailInternal, setDefaultThumbnailInternal] = useState(defaultThumbnail || 0);
|
|
21
|
+
// Effects
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
setDefaultThumbnailInternal(defaultThumbnail || 0);
|
|
24
|
+
}, [defaultThumbnail]);
|
|
21
25
|
const handleScroll = useCallback((scrollIndex) => {
|
|
22
26
|
var _a, _b;
|
|
23
27
|
(_a = thumbnailSelectedRef.current) === null || _a === void 0 ? void 0 : _a.scrollTo({
|
|
@@ -55,8 +59,8 @@ export const ImageSlider = props => {
|
|
|
55
59
|
}
|
|
56
60
|
}, [onSelectDefault]);
|
|
57
61
|
return (React.createElement(ImageSliderStyled, { className: className || '', "$skeleton": skeleton, "$imageWidth": imageWidth, "$smallImageWidth": smallImageWidth, "$imageHeight": imageHeight, vertical: true, gap: 10 },
|
|
58
|
-
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, isDefaultThumbnail: defaultThumbnailInternal === index, isHideDefaultButton: hideDefaultButton || hideThumbnailsList || thumbnails.length <= 1, onClickDefaultButton: handleClickDefault }))))),
|
|
59
|
-
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, { key: `${url}_${index * 2}`, isSelected: index === selectedThumbnail, url: url, index: index, onClick: handleSelectThumbnail })))))),
|
|
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 })))))),
|
|
60
64
|
previewNavigation && !isLoading ? (React.createElement(React.Fragment, null,
|
|
61
65
|
React.createElement(ButtonSlider, { direction: "left", type: "preview", onClick: handlePrevThumbnail }),
|
|
62
66
|
React.createElement(ButtonSlider, { direction: "right", type: "preview", onClick: handleNextThumbnail }))) : null,
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
import { Image } from 'antd';
|
|
3
|
+
import { checkShowSkeletonBaseUrl, getUrlNoCache } from '@antscorp/antsomi-ui/es/utils';
|
|
3
4
|
export const SmallImage = React.memo(props => {
|
|
4
|
-
const { url, isSelected, index, onClick } = props;
|
|
5
|
+
const { url, isSelected, index, imageFit, showSkeleton, onClick } = props;
|
|
5
6
|
const currentTime = useMemo(() => new Date(), []);
|
|
6
7
|
const timeGenerated = Math.floor(currentTime.getTime() / 1000 - (currentTime.getTime() % 3)) * 1000;
|
|
7
|
-
const urlNoCache = url
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
: `${url}?nocache=${timeGenerated}`
|
|
11
|
-
: undefined;
|
|
12
|
-
return (React.createElement("div", { className: `image-container--small ${isSelected ? 'image-container--selected' : ''}`, onClick: () => onClick && onClick(index) }, url ? (React.createElement(Image, { preview: false, width: "80%", height: "96%",
|
|
8
|
+
const urlNoCache = getUrlNoCache(url, timeGenerated);
|
|
9
|
+
const showSkeletonMemo = showSkeleton !== undefined ? showSkeleton : checkShowSkeletonBaseUrl(urlNoCache);
|
|
10
|
+
return (React.createElement("div", { className: `image-container--small ${isSelected ? 'image-container--selected' : ''} ${!showSkeletonMemo ? 'hide-skeleton' : ''}`, onClick: () => onClick && onClick(index) }, url ? (React.createElement(Image, { preview: false, width: "100%", height: "100%", style: { objectFit: imageFit },
|
|
13
11
|
// src={imageUrl}
|
|
14
12
|
// src={url}
|
|
15
|
-
src: urlNoCache
|
|
13
|
+
src: urlNoCache, onError: e => {
|
|
14
|
+
e.currentTarget.style.display = 'none';
|
|
15
|
+
} })) : null));
|
|
16
16
|
});
|
|
@@ -4,14 +4,10 @@ import { Flex } from '@antscorp/antsomi-ui/es/components';
|
|
|
4
4
|
// Assets
|
|
5
5
|
import SkeletonBg from '@antscorp/antsomi-ui/es/assets/images/skeleton_bg.png';
|
|
6
6
|
const backgroundImage = css `
|
|
7
|
-
${
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
`
|
|
12
|
-
: css `
|
|
13
|
-
background: #e5e5e5;
|
|
14
|
-
`}
|
|
7
|
+
${() => css `
|
|
8
|
+
background: url(${SkeletonBg}) no-repeat center center, #e5e5e5;
|
|
9
|
+
background-size: contain;
|
|
10
|
+
`}
|
|
15
11
|
`;
|
|
16
12
|
const setWidthHeight = ({ w, h }) => `
|
|
17
13
|
width: ${w};
|
|
@@ -141,8 +137,12 @@ export const ImageSliderStyled = styled(Flex) `
|
|
|
141
137
|
.image-container {
|
|
142
138
|
&--big,
|
|
143
139
|
&--small {
|
|
140
|
+
background: #e5e5e5;
|
|
144
141
|
${centerBlock}
|
|
145
|
-
|
|
142
|
+
&:not(.hide-skeleton) {
|
|
143
|
+
${backgroundImage}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
146
|
img {
|
|
147
147
|
object-fit: contain;
|
|
148
148
|
}
|
|
@@ -28,16 +28,22 @@ import { ThumbnailCardWrapper } from './styled';
|
|
|
28
28
|
import { Button, Flex, Typography, Spin } from '../../atoms';
|
|
29
29
|
// Constants
|
|
30
30
|
import { THUMBNAIL_CARD_DEFAULT_HEIGHT, THUMBNAIL_CARD_DEFAULT_WIDTH } from './constants';
|
|
31
|
-
import { getUrlNoCache } from '@antscorp/antsomi-ui/es/utils';
|
|
31
|
+
import { getUrlNoCache, checkShowSkeletonBaseUrl } from '@antscorp/antsomi-ui/es/utils';
|
|
32
32
|
const cacheValue = new Date().getTime();
|
|
33
33
|
export const ThumbnailCard = memo(props => {
|
|
34
34
|
const [modal, contextHolder] = Modal.useModal();
|
|
35
|
-
const { id, name, width = THUMBNAIL_CARD_DEFAULT_WIDTH, height = THUMBNAIL_CARD_DEFAULT_HEIGHT, thumbnail, removable = true, actionAvailable = true, showSkeleton
|
|
35
|
+
const { id, name, width = THUMBNAIL_CARD_DEFAULT_WIDTH, height = THUMBNAIL_CARD_DEFAULT_HEIGHT, thumbnail, thumbnailFit, removable = true, actionAvailable = true, showSkeleton, loading = false, removeModalProps, editBtnProps, previewBtnProps, onClickWrapper } = props, restOfProps = __rest(props, ["id", "name", "width", "height", "thumbnail", "thumbnailFit", "removable", "actionAvailable", "showSkeleton", "loading", "removeModalProps", "editBtnProps", "previewBtnProps", "onClickWrapper"]);
|
|
36
36
|
const _a = removeModalProps || {}, { onOk } = _a, restOfRemoveTemplateModalProps = __rest(_a, ["onOk"]);
|
|
37
37
|
const _b = editBtnProps || {}, { text: editText = 'Edit thumbnail', onClick: onClickEdit } = _b, restOfEditBtnProps = __rest(_b, ["text", "onClick"]);
|
|
38
38
|
const _c = previewBtnProps || {}, { text: previewText = 'Preview', onClick: onClickPreview } = _c, restOfPreviewBtnProps = __rest(_c, ["text", "onClick"]);
|
|
39
39
|
// Memo
|
|
40
|
-
const showSkeletonMemo =
|
|
40
|
+
const showSkeletonMemo =
|
|
41
|
+
// NOTES: Hot fix for showSkeleton base url if showSkeleton is not defined
|
|
42
|
+
typeof showSkeleton === 'undefined'
|
|
43
|
+
? checkShowSkeletonBaseUrl(thumbnail)
|
|
44
|
+
: typeof showSkeleton === 'function'
|
|
45
|
+
? showSkeleton(props)
|
|
46
|
+
: showSkeleton;
|
|
41
47
|
// Handlers
|
|
42
48
|
const handleRemoveThumbnail = e => {
|
|
43
49
|
e.stopPropagation();
|
|
@@ -54,7 +60,9 @@ export const ThumbnailCard = memo(props => {
|
|
|
54
60
|
};
|
|
55
61
|
return (React.createElement(Flex, Object.assign({ gap: 10, vertical: true }, restOfProps, { style: Object.assign({ width }, restOfProps.style) }),
|
|
56
62
|
React.createElement(ThumbnailCardWrapper, { "$showSkeleton": showSkeletonMemo, style: { height, cursor: actionAvailable ? 'default' : 'pointer' }, onClick: handleWrapperClick },
|
|
57
|
-
React.createElement("div", { className: "screen" }, thumbnail && React.createElement("img", { src: getUrlNoCache(thumbnail, cacheValue), alt: "" }
|
|
63
|
+
React.createElement("div", { className: "screen" }, thumbnail && (React.createElement("img", { src: getUrlNoCache(thumbnail, cacheValue), alt: "", style: { objectFit: thumbnailFit }, onError: e => {
|
|
64
|
+
e.currentTarget.style.display = 'none';
|
|
65
|
+
} }))),
|
|
58
66
|
actionAvailable && !loading && (React.createElement(React.Fragment, null,
|
|
59
67
|
React.createElement(Flex, { className: "center-action", align: "center", gap: 10, vertical: true },
|
|
60
68
|
React.createElement(Button, Object.assign({ type: "primary", className: "animate__animated animate__fadeIn" }, restOfEditBtnProps, { onClick: e => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ModalFuncProps, ButtonProps } from 'antd';
|
|
2
|
-
import { HTMLAttributes } from 'react';
|
|
2
|
+
import React, { HTMLAttributes } from 'react';
|
|
3
3
|
export type TThumbnailCardId = string | number;
|
|
4
4
|
export type TRemoveModalProps = Omit<ModalFuncProps, 'onOk'> & {
|
|
5
5
|
onOk?: (id: TThumbnailCardId) => void;
|
|
@@ -21,5 +21,6 @@ export interface ThumbnailCardProps extends Omit<HTMLAttributes<HTMLDivElement>,
|
|
|
21
21
|
previewBtnProps?: TThumbnailButton;
|
|
22
22
|
actionAvailable?: boolean;
|
|
23
23
|
removeModalProps?: TRemoveModalProps;
|
|
24
|
+
thumbnailFit?: React.CSSProperties['objectFit'];
|
|
24
25
|
onClickWrapper?: (id: TThumbnailCardId) => void;
|
|
25
26
|
}
|
|
@@ -17,7 +17,12 @@ export const InformationWrapper = styled(Flex) `
|
|
|
17
17
|
max-width: 100%;
|
|
18
18
|
color: inherit;
|
|
19
19
|
padding-right: 25px;
|
|
20
|
-
word-break: break-
|
|
20
|
+
word-break: break-word;
|
|
21
|
+
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
display: -webkit-box;
|
|
24
|
+
-webkit-box-orient: vertical;
|
|
25
|
+
-webkit-line-clamp: 3;
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
.antsomi-radio-group {
|
package/es/constants/theme.js
CHANGED
|
@@ -12,7 +12,7 @@ export const THEME = {
|
|
|
12
12
|
colorTextDark: '#333333',
|
|
13
13
|
colorTextPlaceholder: '#BEBEBE',
|
|
14
14
|
colorTextDisabled: '#999999',
|
|
15
|
-
colorError: '#
|
|
15
|
+
colorError: '#EF3340',
|
|
16
16
|
colorWarning: '#faad14',
|
|
17
17
|
colorPrimary: '#005fb8',
|
|
18
18
|
colorTextHover: '#3a72b6',
|
|
@@ -181,4 +181,5 @@ THEME.components = {
|
|
|
181
181
|
Dropdown: {
|
|
182
182
|
controlItemBgHover: '#F2F9FF',
|
|
183
183
|
},
|
|
184
|
+
Form: {},
|
|
184
185
|
};
|
package/es/utils/common.d.ts
CHANGED
|
@@ -58,4 +58,4 @@ export declare const searchParamsToObject: (searchParams?: string) => Record<str
|
|
|
58
58
|
export declare const getShuffleArray: <T>(array: T[]) => T[];
|
|
59
59
|
export declare const snakeCaseToCamelCase: <T = Record<string, any>>(object: Record<string, any> | Record<string, any>[], recursive?: boolean) => T;
|
|
60
60
|
export declare const camelCaseToSnakeCase: <T = Record<string, any>>(object: Record<string, any>, recursive?: boolean) => T;
|
|
61
|
-
export declare const getUrlNoCache: (url?: string, cacheValue?: number | string) => string
|
|
61
|
+
export declare const getUrlNoCache: (url?: string, cacheValue?: number | string) => string;
|
package/es/utils/common.js
CHANGED
|
@@ -410,10 +410,19 @@ export const camelCaseToSnakeCase = (object, recursive = false) => {
|
|
|
410
410
|
return newObject;
|
|
411
411
|
};
|
|
412
412
|
export const getUrlNoCache = (url = '', cacheValue = 0) => {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
413
|
+
let urlNoCache = url;
|
|
414
|
+
if (urlNoCache.includes('nocache') || url.startsWith('data:image')) {
|
|
415
|
+
urlNoCache = url;
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
try {
|
|
419
|
+
const newUrl = new URL(url);
|
|
420
|
+
newUrl.searchParams.append('nocache', `${cacheValue}`);
|
|
421
|
+
urlNoCache = newUrl.toString();
|
|
422
|
+
}
|
|
423
|
+
catch (error) {
|
|
424
|
+
urlNoCache = url;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
418
427
|
return urlNoCache;
|
|
419
428
|
};
|
|
@@ -10,3 +10,20 @@ export const getCategoriesFromObjectTemplate = (objectTemplate) => {
|
|
|
10
10
|
});
|
|
11
11
|
return categories;
|
|
12
12
|
};
|
|
13
|
+
export const checkShowSkeletonBaseUrl = (url = '') => {
|
|
14
|
+
if (url.includes('type')) {
|
|
15
|
+
switch (true) {
|
|
16
|
+
case url.includes('type=media'):
|
|
17
|
+
return true;
|
|
18
|
+
case url.includes('type=email'):
|
|
19
|
+
return false;
|
|
20
|
+
case url.includes('type=tactic'):
|
|
21
|
+
default:
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
return (`${url || ''}`.includes('base64-img') &&
|
|
27
|
+
['jn_thumb_', 'v_thumb_'].every(prefix => !`${url || ''}`.includes(prefix)));
|
|
28
|
+
}
|
|
29
|
+
};
|