From bb0d29fe8fa446113a31797dd8c421a3f9ca4f63 Mon Sep 17 00:00:00 2001 From: Cristian Necula Date: Thu, 2 Sep 2021 14:48:18 +0300 Subject: [PATCH 1/4] fix(settings): resize columns and settings UI fixes Fixed multiple issues with the interaction between the settings UI and the resize columns feature. Fixed performance issue. BREAKING CHANGE: dropped cosmoz-omnitable-column-{index} classes BREAKING CHANGE: dropped visibleColumns BREAKING CHANGE: dropped disabledColumns Re #418 --- cosmoz-omnitable-column-mixin.js | 11 +--- cosmoz-omnitable-column-number.js | 4 ++ cosmoz-omnitable-header-row.js | 4 +- cosmoz-omnitable-item-row.js | 5 +- cosmoz-omnitable.js | 69 +++++--------------------- lib/compute-layout.js | 16 +++--- lib/cosmoz-omnitable-resize-nub.js | 12 ++--- lib/cosmoz-omnitable-settings.js | 20 +++++++- lib/layout.js | 21 +++++--- lib/normalize-settings.js | 27 ++++++++++ lib/use-fast-layout.js | 27 +++++++--- lib/use-layout.js | 7 +-- lib/use-omnitable.js | 31 ++++-------- lib/use-resizable-columns.js | 32 ++++++------ lib/use-track-size.js | 1 + test/autocomplete.test.js | 7 +-- test/basic.test.js | 15 ------ test/boolean.test.js | 2 +- test/group.test.js | 2 +- test/hash-param.test.js | 5 +- test/integration/column-number.test.js | 3 +- test/integration/templatize.test.js | 9 ++-- test/list.test.js | 5 +- test/range-date.test.js | 5 +- test/range.test.js | 2 +- test/xlsx-export.test.js | 2 +- 26 files changed, 169 insertions(+), 175 deletions(-) create mode 100644 lib/normalize-settings.js diff --git a/cosmoz-omnitable-column-mixin.js b/cosmoz-omnitable-column-mixin.js index 887e6fdf..69e02a9f 100644 --- a/cosmoz-omnitable-column-mixin.js +++ b/cosmoz-omnitable-column-mixin.js @@ -201,16 +201,10 @@ export const columnMixin = dedupingMixin(base => class extends base { // eslint- reflectToAttribute: true, observer: '_hiddenChanged' }, - /** - * Index of this column in the list of displayed columns (excluding disabled/hidden columns). - */ - columnIndex: { - type: Number - }, preferredDropdownHorizontalAlign: { type: String, - computed: '_computePreferredDropdownHorizontalAlign(columnIndex)' + value: 'right' }, renderHeader: { @@ -260,9 +254,6 @@ export const columnMixin = dedupingMixin(base => class extends base { // eslint- * Override this in column elements if you need a different default width */ - _computePreferredDropdownHorizontalAlign(columnIndex) { - return columnIndex === 0 ? 'left' : 'right'; - } getString(item, valuePath = this.valuePath) { if (valuePath === undefined) { // eslint-disable-next-line no-console diff --git a/cosmoz-omnitable-column-number.js b/cosmoz-omnitable-column-number.js index abc78b6e..da74e232 100644 --- a/cosmoz-omnitable-column-number.js +++ b/cosmoz-omnitable-column-number.js @@ -39,6 +39,10 @@ class OmnitableColumnNumber extends rangeColumnMixin( type: String, value: '30px' }, + minWidth: { + type: String, + value: '30px' + }, editWidth: { type: String, value: '30px' diff --git a/cosmoz-omnitable-header-row.js b/cosmoz-omnitable-header-row.js index 18510150..49f752ad 100644 --- a/cosmoz-omnitable-header-row.js +++ b/cosmoz-omnitable-header-row.js @@ -9,13 +9,13 @@ const return repeat(columns, column => column.name, column => [ html`
${ column.renderHeader(column) }
`, html`` ]); }, diff --git a/cosmoz-omnitable-item-row.js b/cosmoz-omnitable-item-row.js index f17cb948..acfc0d27 100644 --- a/cosmoz-omnitable-item-row.js +++ b/cosmoz-omnitable-item-row.js @@ -93,7 +93,7 @@ class OmnitableItemRow extends repeaterMixin(PolymerElement) { element.toggleAttribute('editable', !!column.editable); element.setAttribute('title', this._getCellTitle(column, this.item)); element.setAttribute('class', this._computeItemRowCellClasses(column)); - element.setAttribute('index', column.columnIndex); + element.setAttribute('for', column.name); } _itemUpdated(changeRecord) { @@ -123,8 +123,7 @@ class OmnitableItemRow extends repeaterMixin(PolymerElement) { _computeItemRowCellClasses(column) { return 'cell itemRow-cell' - + (column.cellClass ? ' ' + column.cellClass + ' ' : '') - + ' cosmoz-omnitable-column-' + column.columnIndex; + + (column.cellClass ? ' ' + column.cellClass + ' ' : ''); } } customElements.define(OmnitableItemRow.is, OmnitableItemRow); diff --git a/cosmoz-omnitable.js b/cosmoz-omnitable.js index e6246832..0b2bbba6 100644 --- a/cosmoz-omnitable.js +++ b/cosmoz-omnitable.js @@ -37,20 +37,9 @@ import { mixin, hauntedPolymer } from '@neovici/cosmoz-utils'; import { isEmpty } from '@neovici/cosmoz-utils/lib/template.js'; import { useOmnitable } from './lib/use-omnitable'; import './lib/cosmoz-omnitable-settings'; +import { columnSymbol } from './lib/normalize-settings'; -const PROPERTY_HASH_PARAMS = ['sortOn', 'groupOn', 'descending', 'groupOnDescending'], - - normalizeSettings = (columns = [], settings = []) => { - const cols = columns.slice(); - for (const setting of settings) { - const idx = cols.findIndex(c => c.name === setting.name); - if (idx < 0) { - continue; - } - cols.splice(idx, 1); - } - return [...settings, ...cols.map(({ name, title, priority }) => ({ name, title, priority }))]; - }; +const PROPERTY_HASH_PARAMS = ['sortOn', 'groupOn', 'descending', 'groupOnDescending']; /** * @polymer @@ -74,9 +63,9 @@ class Omnitable extends hauntedPolymer(useOmnitable)(mixin({ isEmpty }, translat
@@ -120,7 +109,7 @@ class Omnitable extends hauntedPolymer(useOmnitable)(mixin({ isEmpty }, translat
- @@ -394,25 +383,7 @@ class Omnitable extends hauntedPolymer(useOmnitable)(mixin({ isEmpty }, translat }, settings: { - type: Object - }, - - /** - * List of visible columns. - */ - visibleColumns: { - type: Array, - notify: true, - computed: '_computeVisibleColumns(columns, settings)' - }, - - - /** - * @deprecated - * // TODO: drop with next major release - */ - disabledColumns: { - type: Array, + type: Object, notify: true }, @@ -577,7 +548,7 @@ class Omnitable extends hauntedPolymer(useOmnitable)(mixin({ isEmpty }, translat _onColumnEditableChanged(event) { event.stopPropagation(); const { detail: { column }} = event, - { visibleColumns: columns } = this; + { columns } = this; if (!Array.isArray(columns) || columns.length === 0) { return; @@ -587,8 +558,8 @@ class Omnitable extends hauntedPolymer(useOmnitable)(mixin({ isEmpty }, translat if (index < 0) { return; } - // TODO: review if this is necessary - this.notifyPath(['visibleColumns', index, 'editable']); + + this.columns = [...this.columns]; } _onKey(e) { @@ -757,21 +728,6 @@ class Omnitable extends hauntedPolymer(useOmnitable)(mixin({ isEmpty }, translat } } - _computeVisibleColumns(columns, settings) { - return normalizeSettings(columns, settings) - .flatMap(s => { - if (s.disabled) { - return []; - } - const column = columns.find(c => c.name === s.name); - if (!column) { - return []; - } - return [Object.assign(column, { priority: s.priority ?? column.priority })]; - }) - .map((c, i) => Object.assign(c, { columnIndex: i })); - } - /** * Checks if the column setup is valid and logs errors. * As a separate functions to make testing easier. @@ -1403,11 +1359,10 @@ class Omnitable extends hauntedPolymer(useOmnitable)(mixin({ isEmpty }, translat }; } - _renderSettings(columns, settings, collapsed) { - const that = this; + _renderSettings(normalizedSettings, collapsed) { return litHtml` that.settings = s /* eslint-disable-line no-return-assign */ } + .settings=${ normalizedSettings } + .onSettings=${ this.setSettings } .collapsed=${ collapsed.map(c => c.name) } >`; } diff --git a/lib/compute-layout.js b/lib/compute-layout.js index 34f79372..4e54e79e 100644 --- a/lib/compute-layout.js +++ b/lib/compute-layout.js @@ -2,20 +2,18 @@ import { html } from 'haunted'; import { FORCE_FIT, layout } from './layout'; const - _toCss = layout => + _toCss = (layout, config) => layout .map((width, index) => width == null || width === 0 - ? `cosmoz-omnitable-resize-nub[index="${ index }"], .cell[index="${ index }"]{display:none}` - : `.cell[index="${ index }"]{width: ${ width }px;padding: 0 min(3px, ${ width / 2 }px)}` + ? `cosmoz-omnitable-resize-nub[for="${ config[index].name }"], .cell[for="${ config[index].name }"]{display:none}` + : `.cell[for="${ config[index].name }"]{width: ${ width }px;padding: 0 min(3px, ${ width / 2 }px)}` ) .join('\n'); export const computeLayout = (_columnConfigs, canvasWidth, numColumns) => { - const columnConfigs = _columnConfigs.map(({ hidden, ...config }) => - hidden ? { ...config, basis: 0, minWidth: 0, grow: 0 } : config - ), + const columnConfigs = _columnConfigs.filter(c => !c.hidden), totalWidths = columnConfigs.reduce((sum, { basis }) => sum + basis, 0); if (columnConfigs.length > 1 && totalWidths > canvasWidth) { @@ -23,14 +21,14 @@ export const return computeLayout(columnConfigs.slice(1), canvasWidth, numColumns); } - const widths = layout(columnConfigs, Math.max(canvasWidth, totalWidths), FORCE_FIT); + const widths = layout(columnConfigs, canvasWidth, FORCE_FIT); return widths.reduce((sorted, width, i) => { sorted[columnConfigs[i].index] = width; return sorted; }, new Array(numColumns).fill(undefined)); }, - toCss = layout => + toCss = (layout, config) => layout.length === 0 ? html`` - : html``; + : html``; diff --git a/lib/cosmoz-omnitable-resize-nub.js b/lib/cosmoz-omnitable-resize-nub.js index 2b6292ac..48c50adc 100644 --- a/lib/cosmoz-omnitable-resize-nub.js +++ b/lib/cosmoz-omnitable-resize-nub.js @@ -4,33 +4,33 @@ import { nothing } from 'lit-html'; const ResizeNub = host => { useEffect(() => { - let initial = 0; + let initial = 0, + initialWidth = 0; const move = ev => { host.dispatchEvent(new CustomEvent('column-resize', { bubbles: true, composed: true, detail: { - delta: ev.clientX - initial, + newWidth: Math.ceil(initialWidth + ev.pageX - initial), column: host.column } })); - initial = ev.clientX; - }, stop = () => { document.removeEventListener('pointermove', move); document.removeEventListener('pointerup', stop); }, start = ev => { - initial = ev.clientX; + initial = ev.pageX; + initialWidth = host.previousElementSibling.getBoundingClientRect().width; document.addEventListener('pointermove', move); document.addEventListener('pointerup', stop); }; host.addEventListener('pointerdown', start); return () => host.removeEventListener('pointerdown', start); - }, []); + }, [host.nextElementSibling]); return nothing; }; diff --git a/lib/cosmoz-omnitable-settings.js b/lib/cosmoz-omnitable-settings.js index bc8d121a..12af0aa3 100644 --- a/lib/cosmoz-omnitable-settings.js +++ b/lib/cosmoz-omnitable-settings.js @@ -54,56 +54,72 @@ const settingsStyles = ` } ${ checkbox } `, + parseIndex = str => { const idx = parseInt(str, 10); return isFinite(idx) ? idx : undefined; }, + // eslint-disable-next-line max-lines-per-function useSettings = host => { usePosition({ anchor: host.anchor, host }); - const { settings, onSettings } = host, + + const + { settings, onSettings } = host, meta = useMeta({ settings, onSettings }); + return { settings: host.settings, collapsed: host.collapsed, + onDown: useCallback(e => { if (!e.target.closest('.sort')) { return; } + meta.handle = e.currentTarget; }, [meta]), + onDragStart: useCallback(e => { const { target } = e, index = parseIndex(target.dataset.index); + if (!meta.handle?.contains(target) || index == null) { return e.preventDefault(); } + meta.handle = null; e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('omnitable/sort-index', index); setTimeout(() => target.classList.add('drag'), 0); target.addEventListener('dragend', e => e.target.classList.remove('drag'), { once: true }); }, [meta]), + onDragEnter: useCallback(e => { const ctg = e.currentTarget; if (ctg !== e.target) { return; } + e.preventDefault(); e.dataTransfer.dropEffect = 'move'; ctg.classList.add('dragover'); }, []), + onDragOver: useCallback(e => { e.preventDefault(); e.currentTarget.classList.add('dragover'); }, []), + onDragLeave: useCallback(e => { const ctg = e.currentTarget; if (ctg.contains(e.relatedTarget)) { return; } + ctg.classList.remove('dragover'); }, []), + onDrop: useCallback(e => { const from = parseIndex(e.dataTransfer.getData('omnitable/sort-index')), to = parseIndex(e.currentTarget.dataset.index), @@ -116,6 +132,7 @@ const settingsStyles = ` newSettings.splice(to + (from >= to ? 0 : -1), 0, newSettings.splice(from, 1)[0]); onSettings(newSettings); }, [meta]), + onToggle: useCallback(e => { const checked = e.target.checked, idx = parseIndex(e.target.closest('[data-index]')?.dataset.index), @@ -123,6 +140,7 @@ const settingsStyles = ` newSettings = settings.slice(), setting = settings[idx], priority = e.target.windeterminate ? settings.reduce((acc, s) => Math.max(acc, s.priority), 0) + 1 : setting.priority; + newSettings.splice(idx, 1, { ...settings[idx], disabled: !checked, priority }); onSettings(newSettings); }, [meta]) diff --git a/lib/layout.js b/lib/layout.js index 9f214d68..6834448d 100644 --- a/lib/layout.js +++ b/lib/layout.js @@ -1,7 +1,7 @@ const finite = num => Number.isFinite(num) ? num : 0; export const FORCE_FIT = true, - // eslint-disable-next-line max-statements + // eslint-disable-next-line max-lines-per-function, max-statements layout = (_columns, container, forceFit) => { const result = []; let columns = _columns; @@ -24,21 +24,27 @@ export const droppedContainerWidth = 0, droppedLots = 0; - // first pass: apply and drop lots with minWidth + // first pass: apply and drop lots with minWidth or grow 0 for (let i = 0; i < columns.length; i++) { const { basis, minWidth, grow } = columns[i], adjustment = freeRealEstate >= 0 ? lotSize * grow : basis * freeRealEstate / basisSum; - if (minWidth < basis + adjustment) { + if (minWidth > basis + adjustment) { + droppedBasis += basis; + droppedContainerWidth += minWidth; + droppedLots += grow; + result[i] = minWidth; continue; } - droppedBasis += basis; - droppedContainerWidth += minWidth; - droppedLots += grow; - result[i] = minWidth; + if (grow === 0) { + droppedBasis += basis; + droppedContainerWidth += basis; + result[i] = basis; + continue; + } } basisSum -= droppedBasis; @@ -56,6 +62,7 @@ export const adjustment = freeRealEstate >= 0 ? lotSize * grow : basis * freeRealEstate / basisSum; + result[i] = basis + adjustment; } diff --git a/lib/normalize-settings.js b/lib/normalize-settings.js new file mode 100644 index 00000000..7fedf17e --- /dev/null +++ b/lib/normalize-settings.js @@ -0,0 +1,27 @@ +export const + columnSymbol = Symbol('column'), + normalizeSettings = (columns = [], settings = []) => { + const cols = columns.slice(); + for (const setting of settings) { + const idx = cols.findIndex(c => c.name === setting.name); + if (idx < 0) { + continue; + } + cols.splice(idx, 1); + } + return [ + ...settings, + ...cols.map(column => { + const { name, title, priority, minWidth, width, flex } = column; + return { + name, + title, + priority, + minWidth: parseInt(minWidth, 10), + width: parseInt(width, 10), + flex: parseInt(flex, 10), + [columnSymbol]: column + }; + }) + ]; + }; diff --git a/lib/use-fast-layout.js b/lib/use-fast-layout.js index eb8aba3d..2dea3bc1 100644 --- a/lib/use-fast-layout.js +++ b/lib/use-fast-layout.js @@ -1,23 +1,34 @@ -import { useMemo } from 'haunted'; +import { useEffect, useMemo } from 'haunted'; import { toCss } from './compute-layout'; import { useResizableColumns } from './use-resizable-columns'; import { useCanvasWidth } from './use-canvas-width'; import { useTweenArray } from './use-tween-array'; -import { useLayoutConfig } from './use-layout-config'; +// import { useLayoutConfig } from './use-layout-config'; import { useLayout } from './use-layout'; +import { columnSymbol } from './normalize-settings'; -export const useFastLayout = ({ host, columns, groupOnColumn, resizeSpeedFactor }) => { +export const useFastLayout = ({ host, settings, setSettings, groupOnColumn, resizeSpeedFactor }) => { const canvasWidth = useCanvasWidth(host), - { config, setUserConfig } = useLayoutConfig(columns), - layout = useLayout({ canvasWidth, groupOnColumn, config }), + layout = useLayout({ canvasWidth, groupOnColumn, config: settings }), tweenedlayout = useTweenArray(layout, resizeSpeedFactor), - layoutCss = useMemo(() => toCss(tweenedlayout), [tweenedlayout]); + layoutCss = useMemo(() => toCss(tweenedlayout, settings), [tweenedlayout]), - useResizableColumns({ host, canvasWidth, layout, config, setUserConfig }); + collapsedColumns = useMemo(() => Array.isArray(settings) + ? settings.reduce((acc, column, index) => + layout[index] != null + || column.name === groupOnColumn?.name + || column.disabled + ? acc + : [...acc, column[columnSymbol]], + []) + : [] + , [settings, layout]); + + useResizableColumns({ host, canvasWidth, layout, setSettings: update => setSettings(update(settings)) }); return { layoutCss, - layout + collapsedColumns }; }; diff --git a/lib/use-layout.js b/lib/use-layout.js index a30a4b9a..4d059423 100644 --- a/lib/use-layout.js +++ b/lib/use-layout.js @@ -7,13 +7,14 @@ export const useLayout = ({ canvasWidth, groupOnColumn, config }) => useMemo(() } const columnConfigs = config - .map(c => ({ + .map((c, index) => ({ minWidth: c.minWidth, basis: c.width, grow: c.flex, priority: c.priority, - index: c.index, - hidden: c.column === groupOnColumn + name: c.name, + index, + hidden: c.name === groupOnColumn?.name || c.disabled })) .sort( ( diff --git a/lib/use-omnitable.js b/lib/use-omnitable.js index 49c71761..93629fea 100644 --- a/lib/use-omnitable.js +++ b/lib/use-omnitable.js @@ -1,30 +1,21 @@ -import { useMemo } from 'haunted'; +import { useMemo, useState } from 'haunted'; +import { columnSymbol, normalizeSettings } from './normalize-settings'; import { useFastLayout } from './use-fast-layout'; // eslint-disable-next-line max-lines-per-function export const useOmnitable = host => { const - { visibleColumns: columns, groupOnColumn, resizeSpeedFactor } = host, - { layoutCss, layout } = useFastLayout({ host, columns, groupOnColumn, resizeSpeedFactor }), - collapsedColumns = useMemo( - () => - Array.isArray(columns) - ? columns.reduce( - (acc, column) => - layout[column.columnIndex] != null || - column === groupOnColumn - ? acc - : [...acc, column], - [] - ) - : [], - [columns, layout] - ); + { columns, groupOnColumn, resizeSpeedFactor } = host, + [settings, setSettings] = useState([]), + normalizedSettings = useMemo(() => normalizeSettings(columns, settings), [columns, settings]), + normalizedColumns = useMemo(() => normalizedSettings.map(s => s[columnSymbol]), [columns, ...normalizedSettings.map(s => s.name)]), + { layoutCss, collapsedColumns } = useFastLayout({ host, settings: normalizedSettings, setSettings, groupOnColumn, resizeSpeedFactor }); return { layoutCss, - collapsedColumns, - // TODO: drop with next major release - disabledColumns: collapsedColumns + setSettings, + normalizedSettings, + normalizedColumns, + collapsedColumns }; }; diff --git a/lib/use-resizable-columns.js b/lib/use-resizable-columns.js index 300b911a..9cd1ba53 100644 --- a/lib/use-resizable-columns.js +++ b/lib/use-resizable-columns.js @@ -1,29 +1,27 @@ import { useEffect, useRef } from 'haunted'; +import { columnSymbol } from './normalize-settings'; -export const useResizableColumns = ({ host, canvasWidth, layout, config, setUserConfig }) => { +export const useResizableColumns = ({ host, canvasWidth, layout, setSettings }) => { const onColumnResizeRef = useRef(); - onColumnResizeRef.current = ev => setUserConfig(oldUserConfig => { + onColumnResizeRef.current = ev => setSettings(config => { const - { detail: { delta, column: { columnIndex }}} = ev, - newUserConfig = [], + { detail: { newWidth, column }} = ev, + columnIndex = config.findIndex(c => c[columnSymbol] === column), + newConfig = [], maxPriority = config.reduce((p, c) => Math.max(p, c.priority), -Infinity); for (let i = 0; i < layout.length; i++) { - newUserConfig[i] = { - width: oldUserConfig[i]?.width, - minWidth: config[i].minWidth, - priority: config[i].priority - }; + newConfig[i] = { ...config[i] }; // for visible columns to the left of the resized column - if (i <= columnIndex && layout[i]) { + if (i < columnIndex && layout[i]) { // save the current width - newUserConfig[i].width = newUserConfig[i].width ?? layout[i]; + newConfig[i].width = layout[i]; // make them fixed width - newUserConfig[i].flex = 0; + newConfig[i].flex = 0; // keep them visible - newUserConfig[i].priority = maxPriority; + newConfig[i].priority = maxPriority; } // update the width of the resized column @@ -36,11 +34,13 @@ export const useResizableColumns = ({ host, canvasWidth, layout, config, setUser return acc; }, canvasWidth); - newUserConfig[i].width = Math.min(maxNewSize, Math.max(newUserConfig[i].width + delta, config[i].minWidth)); + newConfig[i].width = Math.min(maxNewSize, Math.max(newWidth, config[i].minWidth)); + newConfig[i].flex = 0; + newConfig[i].priority = maxPriority; } } - return newUserConfig; + return newConfig; }); useEffect(() => { @@ -48,6 +48,4 @@ export const useResizableColumns = ({ host, canvasWidth, layout, config, setUser host.addEventListener('column-resize', handler); return () => host.removeEventListener('column-resize', handler); }, []); - - return config; }; diff --git a/lib/use-track-size.js b/lib/use-track-size.js index 8dd7e003..8e94f3e8 100644 --- a/lib/use-track-size.js +++ b/lib/use-track-size.js @@ -16,3 +16,4 @@ export const useTrackSize = (host, setCanvasWidth) => observer.observe(host); return () => observer.unobserve(host); }, []); +2; diff --git a/test/autocomplete.test.js b/test/autocomplete.test.js index 67c733da..63255e4c 100644 --- a/test/autocomplete.test.js +++ b/test/autocomplete.test.js @@ -1,5 +1,5 @@ import { - assert, html + assert, html, nextFrame } from '@open-wc/testing'; import { setupOmnitableFixture } from './helpers/utils'; @@ -27,7 +27,7 @@ const data = [{ name: 'Item 3' }], basicFixture = html` - + @@ -46,8 +46,9 @@ suite('autocomplete unit tests', () => { column = omnitable.columns[0]; }); - test('basic render test', () => { + test('basic render test', async () => { polymerFlush(); + await nextFrame(); const cells = Array.from(omnitable.shadowRoot.querySelectorAll('.default-column')); assert.lengthOf(cells, 12); assert.deepEqual(cells.map(cell => cell.innerText), ['0', 'group0', 'Item 0', '1', 'group0', 'Item 1', '2', 'group1', 'Item 2', '3', 'group1', 'Item 3']); diff --git a/test/basic.test.js b/test/basic.test.js index 74997ec2..3df4536c 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -47,18 +47,6 @@ suite('basic', () => { assert.equal(date, omnitable._getColumn('date1')); }); - test('it updates visibleColumns', () => { - assert.deepEqual(omnitable.visibleColumns, omnitable.columns); - - omnitable.groupOn = 'date2'; - omnitable.flush(); - assert.deepEqual(omnitable.visibleColumns, omnitable.columns); - - omnitable.groupOn = ''; - omnitable.flush(); - assert.deepEqual(omnitable.visibleColumns, omnitable.columns); - }); - test('sets column groupOn property to valuePath when group-on attribute is missing', () => { const column = omnitable.columns.find(col => col.name === 'columnWithoutGroupOn'); assert.equal(column.groupOn, 'valuePath'); @@ -321,20 +309,17 @@ suite('visible', () => { `, generateTableDemoData(10, 11, 25)); - assert.isUndefined(omnitable.visibleColumns); assert.isFalse(omnitable.visible); omnitable.style.display = ''; omnitable.flush(); await nextFrame(); - assert.deepEqual(omnitable.visibleColumns, omnitable.columns); assert.isTrue(omnitable.visible); omnitable.style.display = 'none'; omnitable.flush(); await nextFrame(); assert.isFalse(omnitable.visible); - }); }); diff --git a/test/boolean.test.js b/test/boolean.test.js index 8d6ddc82..839431de 100644 --- a/test/boolean.test.js +++ b/test/boolean.test.js @@ -22,7 +22,7 @@ suite('boolen', () => { { boolean: 'true' } ]; const omnitable = await setupOmnitableFixture(html` - + diff --git a/test/group.test.js b/test/group.test.js index fe3d2b6a..ac99500c 100644 --- a/test/group.test.js +++ b/test/group.test.js @@ -15,7 +15,7 @@ suite('id', () => { setup(async () => { data = generateTableDemoData(10, 11, 25); omnitable = await setupOmnitableFixture(html` - + `, data); diff --git a/test/hash-param.test.js b/test/hash-param.test.js index ed241557..6c5e4fcb 100644 --- a/test/hash-param.test.js +++ b/test/hash-param.test.js @@ -1,5 +1,5 @@ import { - assert, html + assert, html, nextFrame } from '@open-wc/testing'; import { setupOmnitableFixture } from './helpers/utils'; @@ -29,7 +29,7 @@ const data = [{ location = window.location, instantiate = async () => { omnitable = await setupOmnitableFixture(html` - + @@ -38,6 +38,7 @@ const data = [{ `, data); + await nextFrame(); }; suite('basic-read', () => { diff --git a/test/integration/column-number.test.js b/test/integration/column-number.test.js index 5e51e21f..3617905f 100644 --- a/test/integration/column-number.test.js +++ b/test/integration/column-number.test.js @@ -63,7 +63,7 @@ suite('cosmoz-omnitable-column-number', () => { setup(async () => { omnitable = await setupOmnitableFixture(html` - + @@ -71,6 +71,7 @@ suite('cosmoz-omnitable-column-number', () => { flush(); omnitable.flush(); + await nextFrame(); }); test('filters the table', async () => { diff --git a/test/integration/templatize.test.js b/test/integration/templatize.test.js index 2d321ce3..07608587 100644 --- a/test/integration/templatize.test.js +++ b/test/integration/templatize.test.js @@ -1,5 +1,5 @@ import { - expect, html + expect, html, nextFrame } from '@open-wc/testing'; import { setupOmnitableFixture } from '../helpers/utils'; @@ -13,7 +13,7 @@ suite('Basic omnitable functionality', () => { setup(async () => { omnitable = await setupOmnitableFixture(html` - + { bool: true }]); polymerFlush(); + await nextFrame(); }); test('should display headers as configured', () => { @@ -80,11 +81,13 @@ suite('Basic omnitable functionality', () => { expect(cells.map(c => c.innerText)).to.deep.equal(['item 4', 'Overriden item 4', 'item 5', 'Overriden item 5', 'item 6', 'Overriden item 6']); }); - test('should use editable template when the column is editable', () => { + test('should use editable template when the column is editable', async () => { omnitable.columns.forEach(c => { c.editable = true; }); + await nextFrame(); + const cells = Array.from(omnitable.shadowRoot.querySelectorAll('.basic-column-cell')); expect(cells.map(c => c.innerText)).to.deep.equal(['Edit: item 1', 'Edit: item 1', 'Edit: item 2', 'Edit: item 2', 'Edit: item 3', 'Edit: item 3']); }); diff --git a/test/list.test.js b/test/list.test.js index c4f97c71..7c431820 100644 --- a/test/list.test.js +++ b/test/list.test.js @@ -1,5 +1,5 @@ import { - assert, html + assert, html, nextFrame } from '@open-wc/testing'; import { setupOmnitableFixture } from './helpers/utils'; @@ -17,7 +17,7 @@ suite('basic', () => { { list: ['item 1', 'item 2', 'item 3']} ]; const omnitable = await setupOmnitableFixture(html` - + @@ -83,6 +83,7 @@ suite('horizontal', () => { test('basic render', async () => { polymerFlush(); + await nextFrame(); const cells = Array.from(omnitable.shadowRoot.querySelectorAll('[slot="item-cell"]')); assert.lengthOf(cells, 2); diff --git a/test/range-date.test.js b/test/range-date.test.js index 27d8db61..7e3846c3 100644 --- a/test/range-date.test.js +++ b/test/range-date.test.js @@ -1,6 +1,6 @@ /* eslint-disable max-lines */ import { - assert, html + assert, html, nextFrame } from '@open-wc/testing'; import sinon from 'sinon'; @@ -51,7 +51,7 @@ const data = [{ time: '00:00:00' }], rangeFixture = html` - + @@ -71,6 +71,7 @@ suite('render', () => { test('basic render', async () => { const omnitable = await setupOmnitableFixture(rangeFixture, data); polymerFlush(); + await nextFrame(); const cells = Array.from(omnitable.shadowRoot.querySelectorAll('[slot="item-cell"]')); assert.isAtLeast(cells.length, 20); diff --git a/test/range.test.js b/test/range.test.js index 72b77db1..d7e28064 100644 --- a/test/range.test.js +++ b/test/range.test.js @@ -58,7 +58,7 @@ const data = [{ } }], rangeFixture = html` - + diff --git a/test/xlsx-export.test.js b/test/xlsx-export.test.js index 20725292..eeb50a3b 100644 --- a/test/xlsx-export.test.js +++ b/test/xlsx-export.test.js @@ -52,7 +52,7 @@ suite('xlsx-export-omnitable', () => { setup(async () => { omnitable = await setupOmnitableFixture(html` - + From c9007f6b98b73ff3bb865dd52880d92788f2aff4 Mon Sep 17 00:00:00 2001 From: Cristian Necula Date: Tue, 7 Sep 2021 12:30:12 +0300 Subject: [PATCH 2/4] refactor: renamed layout vars for consistency --- lib/compute-layout.js | 2 +- lib/layout.js | 48 +++++++++++++++++++++---------------------- lib/use-layout.js | 4 ++-- test/layout.test.js | 2 +- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/compute-layout.js b/lib/compute-layout.js index 4e54e79e..5a9b04f7 100644 --- a/lib/compute-layout.js +++ b/lib/compute-layout.js @@ -14,7 +14,7 @@ const export const computeLayout = (_columnConfigs, canvasWidth, numColumns) => { const columnConfigs = _columnConfigs.filter(c => !c.hidden), - totalWidths = columnConfigs.reduce((sum, { basis }) => sum + basis, 0); + totalWidths = columnConfigs.reduce((sum, { width }) => sum + width, 0); if (columnConfigs.length > 1 && totalWidths > canvasWidth) { // drop a column diff --git a/lib/layout.js b/lib/layout.js index 6834448d..43909e06 100644 --- a/lib/layout.js +++ b/lib/layout.js @@ -7,48 +7,48 @@ export const let columns = _columns; if (forceFit) { - columns = _columns.map((c, index) => index === 0 ? { ...c, grow: 1 } : c); + columns = _columns.map((c, index) => index === 0 ? { ...c, flex: 1 } : c); } // eslint-disable-next-line one-var - let [basisSum, lots] = columns.reduce( - ([basisSum, lots], { basis, grow }) => [ - basisSum + basis, - lots + grow + let [widthSum, lots] = columns.reduce( + ([widthSum, lots], { width, flex }) => [ + widthSum + width, + lots + flex ], [0, 0] ), - freeRealEstate = container - basisSum, + freeRealEstate = container - widthSum, lotSize = finite(freeRealEstate / lots), - droppedBasis = 0, + droppedWidth = 0, droppedContainerWidth = 0, droppedLots = 0; - // first pass: apply and drop lots with minWidth or grow 0 + // first pass: apply and drop lots with minWidth or flex 0 for (let i = 0; i < columns.length; i++) { - const { basis, minWidth, grow } = columns[i], + const { width, minWidth, flex } = columns[i], adjustment = freeRealEstate >= 0 - ? lotSize * grow - : basis * freeRealEstate / basisSum; + ? lotSize * flex + : width * freeRealEstate / widthSum; - if (minWidth > basis + adjustment) { - droppedBasis += basis; + if (minWidth > width + adjustment) { + droppedWidth += width; droppedContainerWidth += minWidth; - droppedLots += grow; + droppedLots += flex; result[i] = minWidth; continue; } - if (grow === 0) { - droppedBasis += basis; - droppedContainerWidth += basis; - result[i] = basis; + if (flex === 0) { + droppedWidth += width; + droppedContainerWidth += width; + result[i] = width; continue; } } - basisSum -= droppedBasis; - freeRealEstate = container - droppedContainerWidth - basisSum; + widthSum -= droppedWidth; + freeRealEstate = container - droppedContainerWidth - widthSum; lots -= droppedLots; lotSize = finite(freeRealEstate / lots); @@ -58,12 +58,12 @@ export const continue; } - const { basis, grow } = columns[i], + const { width, flex } = columns[i], adjustment = freeRealEstate >= 0 - ? lotSize * grow - : basis * freeRealEstate / basisSum; + ? lotSize * flex + : width * freeRealEstate / widthSum; - result[i] = basis + adjustment; + result[i] = width + adjustment; } return result; diff --git a/lib/use-layout.js b/lib/use-layout.js index 4d059423..b0518712 100644 --- a/lib/use-layout.js +++ b/lib/use-layout.js @@ -9,8 +9,8 @@ export const useLayout = ({ canvasWidth, groupOnColumn, config }) => useMemo(() const columnConfigs = config .map((c, index) => ({ minWidth: c.minWidth, - basis: c.width, - grow: c.flex, + width: c.width, + flex: c.flex, priority: c.priority, name: c.name, index, diff --git a/test/layout.test.js b/test/layout.test.js index fab552ef..f633808e 100644 --- a/test/layout.test.js +++ b/test/layout.test.js @@ -1,7 +1,7 @@ import { assert } from '@open-wc/testing'; import { FORCE_FIT, layout } from '../lib/layout'; -const toObj = ([basis, minWidth, grow]) => ({ basis, minWidth, grow }); +const toObj = ([width, minWidth, flex]) => ({ width, minWidth, flex }); suite('layout algorithm', () => { test('it works', () => { From d883bcd9e7272fc16f6c6849b53e0220fb279945 Mon Sep 17 00:00:00 2001 From: Cristian Necula Date: Tue, 7 Sep 2021 12:31:49 +0300 Subject: [PATCH 3/4] chore: fix lint errors --- cosmoz-omnitable.js | 1 - lib/use-fast-layout.js | 3 +-- lib/use-layout-config.js | 27 --------------------------- lib/use-track-size.js | 2 +- 4 files changed, 2 insertions(+), 31 deletions(-) delete mode 100644 lib/use-layout-config.js diff --git a/cosmoz-omnitable.js b/cosmoz-omnitable.js index 0b2bbba6..741554fe 100644 --- a/cosmoz-omnitable.js +++ b/cosmoz-omnitable.js @@ -37,7 +37,6 @@ import { mixin, hauntedPolymer } from '@neovici/cosmoz-utils'; import { isEmpty } from '@neovici/cosmoz-utils/lib/template.js'; import { useOmnitable } from './lib/use-omnitable'; import './lib/cosmoz-omnitable-settings'; -import { columnSymbol } from './lib/normalize-settings'; const PROPERTY_HASH_PARAMS = ['sortOn', 'groupOn', 'descending', 'groupOnDescending']; diff --git a/lib/use-fast-layout.js b/lib/use-fast-layout.js index 2dea3bc1..bc26fa9e 100644 --- a/lib/use-fast-layout.js +++ b/lib/use-fast-layout.js @@ -1,9 +1,8 @@ -import { useEffect, useMemo } from 'haunted'; +import { useMemo } from 'haunted'; import { toCss } from './compute-layout'; import { useResizableColumns } from './use-resizable-columns'; import { useCanvasWidth } from './use-canvas-width'; import { useTweenArray } from './use-tween-array'; -// import { useLayoutConfig } from './use-layout-config'; import { useLayout } from './use-layout'; import { columnSymbol } from './normalize-settings'; diff --git a/lib/use-layout-config.js b/lib/use-layout-config.js deleted file mode 100644 index a8773cb0..00000000 --- a/lib/use-layout-config.js +++ /dev/null @@ -1,27 +0,0 @@ -import { useMemo, useState } from 'haunted'; - -export const useLayoutConfig = columns => { - const - initialConfig = useMemo(() => !columns - ? [] - : columns.map(column => ({ - column, - minWidth: parseInt(column.minWidth, 10), - width: parseInt(column.width, 10), - flex: parseInt(column.flex, 10), - priority: column.priority ?? 0, - index: column.columnIndex - })), [columns]), - - [userConfig, setUserConfig] = useState([]), - - config = useMemo(() => initialConfig.map(c => ({ - ...c, - minWidth: userConfig[c.index]?.minWidth ?? c.minWidth, - width: userConfig[c.index]?.width ?? c.width, - flex: userConfig[c.index]?.flex ?? c.flex, - priority: userConfig[c.index]?.priority ?? c.priority - })), [initialConfig, userConfig]); - - return { config, setUserConfig }; -}; diff --git a/lib/use-track-size.js b/lib/use-track-size.js index 8e94f3e8..ec60f3e2 100644 --- a/lib/use-track-size.js +++ b/lib/use-track-size.js @@ -16,4 +16,4 @@ export const useTrackSize = (host, setCanvasWidth) => observer.observe(host); return () => observer.unobserve(host); }, []); -2; + From 9eb1ce2da5eb10d6462d7dd3b295e09f2ddc3e9f Mon Sep 17 00:00:00 2001 From: Cristian Necula Date: Tue, 7 Sep 2021 12:52:37 +0300 Subject: [PATCH 4/4] fix: resize handle misaligned when filters are set --- cosmoz-omnitable-styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cosmoz-omnitable-styles.js b/cosmoz-omnitable-styles.js index e6cca0b2..b6d8c308 100644 --- a/cosmoz-omnitable-styles.js +++ b/cosmoz-omnitable-styles.js @@ -139,7 +139,7 @@ export default `