@antscorp/antsomi-ui 1.3.5-beta.130 → 1.3.5-beta.131

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.
@@ -1 +1,6 @@
1
- export { Tabs } from 'antd';
1
+ /// <reference types="react" />
2
+ export declare const Tabs: import("styled-components").StyledComponent<import("react").FC<import("antd").TabsProps> & {
3
+ TabPane: import("react").FC<import("antd").TabPaneProps>;
4
+ }, any, {
5
+ shadow?: boolean | undefined;
6
+ }, never>;
@@ -1 +1,7 @@
1
- export { Tabs } from 'antd';
1
+ import { Tabs as AntdTabs } from 'antd';
2
+ import styled from 'styled-components';
3
+ export const Tabs = styled(AntdTabs) `
4
+ > .antsomi-tabs-nav {
5
+ ${({ shadow }) => (shadow ? 'box-shadow: 0px 3px 3px 0px #002E591A;' : '')}
6
+ }
7
+ `;
@@ -25,12 +25,12 @@ import { Modal } from 'antd';
25
25
  // Styled
26
26
  import { ThumbnailCardWrapper } from './styled';
27
27
  // Components
28
- import { Button, Flex, Typography } from '../../atoms';
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
31
  export const ThumbnailCard = memo(props => {
32
32
  const [modal, contextHolder] = Modal.useModal();
33
- const { id, name, width = THUMBNAIL_CARD_DEFAULT_WIDTH, height = THUMBNAIL_CARD_DEFAULT_HEIGHT, thumbnail, removable = true, actionAvailable = true, showSkeleton = true, removeModalProps, editBtnProps, previewBtnProps, onClickWrapper } = props, restOfProps = __rest(props, ["id", "name", "width", "height", "thumbnail", "removable", "actionAvailable", "showSkeleton", "removeModalProps", "editBtnProps", "previewBtnProps", "onClickWrapper"]);
33
+ 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"]);
34
34
  const _a = removeModalProps || {}, { onOk } = _a, restOfRemoveTemplateModalProps = __rest(_a, ["onOk"]);
35
35
  const _b = editBtnProps || {}, { text: editText = 'Edit thumbnail', onClick: onClickEdit } = _b, restOfEditBtnProps = __rest(_b, ["text", "onClick"]);
36
36
  const _c = previewBtnProps || {}, { text: previewText = 'Preview', onClick: onClickPreview } = _c, restOfPreviewBtnProps = __rest(_c, ["text", "onClick"]);
@@ -51,7 +51,7 @@ export const ThumbnailCard = memo(props => {
51
51
  return (React.createElement(Flex, Object.assign({ gap: 10, vertical: true }, restOfProps, { style: Object.assign({ width }, restOfProps.style) }),
52
52
  React.createElement(ThumbnailCardWrapper, { "$showSkeleton": showSkeleton, style: { height, cursor: actionAvailable ? 'default' : 'pointer' }, onClick: handleWrapperClick },
53
53
  React.createElement("div", { className: "screen" }, thumbnail && React.createElement("img", { src: thumbnail, alt: "" })),
54
- actionAvailable && (React.createElement(React.Fragment, null,
54
+ actionAvailable && !loading && (React.createElement(React.Fragment, null,
55
55
  React.createElement(Flex, { className: "center-action", align: "center", gap: 10, vertical: true },
56
56
  React.createElement(Button, Object.assign({ type: "primary", className: "animate__animated animate__fadeIn" }, restOfEditBtnProps, { onClick: e => {
57
57
  e.stopPropagation();
@@ -66,7 +66,8 @@ export const ThumbnailCard = memo(props => {
66
66
  removable && (React.createElement("div", { className: "top-right-corner-action animate__animated animate__fadeIn" },
67
67
  React.createElement(Button, { type: "primary", icon: React.createElement(Icon, { type: "icon-ants-trash-outline", style: { fontSize: 24, color: '#FFFFFF' } }), onClick: handleRemoveThumbnail }))),
68
68
  React.createElement("div", { className: "backdrop" }),
69
- React.createElement("div", null, contextHolder)))),
69
+ React.createElement("div", null, contextHolder))),
70
+ loading && React.createElement(Spin, { className: "thumbnail__loading", spinning: true })),
70
71
  !!name && (React.createElement(Typography.Text, { ellipsis: { tooltip: name }, style: { maxWidth: '100%' } }, name))));
71
72
  });
72
73
  ThumbnailCard.displayName = 'ThumbnailCard';
@@ -10,6 +10,9 @@ export const ThumbnailCardWrapper = styled.div `
10
10
  position: relative;
11
11
  box-sizing: border-box;
12
12
  width: 100%;
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
13
16
 
14
17
  :hover {
15
18
  .center-action {
@@ -64,13 +67,11 @@ export const ThumbnailCardWrapper = styled.div `
64
67
  z-index: 12;
65
68
 
66
69
  button {
67
- background-color: black;
68
- opacity: 0.4;
70
+ background: #00000040;
69
71
 
70
72
  :hover {
71
73
  background: none !important;
72
74
  background-color: black !important;
73
- opacity: 0.5;
74
75
  }
75
76
  }
76
77
  }
@@ -87,4 +88,8 @@ export const ThumbnailCardWrapper = styled.div `
87
88
  top: 0;
88
89
  left: 0;
89
90
  }
91
+
92
+ .thumbnail__loading {
93
+ position: absolute;
94
+ }
90
95
  `;
@@ -16,6 +16,7 @@ export interface ThumbnailCardProps extends Omit<HTMLAttributes<HTMLDivElement>,
16
16
  thumbnail?: string;
17
17
  removable?: boolean;
18
18
  showSkeleton?: boolean;
19
+ loading?: boolean;
19
20
  editBtnProps?: TThumbnailButton;
20
21
  previewBtnProps?: TThumbnailButton;
21
22
  actionAvailable?: boolean;
@@ -122,6 +122,6 @@ export const CategoryListing = memo(props => {
122
122
  }, [getItem, items]);
123
123
  return show ? (React.createElement(MenuWrapper, { "$width": width },
124
124
  React.createElement(Spin, { spinning: loading, wrapperClassName: "template-listing__loading" }, isEmpty(menuItems) && !loading ? (React.createElement("div", { className: "empty-wrapper" },
125
- React.createElement(Empty, Object.assign({}, emptyProps)))) : (React.createElement(Menu, Object.assign({ items: menuItems, inlineIndent: 0, mode: "inline", defaultOpenKeys: items === null || items === void 0 ? void 0 : items.map(item => String(item.key)), expandIcon: React.createElement(Icon, { type: "icon-ants-expand-more", style: { fontSize: 20, color: (_a = THEME === null || THEME === void 0 ? void 0 : THEME.token) === null || _a === void 0 ? void 0 : _a.bw8 } }), onClick: handleClickMenu }, restOfProps)))))) : null;
125
+ React.createElement(Empty, Object.assign({}, emptyProps)))) : (React.createElement(Menu, Object.assign({ selectedKeys: [], items: menuItems, inlineIndent: 0, mode: "inline", defaultOpenKeys: items === null || items === void 0 ? void 0 : items.map(item => String(item.key)), expandIcon: React.createElement(Icon, { type: "icon-ants-expand-more", style: { fontSize: 20, color: (_a = THEME === null || THEME === void 0 ? void 0 : THEME.token) === null || _a === void 0 ? void 0 : _a.bw8 } }), onClick: handleClickMenu }, restOfProps)))))) : null;
126
126
  });
127
127
  CategoryListing.displayName = 'CategoryListing';
@@ -9,11 +9,27 @@ interface TemplateListingOptions {
9
9
  config: TTemplateListingConfig;
10
10
  checkedCategoriesDefault?: TCheckedCategories;
11
11
  }
12
+ /**
13
+ * Represents the state of a system with generic data types.
14
+ * @template T - The type of data contained in the state.
15
+ */
12
16
  type TState<T> = {
17
+ /** An object representing the checked categories. */
13
18
  checkedCategories: TCheckedCategories;
19
+ /** An array containing keys of open categories. */
14
20
  openCategoryKeys: string[];
21
+ /** An optional ID representing the selected template. */
15
22
  selectedTemplateId?: TThumbnailCardId;
23
+ /**
24
+ * An optional action related to selecting a template.
25
+ * This can be of type `TSelectTemplateAction` or any other custom type `T`.
26
+ */
16
27
  selectTemplateAction?: TSelectTemplateAction | T;
28
+ /**
29
+ * Mock template items are intended to show fake data in the UI first.
30
+ * After the template items are loaded, they will be mapped to these MockItems. The purpose is to increase user experience
31
+ */
32
+ mockTemplateItems: (TTemplateItem | undefined)[];
17
33
  };
18
34
  /**
19
35
  * Custom React Hook for managing state and data fetching logic related to a template listing.
@@ -40,9 +56,9 @@ type TState<T> = {
40
56
  */
41
57
  export declare const useTemplateListing: <T = undefined>(options: TemplateListingOptions) => {
42
58
  categoryItems: TCategoryItem[];
43
- templateItems: TTemplateItem[];
59
+ templateItems: (TTemplateItem | undefined)[];
44
60
  openCategoryKeys: string[];
45
- similarTemplates: TTemplateItem[];
61
+ similarTemplates: (TTemplateItem | undefined)[];
46
62
  templateDetail: import("@antscorp/antsomi-ui/es/models/ObjectTemplate").ObjectTemplate | undefined;
47
63
  checkedCategories: TCheckedCategories;
48
64
  selectTemplateAction: TSelectTemplateAction | T | undefined;
@@ -44,8 +44,9 @@ export const useTemplateListing = (options) => {
44
44
  const [state, setState] = useState({
45
45
  checkedCategories: {},
46
46
  openCategoryKeys: [],
47
+ mockTemplateItems: Array.from({ length: limitListPerPage }).map(() => undefined),
47
48
  });
48
- const { checkedCategories, openCategoryKeys, selectedTemplateId, selectTemplateAction } = state;
49
+ const { checkedCategories, openCategoryKeys, mockTemplateItems, selectedTemplateId, selectTemplateAction, } = state;
49
50
  const { data: categoryList, isLoading: isLoadingCategoryList, refetch: refetchCategoryList, } = useGetTemplateCategoryList({
50
51
  args: {
51
52
  auth: serviceAuth,
@@ -81,17 +82,19 @@ export const useTemplateListing = (options) => {
81
82
  }
82
83
  return draftFilter;
83
84
  }, [checkedCategories, channel]);
85
+ // Variables
86
+ const getTemplateListParams = {
87
+ object_type: objectType,
88
+ public_level: publicLevel,
89
+ get_list_type: getListType,
90
+ limit: limitListPerPage,
91
+ filter: JSON.stringify(filter),
92
+ };
84
93
  // Queries
85
94
  const { data: infiniteObjectTemplate, isFetchingNextPage, isFetching, hasNextPage, fetchNextPage, refetch: refetchTemplateList, } = useGetObjectTemplateList({
86
95
  args: {
87
96
  auth: serviceAuth,
88
- params: {
89
- object_type: objectType,
90
- public_level: publicLevel,
91
- get_list_type: getListType,
92
- limit: limitListPerPage,
93
- filter: JSON.stringify(filter),
94
- },
97
+ params: getTemplateListParams,
95
98
  },
96
99
  });
97
100
  const { mutateAsync: bulkUpdateTemplate } = useBulkUpdateTemplate({
@@ -124,6 +127,10 @@ export const useTemplateListing = (options) => {
124
127
  // Variables
125
128
  const isLoadingTemplateList = isFetching || isFetchingNextPage;
126
129
  // Memo
130
+ const flatTemplateItems = useDeepCompareMemo(() => {
131
+ const { pages } = infiniteObjectTemplate || {};
132
+ return pages === null || pages === void 0 ? void 0 : pages.flatMap(({ entities }) => entities.flatMap(entity => entity.toJson()));
133
+ }, [infiniteObjectTemplate]);
127
134
  const templateDetail = useDeepCompareMemo(() => {
128
135
  if (infiniteObjectTemplate && selectedTemplateId) {
129
136
  return infiniteObjectTemplate.pages
@@ -147,16 +154,10 @@ export const useTemplateListing = (options) => {
147
154
  });
148
155
  return recursiveCategory(categoryList || []);
149
156
  }, [categoryList]);
150
- const templateItems = useMemo(() => {
151
- if (infiniteObjectTemplate) {
152
- const { pages } = infiniteObjectTemplate;
153
- return pages.flatMap(({ entities }) => entities.flatMap(entity => entity.toJson()));
154
- }
155
- return [];
156
- }, [infiniteObjectTemplate]);
157
+ const templateItems = useMemo(() => mockTemplateItems.map((_, index) => flatTemplateItems === null || flatTemplateItems === void 0 ? void 0 : flatTemplateItems[index]) || [], [flatTemplateItems, mockTemplateItems]);
157
158
  const similarTemplates = useMemo(() => {
158
159
  const maxSimilarTemplateLength = 4;
159
- return (getShuffleArray(templateItems.filter(item => item.id !== selectedTemplateId)).slice(0, maxSimilarTemplateLength) || []);
160
+ return (getShuffleArray(templateItems.filter(item => (item === null || item === void 0 ? void 0 : item.id) !== selectedTemplateId)).slice(0, maxSimilarTemplateLength) || []);
160
161
  }, [templateItems, selectedTemplateId]);
161
162
  const previewTemplateCategories = useDeepCompareMemo(() => {
162
163
  if ((categoryItems === null || categoryItems === void 0 ? void 0 : categoryItems.length) && !!templateDetail) {
@@ -181,6 +182,15 @@ export const useTemplateListing = (options) => {
181
182
  return [];
182
183
  }, [categoryItems, templateDetail]);
183
184
  // Effects
185
+ /**
186
+ * This effect will check flatTemplateItems length from api is not equal mockTemplateItems length
187
+ * Then set MockTemplateItems length equal flatTemplateItems
188
+ */
189
+ useDeepCompareEffect(() => {
190
+ if (flatTemplateItems && (flatTemplateItems === null || flatTemplateItems === void 0 ? void 0 : flatTemplateItems.length) !== (mockTemplateItems === null || mockTemplateItems === void 0 ? void 0 : mockTemplateItems.length)) {
191
+ setState(prev => (Object.assign(Object.assign({}, prev), { mockTemplateItems: Array.from({ length: flatTemplateItems === null || flatTemplateItems === void 0 ? void 0 : flatTemplateItems.length }) })));
192
+ }
193
+ }, [flatTemplateItems]);
184
194
  useDeepCompareEffect(() => {
185
195
  setState(prev => (Object.assign(Object.assign({}, prev), { openCategoryKeys: (categoryList === null || categoryList === void 0 ? void 0 : categoryList.map(({ categoryCode }) => categoryCode)) || [] })));
186
196
  }, [categoryList]);
@@ -212,10 +222,25 @@ export const useTemplateListing = (options) => {
212
222
  });
213
223
  }, [bulkUpdateTemplate, serviceAuth]);
214
224
  const onLoadMore = useCallback(() => {
225
+ var _a;
226
+ const { pages } = infiniteObjectTemplate || {};
227
+ const totalTemplateItems = ((_a = pages === null || pages === void 0 ? void 0 : pages[0].meta) === null || _a === void 0 ? void 0 : _a.totalItems) || 0;
228
+ const newMockItemLength = Math.min(totalTemplateItems, mockTemplateItems.length + limitListPerPage);
229
+ // If there is no more data, return
230
+ if (newMockItemLength > totalTemplateItems)
231
+ return;
215
232
  if (!isFetchingNextPage && hasNextPage) {
233
+ setState(prev => (Object.assign(Object.assign({}, prev), { mockTemplateItems: Array.from({ length: newMockItemLength }) })));
216
234
  fetchNextPage();
217
235
  }
218
- }, [fetchNextPage, hasNextPage, isFetchingNextPage]);
236
+ }, [
237
+ infiniteObjectTemplate,
238
+ mockTemplateItems.length,
239
+ limitListPerPage,
240
+ isFetchingNextPage,
241
+ hasNextPage,
242
+ fetchNextPage,
243
+ ]);
219
244
  const onSelectTemplate = useCallback((id, action) => {
220
245
  setState(prev => (Object.assign(Object.assign({}, prev), { selectedTemplateId: id, selectTemplateAction: action })));
221
246
  }, []);
@@ -72,11 +72,15 @@ export const TemplateListing = memo(props => {
72
72
  gridTemplateColumns: `repeat(${itemPerRow}, minmax(0, 1fr))`,
73
73
  } },
74
74
  React.createElement(BlankTemplate, Object.assign({ width: width * ratio, height: height * ratio }, blankTemplateProps)), items === null || items === void 0 ? void 0 :
75
- items.map(({ id, name, thumbnail }, index) => (React.createElement("div", { key: id },
76
- React.createElement(ThumbnailCard, Object.assign({ id: id, name: name, width: width * ratio, height: height * ratio, thumbnail: thumbnail, className: `animate__animated animate__fadeIn ${templateItemProps.className}`, previewBtnProps: {
77
- onClick: handleClickThumbnailPreview,
78
- } }, restOfTemplateItemProps)),
79
- index === items.length - 1 && React.createElement(LoadMoreBlock, { ref: loadMoreRef }))))),
75
+ items.map((item, index) => {
76
+ const { id, name, thumbnail } = item || {};
77
+ const loading = typeof item === 'undefined';
78
+ return (React.createElement("div", { key: id || index },
79
+ index === items.length - 2 && React.createElement(LoadMoreBlock, { ref: loadMoreRef }),
80
+ React.createElement(ThumbnailCard, Object.assign({ id: id || index, name: name || 'Untitled', loading: loading, width: width * ratio, height: height * ratio, thumbnail: thumbnail, className: `${templateItemProps.className}`, previewBtnProps: {
81
+ onClick: handleClickThumbnailPreview,
82
+ } }, restOfTemplateItemProps))));
83
+ })),
80
84
  !loading && !blankTemplateProps.show && !isHasData && React.createElement(Empty, Object.assign({}, emptyProps)))),
81
85
  React.createElement(PreviewTemplateModal, Object.assign({ open: openPreviewModal, onOk: handleOkPreviewModal, onCancel: handleCancelPreviewModal }, restOfPreviewModalProps))));
82
86
  });
@@ -13,7 +13,7 @@ export interface TemplateListingProps<T = {}> {
13
13
  previewModalProps?: PreviewTemplateModalProps;
14
14
  }
15
15
  export type TemplatesProps<T = {}> = {
16
- items?: (TTemplateItem & T)[];
16
+ items?: ((TTemplateItem & T) | undefined)[];
17
17
  loading?: boolean;
18
18
  gap?: number;
19
19
  onLoadMoreTemplates?: () => void;
@@ -1,4 +1,4 @@
1
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
1
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
2
2
  // Types
3
3
  import { theme } from 'antd';
4
4
  // Variables
@@ -138,6 +138,8 @@ THEME.components = {
138
138
  },
139
139
  Checkbox: {
140
140
  controlInteractiveSize: 18,
141
+ colorBorder: (_s = THEME.token) === null || _s === void 0 ? void 0 : _s.colorPrimary,
142
+ lineWidth: 2,
141
143
  },
142
144
  Modal: {
143
145
  titleFontSize: 16,
@@ -148,7 +150,7 @@ THEME.components = {
148
150
  paddingMD: 0,
149
151
  },
150
152
  Tabs: {
151
- itemColor: (_s = THEME.token) === null || _s === void 0 ? void 0 : _s.bw8,
153
+ itemColor: (_t = THEME.token) === null || _t === void 0 ? void 0 : _t.bw8,
152
154
  horizontalItemPadding: '17px 30px',
153
155
  horizontalItemGutter: 0,
154
156
  lineWidthBold: 3,
@@ -163,11 +165,14 @@ THEME.components = {
163
165
  headerPadding: '15px 10px',
164
166
  },
165
167
  Switch: {
166
- colorTextQuaternary: (_t = THEME.token) === null || _t === void 0 ? void 0 : _t.bw0,
167
- colorTextTertiary: (_u = THEME.token) === null || _u === void 0 ? void 0 : _u.bw0,
168
+ colorTextQuaternary: (_u = THEME.token) === null || _u === void 0 ? void 0 : _u.bw0,
169
+ colorTextTertiary: (_v = THEME.token) === null || _v === void 0 ? void 0 : _v.bw0,
168
170
  handleSize: 12,
169
171
  handleSizeSM: 7,
170
172
  trackMinWidth: 30,
171
- handleBg: (_v = THEME.token) === null || _v === void 0 ? void 0 : _v.colorPrimary,
173
+ handleBg: (_w = THEME.token) === null || _w === void 0 ? void 0 : _w.colorPrimary,
174
+ },
175
+ Menu: {
176
+ itemHoverBg: '#F2F9FF',
172
177
  },
173
178
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antscorp/antsomi-ui",
3
- "version": "1.3.5-beta.130",
3
+ "version": "1.3.5-beta.131",
4
4
  "description": "An enterprise-class UI design language and React UI library.",
5
5
  "sideEffects": [
6
6
  "dist/*",