@steroidsjs/core 3.0.38 → 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": [],
@@ -35134,6 +35167,15 @@
35134
35167
  "example": null,
35135
35168
  "defaultValue": "true"
35136
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
+ },
35137
35179
  {
35138
35180
  "name": "initialItems",
35139
35181
  "decorators": [],
@@ -35469,6 +35511,15 @@
35469
35511
  "example": null,
35470
35512
  "parameters": []
35471
35513
  },
35514
+ {
35515
+ "name": "renderInfiniteScroll",
35516
+ "decorators": [],
35517
+ "description": "",
35518
+ "required": false,
35519
+ "type": "any",
35520
+ "example": null,
35521
+ "parameters": []
35522
+ },
35472
35523
  {
35473
35524
  "name": "renderLayoutNames",
35474
35525
  "decorators": [],
@@ -35560,6 +35611,73 @@
35560
35611
  }
35561
35612
  ]
35562
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
+ },
35563
35681
  "ILayoutNamesProps": {
35564
35682
  "name": "ILayoutNamesProps",
35565
35683
  "moduleName": "ui/list/LayoutNames/LayoutNames",
@@ -35786,6 +35904,15 @@
35786
35904
  "example": "{\n text: 'Записи не найдены'\n}",
35787
35905
  "defaultValue": null
35788
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
+ },
35789
35916
  {
35790
35917
  "name": "initialItems",
35791
35918
  "decorators": [],
@@ -36131,6 +36258,15 @@
36131
36258
  "example": null,
36132
36259
  "parameters": []
36133
36260
  },
36261
+ {
36262
+ "name": "renderInfiniteScroll",
36263
+ "decorators": [],
36264
+ "description": "",
36265
+ "required": false,
36266
+ "type": "any",
36267
+ "example": null,
36268
+ "parameters": []
36269
+ },
36134
36270
  {
36135
36271
  "name": "renderLayoutNames",
36136
36272
  "decorators": [],
@@ -44509,6 +44645,13 @@
44509
44645
  "description": "",
44510
44646
  "tags": {}
44511
44647
  },
44648
+ "ui/list/InfiniteScroll/InfiniteScroll": {
44649
+ "name": "default",
44650
+ "moduleName": "ui/list/InfiniteScroll/InfiniteScroll",
44651
+ "title": "",
44652
+ "description": "",
44653
+ "tags": {}
44654
+ },
44512
44655
  "ui/list/LayoutNames/LayoutNames": {
44513
44656
  "name": "default",
44514
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.38",
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
  }
@@ -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"];