@neovici/cosmoz-omnitable 8.8.1 → 8.9.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.
@@ -0,0 +1,116 @@
1
+ import { useCallback } from 'haunted';
2
+ import { useMeta } from '@neovici/cosmoz-utils/lib/hooks/use-meta';
3
+
4
+ const parseIndex = (str) => {
5
+ const idx = parseInt(str, 10);
6
+ return isFinite(idx) ? idx : undefined;
7
+ };
8
+
9
+ // eslint-disable-next-line max-lines-per-function
10
+ export default (host) => {
11
+ const { config } = host,
12
+ { settings, setSettings } = config,
13
+ meta = useMeta({ settings, setSettings });
14
+
15
+ return {
16
+ ...config,
17
+ onDown: useCallback(
18
+ (e) => {
19
+ if (!e.target.closest('.pull')) {
20
+ return;
21
+ }
22
+
23
+ meta.handle = e.currentTarget;
24
+ },
25
+ [meta]
26
+ ),
27
+
28
+ onDragStart: useCallback(
29
+ (e) => {
30
+ const { target } = e,
31
+ index = parseIndex(target.dataset.index);
32
+
33
+ if (!meta.handle?.contains(target) || index == null) {
34
+ return e.preventDefault();
35
+ }
36
+
37
+ meta.handle = null;
38
+ e.dataTransfer.effectAllowed = 'move';
39
+ e.dataTransfer.setData('omnitable/sort-index', index);
40
+ setTimeout(() => target.classList.add('drag'), 0);
41
+ target.addEventListener(
42
+ 'dragend',
43
+ (e) => e.target.classList.remove('drag'),
44
+ { once: true }
45
+ );
46
+ },
47
+ [meta]
48
+ ),
49
+
50
+ onDragEnter: useCallback((e) => {
51
+ const ctg = e.currentTarget;
52
+ if (ctg !== e.target) {
53
+ return;
54
+ }
55
+
56
+ e.preventDefault();
57
+ e.dataTransfer.dropEffect = 'move';
58
+ ctg.classList.add('dragover');
59
+ }, []),
60
+
61
+ onDragOver: useCallback((e) => {
62
+ e.preventDefault();
63
+ e.currentTarget.classList.add('dragover');
64
+ }, []),
65
+
66
+ onDragLeave: useCallback((e) => {
67
+ const ctg = e.currentTarget;
68
+ if (ctg.contains(e.relatedTarget)) {
69
+ return;
70
+ }
71
+
72
+ ctg.classList.remove('dragover');
73
+ }, []),
74
+
75
+ onDrop: useCallback(
76
+ (e) => {
77
+ const from = parseIndex(e.dataTransfer.getData('omnitable/sort-index')),
78
+ to = parseIndex(e.currentTarget.dataset.index),
79
+ { settings, setSettings } = meta;
80
+
81
+ e.currentTarget.classList.remove('dragover');
82
+ e.preventDefault();
83
+
84
+ const newSettings = settings.slice();
85
+ newSettings.splice(
86
+ to + (from >= to ? 0 : -1),
87
+ 0,
88
+ newSettings.splice(from, 1)[0]
89
+ );
90
+ setSettings(newSettings);
91
+ },
92
+ [meta]
93
+ ),
94
+
95
+ onToggle: useCallback(
96
+ (e) => {
97
+ const checked = e.target.checked,
98
+ idx = parseIndex(e.target.closest('[data-index]')?.dataset.index),
99
+ { settings, setSettings } = meta,
100
+ newSettings = settings.slice(),
101
+ setting = settings[idx],
102
+ priority = e.target.windeterminate
103
+ ? settings.reduce((acc, s) => Math.max(acc, s.priority), 0) + 1
104
+ : setting.priority;
105
+
106
+ newSettings.splice(idx, 1, {
107
+ ...settings[idx],
108
+ disabled: !checked,
109
+ priority,
110
+ });
111
+ setSettings(newSettings);
112
+ },
113
+ [meta]
114
+ ),
115
+ };
116
+ };
@@ -0,0 +1,32 @@
1
+ import { useMemo, useState } from 'haunted';
2
+
3
+ import useSavedSettings from './use-saved-settings';
4
+ import normalize from './normalize';
5
+
6
+ export default ({ settingsId, columns }) => {
7
+ const [settings, setSettings] = useState([]),
8
+ [opened, setOpened] = useState({ columns: true, group: true }),
9
+ { savedSettings, ...thru } = useSavedSettings(
10
+ settingsId,
11
+ settings,
12
+ setSettings
13
+ ),
14
+ normalizedSettings = useMemo(
15
+ () => normalize(columns, settings, savedSettings),
16
+ [columns, settings, savedSettings]
17
+ ),
18
+ normalizedColumns = useMemo(
19
+ () => normalizedSettings.map(s => columns.find(c => c.name === s.name)),
20
+ [columns, ...normalizedSettings.map(s => s.name)]
21
+ );
22
+
23
+ return {
24
+ ...thru,
25
+ opened,
26
+ setOpened,
27
+ settings: normalizedSettings,
28
+ normalizedColumns,
29
+ setSettings,
30
+ };
31
+ };
32
+
@@ -1,22 +1,18 @@
1
- import { useCallback, useMemo, useState, useEffect } from 'haunted';
2
- import { normalizeSettings } from './normalize-settings';
1
+ import { useCallback, useMemo, useEffect } from 'haunted';
3
2
  import { useProcessedItems } from './use-processed-items';
4
3
  import { useFastLayout } from './use-fast-layout';
5
- import { useSavedSettings } from './use-saved-settings';
4
+ import { useSettings } from './settings';
6
5
  import { useDOMColumns } from './use-dom-columns';
7
6
  import { useSortAndGroupOptions } from './use-sort-and-group-options';
8
7
  import { onItemChange } from './utils-data';
9
8
 
10
9
  // eslint-disable-next-line max-lines-per-function
11
- export const useOmnitable = host => {
10
+ export const useOmnitable = (host) => {
12
11
  const { enabledColumns, hashParam } = host,
13
12
  columns = useDOMColumns(host, { enabledColumns }),
14
- sortAndGroupOptions = useSortAndGroupOptions(
15
- columns,
16
- hashParam,
17
- host
18
- ),
19
- { groupOnColumn, groupOnDescending, sortOnColumn, descending } = sortAndGroupOptions,
13
+ sortAndGroupOptions = useSortAndGroupOptions(columns, hashParam, host),
14
+ { groupOnColumn, groupOnDescending, sortOnColumn, descending } =
15
+ sortAndGroupOptions,
20
16
  { data, resizeSpeedFactor, settingsId } = host,
21
17
  // TODO: drop filterFunctions
22
18
  {
@@ -25,7 +21,7 @@ export const useOmnitable = host => {
25
21
  setFilterState,
26
22
  numProcessedItems,
27
23
  filterFunctions,
28
- groupsCount
24
+ groupsCount,
29
25
  } = useProcessedItems({
30
26
  data,
31
27
  columns,
@@ -33,73 +29,93 @@ export const useOmnitable = host => {
33
29
  groupOnDescending,
34
30
  sortOnColumn,
35
31
  descending,
36
- hashParam
32
+ hashParam,
37
33
  }),
38
- [settings, setSettings] = useState([]),
39
- { savedSettings, onSettingsSave, onSettingsReset, hasChangedSettings } =
40
- useSavedSettings(settingsId, settings, setSettings),
41
- normalizedSettings = useMemo(
42
- () => normalizeSettings(columns, settings, savedSettings),
43
- [columns, settings, savedSettings]
44
- ),
45
- normalizedColumns = useMemo(
46
- () => normalizedSettings.map(s => columns.find(c => c.name === s.name)),
47
- [columns, ...normalizedSettings.map(s => s.name)]
48
- ),
34
+ settingsOpts = useSettings({ settingsId, columns }),
35
+ { settings, setSettings, normalizedColumns } = settingsOpts,
49
36
  layout = useFastLayout({
50
37
  host,
51
- settings: normalizedSettings,
38
+ settings,
52
39
  setSettings,
53
40
  groupOnColumn,
54
- resizeSpeedFactor
41
+ resizeSpeedFactor,
55
42
  }),
56
43
  collapsedColumns = useMemo(
57
- () => normalizedSettings.reduce((acc, column, index) =>
58
- layout[index] != null ||
44
+ () =>
45
+ settings.reduce(
46
+ (acc, column, index) =>
47
+ layout[index] != null ||
59
48
  column.name === groupOnColumn?.name ||
60
49
  column.disabled
61
- ? acc
62
- : [...acc, columns.find(c => c.name === column.name)],
63
- []),
64
- [columns, normalizedSettings, layout]
50
+ ? acc
51
+ : [...acc, columns.find((c) => c.name === column.name)],
52
+ []
53
+ ),
54
+ [columns, settings, layout]
65
55
  ),
66
56
  hasHiddenFilter = useMemo(
67
57
  () =>
68
58
  [
69
59
  groupOnColumn,
70
60
  ...collapsedColumns,
71
- ...normalizedSettings.filter(s => s.disabled)
72
- ].some(column => column && Object.keys(filterFunctions).includes(column.name)),
73
- [filterFunctions, normalizedSettings, collapsedColumns]
61
+ ...settings.filter((s) => s.disabled),
62
+ ].some(
63
+ (column) =>
64
+ column && Object.keys(filterFunctions).includes(column.name)
65
+ ),
66
+ [filterFunctions, settings, collapsedColumns]
67
+ ),
68
+ settingsConfig = useMemo(
69
+ () => ({
70
+ ...settingsOpts,
71
+ collapsed: collapsedColumns,
72
+ badge: hasHiddenFilter,
73
+ filters,
74
+ }),
75
+ [settingsOpts, collapsedColumns, hasHiddenFilter, filters]
74
76
  );
75
77
 
76
78
  useEffect(() => {
77
- const handler = ev => setFilterState(ev.detail.name, state => ({ ...state, ...ev.detail.state }));
79
+ const handler = (ev) =>
80
+ setFilterState(ev.detail.name, (state) => ({
81
+ ...state,
82
+ ...ev.detail.state,
83
+ }));
78
84
  host.addEventListener('legacy-filter-changed', handler);
79
85
  return () => host.removeEventListener('legacy-filter-changed', handler);
80
86
  }, []);
81
87
 
82
- return {
83
- columns,
88
+ useEffect(() => {
89
+ const el = host.shadowRoot.querySelector('#tableContent'),
90
+ observer = new ResizeObserver((entries) =>
91
+ requestAnimationFrame(() => {
92
+ host.style.setProperty(
93
+ '--ot-height',
94
+ entries[0]?.contentRect.height + 'px'
95
+ );
96
+ })
97
+ );
98
+ observer.observe(el);
99
+ return () => observer.unobserve(el);
100
+ }, []);
84
101
 
102
+ return {
85
103
  ...sortAndGroupOptions,
86
104
 
87
- setSettings,
88
- normalizedSettings,
105
+ columns,
89
106
  normalizedColumns,
90
107
  collapsedColumns,
91
- hasHiddenFilter,
92
- onSettingsSave,
93
- onSettingsReset,
94
- hasChangedSettings,
108
+
109
+ settingsConfig,
110
+
95
111
  filters,
96
112
  setFilterState,
97
113
  onItemChange: useCallback(
98
- (column, item) => value => onItemChange(host, column, item, value),
114
+ (column, item) => (value) => onItemChange(host, column, item, value),
99
115
  []
100
116
  ),
101
117
  numProcessedItems,
102
118
  groupsCount,
103
- sortedFilteredGroupedItems: processedItems
119
+ sortedFilteredGroupedItems: processedItems,
104
120
  };
105
121
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neovici/cosmoz-omnitable",
3
- "version": "8.8.1",
3
+ "version": "8.9.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"
@@ -54,6 +54,7 @@
54
54
  "dependencies": {
55
55
  "@neovici/cosmoz-autocomplete": "^3.1.0",
56
56
  "@neovici/cosmoz-bottom-bar": "^5.0.0",
57
+ "@neovici/cosmoz-collapse": "^1.1.0",
57
58
  "@neovici/cosmoz-datetime-input": "^3.0.3",
58
59
  "@neovici/cosmoz-dropdown": "^1.5.0",
59
60
  "@neovici/cosmoz-grouped-list": "^3.2.0",
@@ -1,84 +0,0 @@
1
- import { html } from 'haunted';
2
- import { _ } from '@neovici/cosmoz-i18next';
3
- import { without } from '@neovici/cosmoz-utils/lib/array';
4
-
5
- const direction = (descending) =>
6
- `(${descending ? _('Descending') : _('Ascending')})`,
7
- values = (columns, groupOn) => {
8
- const value = columns.find((column) => column.name === groupOn);
9
- return [
10
- value,
11
- columns
12
- ?.filter?.((c) => c['groupOn'])
13
- /* eslint-disable-next-line no-bitwise */
14
- .sort((a, b) => ((b.name === value) >> 0) - ((a.name === value) >> 0)),
15
- ];
16
- },
17
- onSelect = (newVal, { value, onChange, onText, limit }) => {
18
- onText('');
19
- onChange([...without(newVal)(value), newVal].slice(-limit));
20
- },
21
- onChange = ({ setGroupOn, setGroupOnDescending }) => {
22
- return (val, close) => {
23
- const value = (val[0] ?? val)?.name ?? '',
24
- setter = setGroupOn,
25
- directionSetter = setGroupOnDescending;
26
-
27
- setter((oldValue) => {
28
- if (value) {
29
- directionSetter((oldDirection) =>
30
- value === oldValue ? !oldDirection : false
31
- );
32
- } else {
33
- directionSetter(null);
34
- }
35
- return value;
36
- });
37
-
38
- value && close(); /* eslint-disable-line no-unused-expressions */
39
- };
40
- };
41
-
42
- export default () => html`
43
- <sort-and-group-consumer
44
- style="display: contents"
45
- .render=${({
46
- columns,
47
- groupOnDescending,
48
- groupOn,
49
- setGroupOn,
50
- setGroupOnDescending,
51
- } = {}) => {
52
- const [groupOnColumn, source] = values(columns, groupOn);
53
- return html` <div class="group">
54
- <cosmoz-autocomplete
55
- .label="${_('Group on')} ${direction(groupOnDescending)}"
56
- .placeholder=${_('No grouping')}
57
- .source=${source}
58
- .value=${groupOnColumn}
59
- limit="1"
60
- text-property="title"
61
- always-float-label
62
- .itemHeight=${48}
63
- .itemLimit=${8}
64
- .onChange=${onChange({ setGroupOn, setGroupOnDescending })}
65
- .onSelect=${onSelect}
66
- default-index="-1"
67
- show-single
68
- >
69
- <svg
70
- slot="suffix"
71
- viewBox="0 0 24 24"
72
- preserveAspectRatio="xMidYMid meet"
73
- focusable="false"
74
- width="24"
75
- fill="currentColor"
76
- >
77
- <path d="M7 10l5 5 5-5z"></path>
78
- </svg>
79
- </cosmoz-autocomplete>
80
- </div>`;
81
- }}
82
- >
83
- </sort-and-group-consumer>
84
- `;