@steroidsjs/core 3.0.37 → 3.0.39

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/actions/list.d.ts CHANGED
@@ -41,6 +41,14 @@ export interface IList {
41
41
  * Логическое значение, указывающее, является ли список удаленным или нет.
42
42
  */
43
43
  isRemote?: boolean;
44
+ /**
45
+ * Логическое значение, указывающее, можно ли загрузить еще элементы для списка при скролле.
46
+ */
47
+ hasInfiniteScroll?: boolean;
48
+ /**
49
+ * Значение страницы по умолчанию.
50
+ */
51
+ defaultPageValue?: number;
44
52
  /**
45
53
  * Логическое значение, указывающее, можно ли загрузить еще элементы для списка.
46
54
  */
package/actions/list.js CHANGED
@@ -200,6 +200,7 @@ var listFetch = function (listId, query) {
200
200
  }
201
201
  // Send request
202
202
  toDispatch.push(Promise.resolve(onFetch(list, formValues, components)).then(function (data) {
203
+ var _a;
203
204
  // Skip on empty
204
205
  if (!data) {
205
206
  return [];
@@ -215,16 +216,24 @@ var listFetch = function (listId, query) {
215
216
  meta: null
216
217
  };
217
218
  }
219
+ var items = data.items || [];
220
+ var total = data.total || items.length || null;
221
+ var page = formValues[list.pageAttribute];
222
+ var pageSize = formValues[list.pageSizeAttribute];
223
+ var totalPages = Math.ceil(((list === null || list === void 0 ? void 0 : list.total) || 0) / (pageSize || 1));
224
+ var hasNextPage = (_a = data === null || data === void 0 ? void 0 : data.hasNextPage) !== null && _a !== void 0 ? _a : (page !== totalPages || null);
218
225
  return [
219
226
  // Check has errors
220
227
  (0, form_2.formSetErrors)(list.formId, data.errors || null),
221
228
  {
222
- items: data.items || [],
223
- total: data.total || null,
229
+ items: items,
230
+ total: total,
231
+ hasNextPage: hasNextPage,
224
232
  meta: data.meta || null,
225
- page: formValues[list.pageAttribute],
226
- pageSize: formValues[list.pageSizeAttribute],
233
+ page: page,
234
+ pageSize: pageSize,
227
235
  listId: listId,
236
+ defaultPageValue: list.defaultPageValue,
228
237
  type: exports.LIST_AFTER_FETCH
229
238
  },
230
239
  ];
@@ -25,6 +25,14 @@
25
25
  "type": "string",
26
26
  "example": null
27
27
  },
28
+ {
29
+ "name": "defaultPageValue",
30
+ "decorators": [],
31
+ "description": "Значение страницы по умолчанию.",
32
+ "required": false,
33
+ "type": "number",
34
+ "example": null
35
+ },
28
36
  {
29
37
  "name": "formId",
30
38
  "decorators": [],
@@ -33,6 +41,14 @@
33
41
  "type": "string",
34
42
  "example": null
35
43
  },
44
+ {
45
+ "name": "hasInfiniteScroll",
46
+ "decorators": [],
47
+ "description": "Логическое значение, указывающее, можно ли загрузить еще элементы для списка при скролле.",
48
+ "required": false,
49
+ "type": "boolean",
50
+ "example": null
51
+ },
36
52
  {
37
53
  "name": "isFetched",
38
54
  "decorators": [],
@@ -3845,6 +3861,14 @@
3845
3861
  "type": "string | boolean | IEmptyProps",
3846
3862
  "example": "{\n text: 'Записи не найдены'\n}"
3847
3863
  },
3864
+ {
3865
+ "name": "infiniteScroll",
3866
+ "decorators": [],
3867
+ "description": "Подключение бесконечного скролла",
3868
+ "required": false,
3869
+ "type": "boolean | IInfiniteScrollProps",
3870
+ "example": "{\n enable: true\n}"
3871
+ },
3848
3872
  {
3849
3873
  "name": "initialItems",
3850
3874
  "decorators": [],
@@ -4143,6 +4167,15 @@
4143
4167
  "example": null,
4144
4168
  "parameters": []
4145
4169
  },
4170
+ {
4171
+ "name": "renderInfiniteScroll",
4172
+ "decorators": [],
4173
+ "description": "",
4174
+ "required": false,
4175
+ "type": "any",
4176
+ "example": null,
4177
+ "parameters": []
4178
+ },
4146
4179
  {
4147
4180
  "name": "renderLayoutNames",
4148
4181
  "decorators": [],
@@ -13866,6 +13899,24 @@
13866
13899
  "example": null
13867
13900
  }
13868
13901
  ]
13902
+ },
13903
+ {
13904
+ "name": "onClear",
13905
+ "decorators": [],
13906
+ "description": "Callback-функция, которая вызывается при очистке input",
13907
+ "required": false,
13908
+ "type": "void",
13909
+ "example": null,
13910
+ "parameters": [
13911
+ {
13912
+ "name": "value",
13913
+ "decorators": [],
13914
+ "description": "",
13915
+ "required": true,
13916
+ "type": "string",
13917
+ "example": null
13918
+ }
13919
+ ]
13869
13920
  }
13870
13921
  ]
13871
13922
  },
@@ -19853,6 +19904,24 @@
19853
19904
  "example": null
19854
19905
  }
19855
19906
  ]
19907
+ },
19908
+ {
19909
+ "name": "onClear",
19910
+ "decorators": [],
19911
+ "description": "Callback-функция, которая вызывается при очистке input",
19912
+ "required": false,
19913
+ "type": "void",
19914
+ "example": null,
19915
+ "parameters": [
19916
+ {
19917
+ "name": "value",
19918
+ "decorators": [],
19919
+ "description": "",
19920
+ "required": true,
19921
+ "type": "string",
19922
+ "example": null
19923
+ }
19924
+ ]
19856
19925
  }
19857
19926
  ]
19858
19927
  },
@@ -24599,6 +24668,24 @@
24599
24668
  "example": null
24600
24669
  }
24601
24670
  ]
24671
+ },
24672
+ {
24673
+ "name": "onClear",
24674
+ "decorators": [],
24675
+ "description": "Callback-функция, которая вызывается при очистке input",
24676
+ "required": false,
24677
+ "type": "void",
24678
+ "example": null,
24679
+ "parameters": [
24680
+ {
24681
+ "name": "value",
24682
+ "decorators": [],
24683
+ "description": "",
24684
+ "required": true,
24685
+ "type": "string",
24686
+ "example": null
24687
+ }
24688
+ ]
24602
24689
  }
24603
24690
  ]
24604
24691
  },
@@ -24884,6 +24971,24 @@
24884
24971
  "example": null
24885
24972
  }
24886
24973
  ]
24974
+ },
24975
+ {
24976
+ "name": "onClear",
24977
+ "decorators": [],
24978
+ "description": "Callback-функция, которая вызывается при очистке input",
24979
+ "required": false,
24980
+ "type": "void",
24981
+ "example": null,
24982
+ "parameters": [
24983
+ {
24984
+ "name": "value",
24985
+ "decorators": [],
24986
+ "description": "",
24987
+ "required": true,
24988
+ "type": "string",
24989
+ "example": null
24990
+ }
24991
+ ]
24887
24992
  }
24888
24993
  ]
24889
24994
  },
@@ -25196,7 +25301,7 @@
25196
25301
  {
25197
25302
  "name": "onClear",
25198
25303
  "decorators": [],
25199
- "description": "",
25304
+ "description": "Callback-функция, которая вызывается при очистке input",
25200
25305
  "required": false,
25201
25306
  "type": "void",
25202
25307
  "example": null,
@@ -25793,6 +25898,24 @@
25793
25898
  "example": null
25794
25899
  }
25795
25900
  ]
25901
+ },
25902
+ {
25903
+ "name": "onClear",
25904
+ "decorators": [],
25905
+ "description": "Callback-функция, которая вызывается при очистке input",
25906
+ "required": false,
25907
+ "type": "void",
25908
+ "example": null,
25909
+ "parameters": [
25910
+ {
25911
+ "name": "value",
25912
+ "decorators": [],
25913
+ "description": "",
25914
+ "required": true,
25915
+ "type": "string",
25916
+ "example": null
25917
+ }
25918
+ ]
25796
25919
  }
25797
25920
  ]
25798
25921
  },
@@ -26091,6 +26214,24 @@
26091
26214
  "example": null
26092
26215
  }
26093
26216
  ]
26217
+ },
26218
+ {
26219
+ "name": "onClear",
26220
+ "decorators": [],
26221
+ "description": "Callback-функция, которая вызывается при очистке input",
26222
+ "required": false,
26223
+ "type": "void",
26224
+ "example": null,
26225
+ "parameters": [
26226
+ {
26227
+ "name": "value",
26228
+ "decorators": [],
26229
+ "description": "",
26230
+ "required": true,
26231
+ "type": "string",
26232
+ "example": null
26233
+ }
26234
+ ]
26094
26235
  }
26095
26236
  ]
26096
26237
  },
@@ -26331,6 +26472,24 @@
26331
26472
  "example": null
26332
26473
  }
26333
26474
  ]
26475
+ },
26476
+ {
26477
+ "name": "onClear",
26478
+ "decorators": [],
26479
+ "description": "Callback-функция, которая вызывается при очистке input",
26480
+ "required": false,
26481
+ "type": "void",
26482
+ "example": null,
26483
+ "parameters": [
26484
+ {
26485
+ "name": "value",
26486
+ "decorators": [],
26487
+ "description": "",
26488
+ "required": true,
26489
+ "type": "string",
26490
+ "example": null
26491
+ }
26492
+ ]
26334
26493
  }
26335
26494
  ]
26336
26495
  },
@@ -26585,7 +26744,7 @@
26585
26744
  {
26586
26745
  "name": "onClear",
26587
26746
  "decorators": [],
26588
- "description": "",
26747
+ "description": "Callback-функция, которая вызывается при очистке input",
26589
26748
  "required": false,
26590
26749
  "type": "void",
26591
26750
  "example": null,
@@ -29937,6 +30096,24 @@
29937
30096
  "example": null
29938
30097
  }
29939
30098
  ]
30099
+ },
30100
+ {
30101
+ "name": "onClear",
30102
+ "decorators": [],
30103
+ "description": "Callback-функция, которая вызывается при очистке input",
30104
+ "required": false,
30105
+ "type": "void",
30106
+ "example": null,
30107
+ "parameters": [
30108
+ {
30109
+ "name": "value",
30110
+ "decorators": [],
30111
+ "description": "",
30112
+ "required": true,
30113
+ "type": "string",
30114
+ "example": null
30115
+ }
30116
+ ]
29940
30117
  }
29941
30118
  ]
29942
30119
  },
@@ -34990,6 +35167,15 @@
34990
35167
  "example": null,
34991
35168
  "defaultValue": "true"
34992
35169
  },
35170
+ {
35171
+ "name": "infiniteScroll",
35172
+ "decorators": [],
35173
+ "description": "Подключение бесконечного скролла",
35174
+ "required": false,
35175
+ "type": "boolean | IInfiniteScrollProps",
35176
+ "example": "{\n enable: true\n}",
35177
+ "defaultValue": null
35178
+ },
34993
35179
  {
34994
35180
  "name": "initialItems",
34995
35181
  "decorators": [],
@@ -35325,6 +35511,15 @@
35325
35511
  "example": null,
35326
35512
  "parameters": []
35327
35513
  },
35514
+ {
35515
+ "name": "renderInfiniteScroll",
35516
+ "decorators": [],
35517
+ "description": "",
35518
+ "required": false,
35519
+ "type": "any",
35520
+ "example": null,
35521
+ "parameters": []
35522
+ },
35328
35523
  {
35329
35524
  "name": "renderLayoutNames",
35330
35525
  "decorators": [],
@@ -35416,6 +35611,73 @@
35416
35611
  }
35417
35612
  ]
35418
35613
  },
35614
+ "IInfiniteScrollProps": {
35615
+ "name": "IInfiniteScrollProps",
35616
+ "moduleName": "ui/list/InfiniteScroll/InfiniteScroll",
35617
+ "title": "InfiniteScroll",
35618
+ "description": "Компонент с бесконечным скроллом страниц.",
35619
+ "tags": {},
35620
+ "defaultProps": null,
35621
+ "extends": [],
35622
+ "properties": [
35623
+ {
35624
+ "name": "enable",
35625
+ "decorators": [],
35626
+ "description": "Подключить бесконечный скролл",
35627
+ "required": false,
35628
+ "type": "boolean",
35629
+ "example": "true",
35630
+ "defaultValue": null
35631
+ },
35632
+ {
35633
+ "name": "hasNextPageAttribute",
35634
+ "decorators": [],
35635
+ "description": "Аттрибут (название) в форме для поля с флагом, определяющим есть ли следующая страница",
35636
+ "required": false,
35637
+ "type": "string",
35638
+ "example": "hasNextPage",
35639
+ "defaultValue": null
35640
+ },
35641
+ {
35642
+ "name": "list",
35643
+ "decorators": [],
35644
+ "description": "Список, для которого используется пагинация",
35645
+ "required": false,
35646
+ "type": "any",
35647
+ "example": null,
35648
+ "defaultValue": null
35649
+ },
35650
+ {
35651
+ "name": "pageAttribute",
35652
+ "decorators": [],
35653
+ "description": "Аттрибут (название) в форме для поля с номером текущей страницы",
35654
+ "required": false,
35655
+ "type": "string",
35656
+ "example": "page",
35657
+ "defaultValue": null
35658
+ }
35659
+ ],
35660
+ "methods": [
35661
+ {
35662
+ "name": "onChange",
35663
+ "decorators": [],
35664
+ "description": "Обработчик, который вызывается после смены страницы",
35665
+ "required": false,
35666
+ "type": "void",
35667
+ "example": null,
35668
+ "parameters": [
35669
+ {
35670
+ "name": "value",
35671
+ "decorators": [],
35672
+ "description": "",
35673
+ "required": true,
35674
+ "type": "number",
35675
+ "example": null
35676
+ }
35677
+ ]
35678
+ }
35679
+ ]
35680
+ },
35419
35681
  "ILayoutNamesProps": {
35420
35682
  "name": "ILayoutNamesProps",
35421
35683
  "moduleName": "ui/list/LayoutNames/LayoutNames",
@@ -35642,6 +35904,15 @@
35642
35904
  "example": "{\n text: 'Записи не найдены'\n}",
35643
35905
  "defaultValue": null
35644
35906
  },
35907
+ {
35908
+ "name": "infiniteScroll",
35909
+ "decorators": [],
35910
+ "description": "Подключение бесконечного скролла",
35911
+ "required": false,
35912
+ "type": "boolean | IInfiniteScrollProps",
35913
+ "example": "{\n enable: true\n}",
35914
+ "defaultValue": null
35915
+ },
35645
35916
  {
35646
35917
  "name": "initialItems",
35647
35918
  "decorators": [],
@@ -35987,6 +36258,15 @@
35987
36258
  "example": null,
35988
36259
  "parameters": []
35989
36260
  },
36261
+ {
36262
+ "name": "renderInfiniteScroll",
36263
+ "decorators": [],
36264
+ "description": "",
36265
+ "required": false,
36266
+ "type": "any",
36267
+ "example": null,
36268
+ "parameters": []
36269
+ },
35990
36270
  {
35991
36271
  "name": "renderLayoutNames",
35992
36272
  "decorators": [],
@@ -44365,6 +44645,13 @@
44365
44645
  "description": "",
44366
44646
  "tags": {}
44367
44647
  },
44648
+ "ui/list/InfiniteScroll/InfiniteScroll": {
44649
+ "name": "default",
44650
+ "moduleName": "ui/list/InfiniteScroll/InfiniteScroll",
44651
+ "title": "",
44652
+ "description": "",
44653
+ "tags": {}
44654
+ },
44368
44655
  "ui/list/LayoutNames/LayoutNames": {
44369
44656
  "name": "default",
44370
44657
  "moduleName": "ui/list/LayoutNames/LayoutNames",
package/en.json CHANGED
@@ -979,7 +979,11 @@
979
979
  "Скрыть иконку c лева от элемента": "",
980
980
  "\nКомпонент `Kanban` позволяет создать доску для управления задачами.\nКоличество столбцов задается с помощью пропа `columns`.\nЗадачи на доске можно создавать, редактировать и перемещать с визуальным отображением.\n\nДля работы этого компонента необходимо установить в проекте зависимости `react-beautiful-dnd`\nи передать в пропсы `droppableComponent`, `draggableComponent` и `dndContext`\nкомпоненты `Droppable`, `Draggable` и `DragDropContext` соответственно.\n\nДля корректной работы функционала создания задач,\nнеобходимо установить в проекте зависимости `@ckeditor/ckeditor5-react` и `@steroidsjs/ckeditor5`,\nзатем импортировать `CKEditor` из `@ckeditor/ckeditor5-react` и `ClassicEditor` из `@steroidsjs/ckeditor5/packages/ckeditor5-build-classic`.\nИмпортированные компоненты нужно передать в проп `createTaskEditorConfig`,\nв поле `htmlComponent` передать `CKEditor`, а в `editorConstructor` передать `ClassicEditor`.\n": "",
981
981
  "Компонент для создания HTML-разметки, использующий WYSIWYG редактор.\n\nДля использования WYSIWYG редактора, необходимо установить в проекте зависимости `@ckeditor/ckeditor5-react` и `@steroidsjs/ckeditor5`,\nзатем импортировать `CKEditor` из `@ckeditor/ckeditor5-react` и `ClassicEditor` из `@steroidsjs/ckeditor5/packages/ckeditor5-build-classic`.\nКомпонент `CKEditor` нужно передать в проп `htmlComponent`, а конструктор `ClassicEditor` в проп `editorConstructor`.\n\nПри передаче `HtmlField` с бэкенда, необходимо переопределить `view` компонента, указав локальный.\nВ локальном компоненте добавить вместо пропсов `htmlComponent` и `editorConstructor` импорты `CKEditor` и `ClassicEditor` соотвественно.\n": "",
982
+ "Компонент с бесконечным скроллом страниц.": "",
982
983
  "Компонент, который представляет в виде дерева список с иерархической структурой данных\n\nДополнительный функционал: в кастомном view компонента есть возможность реализовать кнопку, по клику на которую\nбудет вызываться функция props.onItemFocus. Данная функция \"находит\" текущий роут в дереве -\nраскрывает родительские уровни, делает элемент активным.\nДанная функция не включает скролл к активному компоненту внутри дерева, это также необходимо\nреализовать в кастомном view локально в проекте.\n": "",
984
+ "Значение страницы по умолчанию.": "",
985
+ "Логическое значение, указывающее, можно ли загрузить еще элементы для списка при скролле.": "",
986
+ "Подключение бесконечного скролла": "",
983
987
  "Дополнительный свойства для view части компонента": "",
984
988
  "Используется для управления раскрытием всех элементов в дереве": "",
985
989
  "Идентификатор (ключ) для сохранения в LocalStorage коллекции.": "",
@@ -1013,6 +1017,9 @@
1013
1017
  "Компонент редактора 'ckeditor5-react' из библиотеки @ckeditor\nПримечание: для использования встроенного отображения 'HtmlField', данный компонент должен быть передан": "",
1014
1018
  "Допустимое количество символов после разделителя": "",
1015
1019
  "Может ли число быть отрицательным": "",
1020
+ "Подключить бесконечный скролл": "",
1021
+ "Аттрибут (название) в форме для поля с флагом, определяющим есть ли следующая страница": "",
1022
+ "Аттрибут (название) в форме для поля с номером текущей страницы": "",
1016
1023
  "CSS-класс для элемента навигации.": "",
1017
1024
  "Тип данных для параметров маршрута.": "",
1018
1025
  "Обертка над Redux Store со встроенными middleware (thunk, multi, promise..) и react-router.": ""
@@ -1,3 +1,4 @@
1
+ import { IInfiniteScrollProps } from '@steroidsjs/core/ui/list/InfiniteScroll/InfiniteScroll';
1
2
  import { IAddressBarConfig } from '../hooks/useAddressBar';
2
3
  import { IList } from '../actions/list';
3
4
  import { ILayoutNamesProps } from '../ui/list/LayoutNames/LayoutNames';
@@ -63,6 +64,14 @@ export interface IListConfig {
63
64
  * }
64
65
  */
65
66
  paginationSize?: boolean | IPaginationSizeProps;
67
+ /**
68
+ * Подключение бесконечного скролла
69
+ * @example
70
+ * {
71
+ * enable: true
72
+ * }
73
+ */
74
+ infiniteScroll?: boolean | IInfiniteScrollProps;
66
75
  /**
67
76
  * Подключение сортировки
68
77
  * @example
@@ -208,6 +217,7 @@ export interface IListOutput {
208
217
  renderPaginationSize: () => any;
209
218
  renderLayoutNames: () => any;
210
219
  renderSearchForm: () => any;
220
+ renderInfiniteScroll: () => any;
211
221
  onFetch: (params?: Record<string, unknown>) => void;
212
222
  onSort: (value: any) => void;
213
223
  }
package/hooks/useList.js CHANGED
@@ -44,6 +44,7 @@ var get_1 = __importDefault(require("lodash-es/get"));
44
44
  var union_1 = __importDefault(require("lodash-es/union"));
45
45
  var isEqual_1 = __importDefault(require("lodash-es/isEqual"));
46
46
  var react_use_1 = require("react-use");
47
+ var InfiniteScroll_1 = require("@steroidsjs/core/ui/list/InfiniteScroll/InfiniteScroll");
47
48
  var useSelector_1 = __importDefault(require("./useSelector"));
48
49
  var list_1 = require("../reducers/list");
49
50
  var useModel_1 = __importDefault(require("../hooks/useModel"));
@@ -105,6 +106,7 @@ var createInitialValues = function (_a) {
105
106
  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
107
  };
107
108
  exports.createInitialValues = createInitialValues;
109
+ var FIRST_PAGE = 1;
108
110
  /**
109
111
  * useList
110
112
  * Добавляет массу возможностей для взаимодействия с коллекциями. Коллекции можно получать как с бекенда,
@@ -143,6 +145,12 @@ function useList(config) {
143
145
  var renderPagination = function () { return paginationProps.enable && (list === null || list === void 0 ? void 0 : list.isFetched)
144
146
  ? (react_1["default"].createElement(Pagination, __assign({ list: list }, paginationProps, { sizeAttribute: paginationSizeProps.attribute })))
145
147
  : null; };
148
+ // InfiniteScroll
149
+ var InfiniteScroll = require('../ui/list/InfiniteScroll')["default"];
150
+ var infiniteScrollProps = (0, InfiniteScroll_1.normalizeInfiniteScrollProps)(config.infiniteScroll);
151
+ var renderInfiniteScroll = function () { return infiniteScrollProps.enable && (list === null || list === void 0 ? void 0 : list.isFetched) && !(list === null || list === void 0 ? void 0 : list.isLoading)
152
+ ? (react_1["default"].createElement(InfiniteScroll, __assign({ list: list }, infiniteScrollProps, { sizeAttribute: infiniteScrollProps.attribute })))
153
+ : null; };
146
154
  // Layout switcher
147
155
  var LayoutNames = require('../ui/list/LayoutNames')["default"];
148
156
  var layoutNamesProps = (0, LayoutNames_1.normalizeLayoutNamesProps)(config.layout);
@@ -193,6 +201,7 @@ function useList(config) {
193
201
  }, [formId, initialValues]);
194
202
  // Init list in redux store
195
203
  (0, react_use_1.useMount)(function () {
204
+ var _a;
196
205
  if (!list) {
197
206
  var toDispatch = [
198
207
  (0, list_2.listInit)(config.listId, {
@@ -213,7 +222,9 @@ function useList(config) {
213
222
  pageAttribute: paginationProps.attribute || null,
214
223
  pageSizeAttribute: paginationSizeProps.attribute || null,
215
224
  sortAttribute: sort.attribute || null,
216
- layoutAttribute: layoutNamesProps.attribute || null
225
+ layoutAttribute: layoutNamesProps.attribute || null,
226
+ hasInfiniteScroll: (infiniteScrollProps === null || infiniteScrollProps === void 0 ? void 0 : infiniteScrollProps.enable) || null,
227
+ defaultPageValue: (_a = paginationProps.defaultValue) !== null && _a !== void 0 ? _a : FIRST_PAGE
217
228
  }),
218
229
  ];
219
230
  if (config.initialItems || config.items) {
@@ -297,6 +308,7 @@ function useList(config) {
297
308
  renderPaginationSize: renderPaginationSize,
298
309
  renderLayoutNames: renderLayoutNames,
299
310
  renderSearchForm: renderSearchForm,
311
+ renderInfiniteScroll: renderInfiniteScroll,
300
312
  onFetch: onFetch,
301
313
  onSort: onSort
302
314
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steroidsjs/core",
3
- "version": "3.0.37",
3
+ "version": "3.0.39",
4
4
  "description": "",
5
5
  "author": "Vladimir Kozhin <hello@kozhindev.com>",
6
6
  "repository": {
package/reducers/list.js CHANGED
@@ -51,7 +51,7 @@ var reducerMap = (_a = {},
51
51
  var _a;
52
52
  var items;
53
53
  var list = state.lists[action.listId];
54
- if (list.items === action.items) {
54
+ if (list.items === action.items && !list.hasInfiniteScroll) {
55
55
  // No changes
56
56
  items = list.items;
57
57
  }
@@ -62,6 +62,14 @@ var reducerMap = (_a = {},
62
62
  items[index] = entry;
63
63
  });
64
64
  }
65
+ else if (list && list.items && list.hasInfiniteScroll) {
66
+ if (action.page === list.defaultPageValue) {
67
+ items = [].concat(action.items);
68
+ }
69
+ else {
70
+ items = [].concat(list.items, action.items);
71
+ }
72
+ }
65
73
  else {
66
74
  items = [].concat(action.items);
67
75
  }
@@ -23,6 +23,10 @@ export interface IBaseFieldProps extends IFieldWrapperInputProps, IUiComponent {
23
23
  * @example true
24
24
  */
25
25
  showClear?: boolean;
26
+ /**
27
+ * Callback-функция, которая вызывается при очистке input
28
+ */
29
+ onClear?: (value: string) => void;
26
30
  /**
27
31
  * Свойства для компонента отображения
28
32
  * @example
@@ -90,14 +90,19 @@ function InputField(props) {
90
90
  var maskedInputRef = (0, react_2.useMaskito)({
91
91
  options: props.maskOptions
92
92
  });
93
- var _a = (0, hooks_1.useSaveCursorPosition)(props.input), inputRef = _a.inputRef, onChange = _a.onChange;
93
+ var _a = (0, hooks_1.useSaveCursorPosition)(props.input, props.onChange), inputRef = _a.inputRef, onChange = _a.onChange;
94
94
  React.useEffect(function () {
95
95
  if (inputRef.current) {
96
96
  maskedInputRef(inputRef.current);
97
97
  }
98
98
  }, [inputRef, maskedInputRef]);
99
99
  (0, useInputFieldWarningByType_1.useInputFieldWarningByType)(props.type);
100
- var onClear = React.useCallback(function () { return props.input.onChange(''); }, [props.input]);
100
+ var onClear = React.useCallback(function () {
101
+ if (props.onClear) {
102
+ props.onClear('');
103
+ }
104
+ props.input.onChange('');
105
+ }, [props.input, props.onClear]);
101
106
  var inputProps = (0, react_1.useMemo)(function () {
102
107
  var _a;
103
108
  return (__assign({ type: props.type, name: props.input.name, value: (_a = props.input.value) !== null && _a !== void 0 ? _a : '', onInput: onChange, placeholder: props.placeholder }, props.inputProps));
@@ -198,6 +198,7 @@ export interface IGridViewProps extends Omit<IGridProps, 'onFetch'> {
198
198
  renderPaginationSize: () => any;
199
199
  renderLayoutNames: () => any;
200
200
  renderSearchForm: () => any;
201
+ renderInfiniteScroll: () => any;
201
202
  renderValue: (item: Record<string, unknown>, column: IGridColumn) => any;
202
203
  onFetch: (params?: Record<string, unknown>) => void;
203
204
  onSort: (value: any) => void;
@@ -53,6 +53,7 @@ function Grid(props) {
53
53
  actionMethod: props.actionMethod,
54
54
  pagination: props.pagination,
55
55
  paginationSize: props.paginationSize,
56
+ infiniteScroll: props.infiniteScroll,
56
57
  sort: props.sort,
57
58
  layout: props.layout,
58
59
  empty: props.empty,
@@ -69,7 +70,7 @@ function Grid(props) {
69
70
  initialItems: props.initialItems,
70
71
  initialTotal: props.initialTotal,
71
72
  autoFetchOnFormChanges: props.autoFetchOnFormChanges
72
- }), list = _a.list, model = _a.model, searchModel = _a.searchModel, paginationPosition = _a.paginationPosition, paginationSizePosition = _a.paginationSizePosition, layoutNamesPosition = _a.layoutNamesPosition, renderList = _a.renderList, renderLoading = _a.renderLoading, renderEmpty = _a.renderEmpty, renderPagination = _a.renderPagination, renderPaginationSize = _a.renderPaginationSize, renderLayoutNames = _a.renderLayoutNames, renderSearchForm = _a.renderSearchForm, onFetch = _a.onFetch, onSort = _a.onSort;
73
+ }), list = _a.list, model = _a.model, searchModel = _a.searchModel, paginationPosition = _a.paginationPosition, paginationSizePosition = _a.paginationSizePosition, layoutNamesPosition = _a.layoutNamesPosition, renderList = _a.renderList, renderLoading = _a.renderLoading, renderEmpty = _a.renderEmpty, renderPagination = _a.renderPagination, renderPaginationSize = _a.renderPaginationSize, renderLayoutNames = _a.renderLayoutNames, renderSearchForm = _a.renderSearchForm, renderInfiniteScroll = _a.renderInfiniteScroll, onFetch = _a.onFetch, onSort = _a.onSort;
73
74
  var renderLabel = (0, react_1.useCallback)(function (column) {
74
75
  if (column.headerView) {
75
76
  var HeaderView = column.headerView;
@@ -130,6 +131,7 @@ function Grid(props) {
130
131
  renderPaginationSize: renderPaginationSize,
131
132
  renderLayoutNames: renderLayoutNames,
132
133
  renderSearchForm: renderSearchForm,
134
+ renderInfiniteScroll: renderInfiniteScroll,
133
135
  renderValue: renderValue,
134
136
  columns: columns,
135
137
  onFetch: onFetch,
@@ -142,9 +144,9 @@ function Grid(props) {
142
144
  hasAlternatingColors: props.hasAlternatingColors,
143
145
  className: props.className,
144
146
  primaryKey: props.primaryKey
145
- }); }, [columns, layoutNamesPosition, list, onFetch, onSort, paginationPosition, paginationSizePosition, props.className,
146
- props.hasAlternatingColors, props.isLoading, props.listId, props.primaryKey, props.searchForm, props.size, renderEmpty,
147
- renderLayoutNames, renderList, renderPagination, renderPaginationSize, renderSearchForm, renderValue, renderLoading]);
147
+ }); }, [list, paginationPosition, paginationSizePosition, layoutNamesPosition, renderList, renderLoading, renderEmpty,
148
+ renderPagination, renderPaginationSize, renderLayoutNames, renderSearchForm, renderInfiniteScroll, renderValue, columns,
149
+ onFetch, onSort, props.searchForm, props.listId, props.isLoading, props.size, props.hasAlternatingColors, props.className, props.primaryKey]);
148
150
  return components.ui.renderView(props.view || 'list.GridView', viewProps);
149
151
  }
150
152
  exports["default"] = Grid;
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ /**
3
+ * InfiniteScroll
4
+ * Компонент с бесконечным скроллом страниц.
5
+ */
6
+ export interface IInfiniteScrollProps {
7
+ /**
8
+ * Подключить бесконечный скролл
9
+ * @example true
10
+ */
11
+ enable?: boolean;
12
+ /**
13
+ * Аттрибут (название) в форме для поля с номером текущей страницы
14
+ * @example page
15
+ */
16
+ pageAttribute?: string;
17
+ /**
18
+ * Аттрибут (название) в форме для поля с флагом, определяющим есть ли следующая страница
19
+ * @example hasNextPage
20
+ */
21
+ hasNextPageAttribute?: string;
22
+ /**
23
+ * Обработчик, который вызывается после смены страницы
24
+ * @param {number} value
25
+ * @return {void}
26
+ */
27
+ onChange?: (value: number) => void;
28
+ /**
29
+ * Список, для которого используется пагинация
30
+ */
31
+ list?: any;
32
+ [key: string]: any;
33
+ }
34
+ declare function InfiniteScroll(props: IInfiniteScrollProps): JSX.Element;
35
+ declare namespace InfiniteScroll {
36
+ var defaultProps: {
37
+ enable: boolean;
38
+ pageAttribute: string;
39
+ hasNextPageAttribute: string;
40
+ };
41
+ }
42
+ export declare const normalizeInfiniteScrollProps: (props: any) => any;
43
+ declare const _default: React.MemoExoticComponent<typeof InfiniteScroll>;
44
+ export default _default;
@@ -0,0 +1,89 @@
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 __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ exports.__esModule = true;
40
+ exports.normalizeInfiniteScrollProps = void 0;
41
+ var react_1 = __importStar(require("react"));
42
+ var get_1 = __importDefault(require("lodash-es/get"));
43
+ var hooks_1 = require("./hooks");
44
+ var useForm_1 = __importDefault(require("../../../hooks/useForm"));
45
+ var form_1 = require("../../../actions/form");
46
+ function InfiniteScroll(props) {
47
+ var _a, _b;
48
+ var observerTarget = (0, react_1.useRef)(null);
49
+ var _c = (0, react_1.useState)(false), isScrollRefSet = _c[0], setIsScrollRefSet = _c[1];
50
+ var setScrollContainerRef = (0, react_1.useCallback)(function (scrollContainerNode) {
51
+ if (scrollContainerNode) {
52
+ observerTarget.current = scrollContainerNode;
53
+ setIsScrollRefSet(true);
54
+ }
55
+ }, []);
56
+ var initialValues = {
57
+ page: (_a = props.list) === null || _a === void 0 ? void 0 : _a[props.pageAttribute]
58
+ };
59
+ var _d = (0, useForm_1["default"])(), formId = _d.formId, formDispatch = _d.formDispatch, formSelector = _d.formSelector;
60
+ var page = (formSelector(function (_a) {
61
+ var values = _a.values;
62
+ return ({
63
+ page: (0, get_1["default"])(values, props.pageAttribute)
64
+ });
65
+ }) || initialValues).page;
66
+ var onScrollFetch = (0, react_1.useCallback)(function () {
67
+ var nextPage = page + 1;
68
+ if (formDispatch) {
69
+ formDispatch((0, form_1.formChange)(formId, props.pageAttribute, nextPage));
70
+ }
71
+ if (props.onChange) {
72
+ props.onChange(nextPage);
73
+ }
74
+ }, [formDispatch, formId, page, props]);
75
+ (0, hooks_1.useIntersectionObserver)({
76
+ target: observerTarget,
77
+ onIntersect: function () { return onScrollFetch(); },
78
+ enabled: Boolean(!props.list.isLoading && ((_b = props.list) === null || _b === void 0 ? void 0 : _b[props.hasNextPageAttribute]) && isScrollRefSet)
79
+ });
80
+ return react_1["default"].createElement("div", { ref: setScrollContainerRef });
81
+ }
82
+ InfiniteScroll.defaultProps = {
83
+ enable: false,
84
+ pageAttribute: 'page',
85
+ hasNextPageAttribute: 'hasNextPage'
86
+ };
87
+ var normalizeInfiniteScrollProps = function (props) { return (__assign(__assign({}, InfiniteScroll.defaultProps), (typeof props === 'boolean' ? { enable: props } : props))); };
88
+ exports.normalizeInfiniteScrollProps = normalizeInfiniteScrollProps;
89
+ exports["default"] = (0, react_1.memo)(InfiniteScroll);
@@ -0,0 +1,12 @@
1
+ import { RefObject } from 'react';
2
+ interface IIntersectionObserverConfig {
3
+ target: RefObject<any>;
4
+ onIntersect: (...args: any[]) => void;
5
+ enabled: boolean;
6
+ }
7
+ export declare const defaultConfig: {
8
+ threshold: number;
9
+ rootMargin: string;
10
+ };
11
+ export declare const useIntersectionObserver: (config: IIntersectionObserverConfig) => void;
12
+ export {};
@@ -0,0 +1,41 @@
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
+ exports.__esModule = true;
14
+ exports.useIntersectionObserver = exports.defaultConfig = void 0;
15
+ var react_1 = require("react");
16
+ exports.defaultConfig = {
17
+ threshold: 0,
18
+ rootMargin: '0px'
19
+ };
20
+ var useIntersectionObserver = function (config) {
21
+ (0, react_1.useEffect)(function () {
22
+ if (!config.enabled) {
23
+ return;
24
+ }
25
+ var observer = new IntersectionObserver(function (entries) {
26
+ if (entries[0].isIntersecting) {
27
+ config.onIntersect();
28
+ }
29
+ }, __assign({}, exports.defaultConfig));
30
+ var ref = config.target;
31
+ if (!ref.current) {
32
+ return;
33
+ }
34
+ observer.observe(ref.current);
35
+ // eslint-disable-next-line consistent-return
36
+ return function () {
37
+ observer.unobserve(ref.current);
38
+ };
39
+ }, [config.target.current, config.enabled]);
40
+ };
41
+ exports.useIntersectionObserver = useIntersectionObserver;
@@ -0,0 +1,2 @@
1
+ import InfiniteScroll from './InfiniteScroll';
2
+ export default InfiniteScroll;
@@ -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 InfiniteScroll_1 = __importDefault(require("./InfiniteScroll"));
7
+ exports["default"] = InfiniteScroll_1["default"];