diff --git a/change/@microsoft-fast-element-e173d34b-0061-4c9d-94b5-415929d7dc5e.json b/change/@microsoft-fast-element-e173d34b-0061-4c9d-94b5-415929d7dc5e.json new file mode 100644 index 00000000000..076ceecae26 --- /dev/null +++ b/change/@microsoft-fast-element-e173d34b-0061-4c9d-94b5-415929d7dc5e.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Support element filters for declarative f-children directives.", + "packageName": "@microsoft/fast-element", + "email": "pradeepramolaa@gmail.com", + "dependentChangeType": "none" +} diff --git a/packages/fast-element/docs/declarative/syntax.md b/packages/fast-element/docs/declarative/syntax.md index f2f7fff4b9b..cdfa2058695 100644 --- a/packages/fast-element/docs/declarative/syntax.md +++ b/packages/fast-element/docs/declarative/syntax.md @@ -336,6 +336,8 @@ Attribute directives include: Example: ```html + + ``` - **ref** diff --git a/packages/fast-element/src/declarative/template-parser.ts b/packages/fast-element/src/declarative/template-parser.ts index 4df9c5e8993..7bf75ebdbf5 100644 --- a/packages/fast-element/src/declarative/template-parser.ts +++ b/packages/fast-element/src/declarative/template-parser.ts @@ -45,6 +45,11 @@ interface TemplateResolutionContext { schema: Schema; } +interface NodeDirectiveOptions { + property: string; + filter?: ReturnType; +} + /** * Tracks string segments accumulated during template parsing and maintains * a running concatenation so that `bindingResolver` can receive the full @@ -232,27 +237,12 @@ export class TemplateParser { ): void { switch (name) { case "children": { - externalValues.push(children(propName)); + externalValues.push(children(this.resolveNodeDirectiveOptions(propName))); break; } case "slotted": { - const parts = propName.trim().split(" filter "); - const slottedOption = { - property: parts[0], - }; - - if (parts[1]) { - if (parts[1].startsWith("elements(")) { - let params = parts[1].replace("elements(", ""); - params = params.substring(0, params.lastIndexOf(")")); - Object.assign(slottedOption, { - filter: elements(params || undefined), - }); - } - } - - externalValues.push(slotted(slottedOption)); + externalValues.push(slotted(this.resolveNodeDirectiveOptions(propName))); break; } @@ -264,6 +254,21 @@ export class TemplateParser { } } + private resolveNodeDirectiveOptions(propName: string): NodeDirectiveOptions { + const parts = propName.trim().split(" filter "); + const options: NodeDirectiveOptions = { + property: parts[0], + }; + + if (parts[1]?.startsWith("elements(")) { + let params = parts[1].replace("elements(", ""); + params = params.substring(0, params.lastIndexOf(")")); + options.filter = elements(params || undefined); + } + + return options; + } + /** * Resolve an access binding — shared by content bindings, boolean-attribute * fallback, and default attribute bindings. diff --git a/packages/fast-element/test/declarative/fixtures/directives/children/children.spec.ts b/packages/fast-element/test/declarative/fixtures/directives/children/children.spec.ts index d88e1005e96..1dfe6b890e6 100644 --- a/packages/fast-element/test/declarative/fixtures/directives/children/children.spec.ts +++ b/packages/fast-element/test/declarative/fixtures/directives/children/children.spec.ts @@ -11,12 +11,29 @@ test.describe("f-template", async () => { await hydrationCompleted; const element = page.locator("test-element"); - const listItems = element.locator("li"); + const listItems = element.locator("[data-testid='list-items'] li"); await expect(listItems).toHaveCount(2); await expect(listItems).toHaveText(["Foo", "Bar"]); + const filteredNodeNames = await element.evaluate( + ( + node: HTMLElement & { + allChildren: Node[]; + filteredChildren: Node[]; + }, + ) => ({ + allChildren: node.allChildren.map(child => child.nodeName), + filteredChildren: node.filteredChildren.map(child => child.nodeName), + }), + ); + + expect(filteredNodeNames).toEqual({ + allChildren: ["LI", "LI"], + filteredChildren: ["SPAN"], + }); + await element.evaluate((node: HTMLElement & { list: Array }) => { node.list = ["A", "B", "C"]; }); @@ -24,5 +41,6 @@ test.describe("f-template", async () => { await expect(listItems).toHaveCount(3); await expect(listItems).toHaveText(["A", "B", "C"]); + await expect(element).toHaveJSProperty("allChildren.length", 3); }); }); diff --git a/packages/fast-element/test/declarative/fixtures/directives/children/index.html b/packages/fast-element/test/declarative/fixtures/directives/children/index.html index bb848854e28..ce4101fb882 100644 --- a/packages/fast-element/test/declarative/fixtures/directives/children/index.html +++ b/packages/fast-element/test/declarative/fixtures/directives/children/index.html @@ -5,9 +5,15 @@ - + - + diff --git a/packages/fast-element/test/declarative/fixtures/directives/children/main.ts b/packages/fast-element/test/declarative/fixtures/directives/children/main.ts index a05c96d1d35..215509ad4c6 100644 --- a/packages/fast-element/test/declarative/fixtures/directives/children/main.ts +++ b/packages/fast-element/test/declarative/fixtures/directives/children/main.ts @@ -7,6 +7,12 @@ class TestElement extends FASTElement { @observable listItems: Node[] = []; + @observable + allChildren: Node[] = []; + + @observable + filteredChildren: Node[] = []; + @observable list: Array = ["Foo", "Bar"]; } diff --git a/packages/fast-element/test/declarative/fixtures/directives/children/templates.html b/packages/fast-element/test/declarative/fixtures/directives/children/templates.html index 52c239daf52..eb214786789 100644 --- a/packages/fast-element/test/declarative/fixtures/directives/children/templates.html +++ b/packages/fast-element/test/declarative/fixtures/directives/children/templates.html @@ -1,3 +1,7 @@ - +