diff --git a/spec/e2e/html/2864_nested_resize_reflow.html b/spec/e2e/html/2864_nested_resize_reflow.html new file mode 100644 index 00000000..a325604e --- /dev/null +++ b/spec/e2e/html/2864_nested_resize_reflow.html @@ -0,0 +1,42 @@ + + + + + + + 2864 nest grid resize + + + + + +

2864 nest grid resize

+

Test for nested grid resize reflowing content (manually and API)

+ resize +
+ +
+ + + diff --git a/spec/regression-spec.ts b/spec/regression-spec.ts index a4c86104..5d296a6c 100644 --- a/spec/regression-spec.ts +++ b/spec/regression-spec.ts @@ -7,6 +7,10 @@ describe('regression >', function() { let findEl = function(id: string): GridItemHTMLElement { return grid.engine.nodes.find(n => n.id === id)!.el!; }; + let findSubEl = function(id: string, index = 0): GridItemHTMLElement { + return grid.engine.nodes[index].subGrid?.engine.nodes.find(n => n.id === id)!.el!; + }; + // empty grid let gridstackEmptyHTML = @@ -55,4 +59,51 @@ describe('regression >', function() { expect(parseInt(el2.getAttribute('gs-y'), 10)).toBe(0); }); }); + + describe('2865 nested grid resize >', function() { + beforeEach(function() { + document.body.insertAdjacentHTML('afterbegin', gridstackEmptyHTML); + }); + afterEach(function() { + document.body.removeChild(document.getElementById('gs-cont')); + }); + it('', function() { + let children: GridStackWidget[] = [{},{},{}]; + let items: GridStackWidget[] = [ + {x: 0, y: 0, w:3, h:3, sizeToContent: true, subGridOpts: {children, column: 'auto'}} + ]; + let count = 0; + [...items, ...children].forEach(n => n.id = String(count++)); + grid = GridStack.init({cellHeight: 70, margin: 5, children: items}); + + let nested = findEl('0'); + let el1 = findSubEl('1'); + let el2 = findSubEl('2'); + let el3 = findSubEl('3'); + expect(parseInt(nested.getAttribute('gs-x'), 10)).toBe(0); + expect(parseInt(nested.getAttribute('gs-y'), 10)).toBe(0); + expect(parseInt(nested.getAttribute('gs-w'), 10)).toBe(3); + expect(nested.getAttribute('gs-h')).toBe(null); // sizeToContent 3 -> 1 which is null + expect(parseInt(el1.getAttribute('gs-x'), 10)).toBe(0); + expect(parseInt(el1.getAttribute('gs-y'), 10)).toBe(0); + expect(parseInt(el2.getAttribute('gs-x'), 10)).toBe(1); + expect(parseInt(el2.getAttribute('gs-y'), 10)).toBe(0); + expect(parseInt(el3.getAttribute('gs-x'), 10)).toBe(2); + expect(parseInt(el3.getAttribute('gs-y'), 10)).toBe(0); + + // now resize the nested grid to 2 -> should reflow el3 + grid.update(nested, {w:2}); + expect(parseInt(nested.getAttribute('gs-x'), 10)).toBe(0); + expect(parseInt(nested.getAttribute('gs-y'), 10)).toBe(0); + expect(parseInt(nested.getAttribute('gs-w'), 10)).toBe(2); + expect(nested.getAttribute('gs-h')).toBe(null); // sizeToContent not called until some delay + expect(parseInt(el1.getAttribute('gs-x'), 10)).toBe(0); + expect(parseInt(el1.getAttribute('gs-y'), 10)).toBe(0); + expect(parseInt(el2.getAttribute('gs-x'), 10)).toBe(1); + expect(parseInt(el2.getAttribute('gs-y'), 10)).toBe(0); + // 3rd item pushed to next row + expect(parseInt(el3.getAttribute('gs-x'), 10)).toBe(0); + expect(parseInt(el3.getAttribute('gs-y'), 10)).toBe(1); + }); + }); }); diff --git a/spec/test.html b/spec/test.html index 32693f39..b69153ed 100644 --- a/spec/test.html +++ b/spec/test.html @@ -6,6 +6,7 @@ Grid Spec test + @@ -22,15 +23,21 @@

Grid Spec test

diff --git a/src/gridstack.ts b/src/gridstack.ts index af9120a7..a72f0920 100644 --- a/src/gridstack.ts +++ b/src/gridstack.ts @@ -219,6 +219,9 @@ export class GridStack { /** point to a parent grid item if we're nested (inside a grid-item in between 2 Grids) */ public parentGridNode?: GridStackNode; + /** time to wait for animation (if enabled) to be done so content sizing can happen */ + public animationDelay = 300 + 10; + protected static engineClass: typeof GridStackEngine; protected resizeObserver: ResizeObserver; @@ -1345,7 +1348,12 @@ export class GridStack { if (m) { const widthChanged = (m.w !== undefined && m.w !== n.w); this.moveNode(n, m); - this.resizeToContentCheck(widthChanged, n); // wait for animation if we changed width + if (widthChanged && n.subGrid) { + // if we're animating the client size hasn't changed yet, so force a change (not exact size) + n.subGrid.onResize(this.hasAnimationCSS() ? n.w : undefined); + } else { + this.resizeToContentCheck(widthChanged, n); + } delete n._orig; // clear out original position now that we moved #2669 } if (m || changed) { @@ -1774,11 +1782,11 @@ export class GridStack { * and remember the prev columns we used, or get our count from parent, as well as check for cellHeight==='auto' (square) * or `sizeToContent` gridItem options. */ - public onResize(): GridStack { - if (!this.el?.clientWidth) return; // return if we're gone or no size yet (will get called again) - if (this.prevWidth === this.el.clientWidth) return; // no-op - this.prevWidth = this.el.clientWidth - // console.log('onResize ', this.el.clientWidth); + public onResize(clientWidth = this.el?.clientWidth): GridStack { + if (!clientWidth) return; // return if we're gone or no size yet (will get called again) + if (this.prevWidth === clientWidth) return; // no-op + this.prevWidth = clientWidth + // console.log('onResize ', clientWidth); this.batchUpdate(); @@ -1786,7 +1794,7 @@ export class GridStack { let columnChanged = false; if (this._autoColumn && this.parentGridNode) { if (this.opts.column !== this.parentGridNode.w) { - this.column(this.parentGridNode.w, this.opts.layout || 'none'); + this.column(this.parentGridNode.w, this.opts.layout || 'list'); columnChanged = true; } } else { @@ -1816,7 +1824,7 @@ export class GridStack { // update any gridItem height with sizeToContent, but wait for DOM $animation_speed to settle if we changed column count // TODO: is there a way to know what the final (post animation) size of the content will be so we can animate the column width and height together rather than sequentially ? - if (delay && this.hasAnimationCSS()) return setTimeout(() => this.resizeToContentCheck(false, n), 300 + 10); + if (delay && this.hasAnimationCSS()) return setTimeout(() => this.resizeToContentCheck(false, n), this.animationDelay); if (n) { if (Utils.shouldSizeToContent(n)) this.resizeToContentCBCheck(n.el);