Skip to content

Commit

Permalink
tweaks to resizeToContent()
Browse files Browse the repository at this point in the history
* fix resizeToContent() to handle node.h (using when cellHeight changes or we resize) vs DOM sizing (rest of the time)
more gridstack#404
  • Loading branch information
adumesny committed Sep 6, 2023
1 parent bb542d7 commit 75a7fac
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 52 deletions.
1 change: 1 addition & 0 deletions doc/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ Change log

## 9.1.0-dev (TBD)
* fix [#2435](https://github.com/gridstack/gridstack.js/issues/2435) directionCollideCoverage() tweaks
* fix resizeToContent() to handle node.h (using when cellHeight changes or we resize) vs DOM sizing (rest of the time)

## 9.1.0 (2023-09-04)
* renamed fitToContent to sizeToContent (API BREAK)
Expand Down
2 changes: 1 addition & 1 deletion src/gridstack.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ $animation_speed: .3s !default;
overflow-x: hidden;
overflow-y: auto;
}
&.size-to-content > .grid-stack-item-content {
&.size-to-content:not(.size-to-content-max) > .grid-stack-item-content {
overflow-y: hidden;
}
}
Expand Down
102 changes: 51 additions & 51 deletions src/gridstack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ export class GridStack {
this.opts.cellHeightUnit = data.unit;
this.opts.cellHeight = data.h;

this.doContentResize(false);
this.doContentResize(false, true); // no anim wait, but use attributes since we only change row height

if (update) {
this._updateStyles(true); // true = force re-create for current # of rows
Expand Down Expand Up @@ -1002,7 +1002,7 @@ export class GridStack {

this._updateContainerHeight();

this.doContentResize(false, node);
this.doContentResize(false, false, node);

// see if there is a sub-grid to create
if (node.subGridOpts) {
Expand Down Expand Up @@ -1262,54 +1262,54 @@ export class GridStack {
this.engine.endUpdate();
}

/** Updates widget height to match the content height to avoid v-scrollbar or dead space.
Note: this assumes only 1 child under '.grid-stack-item-content' (sized to gridItem minus padding) that is at the entire content size wanted */
public resizeToContent(els: GridStackElement) {
GridStack.getElements(els).forEach(el => {
if (!el.clientHeight) return; // 0 when hidden, skip
let n = el?.gridstackNode;
if (!n) return;
const grid = n.grid;
if (grid !== this) return grid?.resizeToContent(el);
if (el.parentElement !== this.el) return; // skip if we are not inside a grid
const cell = this.getCellHeight();
if (!cell) return;
let height = n.h ? n.h * cell : el.clientHeight; // getBoundingClientRect().height seem to flicker back and forth
let item: Element;
if (n.resizeToContentParent) item = el.querySelector(n.resizeToContentParent);
if (!item) item = el.querySelector(GridStack.resizeToContentParent);
if (!item) return;
const child = item.firstElementChild;
// NOTE: clientHeight & getBoundingClientRect() is undefined for text and other leaf nodes. use <div> container!
if (!child) { console.log(`Error: resizeToContent() '${GridStack.resizeToContentParent}'.firstElementChild is null, make sure to have a div like container. Skipping sizing.`); return; }
const padding = el.clientHeight - item.clientHeight; // full - available height to our child (minus border, padding...)
const itemH = n.h ? n.h * cell - padding : item.clientHeight; // calculated to what cellHeight is or will become (rather than actual to prevent waiting for animation to finish)
const wantedH = child.getBoundingClientRect().height || itemH;
if (itemH === wantedH) return;
height += wantedH - itemH;
let h = Math.ceil(height / cell);
// check for min/max and special sizing
const softMax = Number.isInteger(n.sizeToContent) ? n.sizeToContent as number : 0;
if (softMax) {
if (h > softMax) {
h = softMax;
el.classList.remove('size-to-content'); // get v-scroll back
} else el.classList.add('size-to-content');
}
if (n.minH && h < n.minH) h = n.minH;
else if (n.maxH && h > n.maxH) h = n.maxH;
if (h !== n.h) {
this._ignoreLayoutsNodeChange = true;
this.moveNode(n, {h});
delete this._ignoreLayoutsNodeChange;
}
});
/**
* Updates widget height to match the content height to avoid v-scrollbar or dead space.
* Note: this assumes only 1 child under resizeToContentParent='.grid-stack-item-content' (sized to gridItem minus padding) that is at the entire content size wanted.
* useAttrSize set to true if GridStackNode.h should be used instead of actual container height when we don't need to wait for animation to finish to get actual DOM heights
**/
public resizeToContent(el: GridItemHTMLElement, useAttrSize = false) {
el?.classList.remove('size-to-content-max');
if (!el?.clientHeight) return; // 0 when hidden, skip
let n = el.gridstackNode;
if (!n) return;
const grid = n.grid;
if (!grid) return;
if (el.parentElement !== grid.el) return; // skip if we are not inside a grid
const cell = grid.getCellHeight();
if (!cell) return;
let height = useAttrSize && n.h ? n.h * cell : el.clientHeight; // getBoundingClientRect().height seem to flicker back and forth
let item: Element;
if (n.resizeToContentParent) item = el.querySelector(n.resizeToContentParent);
if (!item) item = el.querySelector(GridStack.resizeToContentParent);
if (!item) return;
const child = item.firstElementChild;
// NOTE: clientHeight & getBoundingClientRect() is undefined for text and other leaf nodes. use <div> container!
if (!child) { console.log(`Error: resizeToContent() '${GridStack.resizeToContentParent}'.firstElementChild is null, make sure to have a div like container. Skipping sizing.`); return; }
const padding = el.clientHeight - item.clientHeight; // full - available height to our child (minus border, padding...)
const itemH = useAttrSize && n.h ? n.h * cell - padding : item.clientHeight; // calculated to what cellHeight is or will become (rather than actual to prevent waiting for animation to finish)
const wantedH = child.getBoundingClientRect().height || itemH;
if (itemH === wantedH) return;
height += wantedH - itemH;
let h = Math.ceil(height / cell);
// check for min/max and special sizing
const softMax = Number.isInteger(n.sizeToContent) ? n.sizeToContent as number : 0;
if (softMax && h > softMax) {
h = softMax;
el.classList.add('size-to-content-max'); // get v-scroll back
}
if (n.minH && h < n.minH) h = n.minH;
else if (n.maxH && h > n.maxH) h = n.maxH;
if (h !== n.h) {
grid._ignoreLayoutsNodeChange = true;
grid.moveNode(n, {h});
delete grid._ignoreLayoutsNodeChange;
}
}

/** call the user resize (so we can do extra work) else our build in version */
protected resizeToContentCheck(el: GridItemHTMLElement) {
protected resizeToContentCheck(el: GridItemHTMLElement, useAttr = false) {
if (GridStack.resizeToContentCB) GridStack.resizeToContentCB(el);
else this.resizeToContent(el);
else this.resizeToContent(el, useAttr);
}

/**
Expand Down Expand Up @@ -1647,24 +1647,24 @@ export class GridStack {
this.engine.nodes.forEach(n => {
if (n.subGrid) n.subGrid.onResize()
});
this.doContentResize(columnChanged);
this.doContentResize(columnChanged); // wait for anim of column changed (DOM reflow before we can size correctly)

this.batchUpdate(false);

return this;
}

private doContentResize(delay = true, n: GridStackNode = undefined) {
private doContentResize(delay = true, useAttr = false, n: GridStackNode = undefined) {
// 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 ?
setTimeout(() => {
if (n) {
if (Utils.shouldSizeToContent(n)) this.resizeToContentCheck(n.el);
if (Utils.shouldSizeToContent(n)) this.resizeToContentCheck(n.el, useAttr);
} else {
const nodes = [...this.engine.nodes]; // in case order changes while resizing one
this.batchUpdate();
nodes.forEach(n => {
if (Utils.shouldSizeToContent(n)) this.resizeToContentCheck(n.el);
if (Utils.shouldSizeToContent(n)) this.resizeToContentCheck(n.el, useAttr);
});
this.batchUpdate(false);
}
Expand Down Expand Up @@ -2247,7 +2247,7 @@ export class GridStack {

if (event.type === 'resizestop') {
if (Number.isInteger(node.sizeToContent)) node.sizeToContent = node.h; // new soft limit
this.doContentResize(false, node);
this.doContentResize(false, true, node); // no amin wait as will use the actual sized coordinate attr
}
}

Expand Down

0 comments on commit 75a7fac

Please sign in to comment.