Skip to content

Commit 35d30d7

Browse files
authored
add element replaceChildren
1 parent f715af6 commit 35d30d7

3 files changed

Lines changed: 64 additions & 1 deletion

File tree

src/element-replacechildren.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
export function replaceChildren(this: Element | Document | DocumentFragment, ...children: Node[]) {
2+
while (this.firstChild) this.removeChild(this.firstChild)
3+
this.append(...children)
4+
}
5+
6+
/*#__PURE__*/
7+
export function isSupported(): boolean {
8+
return (
9+
'replaceChildren' in Element.prototype &&
10+
typeof Element.prototype.replaceChildren === 'function' &&
11+
'replaceChildren' in Document.prototype &&
12+
typeof Document.prototype.replaceChildren === 'function' &&
13+
'replaceChildren' in DocumentFragment.prototype &&
14+
typeof DocumentFragment.prototype.replaceChildren === 'function'
15+
)
16+
}
17+
18+
/*#__PURE__*/
19+
export function isPolyfilled(): boolean {
20+
return (
21+
Element.prototype.replaceChildren === replaceChildren &&
22+
Document.prototype.replaceChildren === replaceChildren &&
23+
DocumentFragment.prototype.replaceChildren === replaceChildren
24+
)
25+
}
26+
27+
export function apply(): void {
28+
if (!isSupported()) {
29+
Element.prototype.replaceChildren =
30+
Document.prototype.replaceChildren =
31+
DocumentFragment.prototype.replaceChildren =
32+
replaceChildren
33+
}
34+
}

src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as abortSignalTimeout from './abortsignal-timeout.js'
33
import * as aggregateError from './aggregateerror.js'
44
import * as arrayAt from './arraylike-at.js'
55
import * as cryptoRandomUUID from './crypto-randomuuid.js'
6+
import * as elementReplaceChildren from './element-replacechildren.js'
67
import * as eventAbortSignal from './event-abortsignal.js'
78
import * as objectHasOwn from './object-hasown.js'
89
import * as promiseAny from './promise-any.js'
@@ -26,7 +27,6 @@ const baseSupport =
2627
typeof globalThis === 'object' &&
2728
'entries' in FormData.prototype &&
2829
'toggleAttribute' in Element.prototype &&
29-
'replaceChildren' in Element.prototype &&
3030
// ES2019
3131
'fromEntries' in Object &&
3232
'flatMap' in Array.prototype &&
@@ -50,6 +50,7 @@ export function isSupported() {
5050
aggregateError.isSupported() &&
5151
arrayAt.isSupported() &&
5252
cryptoRandomUUID.isSupported() &&
53+
elementReplaceChildren.isSupported() &&
5354
eventAbortSignal.isSupported() &&
5455
objectHasOwn.isSupported() &&
5556
promiseAny.isSupported() &&
@@ -64,6 +65,7 @@ export function isPolyfilled() {
6465
aggregateError.isPolyfilled() &&
6566
arrayAt.isPolyfilled() &&
6667
cryptoRandomUUID.isPolyfilled() &&
68+
elementReplaceChildren.isPolyfilled() &&
6769
eventAbortSignal.isPolyfilled() &&
6870
objectHasOwn.isPolyfilled() &&
6971
promiseAny.isPolyfilled() &&
@@ -77,6 +79,7 @@ export function apply() {
7779
aggregateError.apply()
7880
arrayAt.apply()
7981
cryptoRandomUUID.apply()
82+
elementReplaceChildren.apply()
8083
eventAbortSignal.apply()
8184
objectHasOwn.apply()
8285
promiseAny.apply()

test/element-replacechildren.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {apply, isPolyfilled, isSupported, replaceChildren} from '../lib/element-replacechildren.js'
2+
3+
describe('replaceChildren', () => {
4+
it('has standard isSupported, isPolyfilled, apply API', () => {
5+
expect(isSupported).to.be.a('function')
6+
expect(isPolyfilled).to.be.a('function')
7+
expect(apply).to.be.a('function')
8+
expect(isSupported()).to.be.a('boolean')
9+
expect(isPolyfilled()).to.equal(false)
10+
})
11+
12+
it('replaces all Element children with given nodes', async () => {
13+
const el = document.createElement('div')
14+
// eslint-disable-next-line github/no-inner-html, github/unescaped-html-literal
15+
el.innerHTML = '<p></p><span>Hi</span>'
16+
replaceChildren.call(el, 'X')
17+
// eslint-disable-next-line github/no-inner-html
18+
expect(el.innerHTML).to.eql('X')
19+
const s = document.createElement('span')
20+
// eslint-disable-next-line github/unescaped-html-literal
21+
s.textContent = '<foo>'
22+
replaceChildren.call(el, s)
23+
// eslint-disable-next-line github/no-inner-html, github/unescaped-html-literal
24+
expect(el.innerHTML).to.eql('<span>&lt;foo&gt;</span>')
25+
})
26+
})

0 commit comments

Comments
 (0)