@steroidsjs/core 3.0.0-beta.106 → 3.0.0-beta.108

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/hooks/index.d.ts CHANGED
@@ -18,9 +18,10 @@ import useSelector from './useSelector';
18
18
  import useSsr from './useSsr';
19
19
  import useUniqueId from './useUniqueId';
20
20
  import useTheme from './useTheme';
21
+ import useTree from './useTree';
21
22
  import useMonthCalendar from '../ui/content/CalendarSystem/hooks/useMonthCalendar';
22
23
  import useWeekCalendar from '../ui/content/CalendarSystem/hooks/useWeekCalendar';
23
24
  import useDisplayDate from '../ui/content/CalendarSystem/hooks/useDisplayDate';
24
25
  import useCalendarControls from '../ui/content/CalendarSystem/hooks/useCalendarControls';
25
26
  import useSaveCursorPosition from './useSaveCursorPosition';
26
- export { useAbsolutePositioning, useAddressBar, useApplication, useBem, useComponents, useDataProvider, useDataSelect, useDispatch, useFetch, useFile, useForm, useInitial, useLayout, useList, useModel, useScreen, useSelector, useSsr, useUniqueId, useTheme, useMonthCalendar, useWeekCalendar, useDisplayDate, useCalendarControls, useSaveCursorPosition, };
27
+ export { useAbsolutePositioning, useAddressBar, useApplication, useBem, useComponents, useDataProvider, useDataSelect, useDispatch, useFetch, useFile, useForm, useInitial, useLayout, useList, useModel, useScreen, useSelector, useSsr, useUniqueId, useTheme, useTree, useMonthCalendar, useWeekCalendar, useDisplayDate, useCalendarControls, useSaveCursorPosition, };
package/hooks/index.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  exports.__esModule = true;
6
- exports.useSaveCursorPosition = exports.useCalendarControls = exports.useDisplayDate = exports.useWeekCalendar = exports.useMonthCalendar = exports.useTheme = exports.useUniqueId = exports.useSsr = exports.useSelector = exports.useScreen = exports.useModel = exports.useList = exports.useLayout = exports.useInitial = exports.useForm = exports.useFile = exports.useFetch = exports.useDispatch = exports.useDataSelect = exports.useDataProvider = exports.useComponents = exports.useBem = exports.useApplication = exports.useAddressBar = exports.useAbsolutePositioning = void 0;
6
+ exports.useSaveCursorPosition = exports.useCalendarControls = exports.useDisplayDate = exports.useWeekCalendar = exports.useMonthCalendar = exports.useTree = exports.useTheme = exports.useUniqueId = exports.useSsr = exports.useSelector = exports.useScreen = exports.useModel = exports.useList = exports.useLayout = exports.useInitial = exports.useForm = exports.useFile = exports.useFetch = exports.useDispatch = exports.useDataSelect = exports.useDataProvider = exports.useComponents = exports.useBem = exports.useApplication = exports.useAddressBar = exports.useAbsolutePositioning = void 0;
7
7
  var useAbsolutePositioning_1 = __importDefault(require("./useAbsolutePositioning"));
8
8
  exports.useAbsolutePositioning = useAbsolutePositioning_1["default"];
9
9
  var useAddressBar_1 = __importDefault(require("./useAddressBar"));
@@ -44,6 +44,8 @@ var useUniqueId_1 = __importDefault(require("./useUniqueId"));
44
44
  exports.useUniqueId = useUniqueId_1["default"];
45
45
  var useTheme_1 = __importDefault(require("./useTheme"));
46
46
  exports.useTheme = useTheme_1["default"];
47
+ var useTree_1 = __importDefault(require("./useTree"));
48
+ exports.useTree = useTree_1["default"];
47
49
  var useMonthCalendar_1 = __importDefault(require("../ui/content/CalendarSystem/hooks/useMonthCalendar"));
48
50
  exports.useMonthCalendar = useMonthCalendar_1["default"];
49
51
  var useWeekCalendar_1 = __importDefault(require("../ui/content/CalendarSystem/hooks/useWeekCalendar"));
@@ -1,4 +1,3 @@
1
- import { ITreeTableItem } from '../ui/list/TreeTable/TreeTable';
2
1
  import { IAddressBarConfig } from '../hooks/useAddressBar';
3
2
  import { IList } from '../actions/list';
4
3
  import { ILayoutNamesProps } from '../ui/list/LayoutNames/LayoutNames';
@@ -194,10 +193,6 @@ export interface IListConfig {
194
193
  * Количество элементов всего в списке (для отрисовки пагинации), заданное вручную
195
194
  */
196
195
  initialTotal?: number;
197
- /**
198
- * Включает обработку вложенных данных из items
199
- */
200
- hasTreeItems?: boolean;
201
196
  }
202
197
  export interface IListOutput {
203
198
  list: IList;
@@ -256,7 +251,6 @@ export declare const createInitialValues: ({ paginationProps, paginationSizeProp
256
251
  initialQuery: any;
257
252
  configQuery: any;
258
253
  }) => any;
259
- export declare const prepareItemsToTree: (sourceItems: ITreeTableItem[], openedTreeItems: Record<string, boolean>, currentPage: number | null, itemsOnPage: number | null, onTreeItemClick: (uniqueId: string, item: Record<string, any>) => void, parentId?: string, currentLevel?: number) => any[];
260
254
  /**
261
255
  * useList
262
256
  * Добавляет массу возможностей для взаимодействия с коллекциями. Коллекции можно получать как с бекенда,
package/hooks/useList.js CHANGED
@@ -37,19 +37,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
38
  };
39
39
  exports.__esModule = true;
40
- exports.prepareItemsToTree = exports.createInitialValues = exports.getDefaultSearchModel = exports.normalizeSortProps = exports.defaultConfig = void 0;
41
- var react_1 = require("react");
40
+ exports.createInitialValues = exports.getDefaultSearchModel = exports.normalizeSortProps = exports.defaultConfig = void 0;
41
+ var react_1 = __importStar(require("react"));
42
42
  var get_1 = __importDefault(require("lodash-es/get"));
43
43
  var union_1 = __importDefault(require("lodash-es/union"));
44
44
  var isEqual_1 = __importDefault(require("lodash-es/isEqual"));
45
- var React = __importStar(require("react"));
46
45
  var react_use_1 = require("react-use");
47
- var list_1 = require("../utils/list");
48
- var useSelector_1 = __importDefault(require("../hooks/useSelector"));
49
- var list_2 = require("../reducers/list");
46
+ var useSelector_1 = __importDefault(require("./useSelector"));
47
+ var list_1 = require("../reducers/list");
50
48
  var useModel_1 = __importDefault(require("../hooks/useModel"));
51
49
  var useAddressBar_1 = __importDefault(require("../hooks/useAddressBar"));
52
- var list_3 = require("../actions/list");
50
+ var list_2 = require("../actions/list");
53
51
  var useDispatch_1 = __importDefault(require("../hooks/useDispatch"));
54
52
  var form_1 = require("../actions/form");
55
53
  var form_2 = require("../reducers/form");
@@ -105,27 +103,6 @@ var createInitialValues = function (_a) {
105
103
  return (__assign(__assign((_b = {}, _b[paginationProps.attribute] = paginationProps.defaultValue, _b[paginationSizeProps.attribute] = paginationSizeProps.defaultValue, _b[sort.attribute] = sort.defaultValue, _b[layoutNamesProps.attribute] = layoutNamesProps.defaultValue, _b), initialQuery), configQuery));
106
104
  };
107
105
  exports.createInitialValues = createInitialValues;
108
- var TOP_TREE_LEVEL_VALUE = 0;
109
- var prepareItemsToTree = function (sourceItems, openedTreeItems, currentPage, itemsOnPage, onTreeItemClick, parentId, currentLevel) {
110
- if (parentId === void 0) { parentId = ''; }
111
- if (currentLevel === void 0) { currentLevel = TOP_TREE_LEVEL_VALUE; }
112
- var treeItems = [];
113
- if (currentPage && itemsOnPage && currentLevel === TOP_TREE_LEVEL_VALUE) {
114
- var startIndex = (currentPage - 1) * itemsOnPage;
115
- sourceItems = sourceItems.slice(startIndex, startIndex + itemsOnPage);
116
- }
117
- (sourceItems || []).forEach(function (item, index) {
118
- var uniqueId = (0, list_1.getTreeItemUniqId)(item, index, parentId);
119
- var isOpened = !!openedTreeItems[uniqueId];
120
- var hasItems = !!(item.items && item.items.length > 0);
121
- treeItems.push(__assign(__assign({}, item), { uniqueId: uniqueId, level: currentLevel, isOpened: isOpened, hasItems: hasItems, onClick: function () { return onTreeItemClick(uniqueId, item); } }));
122
- if (isOpened) {
123
- treeItems = treeItems.concat((0, exports.prepareItemsToTree)(item.items, openedTreeItems, currentPage, itemsOnPage, onTreeItemClick, uniqueId, currentLevel + 1)).filter(Boolean);
124
- }
125
- });
126
- return treeItems;
127
- };
128
- exports.prepareItemsToTree = prepareItemsToTree;
129
106
  /**
130
107
  * useList
131
108
  * Добавляет массу возможностей для взаимодействия с коллекциями. Коллекции можно получать как с бекенда,
@@ -135,18 +112,7 @@ exports.prepareItemsToTree = prepareItemsToTree;
135
112
  function useList(config) {
136
113
  var _a, _b;
137
114
  // Get list from redux state
138
- var list = (0, useSelector_1["default"])(function (state) { return (0, list_2.getList)(state, config.listId); });
139
- var _c = (0, react_1.useState)({}), openedTreeItems = _c[0], setOpenedTreeItems = _c[1];
140
- var onTreeItemClick = (0, react_1.useCallback)(function (uniqueId, item) {
141
- var _a;
142
- if (((_a = item.items) === null || _a === void 0 ? void 0 : _a.length) > 0) {
143
- setOpenedTreeItems(function (prevItems) {
144
- var _a;
145
- return (__assign(__assign({}, prevItems), (_a = {}, _a[uniqueId] = !prevItems[uniqueId], _a)));
146
- });
147
- }
148
- }, []);
149
- var getTreeItems = (0, react_1.useCallback)(function (sourceItems) { return (0, exports.prepareItemsToTree)(sourceItems, openedTreeItems, list === null || list === void 0 ? void 0 : list.page, list === null || list === void 0 ? void 0 : list.pageSize, onTreeItemClick); }, [onTreeItemClick, openedTreeItems, list]);
115
+ var list = (0, useSelector_1["default"])(function (state) { return (0, list_1.getList)(state, config.listId); });
150
116
  // Normalize sort config
151
117
  var sort = (0, exports.normalizeSortProps)(config.sort);
152
118
  // Empty
@@ -157,24 +123,24 @@ function useList(config) {
157
123
  if (!emptyProps.enable || (list === null || list === void 0 ? void 0 : list.isLoading) || ((_a = list === null || list === void 0 ? void 0 : list.items) === null || _a === void 0 ? void 0 : _a.length) > 0) {
158
124
  return null;
159
125
  }
160
- return (React.createElement(Empty, __assign({ list: list }, emptyProps)));
126
+ return (react_1["default"].createElement(Empty, __assign({ list: list }, emptyProps)));
161
127
  };
162
128
  // Pagination size
163
129
  var PaginationSize = require('../ui/list/PaginationSize')["default"];
164
130
  var paginationSizeProps = (0, PaginationSize_1.normalizePaginationSizeProps)(config.paginationSize);
165
131
  var renderPaginationSize = function () { return paginationSizeProps.enable
166
- ? (React.createElement(PaginationSize, __assign({ list: list }, paginationSizeProps)))
132
+ ? (react_1["default"].createElement(PaginationSize, __assign({ list: list }, paginationSizeProps)))
167
133
  : null; };
168
134
  // Pagination
169
135
  var Pagination = require('../ui/list/Pagination')["default"];
170
136
  var paginationProps = (0, Pagination_1.normalizePaginationProps)(config.pagination);
171
137
  var renderPagination = function () { return paginationProps.enable
172
- ? (React.createElement(Pagination, __assign({ list: list }, paginationProps, { sizeAttribute: paginationSizeProps.attribute })))
138
+ ? (react_1["default"].createElement(Pagination, __assign({ list: list }, paginationProps, { sizeAttribute: paginationSizeProps.attribute })))
173
139
  : null; };
174
140
  // Layout switcher
175
141
  var LayoutNames = require('../ui/list/LayoutNames')["default"];
176
142
  var layoutNamesProps = (0, LayoutNames_1.normalizeLayoutNamesProps)(config.layout);
177
- var renderLayoutNames = function () { return (React.createElement(LayoutNames, __assign({ list: list }, layoutNamesProps))); };
143
+ var renderLayoutNames = function () { return (react_1["default"].createElement(LayoutNames, __assign({ list: list }, layoutNamesProps))); };
178
144
  // Models
179
145
  var defaultSearchModel = (0, react_1.useMemo)(function () { return (0, exports.getDefaultSearchModel)({
180
146
  paginationProps: paginationProps,
@@ -185,7 +151,7 @@ function useList(config) {
185
151
  var model = (0, useModel_1["default"])(config.model);
186
152
  var searchModel = (0, useModel_1["default"])(config.searchModel || ((_a = config.searchForm) === null || _a === void 0 ? void 0 : _a.model), defaultSearchModel);
187
153
  // Address bar synchronization
188
- var _d = (0, useAddressBar_1["default"])(__assign({ enable: !!config.addressBar, model: searchModel }, (typeof config.addressBar === 'boolean' ? { enable: config.addressBar } : config.addressBar))), initialQuery = _d.initialQuery, updateQuery = _d.updateQuery;
154
+ var _c = (0, useAddressBar_1["default"])(__assign({ enable: !!config.addressBar, model: searchModel }, (typeof config.addressBar === 'boolean' ? { enable: config.addressBar } : config.addressBar))), initialQuery = _c.initialQuery, updateQuery = _c.updateQuery;
189
155
  // Outside search form
190
156
  var searchFormFields = (_b = config.searchForm) === null || _b === void 0 ? void 0 : _b.fields;
191
157
  var SearchForm = require('../ui/list/SearchForm')["default"];
@@ -195,7 +161,7 @@ function useList(config) {
195
161
  return acc;
196
162
  }, {}); }, [searchFormFields, initialQuery]);
197
163
  var searchFormProps = __assign(__assign({ listId: config.listId }, config.searchForm), { model: searchModel, initialValues: initialValuesSearchForm });
198
- var renderSearchForm = function () { return React.createElement(SearchForm, __assign({}, searchFormProps)); };
164
+ var renderSearchForm = function () { return react_1["default"].createElement(SearchForm, __assign({}, searchFormProps)); };
199
165
  // Form id
200
166
  var formId = (0, get_1["default"])(config, 'searchForm.formId') || config.listId;
201
167
  var dispatch = (0, useDispatch_1["default"])();
@@ -211,14 +177,13 @@ function useList(config) {
211
177
  var initialValues = (0, useInitial_1["default"])(function () { return _initialValues; });
212
178
  var renderList = (0, react_1.useCallback)(function (children) {
213
179
  var Form = require('../ui/form/Form')["default"];
214
- return (React.createElement(Form, { formId: formId, initialValues: initialValues, view: false, useRedux: true }, children));
180
+ return (react_1["default"].createElement(Form, { formId: formId, initialValues: initialValues, view: false, useRedux: true }, children));
215
181
  }, [formId, initialValues]);
216
182
  // Init list in redux store
217
183
  (0, react_use_1.useMount)(function () {
218
184
  if (!list) {
219
- var items = config.hasTreeItems ? getTreeItems(config.items) : config.items;
220
185
  var toDispatch = [
221
- (0, list_3.listInit)(config.listId, {
186
+ (0, list_2.listInit)(config.listId, {
222
187
  listId: config.listId,
223
188
  action: config.action || config.action === '' ? config.action : null,
224
189
  actionMethod: config.actionMethod || exports.defaultConfig.actionMethod,
@@ -227,7 +192,7 @@ function useList(config) {
227
192
  condition: config.condition,
228
193
  scope: config.scope,
229
194
  items: null,
230
- sourceItems: items || null,
195
+ sourceItems: config.items || null,
231
196
  total: config.initialTotal,
232
197
  isRemote: !config.items,
233
198
  primaryKey: config.primaryKey || exports.defaultConfig.primaryKey,
@@ -239,15 +204,11 @@ function useList(config) {
239
204
  layoutAttribute: layoutNamesProps.attribute || null
240
205
  }),
241
206
  ];
242
- if (config.initialItems) {
243
- var initialItems = config.hasTreeItems ? getTreeItems(config.initialItems) : config.initialItems;
244
- toDispatch.push((0, list_3.listSetItems)(config.listId, initialItems));
245
- }
246
- else if (config.items) {
247
- toDispatch.push((0, list_3.listSetItems)(config.listId, items));
207
+ if (config.initialItems || config.items) {
208
+ toDispatch.push((0, list_2.listSetItems)(config.listId, config.initialItems || config.items));
248
209
  }
249
210
  if (!config.initialItems) {
250
- toDispatch.push((0, list_3.listLazyFetch)(config.listId));
211
+ toDispatch.push((0, list_2.listLazyFetch)(config.listId));
251
212
  }
252
213
  dispatch(toDispatch);
253
214
  }
@@ -270,7 +231,7 @@ function useList(config) {
270
231
  updateQuery(formValues);
271
232
  // Send request
272
233
  if (config.autoFetchOnFormChanges !== false) {
273
- dispatch((0, list_3.listLazyFetch)(config.listId));
234
+ dispatch((0, list_2.listLazyFetch)(config.listId));
274
235
  }
275
236
  }
276
237
  }, [config.autoFetchOnFormChanges, config.listId, dispatch, formId, formValues,
@@ -288,29 +249,22 @@ function useList(config) {
288
249
  // Check change items
289
250
  (0, react_use_1.useUpdateEffect)(function () {
290
251
  dispatch([
291
- (0, list_3.listSetItems)(config.listId, config.items),
252
+ (0, list_2.listSetItems)(config.listId, config.items),
292
253
  ]);
293
254
  }, [dispatch, config.items, config.listId]);
294
- (0, react_use_1.useUpdateEffect)(function () {
295
- if (config.hasTreeItems) {
296
- dispatch([
297
- (0, list_3.listSetItems)(config.listId, getTreeItems(config.items)),
298
- ]);
299
- }
300
- }, [dispatch, config.items, config.listId, openedTreeItems, list === null || list === void 0 ? void 0 : list.pageSize, list === null || list === void 0 ? void 0 : list.page]);
301
255
  // Destroy
302
256
  (0, react_use_1.useUnmount)(function () {
303
257
  var autoDestroy = typeof config.autoDestroy === 'boolean' ? config.autoDestroy : exports.defaultConfig.autoDestroy;
304
258
  if (autoDestroy) {
305
259
  dispatch([
306
- (0, list_3.listDestroy)(config.listId),
260
+ (0, list_2.listDestroy)(config.listId),
307
261
  (0, form_1.formDestroy)(config.listId),
308
262
  ]);
309
263
  }
310
264
  });
311
265
  var onFetch = (0, react_1.useCallback)(function (params) {
312
266
  if (params === void 0) { params = {}; }
313
- dispatch((0, list_3.listFetch)(config.listId, params));
267
+ dispatch((0, list_2.listFetch)(config.listId, params));
314
268
  }, [config.listId, dispatch]);
315
269
  var onSort = (0, react_1.useCallback)(function (value) {
316
270
  dispatch((0, form_1.formChange)(formId, sort.attribute, value));
@@ -21,10 +21,8 @@ function useSaveCursorPosition(inputParams) {
21
21
  var onChange = react_1["default"].useCallback(function (event, value) {
22
22
  var _a, _b;
23
23
  if (value === void 0) { value = null; }
24
- if (event) {
25
- setCursor((_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.selectionStart);
26
- }
27
- inputParams.onChange.call(null, value || ((_b = event === null || event === void 0 ? void 0 : event.target) === null || _b === void 0 ? void 0 : _b.value));
24
+ setCursor((_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.selectionStart);
25
+ inputParams.onChange(value || ((_b = event.target) === null || _b === void 0 ? void 0 : _b.value));
28
26
  }, [inputParams]);
29
27
  return {
30
28
  inputRef: inputRef,
@@ -0,0 +1,99 @@
1
+ import React from 'react';
2
+ import { IButtonProps } from '@steroidsjs/core/ui/form/Button/Button';
3
+ export interface ITreeItem extends IButtonProps {
4
+ /**
5
+ * Идентификатор узла
6
+ */
7
+ id?: string | number;
8
+ /**
9
+ * Вложенные элементы
10
+ * @example
11
+ * [
12
+ * {
13
+ * id: 2,
14
+ * label: 'Nested element',
15
+ * items: [...]
16
+ * }
17
+ * ]
18
+ */
19
+ items?: ITreeItem[];
20
+ /**
21
+ * Скрыть или показать узел
22
+ * @example true
23
+ */
24
+ visible?: boolean;
25
+ }
26
+ export interface IPreparedTreeItem extends ITreeItem {
27
+ uniqueId: string;
28
+ index: number;
29
+ level: number;
30
+ isOpened: boolean;
31
+ isSelected: boolean;
32
+ hasItems: boolean;
33
+ onClick: (e: Event | React.MouseEvent | any) => void;
34
+ className?: CssClassName;
35
+ }
36
+ export interface ITreeOutput {
37
+ treeItems: IPreparedTreeItem[];
38
+ }
39
+ export interface ITreeConfig {
40
+ /**
41
+ * Коллекция с узлами. Также можно передать идентификатор роута, тогда компонент найдет все
42
+ * вложенные роуты и отобразит их в виде дерева.
43
+ * @example
44
+ * [
45
+ * {
46
+ * id: 1,
47
+ * label: 'Root',
48
+ * items: [...]
49
+ * }
50
+ * ] | 'root'
51
+ */
52
+ items?: ITreeItem[] | string;
53
+ /**
54
+ * Ограничивает максимальный уровень вложенности дерева
55
+ * @example 2
56
+ */
57
+ level?: number;
58
+ /**
59
+ * Ключ для доступа к вложенным элементам узла
60
+ * @example 'items'
61
+ */
62
+ itemsKey?: string;
63
+ /**
64
+ * Идентификатор узла, которой нужно отобразить в раскрытом виде
65
+ * @example 2
66
+ */
67
+ selectedItemId?: string | number;
68
+ /**
69
+ * Максимальный уровень вложенности, до которого все узлы будут отображаться в развёрнутом виде
70
+ * @example 1
71
+ */
72
+ autoOpenLevels?: number;
73
+ /**
74
+ * Обработчик на клик по узлу
75
+ * @param args
76
+ */
77
+ onExpand?: (...args: any[]) => any;
78
+ /**
79
+ * Используется для управления раскрытием всех элементов в дереве
80
+ * @example: true
81
+ */
82
+ alwaysOpened?: boolean;
83
+ /**
84
+ * Текущая страница, используется для корректного отображения пагинации
85
+ * @example: 1
86
+ */
87
+ currentPage?: number;
88
+ /**
89
+ * Количество элементов на странице, используется для корректного отображения пагинации
90
+ * @example: 4
91
+ */
92
+ itemsOnPage?: number;
93
+ /**
94
+ * Параметры роутинга
95
+ * @example: true
96
+ */
97
+ routerParams?: any;
98
+ }
99
+ export default function useTree(config: ITreeConfig): ITreeOutput;
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ exports.__esModule = true;
17
+ var react_1 = require("react");
18
+ var isString_1 = __importDefault(require("lodash-es/isString"));
19
+ var omit_1 = __importDefault(require("lodash-es/omit"));
20
+ var join_1 = __importDefault(require("lodash-es/join"));
21
+ var isEqual_1 = __importDefault(require("lodash-es/isEqual"));
22
+ var isEmpty_1 = __importDefault(require("lodash-es/isEmpty"));
23
+ var isNil_1 = __importDefault(require("lodash-es/isNil"));
24
+ var keys_1 = __importDefault(require("lodash-es/keys"));
25
+ var useSelector_1 = __importDefault(require("./useSelector"));
26
+ var router_1 = require("../reducers/router");
27
+ var INITIAL_CURRENT_LEVEL = 0;
28
+ var DOT_SEPARATOR = '.';
29
+ var EMPTY_PARENT_ID = '';
30
+ var FIRST_LEVEL_PARENT_ID = '0';
31
+ var defaultProps = {
32
+ itemsKey: 'items',
33
+ autoOpenLevels: 0
34
+ };
35
+ var getTreeItemUniqueId = function (item, index, parentId) { return (0, join_1["default"])([parentId || FIRST_LEVEL_PARENT_ID, String(item.id || index)], DOT_SEPARATOR); };
36
+ var routeToItem = function (route, routerParams) {
37
+ var routeItems = (Array.isArray(route.items)
38
+ ? route.items.map(function (r) { return routeToItem(r, routerParams); })
39
+ : Object.keys(route.items || {}).map(function (id) { return routeToItem(route.items[id], routerParams); })).filter(function (r) { return r.visible; });
40
+ return {
41
+ id: route.id.toLowerCase(),
42
+ label: route.label || route.title,
43
+ visible: route.isNavVisible !== false,
44
+ toRoute: routeItems.length === 0 ? route.id : null,
45
+ toRouteParams: routeItems.length === 0 ? routerParams : null,
46
+ items: routeItems,
47
+ icon: route.icon
48
+ };
49
+ };
50
+ var findChildById = function (sourceItems, itemId, primaryKey, parentId, level) {
51
+ if (parentId === void 0) { parentId = EMPTY_PARENT_ID; }
52
+ if (level === void 0) { level = 1; }
53
+ if ((0, isString_1["default"])(sourceItems)) {
54
+ return null;
55
+ }
56
+ var foundedItem = null;
57
+ (sourceItems || []).forEach(function (item, index) {
58
+ var uniqueId = getTreeItemUniqueId(item, index, parentId);
59
+ if (!foundedItem && (item.id === itemId || uniqueId === itemId)) {
60
+ foundedItem = __assign(__assign({}, item), { uniqueId: uniqueId, level: level });
61
+ }
62
+ if (!foundedItem) {
63
+ foundedItem = findChildById(item[primaryKey], itemId, primaryKey, uniqueId, level + 1);
64
+ }
65
+ });
66
+ return foundedItem;
67
+ };
68
+ var getAutoExpandedItems = function (sourceItems, selectedItemId, primaryKey, autoOpenLevels, parentId, level) {
69
+ if (autoOpenLevels === void 0) { autoOpenLevels = 1; }
70
+ if (parentId === void 0) { parentId = EMPTY_PARENT_ID; }
71
+ if (level === void 0) { level = 1; }
72
+ var opened = {};
73
+ (sourceItems || []).forEach(function (item, index) {
74
+ var uniqueId = getTreeItemUniqueId(item, index, parentId);
75
+ if (autoOpenLevels >= level) {
76
+ opened[uniqueId] = true;
77
+ }
78
+ if (selectedItemId === item.id) {
79
+ opened[uniqueId] = true;
80
+ }
81
+ if (selectedItemId) {
82
+ var finedItem = findChildById(item[primaryKey], selectedItemId, primaryKey);
83
+ if (finedItem) {
84
+ opened[uniqueId] = true;
85
+ }
86
+ }
87
+ opened = __assign(__assign({}, opened), getAutoExpandedItems(item[primaryKey], selectedItemId, primaryKey, autoOpenLevels, uniqueId, level + 1));
88
+ });
89
+ return opened;
90
+ };
91
+ var isSelectedItem = function (selectedUniqueId, uniqueId, activeRouteIds, item, routerParams) { return (selectedUniqueId === uniqueId
92
+ || ((activeRouteIds || []).includes(item.toRoute)
93
+ && (0, isEqual_1["default"])(item.toRouteParams || {}, (0, omit_1["default"])(routerParams, (0, keys_1["default"])(item.toRouteParams))))); };
94
+ function useTree(config) {
95
+ // Get primary key
96
+ var primaryKey = config.itemsKey || defaultProps.itemsKey;
97
+ var _a = (0, react_1.useState)(null), selectedUniqueId = _a[0], setSelectedUniqueId = _a[1];
98
+ var _b = (0, react_1.useState)({}), expandedItems = _b[0], setExpandedItems = _b[1];
99
+ //Redux connection
100
+ var _c = (0, useSelector_1["default"])(function (state) { return ({
101
+ routes: (0, isString_1["default"])(config.items) ? (0, router_1.getNavItems)(state, config.items) : null,
102
+ selectedItemId: (0, isString_1["default"])(config.items) ? (0, router_1.getRouteId)(state) : config.selectedItemId,
103
+ activeRouteIds: (0, router_1.getActiveRouteIds)(state),
104
+ routerParams: (0, router_1.getRouterParams)(state)
105
+ }); }), routes = _c.routes, selectedItemId = _c.selectedItemId, activeRouteIds = _c.activeRouteIds, routerParams = _c.routerParams;
106
+ var items = (0, react_1.useMemo)(function () {
107
+ if (!(0, isNil_1["default"])(routes)) {
108
+ return routes
109
+ .map(function (route) { return routeToItem(route, config.routerParams); })
110
+ .filter(function (route) { return route.visible; });
111
+ }
112
+ if (Array.isArray(config.items)) {
113
+ return config.items;
114
+ }
115
+ return [];
116
+ }, [config.items, config.routerParams, routes]);
117
+ // Initial expanded items
118
+ (0, react_1.useEffect)(function () {
119
+ // TODO add clientStorage
120
+ setExpandedItems(getAutoExpandedItems(items, selectedItemId, primaryKey, config.autoOpenLevels));
121
+ var selectedItem = findChildById(items, selectedItemId, primaryKey);
122
+ setSelectedUniqueId(selectedItem ? selectedItem.uniqueId : null);
123
+ }, [items]);
124
+ var onExpand = (0, react_1.useCallback)(function (e, uniqueId, item) {
125
+ var _a;
126
+ e.preventDefault();
127
+ if (config.onExpand) {
128
+ config.onExpand.call(null, e, item);
129
+ }
130
+ setSelectedUniqueId(selectedUniqueId === uniqueId ? null : uniqueId);
131
+ if (!(0, isEmpty_1["default"])(item[primaryKey])) {
132
+ setExpandedItems(__assign(__assign({}, expandedItems), (_a = {}, _a[uniqueId] = !expandedItems[uniqueId], _a)));
133
+ }
134
+ }, [config.onExpand, expandedItems, primaryKey, selectedUniqueId]);
135
+ var resultTreeItems = (0, react_1.useMemo)(function () {
136
+ var getItems = function (sourceItems, parentId, currentLevel) {
137
+ if (parentId === void 0) { parentId = EMPTY_PARENT_ID; }
138
+ if (currentLevel === void 0) { currentLevel = INITIAL_CURRENT_LEVEL; }
139
+ if (config.level && currentLevel === config.level) {
140
+ return [];
141
+ }
142
+ if (config.currentPage && config.itemsOnPage && currentLevel === INITIAL_CURRENT_LEVEL) {
143
+ var startIndex = (config.currentPage - 1) * config.itemsOnPage;
144
+ sourceItems = sourceItems.slice(startIndex, startIndex + config.itemsOnPage);
145
+ }
146
+ return (sourceItems || []).reduce(function (treeItems, item, index) {
147
+ var uniqueId = getTreeItemUniqueId(item, index, parentId);
148
+ var treeItem = __assign(__assign({}, item), { index: index, level: currentLevel, uniqueId: uniqueId, isOpened: config.alwaysOpened || !!expandedItems[uniqueId], hasItems: !(0, isEmpty_1["default"])(item[primaryKey]), isSelected: isSelectedItem(selectedUniqueId, uniqueId, activeRouteIds, item, routerParams), onClick: function (e) { return onExpand(e, uniqueId, item); } });
149
+ // Ограничивает максимальный уровень вложенности дерева
150
+ if (config.level && (currentLevel === config.level - 1)) {
151
+ treeItem.hasItems = false;
152
+ }
153
+ treeItems.push(treeItem);
154
+ if (treeItem.isOpened) {
155
+ var nestedItem = getItems(item[primaryKey], uniqueId, currentLevel + 1);
156
+ treeItems = treeItems.concat(nestedItem).filter(Boolean);
157
+ }
158
+ return treeItems;
159
+ }, []);
160
+ };
161
+ return getItems(items);
162
+ // eslint-disable-next-line max-len
163
+ }, [activeRouteIds, config.alwaysOpened, config.currentPage, config.itemsOnPage, config.level, expandedItems, items, onExpand, primaryKey, routerParams, selectedUniqueId]);
164
+ return {
165
+ treeItems: resultTreeItems
166
+ };
167
+ }
168
+ exports["default"] = useTree;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steroidsjs/core",
3
- "version": "3.0.0-beta.106",
3
+ "version": "3.0.0-beta.108",
4
4
  "description": "",
5
5
  "author": "Vladimir Kozhin <hello@kozhindev.com>",
6
6
  "repository": {
@@ -33,6 +33,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
33
33
  __setModuleDefault(result, mod);
34
34
  return result;
35
35
  };
36
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
37
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
38
+ if (ar || !(i in from)) {
39
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
40
+ ar[i] = from[i];
41
+ }
42
+ }
43
+ return to.concat(ar || Array.prototype.slice.call(from));
44
+ };
36
45
  var __importDefault = (this && this.__importDefault) || function (mod) {
37
46
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
47
  };
@@ -40,6 +49,10 @@ exports.__esModule = true;
40
49
  var React = __importStar(require("react"));
41
50
  var isBoolean_1 = __importDefault(require("lodash-es/isBoolean"));
42
51
  var range_1 = __importDefault(require("lodash-es/range"));
52
+ var concat_1 = __importDefault(require("lodash-es/concat"));
53
+ var last_1 = __importDefault(require("lodash-es/last"));
54
+ var isEmpty_1 = __importDefault(require("lodash-es/isEmpty"));
55
+ var get_1 = __importDefault(require("lodash-es/get"));
43
56
  var react_use_1 = require("react-use");
44
57
  var react_1 = require("react");
45
58
  var hooks_1 = require("../../../hooks");
@@ -53,15 +66,29 @@ function FieldList(props) {
53
66
  var context = (0, react_1.useContext)(Form_1.FormContext);
54
67
  // Resolve model
55
68
  var modelAttributes = (_a = components.meta.getModel(props.model)) === null || _a === void 0 ? void 0 : _a.attributes;
69
+ var isWithReduxForm = (0, hooks_1.useSelector)(function (state) { return (0, get_1["default"])(state, ['form', context.formId]) || null; });
56
70
  var dispatch = context.provider.useDispatch();
71
+ // Mapper for preserving the correct sequence of rows on the UI
72
+ var _b = (0, react_1.useState)([]), storeToRowIndexMap = _b[0], setStoreToRowIndexMap = _b[1];
73
+ var addRowIndexes = (0, react_1.useCallback)(function (rowsCount) {
74
+ setStoreToRowIndexMap(function (prevMap) {
75
+ var lastIndex = !(0, isEmpty_1["default"])(prevMap) ? (0, last_1["default"])(prevMap) + 1 : 0;
76
+ return (0, concat_1["default"])(prevMap, (0, range_1["default"])(lastIndex, lastIndex + rowsCount));
77
+ });
78
+ }, []);
79
+ var removeRowIndex = (0, react_1.useCallback)(function (rowIndex) {
80
+ setStoreToRowIndexMap(function (prevMap) { return __spreadArray(__spreadArray([], prevMap.slice(0, rowIndex), true), prevMap.slice(rowIndex + 1), true); });
81
+ }, []);
57
82
  // Add and Remove handlers
58
83
  var onAdd = (0, react_1.useCallback)(function (rowsCount) {
59
84
  if (rowsCount === void 0) { rowsCount = 1; }
85
+ addRowIndexes(rowsCount);
60
86
  dispatch((0, form_1.formArrayAdd)(context.formId, props.input.name, rowsCount, props.initialValues));
61
- }, [context.formId, dispatch, props.initialValues, props.input.name]);
87
+ }, [context.formId, dispatch, props.initialValues, props.input.name, addRowIndexes]);
62
88
  var onRemove = (0, react_1.useCallback)(function (rowIndex) {
89
+ removeRowIndex(rowIndex);
63
90
  dispatch((0, form_1.formArrayRemove)(context.formId, props.input.name, rowIndex));
64
- }, [context.formId, dispatch, props.input.name]);
91
+ }, [context.formId, dispatch, props.input.name, removeRowIndex]);
65
92
  // Add initial rows
66
93
  (0, react_use_1.useMount)(function () {
67
94
  if (!props.input.value) {
@@ -106,8 +133,7 @@ function FieldList(props) {
106
133
  var FieldListView = props.view || components.ui.getView('form.FieldListView');
107
134
  var FieldListItemView = props.itemView || components.ui.getView('form.FieldListItemView');
108
135
  return (React.createElement(Form_1.FormContext.Provider, { value: contextValue },
109
- React.createElement(FieldListView, __assign({}, props.viewProps, commonProps, { forwardedRef: nodeRef, onAdd: onAdd, hasAlternatingColors: props.hasAlternatingColors }), (0, range_1["default"])(props.input.value || 0)
110
- .map(function (index) { return (React.createElement(FieldListItemView, __assign({}, props.itemViewProps, commonProps, { key: index, onRemove: onRemove, prefix: props.input.name + '.' + index, rowIndex: index }))); }))));
136
+ React.createElement(FieldListView, __assign({}, props.viewProps, commonProps, { forwardedRef: nodeRef, onAdd: onAdd, hasAlternatingColors: props.hasAlternatingColors }), !(0, isEmpty_1["default"])(storeToRowIndexMap) && (0, range_1["default"])(props.input.value || 0).map(function (index) { return (React.createElement(FieldListItemView, __assign({}, props.itemViewProps, commonProps, { key: isWithReduxForm ? storeToRowIndexMap[index] : index, onRemove: onRemove, prefix: props.input.name + '.' + index, rowIndex: index }))); }))));
111
137
  }
112
138
  FieldList.defaultProps = {
113
139
  initialValues: null,
@@ -97,18 +97,11 @@ function InputField(props) {
97
97
  }
98
98
  }, [inputRef, maskedInputRef]);
99
99
  (0, useInputFieldWarningByType_1.useInputFieldWarningByType)(props.type);
100
- var onChangeHandle = (0, react_1.useCallback)(function (e, value) {
101
- var _a;
102
- var currentValue = value !== null && value !== void 0 ? value : (_a = e.target) === null || _a === void 0 ? void 0 : _a.value;
103
- if (props.onChange) {
104
- props.onChange(e, currentValue);
105
- }
106
- }, [props]);
107
- var onClear = React.useCallback(function () { return onChangeHandle(null, ''); }, [onChangeHandle]);
100
+ var onClear = React.useCallback(function () { return props.input.onChange(''); }, [props.input]);
108
101
  var inputProps = (0, react_1.useMemo)(function () {
109
102
  var _a;
110
- return (__assign({ type: props.type, name: props.input.name, value: (_a = props.input.value) !== null && _a !== void 0 ? _a : '', onInput: onChangeHandle, placeholder: props.placeholder, disabled: props.disabled }, props.inputProps));
111
- }, [onChangeHandle, props.disabled, props.input.name, props.input.value, props.inputProps, props.placeholder, props.type]);
103
+ return (__assign({ type: props.type, name: props.input.name, value: (_a = props.input.value) !== null && _a !== void 0 ? _a : '', onInput: onChange, placeholder: props.placeholder, disabled: props.disabled }, props.inputProps));
104
+ }, [onChange, props.disabled, props.input.name, props.input.value, props.inputProps, props.placeholder, props.type]);
112
105
  // No render for hidden input
113
106
  if (props.type === 'hidden') {
114
107
  return null;
@@ -69,8 +69,7 @@ function Grid(props) {
69
69
  items: props.items,
70
70
  initialItems: props.initialItems,
71
71
  initialTotal: props.initialTotal,
72
- autoFetchOnFormChanges: props.autoFetchOnFormChanges,
73
- hasTreeItems: props.hasTreeItems
72
+ autoFetchOnFormChanges: props.autoFetchOnFormChanges
74
73
  }), list = _a.list, model = _a.model, searchModel = _a.searchModel, paginationPosition = _a.paginationPosition, paginationSizePosition = _a.paginationSizePosition, layoutNamesPosition = _a.layoutNamesPosition, renderList = _a.renderList, renderEmpty = _a.renderEmpty, renderPagination = _a.renderPagination, renderPaginationSize = _a.renderPaginationSize, renderLayoutNames = _a.renderLayoutNames, renderSearchForm = _a.renderSearchForm, onFetch = _a.onFetch, onSort = _a.onSort;
75
74
  var renderLabel = (0, react_1.useCallback)(function (column) {
76
75
  if (column.headerView) {
@@ -1,37 +1,16 @@
1
1
  /// <reference types="react" />
2
+ import { ITreeProps } from '@steroidsjs/core/ui/nav/Tree/Tree';
3
+ import { IPreparedTreeItem, ITreeItem } from '../../../hooks/useTree';
2
4
  import { IColumnViewProps, IGridColumn, IGridProps } from '../Grid/Grid';
3
- export interface ITreeColumnViewProps extends IColumnViewProps {
4
- item: ITreeTableItem & {
5
- uniqueId: string;
6
- level: number;
7
- isOpened: boolean;
8
- hasItems: boolean;
9
- onClick: () => void;
10
- };
11
- }
12
- export interface ITreeTableItem {
13
- /**
14
- * Идентификатор узла
15
- */
16
- id?: string | number;
17
- /**
18
- * Вложенные элементы
19
- * @example
20
- * items: [
21
- * {
22
- * id: 3,
23
- * name: 'Ivan'
24
- * }
25
- * ]
26
- */
27
- items?: ITreeTableItem[];
5
+ export interface ITreeColumnViewProps extends IColumnViewProps, Pick<ITreeTableProps, 'levelPadding'> {
6
+ item: IPreparedTreeItem;
28
7
  }
29
8
  /**
30
9
  * TreeTable
31
10
  *
32
11
  * Компонент для представления данных коллекции в виде иерархической структуры.
33
12
  */
34
- export interface ITreeTableProps extends Omit<IGridProps, 'items'> {
13
+ export interface ITreeTableProps extends Omit<IGridProps, 'items'>, Pick<ITreeProps, 'alwaysOpened' | 'levelPadding'> {
35
14
  /**
36
15
  * Элементы коллекции
37
16
  * @example
@@ -47,18 +26,14 @@ export interface ITreeTableProps extends Omit<IGridProps, 'items'> {
47
26
  * }
48
27
  * ]
49
28
  */
50
- items?: ITreeTableItem[];
51
- /**
52
- * Расстояние вложенных элементов от родителя для каждого уровня
53
- * @example 32
54
- */
55
- levelPadding?: number | string;
29
+ items?: ITreeItem[];
56
30
  }
57
31
  export declare const addTreeColumnFieldsToFirstColumn: (columns: IGridColumn[], levelPadding: string | number) => IGridColumn[];
58
32
  declare function TreeTable(props: ITreeTableProps): JSX.Element;
59
33
  declare namespace TreeTable {
60
34
  var defaultProps: {
61
35
  levelPadding: number;
36
+ alwaysOpened: boolean;
62
37
  };
63
38
  }
64
39
  export default TreeTable;
@@ -50,7 +50,10 @@ exports.addTreeColumnFieldsToFirstColumn = void 0;
50
50
  var React = __importStar(require("react"));
51
51
  var react_1 = require("react");
52
52
  var merge_1 = __importDefault(require("lodash-es/merge"));
53
+ var list_1 = require("@steroidsjs/core/reducers/list");
54
+ var useTree_1 = __importDefault(require("../../../hooks/useTree"));
53
55
  var Grid_1 = __importDefault(require("../Grid"));
56
+ var useSelector_1 = __importDefault(require("../../../hooks/useSelector"));
54
57
  var TREE_COLUMN_VIEW_FIELDS = {
55
58
  valueView: 'TreeColumnView',
56
59
  headerClassName: 'TreeColumnHeader'
@@ -64,9 +67,18 @@ var addTreeColumnFieldsToFirstColumn = function (columns, levelPadding) {
64
67
  exports.addTreeColumnFieldsToFirstColumn = addTreeColumnFieldsToFirstColumn;
65
68
  function TreeTable(props) {
66
69
  var columns = (0, react_1.useMemo)(function () { return (0, exports.addTreeColumnFieldsToFirstColumn)(props.columns, props.levelPadding); }, [props.columns, props.levelPadding]);
67
- return (React.createElement(Grid_1["default"], __assign({}, props, { columns: columns, items: props.items, itemsIndexing: false, hasTreeItems: true })));
70
+ var list = (0, useSelector_1["default"])(function (state) { return (0, list_1.getList)(state, props.listId); });
71
+ var treeItems = (0, useTree_1["default"])({
72
+ items: props.items,
73
+ autoOpenLevels: 0,
74
+ alwaysOpened: props.alwaysOpened,
75
+ currentPage: list === null || list === void 0 ? void 0 : list.page,
76
+ itemsOnPage: list === null || list === void 0 ? void 0 : list.pageSize
77
+ }).treeItems;
78
+ return (React.createElement(Grid_1["default"], __assign({}, props, { columns: columns, items: treeItems, itemsIndexing: false })));
68
79
  }
69
80
  exports["default"] = TreeTable;
70
81
  TreeTable.defaultProps = {
71
- levelPadding: 32
82
+ levelPadding: 32,
83
+ alwaysOpened: false
72
84
  };
@@ -1,66 +1,22 @@
1
1
  import * as React from 'react';
2
- import { IButtonProps } from '../../form/Button/Button';
3
- export interface ITreeItem extends IButtonProps {
4
- /**
5
- * Идентификатор узла
6
- */
7
- id?: string | number;
8
- /**
9
- * Вложенные элементы
10
- * @example
11
- * [
12
- * {
13
- * id: 2,
14
- * label: 'Nested element',
15
- * items: [...]
16
- * }
17
- * ]
18
- */
19
- items?: any[];
20
- /**
21
- * Скрыть или показать узел
22
- * @example true
23
- */
24
- visible?: boolean;
2
+ import { IPreparedTreeItem, ITreeConfig } from '../../../hooks/useTree';
3
+ export interface ITreeViewProps extends ITreeProps {
4
+ items: IPreparedTreeItem[];
5
+ }
6
+ export interface ITreeItemViewProps extends ITreeProps {
7
+ item: IPreparedTreeItem;
8
+ children?: JSX.Element;
25
9
  }
26
10
  /**
27
11
  * Tree
28
12
  * Компонент, который представляет в виде дерева список с иерархической структурой данных
29
13
  */
30
- export interface ITreeProps {
14
+ export interface ITreeProps extends Omit<ITreeConfig, 'currentPage' | 'itemsOnPage'> {
31
15
  /**
32
16
  * Идентификатор (ключ) для сохранения в LocalStorage коллекции с раскрытыми узлами
33
17
  * @example 'exampleTree'
34
18
  */
35
19
  id?: string;
36
- /**
37
- * Коллекция с узлами. Также можно передать идентификатор роута, тогда компонент найдет все
38
- * вложенные роуты и отобразит их в виде дерева.
39
- * @example
40
- * [
41
- * {
42
- * id: 1,
43
- * label: 'Root',
44
- * items: [...]
45
- * }
46
- * ] | 'root'
47
- */
48
- items?: ITreeItem[] | string;
49
- /**
50
- * Ограничивает максимальный уровень вложенности дерева
51
- * @example 2
52
- */
53
- level?: number;
54
- /**
55
- * Ключ для доступа к вложенным элементам узла
56
- * @example 'items'
57
- */
58
- itemsKey?: string;
59
- /**
60
- * Идентификатор узла, которой нужно отобразить в раскрытом виде
61
- * @example 2
62
- */
63
- selectedItemId?: string | number;
64
20
  /**
65
21
  * CSS-класс для элемента отображения
66
22
  */
@@ -70,11 +26,6 @@ export interface ITreeProps {
70
26
  * @example MyCustomView
71
27
  */
72
28
  view?: CustomView;
73
- /**
74
- * Максимальный уровень вложенности, до которого все узлы будут отображаться в развёрнутом виде
75
- * @example 1
76
- */
77
- autoOpenLevels?: number;
78
29
  /**
79
30
  * Обработчик на клик по узлу
80
31
  * @param args
@@ -86,24 +37,11 @@ export interface ITreeProps {
86
37
  */
87
38
  autoSave?: boolean;
88
39
  /**
89
- * Используется для управления раскрытием всех элементов в дереве
90
- * @example: true
91
- */
92
- alwaysOpened?: boolean;
93
- [key: string]: any;
94
- }
95
- export interface ITreeViewProps extends ITreeProps {
96
- items: (ITreeItem & {
97
- uniqId: string;
98
- className: CssClassName;
99
- index: number;
100
- level: number;
101
- isOpened: boolean;
102
- isSelected: boolean;
103
- hasItems: boolean;
104
- onClick: (e: Event | React.MouseEvent | any) => void;
105
- })[];
40
+ * Расстояние вложенных элементов от родителя для каждого уровня
41
+ * @example 32
42
+ */
106
43
  levelPadding?: number;
44
+ [key: string]: any;
107
45
  }
108
46
  declare function Tree(props: ITreeProps): React.ReactElement<any, string | React.JSXElementConstructor<any>>;
109
47
  declare namespace Tree {
@@ -112,6 +50,7 @@ declare namespace Tree {
112
50
  autoOpenLevels: number;
113
51
  autoSave: boolean;
114
52
  level: number;
53
+ levelPadding: number;
115
54
  };
116
55
  }
117
56
  export default Tree;
@@ -10,178 +10,27 @@ var __assign = (this && this.__assign) || function () {
10
10
  };
11
11
  return __assign.apply(this, arguments);
12
12
  };
13
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
- if (k2 === undefined) k2 = k;
15
- var desc = Object.getOwnPropertyDescriptor(m, k);
16
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
- desc = { enumerable: true, get: function() { return m[k]; } };
18
- }
19
- Object.defineProperty(o, k2, desc);
20
- }) : (function(o, m, k, k2) {
21
- if (k2 === undefined) k2 = k;
22
- o[k2] = m[k];
23
- }));
24
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
- Object.defineProperty(o, "default", { enumerable: true, value: v });
26
- }) : function(o, v) {
27
- o["default"] = v;
28
- });
29
- var __importStar = (this && this.__importStar) || function (mod) {
30
- if (mod && mod.__esModule) return mod;
31
- var result = {};
32
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
33
- __setModuleDefault(result, mod);
34
- return result;
35
- };
36
- var __importDefault = (this && this.__importDefault) || function (mod) {
37
- return (mod && mod.__esModule) ? mod : { "default": mod };
38
- };
39
13
  exports.__esModule = true;
40
- var React = __importStar(require("react"));
41
- var isString_1 = __importDefault(require("lodash-es/isString"));
42
- var omit_1 = __importDefault(require("lodash-es/omit"));
43
- var isEqual_1 = __importDefault(require("lodash-es/isEqual"));
44
- var keys_1 = __importDefault(require("lodash-es/keys"));
45
- var react_1 = require("react");
46
- var list_1 = require("../../../utils/list");
47
14
  var hooks_1 = require("../../../hooks");
48
- var router_1 = require("../../../reducers/router");
49
15
  function Tree(props) {
50
16
  var components = (0, hooks_1.useComponents)();
51
- var STORAGE_KEY_PREFIX = 'tree_';
52
- //State
53
- var _a = (0, react_1.useState)(null), selectedUniqId = _a[0], setSelectedUniqId = _a[1];
54
- var _b = (0, react_1.useState)({}), openedItems = _b[0], setOpenedItems = _b[1];
55
- //Redux connection
56
- var _c = (0, hooks_1.useSelector)(function (state) { return ({
57
- routes: (0, isString_1["default"])(props.items) ? (0, router_1.getNavItems)(state, props.items) : null,
58
- selectedItemId: (0, isString_1["default"])(props.items) ? (0, router_1.getRouteId)(state) : props.selectedItemId,
59
- activeRouteIds: (0, router_1.getActiveRouteIds)(state),
60
- routerParams: (0, router_1.getRouterParams)(state)
61
- }); }), routes = _c.routes, selectedItemId = _c.selectedItemId, activeRouteIds = _c.activeRouteIds, routerParams = _c.routerParams;
62
- var items = (0, react_1.useMemo)(function () {
63
- if (routes) {
64
- var routeToItem_1 = function (route) {
65
- var routeItems = (Array.isArray(route.items)
66
- ? route.items.map(function (r) { return routeToItem_1(r); })
67
- : Object.keys(route.items || {}).map(function (id) { return routeToItem_1(route.items[id]); })).filter(function (r) { return r.visible; });
68
- return {
69
- id: route.id.toLowerCase(),
70
- label: route.label || route.title,
71
- visible: route.isNavVisible !== false,
72
- toRoute: routeItems.length === 0 ? route.id : null,
73
- toRouteParams: routeItems.length === 0 ? props.routerParams : null,
74
- items: routeItems,
75
- icon: route.icon
76
- };
77
- };
78
- return routes.map(function (route) { return routeToItem_1(route); }).filter(function (r) { return r.visible; });
79
- }
80
- if (Array.isArray(props.items)) {
81
- return props.items;
82
- }
83
- return [];
84
- }, [props.items, props.routerParams, routes]);
85
- var findChildById = function (sourceItems, itemId, parentId, level) {
86
- if (parentId === void 0) { parentId = ''; }
87
- if (level === void 0) { level = 1; }
88
- var foundItem = null;
89
- if ((0, isString_1["default"])(sourceItems)) {
90
- return null;
91
- }
92
- (sourceItems || []).forEach(function (item, index) {
93
- var uniqId = (0, list_1.getTreeItemUniqId)(item, index, parentId);
94
- if (!foundItem && (item.id === itemId || uniqId === itemId)) {
95
- foundItem = __assign(__assign({}, item), { uniqId: uniqId, level: level });
96
- }
97
- if (!foundItem) {
98
- foundItem = findChildById(item[props.itemsKey], itemId, uniqId, level + 1);
99
- }
100
- });
101
- return foundItem;
102
- };
103
- var autoOpen = function (sourceItems, parentId, level) {
104
- if (parentId === void 0) { parentId = ''; }
105
- if (level === void 0) { level = 1; }
106
- var opened = {};
107
- (sourceItems || []).forEach(function (item, index) {
108
- var uniqId = (0, list_1.getTreeItemUniqId)(item, index, parentId);
109
- if (props.autoOpenLevels >= level) {
110
- opened[uniqId] = true;
111
- }
112
- if (selectedItemId === item.id) {
113
- opened[uniqId] = true;
114
- }
115
- if (selectedItemId) {
116
- var finedItem = findChildById(item[props.itemsKey], selectedItemId);
117
- if (finedItem) {
118
- opened[uniqId] = true;
119
- }
120
- }
121
- opened = __assign(__assign({}, opened), autoOpen(item[props.itemsKey], uniqId, level + 1));
122
- });
123
- return opened;
124
- };
125
- // Initial opened items
126
- React.useEffect(function () {
127
- // TODO add clientStorage
128
- // const key = STORAGE_KEY_PREFIX + props.id;
129
- // const opened = !this.state && this.props.clientStorage.get(key) && this.props.autoSave
130
- // ? JSON.parse(this.props.clientStorage.get(key))
131
- // : this._autoOpen(this.props._items);
132
- var opened = autoOpen(items);
133
- setOpenedItems(opened);
134
- var selectedItem = findChildById(items, selectedItemId);
135
- setSelectedUniqId(selectedItem ? selectedItem.uniqId : null);
136
- }, [items]);
137
- var onItemClick = (0, react_1.useCallback)(function (e, uniqId, item) {
138
- var _a;
139
- var _b;
140
- e.preventDefault();
141
- if (props.onItemClick) {
142
- props.onItemClick.call(null, e, item);
143
- }
144
- setSelectedUniqId(selectedUniqId === uniqId ? null : uniqId);
145
- if (((_b = item.items) === null || _b === void 0 ? void 0 : _b.length) > 0) {
146
- var newItems = __assign(__assign({}, openedItems), (_a = {}, _a[uniqId] = !openedItems[uniqId], _a));
147
- setOpenedItems(newItems);
148
- // TODO add clientStorage
149
- // const key = STORAGE_KEY_PREFIX + this.props.id;
150
- // this.props.clientStorage.set(key, JSON.stringify(this.state.opened));
151
- }
152
- }, [openedItems, props.onItemClick, selectedUniqId]);
153
- var resultItems = (0, react_1.useMemo)(function () {
154
- var getItems = function (sourceItems, parentId, level) {
155
- if (parentId === void 0) { parentId = ''; }
156
- if (level === void 0) { level = 0; }
157
- var result = [];
158
- if (props.level && level === props.level) {
159
- return [];
160
- }
161
- (sourceItems || []).forEach(function (item, index) {
162
- var uniqId = (0, list_1.getTreeItemUniqId)(item, index, parentId);
163
- var isOpened = props.alwaysOpened || !!openedItems[uniqId];
164
- var hasItems = item[props.itemsKey] && item[props.itemsKey].length > 0;
165
- if (props.level && (level === props.level - 1)) {
166
- hasItems = false;
167
- }
168
- result.push(__assign(__assign({}, item), { uniqId: uniqId, index: index, level: level, isOpened: isOpened, isSelected: selectedUniqId === uniqId
169
- || (activeRouteIds.includes(item.toRoute)
170
- && (0, isEqual_1["default"])(item.toRouteParams || {}, (0, omit_1["default"])(routerParams, (0, keys_1["default"])(item.toRouteParams)))), hasItems: hasItems, onClick: function (e) { return onItemClick(e, uniqId, item); } }));
171
- if (isOpened) {
172
- result = result.concat(getItems(item[props.itemsKey], uniqId, level + 1)).filter(Boolean);
173
- }
174
- });
175
- return result;
176
- };
177
- return getItems(items);
178
- }, [activeRouteIds, items, onItemClick, openedItems, props.alwaysOpened, props.itemsKey, props.level, routerParams, selectedUniqId]);
179
- return components.ui.renderView(props.view || 'nav.TreeView', __assign(__assign({}, props), { items: resultItems }));
17
+ var treeItems = (0, hooks_1.useTree)({
18
+ items: props.items,
19
+ selectedItemId: props.selectedItemId,
20
+ routerParams: props.routerParams,
21
+ itemsKey: props.itemsKey,
22
+ autoOpenLevels: props.autoOpenLevels,
23
+ onExpand: props.onItemClick,
24
+ level: props.level,
25
+ alwaysOpened: props.alwaysOpened
26
+ }).treeItems;
27
+ return components.ui.renderView(props.view || 'nav.TreeView', __assign(__assign({}, props), { items: treeItems }));
180
28
  }
29
+ exports["default"] = Tree;
181
30
  Tree.defaultProps = {
182
31
  itemsKey: 'items',
183
32
  autoOpenLevels: 1,
184
33
  autoSave: false,
185
- level: 0
34
+ level: 0,
35
+ levelPadding: 32
186
36
  };
187
- exports["default"] = Tree;
@@ -1,4 +1,12 @@
1
1
  export declare const convertDate: (date: string | Date, fromFormats: string | string[], toFormat?: string, isUtc?: boolean, dateInUtc?: boolean) => any;
2
+ export declare const customLocaleUtils: {
3
+ formatDay: (day: Date, locale?: string) => string;
4
+ formatMonthTitle: (month: Date, locale?: string) => string;
5
+ formatWeekdayShort: (weekday: number, locale?: string) => any;
6
+ formatWeekdayLong: (weekday: number, locale?: string) => any;
7
+ getFirstDayOfWeek: (locale?: string) => any;
8
+ getMonths: (locale?: string) => any;
9
+ };
2
10
  /**
3
11
  * Регулярка проверяет соответствие введенной строки формату 'hh:mm'
4
12
  * Максимальная величина - 23:59
package/utils/calendar.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  exports.__esModule = true;
6
- exports.convertDate = void 0;
6
+ exports.customLocaleUtils = exports.convertDate = void 0;
7
7
  /* eslint-disable import/no-extraneous-dependencies */
8
8
  /* eslint-disable import/prefer-default-export */
9
9
  var dayjs_1 = __importDefault(require("dayjs"));
@@ -45,6 +45,81 @@ var convertDate = function (date, fromFormats, toFormat, isUtc, dateInUtc) {
45
45
  return toFormat ? dayjsDate.format(toFormat) : dayjsDate.toDate();
46
46
  };
47
47
  exports.convertDate = convertDate;
48
+ /**
49
+ * Функции форматирования для локализации Day Picker.
50
+ */
51
+ var WEEKDAYS_LONG = {
52
+ en: [
53
+ 'Sunday',
54
+ 'Monday',
55
+ 'Tuesday',
56
+ 'Wednesday',
57
+ 'Thursday',
58
+ 'Friday',
59
+ 'Saturday',
60
+ ],
61
+ ru: [
62
+ 'Понедельник',
63
+ 'Вторник',
64
+ 'Среда',
65
+ 'Четверг',
66
+ 'Пятница',
67
+ 'Суббота',
68
+ 'Воскресенье',
69
+ ]
70
+ };
71
+ var WEEKDAYS_SHORT = {
72
+ en: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
73
+ ru: ['ВС', 'ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ']
74
+ };
75
+ var MONTHS = {
76
+ en: [
77
+ 'January',
78
+ 'February',
79
+ 'March',
80
+ 'April',
81
+ 'May',
82
+ 'June',
83
+ 'July',
84
+ 'August',
85
+ 'September',
86
+ 'October',
87
+ 'November',
88
+ 'December',
89
+ ],
90
+ ru: [
91
+ 'Январь',
92
+ 'Февраль',
93
+ 'Март',
94
+ 'Апрель',
95
+ 'Май',
96
+ 'Июнь',
97
+ 'Июль',
98
+ 'Август',
99
+ 'Сентябрь',
100
+ 'Октябрь',
101
+ 'Ноябрь',
102
+ 'Декабрь',
103
+ ]
104
+ };
105
+ var FIRST_DAY = {
106
+ en: 0,
107
+ ru: 1
108
+ };
109
+ var formatDay = function (day, locale) { return "".concat(WEEKDAYS_LONG[locale][day.getDay()], ", ").concat(day.getDate(), " ").concat(MONTHS[locale][day.getMonth()], " ").concat(day.getFullYear()); };
110
+ var formatMonthTitle = function (month, locale) { return "".concat(MONTHS[locale][month.getMonth()], " ").concat(month.getFullYear()); };
111
+ var formatWeekdayShort = function (weekday, locale) { return WEEKDAYS_SHORT[locale][weekday]; };
112
+ var formatWeekdayLong = function (weekday, locale) { return WEEKDAYS_SHORT[locale][weekday]; };
113
+ var getFirstDayOfWeek = function (locale) { return FIRST_DAY[locale]; };
114
+ var getMonths = function (locale) { return MONTHS[locale]; };
115
+ exports.customLocaleUtils = {
116
+ formatDay: formatDay,
117
+ formatMonthTitle: formatMonthTitle,
118
+ formatWeekdayShort: formatWeekdayShort,
119
+ formatWeekdayLong: formatWeekdayLong,
120
+ getFirstDayOfWeek: getFirstDayOfWeek,
121
+ getMonths: getMonths
122
+ };
48
123
  /**
49
124
  * Регулярка проверяет соответствие введенной строки формату 'hh:mm'
50
125
  * Максимальная величина - 23:59
package/utils/list.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare const getTreeItemUniqId: (item: any, index: any, parentId: any) => string;
package/utils/list.js DELETED
@@ -1,5 +0,0 @@
1
- "use strict";
2
- exports.__esModule = true;
3
- exports.getTreeItemUniqId = void 0;
4
- var getTreeItemUniqId = function (item, index, parentId) { return (parentId || '0') + '.' + String(item.id || index); };
5
- exports.getTreeItemUniqId = getTreeItemUniqId;