@neovici/cosmoz-omnitable 12.0.2 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,17 @@
1
- import { useCallback, useMemo, useEffect } from 'haunted';
1
+ import { useState } from 'haunted';
2
2
  import { useProcessedItems } from './use-processed-items';
3
3
  import { useFastLayout } from './use-fast-layout';
4
4
  import { useSettings } from './settings';
5
- import { useDOMColumns } from './use-dom-columns';
6
5
  import { useSortAndGroupOptions } from './use-sort-and-group-options';
7
- import { onItemChange } from './utils-data';
8
- import { useNotifyProperty } from '@neovici/cosmoz-utils/hooks/use-notify-property';
6
+ import { usePublicInterface } from './use-public-interface';
7
+ import { useHeader } from './use-header';
8
+ import { useList } from './use-list';
9
+ import { useFooter } from './use-footer';
9
10
 
10
11
  // eslint-disable-next-line max-lines-per-function
11
12
  export const useOmnitable = (host) => {
12
- const { enabledColumns, hashParam, settingsId } = host,
13
- _columns = useDOMColumns(host, { enabledColumns }),
14
- settingS = useSettings({ columns: _columns, settingsId, initial: host }),
13
+ const { hashParam, settingsId, data, resizeSpeedFactor } = host,
14
+ settingS = useSettings({ settingsId, host }),
15
15
  { settings, setSettings, columns, resetRef } = settingS,
16
16
  sortAndGroupOptions = useSortAndGroupOptions(
17
17
  columns,
@@ -20,111 +20,69 @@ export const useOmnitable = (host) => {
20
20
  setSettings,
21
21
  resetRef
22
22
  ),
23
- { groupOnColumn, groupOnDescending, sortOnColumn, descending } =
24
- sortAndGroupOptions,
25
- { data, resizeSpeedFactor } = host,
26
23
  // TODO: drop filterFunctions
27
24
  {
28
25
  processedItems,
29
26
  visibleData,
30
27
  filters,
31
28
  setFilterState,
32
- numProcessedItems,
33
29
  filterFunctions,
34
- groupsCount,
35
30
  } = useProcessedItems({
36
31
  data,
37
32
  columns,
38
- groupOnColumn,
39
- groupOnDescending,
40
- sortOnColumn,
41
- descending,
42
33
  hashParam,
34
+ sortAndGroupOptions,
43
35
  }),
44
- layout = useFastLayout({
36
+ { collapsedColumns } = useFastLayout({
45
37
  host,
38
+ columns,
46
39
  settings,
47
40
  setSettings,
48
- groupOnColumn,
49
41
  resizeSpeedFactor,
42
+ sortAndGroupOptions,
50
43
  }),
51
- collapsedColumns = useMemo(
52
- () =>
53
- settings.columns.reduce(
54
- (acc, column, index) =>
55
- layout[index] != null ||
56
- column.name === groupOnColumn?.name ||
57
- column.disabled
58
- ? acc
59
- : [...acc, columns.find((c) => c.name === column.name)],
60
- []
61
- ),
62
- [columns, settings, layout]
63
- ),
64
- hasHiddenFilter = useMemo(
65
- () =>
66
- [
67
- groupOnColumn,
68
- ...collapsedColumns,
69
- ...settings.columns.filter((s) => s.disabled),
70
- ].some(
71
- (column) =>
72
- column && Object.keys(filterFunctions).includes(column.name)
73
- ),
74
- [filterFunctions, settings, collapsedColumns]
75
- ),
76
- settingsConfig = useMemo(
77
- () => ({
78
- ...settingS,
79
- collapsed: collapsedColumns,
80
- badge: hasHiddenFilter,
81
- filters,
82
- }),
83
- [settingS, collapsedColumns, hasHiddenFilter, filters]
84
- );
85
-
86
- useEffect(() => {
87
- const handler = (ev) =>
88
- setFilterState(ev.detail.name, (state) => ({
89
- ...state,
90
- ...ev.detail.state,
91
- }));
92
- host.addEventListener('legacy-filter-changed', handler);
93
- return () => host.removeEventListener('legacy-filter-changed', handler);
94
- }, []);
95
-
96
- useEffect(() => {
97
- const el = host.shadowRoot.querySelector('#tableContent'),
98
- observer = new ResizeObserver((entries) =>
99
- requestAnimationFrame(() => {
100
- host.style.setProperty(
101
- '--ot-height',
102
- entries[0]?.contentRect.height + 'px'
103
- );
104
- })
105
- );
106
- observer.observe(el);
107
- return () => observer.unobserve(el);
108
- }, []);
109
-
110
- useNotifyProperty('visibleData', visibleData);
111
-
112
- return {
113
- ...sortAndGroupOptions,
44
+ dataIsValid = data && Array.isArray(data) && data.length > 0,
45
+ [selectedItems, setSelectedItems] = useState([]);
114
46
 
47
+ usePublicInterface({
48
+ host,
49
+ visibleData,
50
+ sortedFilteredGroupedItems: processedItems,
115
51
  columns,
116
- collapsedColumns,
117
-
118
- settingsConfig,
119
-
120
52
  filters,
121
53
  setFilterState,
122
- onItemChange: useCallback(
123
- (column, item) => (value) => onItemChange(host, column, item, value),
124
- []
125
- ),
126
- numProcessedItems,
127
- groupsCount,
128
- sortedFilteredGroupedItems: processedItems,
54
+ selectedItems,
55
+ ...sortAndGroupOptions,
56
+ });
57
+
58
+ return {
59
+ header: useHeader({
60
+ host,
61
+ selectedItems,
62
+ sortAndGroupOptions,
63
+ dataIsValid,
64
+ data,
65
+ columns,
66
+ filters,
67
+ collapsedColumns,
68
+ settings,
69
+ filterFunctions,
70
+ settingS,
71
+ setFilterState,
72
+ }),
73
+ list: useList({
74
+ host,
75
+ dataIsValid,
76
+ processedItems,
77
+ setSelectedItems,
78
+ columns,
79
+ collapsedColumns,
80
+ sortAndGroupOptions,
81
+ }),
82
+ footer: useFooter({
83
+ host,
84
+ selectedItems,
85
+ columns,
86
+ }),
129
87
  };
130
88
  };
@@ -1,4 +1,4 @@
1
- import { useCallback, useMemo } from 'haunted';
1
+ import { useCallback, useEffect, useMemo } from 'haunted';
2
2
  import { genericSorter } from './generic-sorter';
3
3
  import { invoke } from './invoke';
4
4
  import { columnSymbol } from './use-dom-columns';
@@ -26,19 +26,19 @@ const sortBy = (valueFn, descending) => (a, b) =>
26
26
  );
27
27
  });
28
28
  },
29
- assignIndex = (item, index) => Object.assign(item, { [indexSymbol]: index });
29
+ assignIndex = (item, index) => Object.assign(item, { [indexSymbol]: index }),
30
+ unparsed = Symbol('unparsed');
30
31
 
31
32
  // eslint-disable-next-line max-lines-per-function
32
33
  export const useProcessedItems = ({
33
34
  data,
34
35
  columns,
35
- groupOnColumn,
36
- groupOnDescending,
37
- sortOnColumn,
38
- descending,
39
36
  hashParam,
37
+ sortAndGroupOptions,
40
38
  }) => {
41
- const write = useCallback(
39
+ const { groupOnColumn, groupOnDescending, sortOnColumn, descending } =
40
+ sortAndGroupOptions,
41
+ write = useCallback(
42
42
  ([filter, value]) => {
43
43
  const column = columns.find(({ name }) => name === filter);
44
44
  if (column == null) {
@@ -55,7 +55,7 @@ export const useProcessedItems = ({
55
55
  ([filter, value]) => {
56
56
  const column = columns.find(({ name }) => name === filter);
57
57
  if (column == null) {
58
- return [filter, undefined];
58
+ return [filter, { [unparsed]: value }];
59
59
  }
60
60
 
61
61
  const state = { filter: column.deserializeFilter(column, value) };
@@ -211,13 +211,12 @@ export const useProcessedItems = ({
211
211
  groupIndex = 0;
212
212
  const result = [];
213
213
  processedItems.forEach((item) => {
214
-
215
- if(Array.isArray(item.items)) {
214
+ if (Array.isArray(item.items)) {
216
215
  assignIndex(item, groupIndex++);
217
- item.items.forEach(groupItem => {
216
+ item.items.forEach((groupItem) => {
218
217
  assignIndex(groupItem, index++);
219
- result.push(groupItem);
220
- })
218
+ result.push(groupItem);
219
+ });
221
220
  return;
222
221
  }
223
222
 
@@ -227,13 +226,35 @@ export const useProcessedItems = ({
227
226
  return result;
228
227
  }, [processedItems]);
229
228
 
229
+ // parse un-parsed filter values
230
+ // filters can be left un-parsed if a column was not defined when the URL is read
231
+ useEffect(() => {
232
+ setFilters((filters) => {
233
+ const hasUnparsedFilters = Object.values(filters).some(
234
+ (value) => value[unparsed] != null
235
+ );
236
+
237
+ if (!hasUnparsedFilters) {
238
+ return filters;
239
+ }
240
+
241
+ return Object.fromEntries(
242
+ Object.entries(filters).map(([name, value]) => {
243
+ if (value[unparsed] == null) {
244
+ return [name, value];
245
+ }
246
+
247
+ return read([name, value[unparsed]]);
248
+ })
249
+ );
250
+ });
251
+ }, [read]);
252
+
230
253
  return {
231
254
  processedItems,
232
255
  visibleData,
233
256
  filters,
234
257
  filterFunctions,
235
- setFilterState,
236
- numProcessedItems: filteredItems.length,
237
- groupsCount: processedItems[0]?.items != null ? processedItems.length : 0,
258
+ setFilterState
238
259
  };
239
260
  };
@@ -0,0 +1,96 @@
1
+ /* eslint-disable max-lines-per-function */
2
+ import { useImperativeApi } from '@neovici/cosmoz-utils/hooks/use-imperative-api';
3
+ import { useEffect } from 'haunted';
4
+ import { useNotifyProperty } from '@neovici/cosmoz-utils/hooks/use-notify-property';
5
+
6
+ export const usePublicInterface = ({ host, visibleData, ...api }) => {
7
+ useImperativeApi(api, Object.values(api));
8
+
9
+ const removeItems = (items) => {
10
+ const removedItems = [];
11
+
12
+ for (let i = items.length - 1; i >= 0; i -= 1) {
13
+ const removed = host.removeItem(items[i]);
14
+ if (removed != null) {
15
+ removedItems.push(removed);
16
+ }
17
+ }
18
+ return removedItems;
19
+ },
20
+ /**
21
+ * Helper method to remove an item from `data`.
22
+ * @param {Object} item Item to remove
23
+ * @return {Object} item removed
24
+ */
25
+ removeItem = (item) => {
26
+ const index = host.data.indexOf(item);
27
+
28
+ if (index < 0) {
29
+ return null;
30
+ }
31
+
32
+ const removed = host.data.splice(index, 1);
33
+ host.data = host.data.slice();
34
+ if (Array.isArray(removed) && removed.length > 0) {
35
+ return removed[0];
36
+ }
37
+ },
38
+ replaceItem = (oldItem, newItem) => {
39
+ const itemIndex = host.data.indexOf(oldItem);
40
+ if (itemIndex > -1) {
41
+ return host.replaceItemAtIndex(itemIndex, newItem);
42
+ }
43
+ },
44
+ replaceItemAtIndex = (index, newItem) => {
45
+ host.data.splice(index, 1, newItem);
46
+ host.data = host.data.slice();
47
+ },
48
+ selectItem = (item) => {
49
+ host.shadowRoot.querySelector('#groupedList').select(item);
50
+ },
51
+ deselectItem = (item) => {
52
+ host.shadowRoot.querySelector('#groupedList').deselect(item);
53
+ },
54
+ isItemSelected = (item) => {
55
+ return host.shadowRoot.querySelector('#groupedList').isItemSelected(item);
56
+ },
57
+ { setFilterState } = api;
58
+
59
+ useEffect(() => {
60
+ const handler = (ev) =>
61
+ setFilterState(ev.detail.name, (state) => ({
62
+ ...state,
63
+ ...ev.detail.state,
64
+ }));
65
+ host.addEventListener('legacy-filter-changed', handler);
66
+ return () => host.removeEventListener('legacy-filter-changed', handler);
67
+ }, []);
68
+
69
+ useNotifyProperty('visibleData', visibleData);
70
+ useNotifyProperty(
71
+ 'sortedFilteredGroupedItems',
72
+ api.sortedFilteredGroupedItems
73
+ );
74
+ useNotifyProperty('selectedItems', api.selectedItems);
75
+
76
+ useImperativeApi(
77
+ {
78
+ removeItems,
79
+ removeItem,
80
+ replaceItem,
81
+ replaceItemAtIndex,
82
+ selectItem,
83
+ deselectItem,
84
+ isItemSelected,
85
+ },
86
+ [
87
+ removeItems,
88
+ removeItem,
89
+ replaceItem,
90
+ replaceItemAtIndex,
91
+ selectItem,
92
+ deselectItem,
93
+ isItemSelected,
94
+ ]
95
+ );
96
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neovici/cosmoz-omnitable",
3
- "version": "12.0.2",
3
+ "version": "12.1.0",
4
4
  "description": "[![Build Status](https://travis-ci.org/Neovici/cosmoz-omnitable.svg?branch=master)](https://travis-ci.org/Neovici/cosmoz-omnitable)",
5
5
  "keywords": [
6
6
  "web-components"