Skip to content

Commit 98d8733

Browse files
committed
Remove special treatment for HTMLTemplateElement
Now that `InnerTemplatePart` exists, the Node walker should yield instances of `InnerTemplatePart` instead of collecting nested `<template>` elements based on their attributes. Consumers are free to override the `TemplateInstance` processor to handle `<template>` elements in whichever way they please, while still being able to fall back to the built-in behavior.
1 parent 4e442b7 commit 98d8733

File tree

3 files changed

+38
-17
lines changed

3 files changed

+38
-17
lines changed

src/processors.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {TemplatePart, TemplateTypeInit} from './types.js'
2-
import type {TemplateInstance} from './template-instance.js'
2+
import {TemplateInstance} from './template-instance.js'
33
import {AttributeTemplatePart} from './attribute-template-part.js'
4+
import {InnerTemplatePart} from './inner-template-part.js'
45

56
type PartProcessor = (part: TemplatePart, value: unknown, state: unknown) => void
67

@@ -9,7 +10,9 @@ export function createProcessor(processPart: PartProcessor): TemplateTypeInit {
910
processCallback(_: TemplateInstance, parts: Iterable<TemplatePart>, state: unknown): void {
1011
if (typeof state !== 'object' || !state) return
1112
for (const part of parts) {
12-
if (part.expression in state) {
13+
if (part instanceof InnerTemplatePart) {
14+
processPart(part, part.expression, state)
15+
} else if (part.expression in state) {
1316
const value = (state as Record<string, unknown>)[part.expression] ?? ''
1417
processPart(part, value, state)
1518
}
@@ -18,8 +21,12 @@ export function createProcessor(processPart: PartProcessor): TemplateTypeInit {
1821
}
1922
}
2023

21-
export function processPropertyIdentity(part: TemplatePart, value: unknown): void {
22-
part.value = value instanceof Node ? value : String(value)
24+
export function processPropertyIdentity(part: TemplatePart, value: unknown, state: unknown): void {
25+
if (part instanceof InnerTemplatePart) {
26+
part.template.content.replaceChildren(new TemplateInstance(part.template, state))
27+
} else {
28+
part.value = value instanceof Node ? value : String(value)
29+
}
2330
}
2431

2532
export function processBooleanAttribute(part: TemplatePart, value: unknown): boolean {
@@ -35,8 +42,10 @@ export function processBooleanAttribute(part: TemplatePart, value: unknown): boo
3542
}
3643

3744
export const propertyIdentity = createProcessor(processPropertyIdentity)
38-
export const propertyIdentityOrBooleanAttribute = createProcessor((part: TemplatePart, value: unknown) => {
39-
if (!processBooleanAttribute(part, value)) {
40-
processPropertyIdentity(part, value)
41-
}
42-
})
45+
export const propertyIdentityOrBooleanAttribute = createProcessor(
46+
(part: TemplatePart, value: unknown, state: unknown) => {
47+
if (!processBooleanAttribute(part, value)) {
48+
processPropertyIdentity(part, value, state)
49+
}
50+
},
51+
)

src/template-instance.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,7 @@ function* collectParts(el: DocumentFragment): Generator<TemplatePart> {
1010
let node
1111
while ((node = walker.nextNode())) {
1212
if (node instanceof HTMLTemplateElement) {
13-
if (node.hasAttribute('directive')) {
14-
yield new InnerTemplatePart(node)
15-
} else {
16-
for (const part of collectParts(node.content)) {
17-
yield part
18-
}
19-
}
13+
yield new InnerTemplatePart(node)
2014
} else if (node instanceof Element && node.hasAttributes()) {
2115
for (let i = 0; i < node.attributes.length; i += 1) {
2216
const attr = node.attributes.item(i)

test/template-instance.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ describe('template-instance', () => {
384384
part.replace()
385385
}
386386
} else {
387-
processPropertyIdentity(part, value)
387+
processPropertyIdentity(part, value, state)
388388
}
389389
})
390390
const template = Object.assign(document.createElement('template'), {
@@ -398,6 +398,24 @@ describe('template-instance', () => {
398398
root.replaceChildren(new TemplateInstance(template, {x: 'x', y: false}, processor))
399399
expect(root.innerHTML).to.equal('x')
400400
})
401+
402+
it('makes outer state available to InnerTemplatePart elements without attributes', () => {
403+
let callCount = 0
404+
const processor = createProcessor((part, value, state) => {
405+
if (part instanceof InnerTemplatePart && value === part.expression) {
406+
callCount += 1
407+
processPropertyIdentity(part, value, state)
408+
}
409+
})
410+
const template = Object.assign(document.createElement('template'), {
411+
innerHTML: '<template>{{x}}</template>',
412+
})
413+
414+
const root = document.createElement('div')
415+
root.appendChild(new TemplateInstance(template, {x: 'Hello world'}, processor))
416+
expect(callCount).to.equal(1)
417+
expect(root.innerHTML).to.equal('<template>Hello world</template>')
418+
})
401419
})
402420
})
403421
})

0 commit comments

Comments
 (0)