зеркало из https://github.com/github/jtml.git
Merge pull request #5 from github/feat-add-support-for-iterables-in-templates
feat: add support for iterables in templates
This commit is contained in:
Коммит
532e115f48
28
src/html.ts
28
src/html.ts
|
@ -25,12 +25,40 @@ function processDocumentFragment(part: TemplatePart, value: unknown): boolean {
|
|||
return false
|
||||
}
|
||||
|
||||
function isIterable(value: unknown): value is Iterable<unknown> {
|
||||
return typeof value === 'object' && Symbol.iterator in ((value as unknown) as Record<symbol, unknown>)
|
||||
}
|
||||
|
||||
function processIterable(part: TemplatePart, value: unknown): boolean {
|
||||
if (!isIterable(value)) return false
|
||||
if (part instanceof NodeTemplatePart) {
|
||||
const nodes = []
|
||||
for (const item of value) {
|
||||
if (item instanceof TemplateResult) {
|
||||
const fragment = document.createDocumentFragment()
|
||||
render(item, fragment)
|
||||
nodes.push(...fragment.children)
|
||||
} else if (item instanceof DocumentFragment) {
|
||||
nodes.push(...item.children)
|
||||
} else {
|
||||
nodes.push(String(item))
|
||||
}
|
||||
}
|
||||
if (nodes.length) part.replace(...nodes)
|
||||
return true
|
||||
} else {
|
||||
part.value = Array.from(value).join(' ')
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
export function processPart(part: TemplatePart, value: unknown): void {
|
||||
processDirective(part, value) ||
|
||||
processBooleanAttribute(part, value) ||
|
||||
processEvent(part, value) ||
|
||||
processSubTemplate(part, value) ||
|
||||
processDocumentFragment(part, value) ||
|
||||
processIterable(part, value) ||
|
||||
processPropertyIdentity(part, value)
|
||||
}
|
||||
|
||||
|
|
63
test/html.ts
63
test/html.ts
|
@ -42,6 +42,69 @@ describe('render', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('iterables', () => {
|
||||
it('supports arrays of strings in nodes', () => {
|
||||
const main = list => html`<div>${list}</div>`
|
||||
render(main(['one', 'two', 'three']), surface)
|
||||
expect(surface.innerHTML).to.equal('<div>onetwothree</div>')
|
||||
render(main(['four', 'five', 'six']), surface)
|
||||
expect(surface.innerHTML).to.equal('<div>fourfivesix</div>')
|
||||
})
|
||||
|
||||
it('supports other strings iterables in nodes', () => {
|
||||
const main = list => html`<div>${list}</div>`
|
||||
render(main(new Set(['one', 'two', 'three'])), surface)
|
||||
expect(surface.innerHTML).to.equal('<div>onetwothree</div>')
|
||||
render(
|
||||
main(
|
||||
new Map([
|
||||
[4, 'four'],
|
||||
[5, 'five'],
|
||||
[6, 'six']
|
||||
]).values()
|
||||
),
|
||||
surface
|
||||
)
|
||||
expect(surface.innerHTML).to.equal('<div>fourfivesix</div>')
|
||||
})
|
||||
|
||||
it('supports iterables of strings in attributes', () => {
|
||||
const main = list => html`<div class="${list}"></div>`
|
||||
render(main(['one', 'two', 'three']), surface)
|
||||
expect(surface.innerHTML).to.equal('<div class="one two three"></div>')
|
||||
render(main(new Set(['four', 'five', 'six'])), surface)
|
||||
expect(surface.innerHTML).to.equal('<div class="four five six"></div>')
|
||||
})
|
||||
|
||||
it('supports nested iterables of document fragments', () => {
|
||||
// prettier-ignore
|
||||
const main = list => html`<ul>${list}</ul>`
|
||||
render(
|
||||
main(
|
||||
['One', 'Two'].map(text => {
|
||||
const f = document.createDocumentFragment()
|
||||
const li = document.createElement('li')
|
||||
li.textContent = text
|
||||
f.append(li)
|
||||
return f
|
||||
})
|
||||
),
|
||||
surface
|
||||
)
|
||||
expect(surface.innerHTML).to.equal('<ul><li>One</li><li>Two</li></ul>')
|
||||
})
|
||||
|
||||
it('supports nested iterables of templates', () => {
|
||||
const child = item => html`<li>${item.name}</li>`
|
||||
// prettier-ignore
|
||||
const main = list => html`<ul>${list.map(child)}</ul>`
|
||||
render(main([{name: 'One'}, {name: 'Two'}, {name: 'Three'}]), surface)
|
||||
expect(surface.innerHTML).to.equal('<ul><li>One</li><li>Two</li><li>Three</li></ul>')
|
||||
render(main([{name: 'Two'}, {name: 'Three'}, {name: 'Four'}]), surface)
|
||||
expect(surface.innerHTML).to.equal('<ul><li>Two</li><li>Three</li><li>Four</li></ul>')
|
||||
})
|
||||
})
|
||||
|
||||
describe('directives', () => {
|
||||
it('handles directives differently', () => {
|
||||
const setAsFoo = directive(() => part => {
|
||||
|
|
Загрузка…
Ссылка в новой задаче