@steroidsjs/core 3.0.0-beta.82 → 3.0.0-beta.84
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/en.json +23 -23
- package/hooks/index.d.ts +2 -1
- package/hooks/index.js +3 -1
- package/hooks/useList.d.ts +10 -4
- package/hooks/useList.js +59 -14
- package/hooks/useSaveCursorPosition.d.ts +6 -0
- package/hooks/useSaveCursorPosition.js +29 -0
- package/package.json +1 -1
- package/providers/ComponentsProvider.d.ts +3 -3
- package/ui/content/Card/Card.d.ts +2 -2
- package/ui/form/Field/fieldWrapper.d.ts +6 -5
- package/ui/form/InputField/InputField.d.ts +1 -2
- package/ui/form/InputField/InputField.js +9 -4
- package/ui/form/NumberField/NumberField.d.ts +6 -2
- package/ui/form/NumberField/NumberField.js +32 -4
- package/ui/form/NumberField/hooks/useInputTypeNumber.d.ts +10 -0
- package/ui/form/NumberField/hooks/useInputTypeNumber.js +45 -0
- package/ui/form/PasswordField/PasswordField.js +3 -2
- package/ui/form/TextField/TextField.js +4 -3
- package/ui/layout/Header/Header.d.ts +5 -5
- package/ui/layout/Sidebar/Sidebar.d.ts +3 -3
- package/ui/layout/Tooltip/Tooltip.d.ts +3 -3
- package/ui/list/Grid/Grid.d.ts +1 -1
- package/ui/list/Grid/Grid.js +2 -1
- package/ui/list/PaginationSize/PaginationSize.d.ts +1 -1
- package/ui/list/TreeTable/TreeTable.d.ts +35 -0
- package/ui/list/TreeTable/TreeTable.js +69 -0
- package/ui/list/TreeTable/index.d.ts +2 -0
- package/ui/list/TreeTable/index.js +7 -0
- package/ui/modal/Modal/Modal.d.ts +1 -1
- package/ui/nav/ButtonGroup/ButtonGroup.d.ts +1 -1
- package/ui/nav/Tree/Tree.js +4 -4
- package/utils/list.d.ts +1 -0
- package/utils/list.js +5 -0
package/en.json
CHANGED
|
@@ -783,26 +783,26 @@
|
|
|
783
783
|
"При указании данного свойства, после нажатия на кнопку и до выполнения действия будет отображено нативное\nокно с текстом подтверждения - `window.confirm('Ваш текст')`.": "When this property is specified, after clicking the button and before performing the action, a native \nwindow with the confirmation text will be displayed - `window.confirm('Your text')`.",
|
|
784
784
|
"Контент, который отобразиться, если элемент навигации будет активен": "The content that will be displayed if the navigation element is active",
|
|
785
785
|
" Используется для управления раскрытием всех элементов в дереве": " Used to control the expansion of all items in the tree",
|
|
786
|
-
"\nСписок с чекбоксами. Используется в формах для выбора нескольких значений.\n": "",
|
|
787
|
-
"Разница времени с бекендом (в микросекундах)": "",
|
|
788
|
-
"Временная зона бекенда": "",
|
|
789
|
-
"Исходный язык": "",
|
|
790
|
-
"Переводы сообщений": "",
|
|
791
|
-
"Показывать ли компонент сразу после рендера страницы": "",
|
|
792
|
-
"Объект стилей для позиционирования стрелки": "",
|
|
793
|
-
"Позиция компонента слева": "",
|
|
794
|
-
"Позиция компонента справа": "",
|
|
795
|
-
"Позиция компонента сверху": "",
|
|
796
|
-
"Обработчик события загрузки файлов": "",
|
|
797
|
-
"Если в форме есть элементы \\<input\\>, то произойдет автоматическая фокусировка на первом из них": "",
|
|
798
|
-
"Варианты абсолютного позиционирования": "",
|
|
799
|
-
"Получение экземпляра `dayjs` с учетом временной зоны бекенда": "",
|
|
800
|
-
"Алиас для метода `translate`": "",
|
|
801
|
-
"Перевод сообщения": "",
|
|
802
|
-
"Компонент графика из библиотеки nivo": "",
|
|
803
|
-
"Конфигурация, настройки отображения графика": "",
|
|
804
|
-
"Данные для графика": "",
|
|
805
|
-
"Фиксированная высота графика в пикселях": "",
|
|
806
|
-
"Использовать ли дефолтную конфигурацию для графика типа line": "",
|
|
807
|
-
"Этот компонент позволяет создавать в проекте графики разных типов. Под капотом для графиков используется библиотека nivo.\nДля работы этого компонента необходимо установить в проекте зависимости @nivo/core и пакет конкретного графика nivo, например @nivo/line.\nКомпонент графика nivo нужно передать в пропс chartComponent": ""
|
|
808
|
-
}
|
|
786
|
+
"\nСписок с чекбоксами. Используется в формах для выбора нескольких значений.\n": "\nCheckbox list. Used in forms to select multiple values.\n",
|
|
787
|
+
"Разница времени с бекендом (в микросекундах)": "Time difference with the backend (in microseconds)",
|
|
788
|
+
"Временная зона бекенда": "Backend time zone",
|
|
789
|
+
"Исходный язык": "Source language",
|
|
790
|
+
"Переводы сообщений": "Message translations",
|
|
791
|
+
"Показывать ли компонент сразу после рендера страницы": "Show the component immediately after page rendering",
|
|
792
|
+
"Объект стилей для позиционирования стрелки": "Style object for arrow positioning",
|
|
793
|
+
"Позиция компонента слева": "Component position on the left",
|
|
794
|
+
"Позиция компонента справа": "Component position on the right",
|
|
795
|
+
"Позиция компонента сверху": "Component position on top",
|
|
796
|
+
"Обработчик события загрузки файлов": "File upload event handler",
|
|
797
|
+
"Если в форме есть элементы \\<input\\>, то произойдет автоматическая фокусировка на первом из них": "If there are \\<input\\> elements in the form, automatic focus will be on the first one",
|
|
798
|
+
"Варианты абсолютного позиционирования": "Absolute positioning options",
|
|
799
|
+
"Получение экземпляра `dayjs` с учетом временной зоны бекенда": "Getting an instance of `dayjs` considering the backend time zone",
|
|
800
|
+
"Алиас для метода `translate`": "Alias for the `translate` method",
|
|
801
|
+
"Перевод сообщения": "Message translation",
|
|
802
|
+
"Компонент графика из библиотеки nivo": "Chart component from the nivo library",
|
|
803
|
+
"Конфигурация, настройки отображения графика": "Chart display configuration and settings",
|
|
804
|
+
"Данные для графика": "Data for the chart",
|
|
805
|
+
"Фиксированная высота графика в пикселях": "Fixed chart height in pixels",
|
|
806
|
+
"Использовать ли дефолтную конфигурацию для графика типа line": "Use default configuration for the line chart",
|
|
807
|
+
"Этот компонент позволяет создавать в проекте графики разных типов. Под капотом для графиков используется библиотека nivo.\nДля работы этого компонента необходимо установить в проекте зависимости @nivo/core и пакет конкретного графика nivo, например @nivo/line.\nКомпонент графика nivo нужно передать в пропс chartComponent": "This component allows you to create various types of graphics in your project. Under the hood, the nivo library is used for charts. \nTo use this component, you need to install dependencies @nivo/core and a specific nivo chart package, for example, @nivo/line. \nPass the nivo chart component as the chartComponent prop"
|
|
808
|
+
}
|
package/hooks/index.d.ts
CHANGED
|
@@ -18,4 +18,5 @@ import useSelector from './useSelector';
|
|
|
18
18
|
import useSsr from './useSsr';
|
|
19
19
|
import useUniqueId from './useUniqueId';
|
|
20
20
|
import useTheme from './useTheme';
|
|
21
|
-
|
|
21
|
+
import useSaveCursorPosition from './useSaveCursorPosition';
|
|
22
|
+
export { useAbsolutePositioning, useAddressBar, useApplication, useBem, useComponents, useDataProvider, useDataSelect, useDispatch, useFetch, useFile, useForm, useInitial, useLayout, useList, useModel, useScreen, useSelector, useSsr, useUniqueId, useTheme, 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.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.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,3 +44,5 @@ 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 useSaveCursorPosition_1 = __importDefault(require("./useSaveCursorPosition"));
|
|
48
|
+
exports.useSaveCursorPosition = useSaveCursorPosition_1["default"];
|
package/hooks/useList.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ITreeTableItem } from '../ui/list/TreeTable/TreeTable';
|
|
1
2
|
import { IAddressBarConfig } from '../hooks/useAddressBar';
|
|
2
3
|
import { IList } from '../actions/list';
|
|
3
4
|
import { ILayoutNamesProps } from '../ui/list/LayoutNames/LayoutNames';
|
|
@@ -118,8 +119,8 @@ export interface IListConfig {
|
|
|
118
119
|
*/
|
|
119
120
|
addressBar?: boolean | IAddressBarConfig;
|
|
120
121
|
/**
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
* Параметр для загрузки данных списка с сервера
|
|
123
|
+
*/
|
|
123
124
|
scope?: string[];
|
|
124
125
|
/**
|
|
125
126
|
* Дополнительные параметры, значения которых нужно передавать в запросе для получения данных
|
|
@@ -127,8 +128,8 @@ export interface IListConfig {
|
|
|
127
128
|
*/
|
|
128
129
|
query?: Record<string, unknown>;
|
|
129
130
|
/**
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
* Модель
|
|
132
|
+
*/
|
|
132
133
|
model?: string;
|
|
133
134
|
/**
|
|
134
135
|
* Модель для синхронизации значений формы с адресной строкой
|
|
@@ -148,6 +149,10 @@ export interface IListConfig {
|
|
|
148
149
|
* Количество элементов всего в списке (для отрисовки пагинации), заданное вручную
|
|
149
150
|
*/
|
|
150
151
|
initialTotal?: number;
|
|
152
|
+
/**
|
|
153
|
+
* Включает обработку вложенных данных из items вида [{id: 1, name: 'John', items: [...]}]
|
|
154
|
+
*/
|
|
155
|
+
hasTreeItems?: boolean;
|
|
151
156
|
}
|
|
152
157
|
export interface IListOutput {
|
|
153
158
|
list: IList;
|
|
@@ -206,6 +211,7 @@ export declare const createInitialValues: ({ paginationProps, paginationSizeProp
|
|
|
206
211
|
initialQuery: any;
|
|
207
212
|
configQuery: any;
|
|
208
213
|
}) => any;
|
|
214
|
+
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[];
|
|
209
215
|
/**
|
|
210
216
|
* useList
|
|
211
217
|
* Добавляет массу возможностей для взаимодействия с коллекциями. Коллекции можно получать как с бекенда,
|
package/hooks/useList.js
CHANGED
|
@@ -37,18 +37,19 @@ 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.createInitialValues = exports.getDefaultSearchModel = exports.normalizeSortProps = exports.defaultConfig = void 0;
|
|
40
|
+
exports.prepareItemsToTree = exports.createInitialValues = exports.getDefaultSearchModel = exports.normalizeSortProps = exports.defaultConfig = void 0;
|
|
41
41
|
var react_1 = 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
45
|
var React = __importStar(require("react"));
|
|
46
46
|
var react_use_1 = require("react-use");
|
|
47
|
+
var list_1 = require("../utils/list");
|
|
47
48
|
var useSelector_1 = __importDefault(require("../hooks/useSelector"));
|
|
48
|
-
var
|
|
49
|
+
var list_2 = require("../reducers/list");
|
|
49
50
|
var useModel_1 = __importDefault(require("../hooks/useModel"));
|
|
50
51
|
var useAddressBar_1 = __importDefault(require("../hooks/useAddressBar"));
|
|
51
|
-
var
|
|
52
|
+
var list_3 = require("../actions/list");
|
|
52
53
|
var useDispatch_1 = __importDefault(require("../hooks/useDispatch"));
|
|
53
54
|
var form_1 = require("../actions/form");
|
|
54
55
|
var form_2 = require("../reducers/form");
|
|
@@ -104,6 +105,27 @@ var createInitialValues = function (_a) {
|
|
|
104
105
|
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));
|
|
105
106
|
};
|
|
106
107
|
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, onTreeItemClick: onTreeItemClick }));
|
|
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;
|
|
107
129
|
/**
|
|
108
130
|
* useList
|
|
109
131
|
* Добавляет массу возможностей для взаимодействия с коллекциями. Коллекции можно получать как с бекенда,
|
|
@@ -113,7 +135,18 @@ exports.createInitialValues = createInitialValues;
|
|
|
113
135
|
function useList(config) {
|
|
114
136
|
var _a, _b;
|
|
115
137
|
// Get list from redux state
|
|
116
|
-
var list = (0, useSelector_1["default"])(function (state) { return (0,
|
|
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]);
|
|
117
150
|
// Normalize sort config
|
|
118
151
|
var sort = (0, exports.normalizeSortProps)(config.sort);
|
|
119
152
|
// Empty
|
|
@@ -152,7 +185,7 @@ function useList(config) {
|
|
|
152
185
|
var model = (0, useModel_1["default"])(config.model);
|
|
153
186
|
var searchModel = (0, useModel_1["default"])(config.searchModel || ((_a = config.searchForm) === null || _a === void 0 ? void 0 : _a.model), defaultSearchModel);
|
|
154
187
|
// Address bar synchronization
|
|
155
|
-
var
|
|
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;
|
|
156
189
|
// Outside search form
|
|
157
190
|
var searchFormFields = (_b = config.searchForm) === null || _b === void 0 ? void 0 : _b.fields;
|
|
158
191
|
var SearchForm = require('../ui/list/SearchForm')["default"];
|
|
@@ -183,8 +216,9 @@ function useList(config) {
|
|
|
183
216
|
// Init list in redux store
|
|
184
217
|
(0, react_use_1.useMount)(function () {
|
|
185
218
|
if (!list) {
|
|
219
|
+
var items = config.hasTreeItems ? getTreeItems(config.items) : config.items;
|
|
186
220
|
var toDispatch = [
|
|
187
|
-
(0,
|
|
221
|
+
(0, list_3.listInit)(config.listId, {
|
|
188
222
|
listId: config.listId,
|
|
189
223
|
action: config.action || config.action === '' ? config.action : null,
|
|
190
224
|
actionMethod: config.actionMethod || exports.defaultConfig.actionMethod,
|
|
@@ -193,7 +227,7 @@ function useList(config) {
|
|
|
193
227
|
condition: config.condition,
|
|
194
228
|
scope: config.scope,
|
|
195
229
|
items: null,
|
|
196
|
-
sourceItems:
|
|
230
|
+
sourceItems: items || null,
|
|
197
231
|
total: config.initialTotal,
|
|
198
232
|
isRemote: !config.items,
|
|
199
233
|
primaryKey: config.primaryKey || exports.defaultConfig.primaryKey,
|
|
@@ -205,11 +239,15 @@ function useList(config) {
|
|
|
205
239
|
layoutAttribute: layoutNamesProps.attribute || null
|
|
206
240
|
}),
|
|
207
241
|
];
|
|
208
|
-
if (config.initialItems
|
|
209
|
-
|
|
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));
|
|
210
248
|
}
|
|
211
249
|
if (!config.initialItems) {
|
|
212
|
-
toDispatch.push((0,
|
|
250
|
+
toDispatch.push((0, list_3.listLazyFetch)(config.listId));
|
|
213
251
|
}
|
|
214
252
|
dispatch(toDispatch);
|
|
215
253
|
}
|
|
@@ -232,7 +270,7 @@ function useList(config) {
|
|
|
232
270
|
updateQuery(formValues);
|
|
233
271
|
// Send request
|
|
234
272
|
if (config.autoFetchOnFormChanges !== false) {
|
|
235
|
-
dispatch((0,
|
|
273
|
+
dispatch((0, list_3.listLazyFetch)(config.listId));
|
|
236
274
|
}
|
|
237
275
|
}
|
|
238
276
|
}, [config.autoFetchOnFormChanges, config.listId, dispatch, formId, formValues,
|
|
@@ -250,22 +288,29 @@ function useList(config) {
|
|
|
250
288
|
// Check change items
|
|
251
289
|
(0, react_use_1.useUpdateEffect)(function () {
|
|
252
290
|
dispatch([
|
|
253
|
-
(0,
|
|
291
|
+
(0, list_3.listSetItems)(config.listId, config.items),
|
|
254
292
|
]);
|
|
255
293
|
}, [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]);
|
|
256
301
|
// Destroy
|
|
257
302
|
(0, react_use_1.useUnmount)(function () {
|
|
258
303
|
var autoDestroy = typeof config.autoDestroy === 'boolean' ? config.autoDestroy : exports.defaultConfig.autoDestroy;
|
|
259
304
|
if (autoDestroy) {
|
|
260
305
|
dispatch([
|
|
261
|
-
(0,
|
|
306
|
+
(0, list_3.listDestroy)(config.listId),
|
|
262
307
|
(0, form_1.formDestroy)(config.listId),
|
|
263
308
|
]);
|
|
264
309
|
}
|
|
265
310
|
});
|
|
266
311
|
var onFetch = (0, react_1.useCallback)(function (params) {
|
|
267
312
|
if (params === void 0) { params = {}; }
|
|
268
|
-
dispatch((0,
|
|
313
|
+
dispatch((0, list_3.listFetch)(config.listId, params));
|
|
269
314
|
}, [config.listId, dispatch]);
|
|
270
315
|
var onSort = (0, react_1.useCallback)(function (value) {
|
|
271
316
|
dispatch((0, form_1.formChange)(formId, sort.attribute, value));
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React, { ChangeEvent } from 'react';
|
|
2
|
+
import { IInputParams } from '../ui/form/Field/fieldWrapper';
|
|
3
|
+
export default function useSaveCursorPosition(inputParams: IInputParams): {
|
|
4
|
+
inputRef: React.MutableRefObject<any>;
|
|
5
|
+
onChange: (event: ChangeEvent<HTMLInputElement>, value?: any) => void;
|
|
6
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
exports.__esModule = true;
|
|
6
|
+
/* eslint-disable no-return-assign */
|
|
7
|
+
/* eslint-disable no-unused-expressions */
|
|
8
|
+
var react_1 = __importDefault(require("react"));
|
|
9
|
+
function useSaveCursorPosition(inputParams) {
|
|
10
|
+
var _a = react_1["default"].useState(null), cursor = _a[0], setCursor = _a[1];
|
|
11
|
+
var inputRef = react_1["default"].useRef(null);
|
|
12
|
+
react_1["default"].useEffect(function () {
|
|
13
|
+
var inputElement = inputRef.current;
|
|
14
|
+
if (inputElement) {
|
|
15
|
+
inputElement.setSelectionRange(cursor, cursor);
|
|
16
|
+
}
|
|
17
|
+
}, [cursor, inputParams.value]);
|
|
18
|
+
var onChange = react_1["default"].useCallback(function (event, value) {
|
|
19
|
+
var _a, _b;
|
|
20
|
+
if (value === void 0) { value = null; }
|
|
21
|
+
setCursor((_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.selectionStart);
|
|
22
|
+
inputParams.onChange(value || ((_b = event.target) === null || _b === void 0 ? void 0 : _b.value));
|
|
23
|
+
}, [inputParams]);
|
|
24
|
+
return {
|
|
25
|
+
inputRef: inputRef,
|
|
26
|
+
onChange: onChange
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
exports["default"] = useSaveCursorPosition;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { PropsWithChildren } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import { ILocaleComponent } from '
|
|
5
|
-
import {
|
|
3
|
+
import { IClientStorageComponent } from '../components/ClientStorageComponent';
|
|
4
|
+
import { ILocaleComponent } from '../components/LocaleComponent';
|
|
5
|
+
import { IUiApplicationComponent } from '../components/UiComponent';
|
|
6
6
|
import { IResourceComponent } from '../components/ResourceComponent';
|
|
7
7
|
declare global {
|
|
8
8
|
interface Window {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { ILinkProps } from '../../nav/Link/Link';
|
|
3
|
+
import { IButtonProps } from '../../form/Button/Button';
|
|
4
4
|
import { IAvatarProps } from '../Avatar/Avatar';
|
|
5
5
|
import { IMenuProps } from '../Menu/Menu';
|
|
6
6
|
export interface ICardHeader {
|
|
@@ -72,6 +72,11 @@ export interface IFieldWrapperInputProps {
|
|
|
72
72
|
isRenderWithoutFieldLayout?: boolean;
|
|
73
73
|
[key: string]: any;
|
|
74
74
|
}
|
|
75
|
+
export interface IInputParams {
|
|
76
|
+
name?: string;
|
|
77
|
+
value?: any;
|
|
78
|
+
onChange: (value: any) => void;
|
|
79
|
+
}
|
|
75
80
|
export interface IFieldWrapperOutputProps {
|
|
76
81
|
/**
|
|
77
82
|
* Id формы
|
|
@@ -88,11 +93,7 @@ export interface IFieldWrapperOutputProps {
|
|
|
88
93
|
/**
|
|
89
94
|
* Параметры для input элемента
|
|
90
95
|
*/
|
|
91
|
-
input?:
|
|
92
|
-
name?: string;
|
|
93
|
-
value?: any;
|
|
94
|
-
onChange: (value: any) => void;
|
|
95
|
-
};
|
|
96
|
+
input?: IInputParams;
|
|
96
97
|
}
|
|
97
98
|
interface IFieldWrapperOptions {
|
|
98
99
|
label?: boolean;
|
|
@@ -85,7 +85,7 @@ export interface IInputFieldViewProps extends IInputFieldProps, IFieldWrapperOut
|
|
|
85
85
|
inputProps: {
|
|
86
86
|
type: string;
|
|
87
87
|
name: string;
|
|
88
|
-
|
|
88
|
+
onInput: (event: any, value?: string) => void;
|
|
89
89
|
value: string | number;
|
|
90
90
|
placeholder: string;
|
|
91
91
|
disabled: boolean;
|
|
@@ -94,7 +94,6 @@ export interface IInputFieldViewProps extends IInputFieldProps, IFieldWrapperOut
|
|
|
94
94
|
onFocus?: (e: Event | React.FocusEvent) => void;
|
|
95
95
|
onBlur?: (e: Event | React.FocusEvent) => void;
|
|
96
96
|
onMouseDown?: (e: Event | React.MouseEvent) => void;
|
|
97
|
-
maskedInputRef?: React.RefCallback<HTMLElement>;
|
|
98
97
|
defaultValue?: string;
|
|
99
98
|
}
|
|
100
99
|
declare const _default: import("../Field/fieldWrapper").FieldWrapperComponent<IInputFieldProps>;
|
|
@@ -87,17 +87,22 @@ function InputField(props) {
|
|
|
87
87
|
var maskedInputRef = (0, react_2.useMaskito)({
|
|
88
88
|
options: props.maskOptions
|
|
89
89
|
});
|
|
90
|
+
var _a = (0, hooks_1.useSaveCursorPosition)(props.input), inputRef = _a.inputRef, onChange = _a.onChange;
|
|
91
|
+
React.useEffect(function () {
|
|
92
|
+
if (inputRef.current) {
|
|
93
|
+
maskedInputRef(inputRef.current);
|
|
94
|
+
}
|
|
95
|
+
}, [inputRef, maskedInputRef]);
|
|
90
96
|
var onClear = React.useCallback(function () { return props.input.onChange(''); }, [props.input]);
|
|
91
|
-
props.onClear = onClear;
|
|
92
97
|
var inputProps = (0, react_1.useMemo)(function () {
|
|
93
98
|
var _a;
|
|
94
|
-
return (__assign({ type: props.type, name: props.input.name,
|
|
95
|
-
}, [props.disabled, props.input, props.inputProps, props.placeholder, props.type]);
|
|
99
|
+
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));
|
|
100
|
+
}, [onChange, props.disabled, props.input.name, props.input.value, props.inputProps, props.placeholder, props.type]);
|
|
96
101
|
// No render for hidden input
|
|
97
102
|
if (props.type === 'hidden') {
|
|
98
103
|
return null;
|
|
99
104
|
}
|
|
100
|
-
return components.ui.renderView(props.view || 'form.InputFieldView', __assign(__assign(__assign({}, props), props.viewProps), { inputProps: inputProps,
|
|
105
|
+
return components.ui.renderView(props.view || 'form.InputFieldView', __assign(__assign(__assign({}, props), props.viewProps), { inputProps: inputProps, inputRef: inputRef, onClear: onClear }));
|
|
101
106
|
}
|
|
102
107
|
InputField.defaultProps = {
|
|
103
108
|
type: 'text',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChangeEvent } from 'react';
|
|
1
|
+
import React, { ChangeEvent } from 'react';
|
|
2
2
|
import { IBaseFieldProps } from '../InputField/InputField';
|
|
3
3
|
import { IFieldWrapperOutputProps } from '../Field/fieldWrapper';
|
|
4
4
|
/**
|
|
@@ -21,7 +21,7 @@ export interface INumberFieldProps extends IBaseFieldProps {
|
|
|
21
21
|
* Шаг увеличения/уменьшения значения
|
|
22
22
|
* @example 5
|
|
23
23
|
*/
|
|
24
|
-
step?:
|
|
24
|
+
step?: number;
|
|
25
25
|
}
|
|
26
26
|
export interface INumberFieldViewProps extends INumberFieldProps, IFieldWrapperOutputProps {
|
|
27
27
|
inputProps: {
|
|
@@ -35,6 +35,10 @@ export interface INumberFieldViewProps extends INumberFieldProps, IFieldWrapperO
|
|
|
35
35
|
max: number;
|
|
36
36
|
step: string | number;
|
|
37
37
|
};
|
|
38
|
+
inputRef: React.MutableRefObject<any>;
|
|
39
|
+
onStepUp: VoidFunction;
|
|
40
|
+
onStepDown: VoidFunction;
|
|
41
|
+
onKeyDown: VoidFunction;
|
|
38
42
|
}
|
|
39
43
|
declare const _default: import("../Field/fieldWrapper").FieldWrapperComponent<INumberFieldProps>;
|
|
40
44
|
export default _default;
|
|
@@ -14,16 +14,44 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
15
|
};
|
|
16
16
|
exports.__esModule = true;
|
|
17
|
+
/* eslint-disable max-len */
|
|
17
18
|
var react_1 = require("react");
|
|
18
19
|
var hooks_1 = require("../../../hooks");
|
|
19
20
|
var fieldWrapper_1 = __importDefault(require("../Field/fieldWrapper"));
|
|
21
|
+
var useInputTypeNumber_1 = __importDefault(require("./hooks/useInputTypeNumber"));
|
|
22
|
+
var DEFAULT_STEP = 1;
|
|
20
23
|
function NumberField(props) {
|
|
21
24
|
var components = (0, hooks_1.useComponents)();
|
|
22
|
-
|
|
25
|
+
var _a = (0, hooks_1.useSaveCursorPosition)(props.input), currentInputRef = _a.inputRef, onChange = _a.onChange;
|
|
26
|
+
var onInputChange = (0, useInputTypeNumber_1["default"])(currentInputRef, {
|
|
27
|
+
max: props.max,
|
|
28
|
+
min: props.min,
|
|
29
|
+
value: props.input.value
|
|
30
|
+
}, onChange).onInputChange;
|
|
31
|
+
var onStep = (0, react_1.useCallback)(function (isIncrement) {
|
|
23
32
|
var _a;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
var step = props.step || DEFAULT_STEP;
|
|
34
|
+
onChange(null, String(Number((_a = currentInputRef === null || currentInputRef === void 0 ? void 0 : currentInputRef.current) === null || _a === void 0 ? void 0 : _a.value) + (isIncrement ? step : -step)));
|
|
35
|
+
}, [currentInputRef, onChange, props.step]);
|
|
36
|
+
var onStepUp = (0, react_1.useCallback)(function () {
|
|
37
|
+
onStep(true);
|
|
38
|
+
}, [onStep]);
|
|
39
|
+
var onStepDown = (0, react_1.useCallback)(function () {
|
|
40
|
+
onStep(false);
|
|
41
|
+
}, [onStep]);
|
|
42
|
+
var onKeyDown = (0, react_1.useCallback)(function (event) {
|
|
43
|
+
if (event.key === 'ArrowUp') {
|
|
44
|
+
onStepUp();
|
|
45
|
+
}
|
|
46
|
+
else if (event.key === 'ArrowDown') {
|
|
47
|
+
onStepDown();
|
|
48
|
+
}
|
|
49
|
+
}, [onStepDown, onStepUp]);
|
|
50
|
+
var inputProps = (0, react_1.useMemo)(function () {
|
|
51
|
+
var _a;
|
|
52
|
+
return (__assign({ name: props.input.name, value: (_a = props.input.value) !== null && _a !== void 0 ? _a : '', onChange: onInputChange, type: 'text', min: props.min, max: props.max, step: props.step, placeholder: props.placeholder, disabled: props.disabled, autoComplete: 'off', onKeyDown: onKeyDown }, props.inputProps));
|
|
53
|
+
}, [props.input.name, props.input.value, props.min, props.max, props.step, props.placeholder, props.disabled, props.inputProps, onInputChange, onKeyDown]);
|
|
54
|
+
return components.ui.renderView(props.view || 'form.NumberFieldView', __assign(__assign({}, props), { inputProps: inputProps, onStepUp: onStepUp, onStepDown: onStepDown, inputRef: currentInputRef }));
|
|
27
55
|
}
|
|
28
56
|
NumberField.defaultProps = {
|
|
29
57
|
disabled: false,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface IInputTypeNumberProps {
|
|
3
|
+
max: any;
|
|
4
|
+
min: any;
|
|
5
|
+
value: any;
|
|
6
|
+
}
|
|
7
|
+
declare const useInputTypeNumber: (currentInputRef: React.MutableRefObject<HTMLInputElement>, inputTypeNumberProps: IInputTypeNumberProps, onChange: (event: React.ChangeEvent<HTMLInputElement>, value?: any) => void) => {
|
|
8
|
+
onInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
9
|
+
};
|
|
10
|
+
export default useInputTypeNumber;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
exports.__esModule = true;
|
|
6
|
+
var react_1 = __importDefault(require("react"));
|
|
7
|
+
var useInputTypeNumber = function (currentInputRef, inputTypeNumberProps, onChange) {
|
|
8
|
+
var setValidity = react_1["default"].useCallback(function (message) {
|
|
9
|
+
var _a;
|
|
10
|
+
(_a = currentInputRef.current) === null || _a === void 0 ? void 0 : _a.setCustomValidity(message);
|
|
11
|
+
}, [currentInputRef]);
|
|
12
|
+
var checkIsValueFalsy = function (value) { return value === '' || value === null || value === undefined; };
|
|
13
|
+
react_1["default"].useEffect(function () {
|
|
14
|
+
var defaultValidity = 'The number is not included in the range';
|
|
15
|
+
// eslint-disable-next-line no-unused-expressions
|
|
16
|
+
inputTypeNumberProps.value > inputTypeNumberProps.max
|
|
17
|
+
|| inputTypeNumberProps.value < inputTypeNumberProps.min
|
|
18
|
+
|| checkIsValueFalsy(inputTypeNumberProps.value)
|
|
19
|
+
? setValidity(__(defaultValidity) + " ".concat(inputTypeNumberProps.min, " \u2014 ").concat(inputTypeNumberProps.max))
|
|
20
|
+
: setValidity('');
|
|
21
|
+
}, [currentInputRef, inputTypeNumberProps.value, inputTypeNumberProps.max, inputTypeNumberProps.min, setValidity]);
|
|
22
|
+
var isValueNumeric = function (value) {
|
|
23
|
+
if (checkIsValueFalsy(value)) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Подходят как отрицательные так и положительные числа
|
|
28
|
+
* @example -1
|
|
29
|
+
* @example 1
|
|
30
|
+
*/
|
|
31
|
+
var numericRegex = /^-?\d*\.?\d+$/;
|
|
32
|
+
return numericRegex.test(value);
|
|
33
|
+
};
|
|
34
|
+
var onInputChange = function (event) {
|
|
35
|
+
var _a;
|
|
36
|
+
var value = (_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.value;
|
|
37
|
+
if (isValueNumeric(value)) {
|
|
38
|
+
onChange(event);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
onInputChange: onInputChange
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
exports["default"] = useInputTypeNumber;
|
|
@@ -55,14 +55,15 @@ exports.checkPassword = checkPassword;
|
|
|
55
55
|
function PasswordField(props) {
|
|
56
56
|
var _a = (0, react_1.useState)(InputType.PASSWORD), type = _a[0], setType = _a[1];
|
|
57
57
|
var components = (0, hooks_1.useComponents)();
|
|
58
|
+
var _b = (0, hooks_1.useSaveCursorPosition)(props.input), inputRef = _b.inputRef, onChange = _b.onChange;
|
|
58
59
|
var onClear = (0, react_1.useCallback)(function () { return props.input.onChange(''); }, [props.input]);
|
|
59
60
|
var onShowButtonClick = (0, react_1.useCallback)(function () {
|
|
60
61
|
type === InputType.PASSWORD ? setType(InputType.TEXT) : setType(InputType.PASSWORD);
|
|
61
62
|
}, [type]);
|
|
62
63
|
var inputProps = (0, react_1.useMemo)(function () {
|
|
63
64
|
var _a;
|
|
64
|
-
return (__assign({ name: props.input.name, defaultValue: (_a = props.input.value) !== null && _a !== void 0 ? _a : '', onChange:
|
|
65
|
-
}, [props.disabled, props.input, props.inputProps, props.placeholder, type]);
|
|
65
|
+
return (__assign({ name: props.input.name, defaultValue: (_a = props.input.value) !== null && _a !== void 0 ? _a : '', onChange: onChange, type: type, placeholder: props.placeholder, disabled: props.disabled, ref: inputRef }, props.inputProps));
|
|
66
|
+
}, [inputRef, onChange, props.disabled, props.input.name, props.input.value, props.inputProps, props.placeholder, type]);
|
|
66
67
|
return components.ui.renderView(props.view || 'form.PasswordFieldView' || 'form.InputFieldView', __assign(__assign({}, props), { inputProps: inputProps, securityLevel: props.showSecurityBar ? (0, exports.checkPassword)(props.input.value) : null, onClear: onClear, onShowButtonClick: onShowButtonClick }));
|
|
67
68
|
}
|
|
68
69
|
PasswordField.defaultProps = {
|
|
@@ -20,6 +20,7 @@ var fieldWrapper_1 = __importDefault(require("../Field/fieldWrapper"));
|
|
|
20
20
|
function TextField(props) {
|
|
21
21
|
// const dispatch = useDispatch();
|
|
22
22
|
var components = (0, hooks_1.useComponents)();
|
|
23
|
+
var _a = (0, hooks_1.useSaveCursorPosition)(props.input), inputRef = _a.inputRef, onChange = _a.onChange;
|
|
23
24
|
var onKeyUp = (0, react_1.useCallback)(function (e) {
|
|
24
25
|
if (props.submitOnEnter
|
|
25
26
|
&& props.formId
|
|
@@ -30,12 +31,12 @@ function TextField(props) {
|
|
|
30
31
|
// dispatch(submit(props.formId));
|
|
31
32
|
}
|
|
32
33
|
}, [props.formId, props.submitOnEnter]);
|
|
33
|
-
var
|
|
34
|
+
var handleChange = (0, react_1.useCallback)(function (event) { return onChange(event, event.target ? event.target.value : event.nativeEvent.text); }, [onChange]);
|
|
34
35
|
var onClear = (0, react_1.useCallback)(function () { return props.input.onChange(''); }, [props.input]);
|
|
35
36
|
var inputProps = (0, react_1.useMemo)(function () {
|
|
36
37
|
var _a;
|
|
37
|
-
return (__assign({ name: props.input.name,
|
|
38
|
-
}, [
|
|
38
|
+
return (__assign({ name: props.input.name, value: (_a = props.input.value) !== null && _a !== void 0 ? _a : '', onChange: handleChange, onKeyUp: onKeyUp, placeholder: props.placeholder, disabled: props.disabled, ref: inputRef }, props.inputProps));
|
|
39
|
+
}, [props.input.name, props.input.value, props.placeholder, props.disabled, props.inputProps, handleChange, onKeyUp, inputRef]);
|
|
39
40
|
return components.ui.renderView(props.view || 'form.TextFieldView', __assign(__assign({}, props), { inputProps: inputProps, onClear: onClear }));
|
|
40
41
|
}
|
|
41
42
|
TextField.defaultProps = {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { IButtonProps } from '../../form/Button/Button';
|
|
3
|
+
import { IAvatarProps } from '../../content/Avatar/Avatar';
|
|
4
|
+
import { ILinkProps } from '../../nav/Link/Link';
|
|
5
|
+
import { IModalProps } from '../../modal/Modal/Modal';
|
|
6
|
+
import { IMenuProps } from '../../content/Menu/Menu';
|
|
7
7
|
import { INavProps } from '../../nav/Nav/Nav';
|
|
8
8
|
/**
|
|
9
9
|
* IHeaderProps
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { IMenuProps } from '
|
|
3
|
-
import { INavItem } from '
|
|
4
|
-
import { IIconProps } from '
|
|
2
|
+
import { IMenuProps } from '../../content/Menu/Menu';
|
|
3
|
+
import { INavItem } from '../../nav/Nav/Nav';
|
|
4
|
+
import { IIconProps } from '../../content/Icon/Icon';
|
|
5
5
|
export interface ISidebarItem extends INavItem {
|
|
6
6
|
/**
|
|
7
7
|
* Наличие верней границы у элемента
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import {
|
|
2
|
+
import { PositionType } from '../../../hooks/useAbsolutePositioning';
|
|
3
3
|
export interface ITooltipArrowPosition {
|
|
4
4
|
/**
|
|
5
5
|
* Позиция стрелки слева
|
|
@@ -50,7 +50,7 @@ export interface ITooltipProps {
|
|
|
50
50
|
/**
|
|
51
51
|
* Позиционирование подсказки, относительно целевого элемента
|
|
52
52
|
*/
|
|
53
|
-
position?:
|
|
53
|
+
position?: PositionType;
|
|
54
54
|
/**
|
|
55
55
|
* Показывать ли подсказку сразу после рендера страницы
|
|
56
56
|
* @example true
|
|
@@ -84,7 +84,7 @@ export interface ITooltipProps {
|
|
|
84
84
|
export interface ITooltipViewProps extends ITooltipProps {
|
|
85
85
|
isTooltipVisible: boolean;
|
|
86
86
|
content: string | any;
|
|
87
|
-
position:
|
|
87
|
+
position: PositionType;
|
|
88
88
|
style: ITooltipStylePosition;
|
|
89
89
|
}
|
|
90
90
|
declare function Tooltip(props: ITooltipProps): JSX.Element;
|
package/ui/list/Grid/Grid.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { ILinkProps } from '
|
|
2
|
+
import { ILinkProps } from '../../nav/Link/Link';
|
|
3
3
|
import { IListConfig, ListControlPosition } from '../../../hooks/useList';
|
|
4
4
|
import { IControlItem } from '../../nav/Controls/Controls';
|
|
5
5
|
export interface IColumnViewProps extends IGridColumn {
|
package/ui/list/Grid/Grid.js
CHANGED
|
@@ -69,7 +69,8 @@ function Grid(props) {
|
|
|
69
69
|
items: props.items,
|
|
70
70
|
initialItems: props.initialItems,
|
|
71
71
|
initialTotal: props.initialTotal,
|
|
72
|
-
autoFetchOnFormChanges: props.autoFetchOnFormChanges
|
|
72
|
+
autoFetchOnFormChanges: props.autoFetchOnFormChanges,
|
|
73
|
+
hasTreeItems: props.hasTreeItems
|
|
73
74
|
}), 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;
|
|
74
75
|
var renderLabel = (0, react_1.useCallback)(function (column) {
|
|
75
76
|
if (column.headerView) {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { IColumnViewProps, IGridColumn, IGridProps } from '../Grid/Grid';
|
|
3
|
+
export interface ITreeColumnViewProps extends IColumnViewProps {
|
|
4
|
+
item: {
|
|
5
|
+
onTreeItemClick?: (uniqueId: string, item: {
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}) => void;
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface ITreeTableItem {
|
|
12
|
+
/**
|
|
13
|
+
* Идентификатор узла
|
|
14
|
+
*/
|
|
15
|
+
id?: string | number;
|
|
16
|
+
/**
|
|
17
|
+
* Вложенные элементы
|
|
18
|
+
* @example items: [{id: 3, name: 'Ivan'}]
|
|
19
|
+
*/
|
|
20
|
+
items?: any[];
|
|
21
|
+
/**
|
|
22
|
+
* Уникальный идентификатор,
|
|
23
|
+
* используется для сохранения состояния открыта или закрыта ячейка
|
|
24
|
+
*/
|
|
25
|
+
uniqueId?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ITreeTableProps extends Omit<IGridProps, 'items'> {
|
|
28
|
+
/**
|
|
29
|
+
* Элементы коллекции
|
|
30
|
+
* @example [{id: 1, name: 'Jane'}, {id: 2, name: 'John', items: [...]}]
|
|
31
|
+
*/
|
|
32
|
+
items?: ITreeTableItem[];
|
|
33
|
+
}
|
|
34
|
+
export declare const addTreeColumnFieldsToFirstColumn: (columns: IGridColumn[]) => IGridColumn[];
|
|
35
|
+
export default function TreeTable(props: ITreeTableProps): JSX.Element;
|
|
@@ -0,0 +1,69 @@
|
|
|
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 __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 __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
|
+
};
|
|
45
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
46
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
47
|
+
};
|
|
48
|
+
exports.__esModule = true;
|
|
49
|
+
exports.addTreeColumnFieldsToFirstColumn = void 0;
|
|
50
|
+
var React = __importStar(require("react"));
|
|
51
|
+
var react_1 = require("react");
|
|
52
|
+
var merge_1 = __importDefault(require("lodash-es/merge"));
|
|
53
|
+
var Grid_1 = __importDefault(require("../Grid"));
|
|
54
|
+
var TREE_COLUMN_VIEW_FIELDS = {
|
|
55
|
+
valueView: 'TreeColumnView',
|
|
56
|
+
headerClassName: 'TreeColumnHeader'
|
|
57
|
+
};
|
|
58
|
+
var addTreeColumnFieldsToFirstColumn = function (columns) {
|
|
59
|
+
var newColumns = __spreadArray([], columns, true);
|
|
60
|
+
// Add tree view to the first column
|
|
61
|
+
(0, merge_1["default"])(newColumns[0], TREE_COLUMN_VIEW_FIELDS);
|
|
62
|
+
return newColumns;
|
|
63
|
+
};
|
|
64
|
+
exports.addTreeColumnFieldsToFirstColumn = addTreeColumnFieldsToFirstColumn;
|
|
65
|
+
function TreeTable(props) {
|
|
66
|
+
var columns = (0, react_1.useMemo)(function () { return (0, exports.addTreeColumnFieldsToFirstColumn)(props.columns); }, [props.columns]);
|
|
67
|
+
return (React.createElement(Grid_1["default"], __assign({}, props, { columns: columns, items: props.items, itemsIndexing: false, hasTreeItems: true })));
|
|
68
|
+
}
|
|
69
|
+
exports["default"] = TreeTable;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
exports.__esModule = true;
|
|
6
|
+
var TreeTable_1 = __importDefault(require("./TreeTable"));
|
|
7
|
+
exports["default"] = TreeTable_1["default"];
|
package/ui/nav/Tree/Tree.js
CHANGED
|
@@ -43,9 +43,9 @@ var omit_1 = __importDefault(require("lodash-es/omit"));
|
|
|
43
43
|
var isEqual_1 = __importDefault(require("lodash-es/isEqual"));
|
|
44
44
|
var keys_1 = __importDefault(require("lodash-es/keys"));
|
|
45
45
|
var react_1 = require("react");
|
|
46
|
+
var list_1 = require("../../../utils/list");
|
|
46
47
|
var hooks_1 = require("../../../hooks");
|
|
47
48
|
var router_1 = require("../../../reducers/router");
|
|
48
|
-
var resolveId = function (item, index, parentId) { return (parentId ? parentId + '.' : '') + String(item.id || index); };
|
|
49
49
|
function Tree(props) {
|
|
50
50
|
var components = (0, hooks_1.useComponents)();
|
|
51
51
|
var STORAGE_KEY_PREFIX = 'tree_';
|
|
@@ -90,7 +90,7 @@ function Tree(props) {
|
|
|
90
90
|
return null;
|
|
91
91
|
}
|
|
92
92
|
(sourceItems || []).forEach(function (item, index) {
|
|
93
|
-
var uniqId =
|
|
93
|
+
var uniqId = (0, list_1.getTreeItemUniqId)(item, index, parentId);
|
|
94
94
|
if (!foundItem && (item.id === itemId || uniqId === itemId)) {
|
|
95
95
|
foundItem = __assign(__assign({}, item), { uniqId: uniqId, level: level });
|
|
96
96
|
}
|
|
@@ -105,7 +105,7 @@ function Tree(props) {
|
|
|
105
105
|
if (level === void 0) { level = 1; }
|
|
106
106
|
var opened = {};
|
|
107
107
|
(sourceItems || []).forEach(function (item, index) {
|
|
108
|
-
var uniqId =
|
|
108
|
+
var uniqId = (0, list_1.getTreeItemUniqId)(item, index, parentId);
|
|
109
109
|
if (props.autoOpenLevels >= level) {
|
|
110
110
|
opened[uniqId] = true;
|
|
111
111
|
}
|
|
@@ -159,7 +159,7 @@ function Tree(props) {
|
|
|
159
159
|
return [];
|
|
160
160
|
}
|
|
161
161
|
(sourceItems || []).forEach(function (item, index) {
|
|
162
|
-
var uniqId =
|
|
162
|
+
var uniqId = (0, list_1.getTreeItemUniqId)(item, index, parentId);
|
|
163
163
|
var isOpened = props.alwaysOpened || !!openedItems[uniqId];
|
|
164
164
|
var hasItems = item[props.itemsKey] && item[props.itemsKey].length > 0;
|
|
165
165
|
if (props.level && (level === props.level - 1)) {
|
package/utils/list.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getTreeItemUniqId: (item: any, index: any, parentId: any) => string;
|
package/utils/list.js
ADDED