@neovici/cosmoz-omnitable 8.8.1 → 8.11.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.11.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,11 +54,12 @@
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",
60
61
  "@neovici/cosmoz-i18next": "^3.1.1",
61
- "@neovici/cosmoz-page-router": "^7.0.0",
62
+ "@neovici/cosmoz-page-router": "^7.0.0 || ^8.0.0",
62
63
  "@neovici/cosmoz-utils": "^3.19.0",
63
64
  "@neovici/nullxlsx": "^3.0.0",
64
65
  "@polymer/iron-icon": "^3.0.0",
@@ -74,8 +75,8 @@
74
75
  "lit-html": "^1.3.0"
75
76
  },
76
77
  "devDependencies": {
77
- "@commitlint/cli": "^16.0.0",
78
- "@commitlint/config-conventional": "^16.0.0",
78
+ "@commitlint/cli": "^17.0.0",
79
+ "@commitlint/config-conventional": "^17.0.0",
79
80
  "@neovici/cfg": "^1.13.0",
80
81
  "@neovici/cosmoz-viewinfo": "^3.1.3",
81
82
  "@neovici/eslint-config": "^1.3.3",
@@ -88,7 +89,7 @@
88
89
  "@semantic-release/changelog": "^6.0.0",
89
90
  "@semantic-release/git": "^10.0.0",
90
91
  "@web/dev-server": "^0.1.10",
91
- "husky": "^7.0.0",
92
+ "husky": "^8.0.0",
92
93
  "semantic-release": "^19.0.0",
93
94
  "sinon": "^13.0.0",
94
95
  "web-animations-js": "^2.3.2"
@@ -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
- `;