Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/dom/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@

- Refine the public types: `getScrollContainer` types `direction` as a union, `isEmpty` takes any `Node`, `isFormElement` accepts a missing element, `getPhrasingContentSchema` returns `ContentSchema`, `allowEmpty` is optional in a `Schema` item, and `Schema` and `SchemaItem` are exported ([#84317](https://github.com/WordPress/gutenberg/pull/84317)).

### Bug Fixes

- `getOffsetParent`: Fix an infinite loop when the parent of the node is not an element ([#84374](https://github.com/WordPress/gutenberg/pull/84374)).

### Internal

- Refactor to TypeScript ([#84317](https://github.com/WordPress/gutenberg/pull/84317)).
Expand Down
13 changes: 6 additions & 7 deletions packages/dom/src/dom/get-offset-parent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import getComputedStyle from './get-computed-style';
import isElement from './is-element';

/**
* Returns the closest positioned element, or null under any of the conditions
Expand All @@ -14,11 +15,9 @@ import getComputedStyle from './get-computed-style';
export default function getOffsetParent( node: Node ): Node | null {
// Cannot retrieve computed style or offset parent only anything other than
// an element node, so find the closest element node.
let closestElement;
while ( ( closestElement = node.parentNode as Node ) ) {
if ( closestElement.nodeType === closestElement.ELEMENT_NODE ) {
break;
}
let closestElement = node.parentNode;
while ( closestElement && ! isElement( closestElement ) ) {
closestElement = closestElement.parentNode;
}

if ( ! closestElement ) {
Expand All @@ -27,10 +26,10 @@ export default function getOffsetParent( node: Node ): Node | null {

// If the closest element is already positioned, return it, as offsetParent
// does not otherwise consider the node itself.
if ( getComputedStyle( closestElement as Element ).position !== 'static' ) {
if ( getComputedStyle( closestElement ).position !== 'static' ) {
return closestElement;
}

// offsetParent is undocumented/draft.
return ( closestElement as Node & { offsetParent: Node } ).offsetParent;
return ( closestElement as HTMLElement ).offsetParent;
}
21 changes: 21 additions & 0 deletions packages/dom/src/test/dom.jsdom.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
isTextField,
removeInvalidHTML,
isEmpty,
getOffsetParent,
} from '../dom';
import { getPhrasingContentSchema } from '../phrasing-content';

Expand Down Expand Up @@ -170,6 +171,26 @@ describe( 'DOM', () => {
);
} );
} );

describe( 'getOffsetParent', () => {
it( 'should return the closest element when it is positioned', () => {
parent.style.position = 'relative';
const text = document.createTextNode( 'text' );
parent.appendChild( text );

expect( getOffsetParent( text ) ).toBe( parent );
} );

it( 'should return null when no ancestor is an element', () => {
expect( getOffsetParent( document.documentElement ) ).toBe( null );

const fragment = document.createDocumentFragment();
const text = document.createTextNode( 'text' );
fragment.appendChild( text );

expect( getOffsetParent( text ) ).toBe( null );
} );
} );
} );

describe( 'removeInvalidHTML', () => {
Expand Down
Loading