@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.
Files changed (26) hide show
  1. package/es/components/common/ConfigProvider/GlobalStyle.js +4 -0
  2. package/es/components/molecules/DatePicker/components/AdvancedPicker/AdvancedPicker.js +1 -1
  3. package/es/components/molecules/DatePicker/components/AdvancedPicker/styled.d.ts +1 -0
  4. package/es/components/molecules/DatePicker/components/AdvancedPicker/styled.js +2 -1
  5. package/es/components/molecules/DatePicker/components/AdvancedPicker/utils.d.ts +12 -0
  6. package/es/components/molecules/DatePicker/components/AdvancedPicker/utils.js +27 -0
  7. package/es/components/molecules/DatePicker/components/AdvancedRangePicker/AdvancedRangePicker.d.ts +4 -0
  8. package/es/components/molecules/DatePicker/components/AdvancedRangePicker/AdvancedRangePicker.js +12 -3
  9. package/es/components/molecules/TemplateSaveAs/TemplateSaveAs.js +4 -1
  10. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/BigImage.d.ts +2 -0
  11. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/BigImage.js +8 -8
  12. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/ImageSlider.d.ts +1 -0
  13. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/ImageSlider.js +8 -4
  14. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/SmallImage.d.ts +2 -0
  15. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/SmallImage.js +8 -8
  16. package/es/components/molecules/TemplateSaveAs/components/ImageSlider/styled.js +9 -9
  17. package/es/components/molecules/TemplateSaveAs/styled.js +2 -1
  18. package/es/components/molecules/ThumbnailCard/ThumbnailCard.js +12 -4
  19. package/es/components/molecules/ThumbnailCard/types.d.ts +2 -1
  20. package/es/components/organism/PreviewTemplateModal/components/Information/styled.js +6 -1
  21. package/es/constants/theme.js +2 -1
  22. package/es/utils/common.d.ts +1 -1
  23. package/es/utils/common.js +14 -5
  24. package/es/utils/templateListing.d.ts +1 -0
  25. package/es/utils/templateListing.js +17 -0
  26. package/package.json +1 -1
@@ -830,6 +830,10 @@ export const GlobalStyle = () => {
830
830
  }
831
831
  }
832
832
  }
833
+
834
+ .antsomi-form-item-explain-error {
835
+ font-size: 11px !important;
836
+ }
833
837
  }
834
838
 
835
839
  /* Popover */
@@ -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
+ };
@@ -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;
@@ -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: ADVANCED_RANGE_PICKER_FORMAT.startDate, 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
+ 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: ADVANCED_RANGE_PICKER_FORMAT.endDate, 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 })));
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: form.getFieldValue('defaultThumbnail'), onSelectDefault: value => {
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
- ? url.includes('nocache') || url.startsWith('data:image')
11
- ? url
12
- : `${url}?nocache=${timeGenerated}`
13
- : undefined;
14
- return (React.createElement("div", { className: "image-container--big" },
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'))));
@@ -11,6 +11,7 @@ export interface ImageSliderProps {
11
11
  imageWidth?: number;
12
12
  imageHeight?: number;
13
13
  infinity?: boolean;
14
+ thumbnailFit?: React.CSSProperties['objectFit'];
14
15
  /**
15
16
  * Default thumbnail - order of default thumbnail in thumbnails array
16
17
  */
@@ -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,
@@ -3,6 +3,8 @@ interface SmallImageProps {
3
3
  url?: string;
4
4
  isSelected?: boolean;
5
5
  index: number;
6
+ showSkeleton?: boolean;
7
+ imageFit?: React.CSSProperties['objectFit'];
6
8
  onClick?: (index: number) => void;
7
9
  }
8
10
  export declare const SmallImage: React.FC<SmallImageProps>;
@@ -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
- ? url.includes('nocache') || url.startsWith('data:image')
9
- ? url
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 })) : null));
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
- ${props => props.$skeleton
8
- ? css `
9
- background: url(${SkeletonBg}) no-repeat center center, #e5e5e5;
10
- background-size: contain;
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
- ${backgroundImage}
142
+ &:not(.hide-skeleton) {
143
+ ${backgroundImage}
144
+ }
145
+
146
146
  img {
147
147
  object-fit: contain;
148
148
  }
@@ -19,7 +19,8 @@ export const TemplateSaveAsStyled = styled(Flex) `
19
19
  }
20
20
 
21
21
  .template-container {
22
- flex: 1 1 60%;
22
+ flex: 0 0 670px;
23
+ /* flex: 1 1 60%; */
23
24
  max-height: 60vh;
24
25
  padding-right: 28px;
25
26
  overflow-y: auto;
@@ -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 = true, loading = false, removeModalProps, editBtnProps, previewBtnProps, onClickWrapper } = props, restOfProps = __rest(props, ["id", "name", "width", "height", "thumbnail", "removable", "actionAvailable", "showSkeleton", "loading", "removeModalProps", "editBtnProps", "previewBtnProps", "onClickWrapper"]);
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 = typeof showSkeleton === 'function' ? showSkeleton(props) : showSkeleton;
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-all;
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 {
@@ -12,7 +12,7 @@ export const THEME = {
12
12
  colorTextDark: '#333333',
13
13
  colorTextPlaceholder: '#BEBEBE',
14
14
  colorTextDisabled: '#999999',
15
- colorError: '#CF1825',
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
  };
@@ -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 | undefined;
61
+ export declare const getUrlNoCache: (url?: string, cacheValue?: number | string) => string;
@@ -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
- const urlNoCache = url
414
- ? url.includes('nocache') || url.startsWith('data:image')
415
- ? url
416
- : `${url}?nocache=${cacheValue}`
417
- : undefined;
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
  };
@@ -1,2 +1,3 @@
1
1
  import { ObjectTemplate } from '../models/ObjectTemplate';
2
2
  export declare const getCategoriesFromObjectTemplate: (objectTemplate: ObjectTemplate) => {};
3
+ export declare const checkShowSkeletonBaseUrl: (url?: string) => boolean;
@@ -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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antscorp/antsomi-ui",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
4
4
  "description": "An enterprise-class UI design language and React UI library.",
5
5
  "sideEffects": [
6
6
  "dist/*",