@neovici/cosmoz-omnitable 8.8.0 → 8.10.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.0",
3
+ "version": "8.10.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,79 +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, type, value) => {
8
- return (
9
- columns
10
- ?.filter?.((c) => c[type])
11
- /* eslint-disable-next-line no-bitwise */
12
- .sort((a, b) => ((b === value) >> 0) - ((a === value) >> 0))
13
- );
14
- },
15
- onSelect = (newVal, { value, onChange, onText, limit }) => {
16
- onText('');
17
- onChange([...without(newVal)(value), newVal].slice(-limit));
18
- },
19
- onChange = ({ setGroupOn, setGroupOnDescending }) => {
20
- return (val, close) => {
21
- const value = (val[0] ?? val)?.name ?? '',
22
- setter = setGroupOn,
23
- directionSetter = setGroupOnDescending;
24
-
25
- setter((oldValue) => {
26
- if (value) {
27
- directionSetter((oldDirection) =>
28
- value === oldValue ? !oldDirection : false
29
- );
30
- } else {
31
- directionSetter(null);
32
- }
33
- return value;
34
- });
35
-
36
- value && close(); /* eslint-disable-line no-unused-expressions */
37
- };
38
- };
39
-
40
- export default () => html`
41
- <sort-and-group-consumer
42
- style="display: contents"
43
- .render=${({
44
- columns,
45
- groupOnDescending,
46
- groupOnColumn,
47
- setGroupOn,
48
- setGroupOnDescending,
49
- } = {}) => html` <div class="group">
50
- <cosmoz-autocomplete
51
- .label="${_('Group on')} ${direction(groupOnDescending)}"
52
- .placeholder=${_('No grouping')}
53
- .source=${values(columns, 'groupOn', groupOnColumn)}
54
- .value=${groupOnColumn}
55
- limit="1"
56
- text-property="title"
57
- always-float-label
58
- .itemHeight=${48}
59
- .itemLimit=${8}
60
- .onChange=${onChange({ setGroupOn, setGroupOnDescending })}
61
- .onSelect=${onSelect}
62
- default-index="-1"
63
- show-single
64
- >
65
- <svg
66
- slot="suffix"
67
- viewBox="0 0 24 24"
68
- preserveAspectRatio="xMidYMid meet"
69
- focusable="false"
70
- width="24"
71
- fill="currentColor"
72
- >
73
- <path d="M7 10l5 5 5-5z"></path>
74
- </svg>
75
- </cosmoz-autocomplete>
76
- </div>`}
77
- >
78
- </sort-and-group-consumer>
79
- `;