-
Notifications
You must be signed in to change notification settings - Fork 599
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the f-template component which can interpret a text binding and c…
…onvert it to a ViewTemplate (#7073) # Pull Request ## 📖 Description This is some initial work to convert declarative HTML into a `ViewTemplate`. ## 👩💻 Reviewer Notes Some of this is preliminary work to get a workflow established for creation of aspect bindings and other requirements for the declarative HTML. This work also exposes the `fastElementRegistry` as well as adding an override for controller updates after a new template has been applied. ## ✅ Checklist ### General <!--- Review the list and put an x in the boxes that apply. --> - [ ] I have included a change request file using `$ npm run change` - [x] I have added tests for my changes. - [x] I have tested my changes. - [x] I have updated the project documentation to reflect my changes. - [x] I have read the [CONTRIBUTING](https://github.com/microsoft/fast/blob/main/CONTRIBUTING.md) documentation and followed the [standards](https://github.com/microsoft/fast/blob/main/CODE_OF_CONDUCT.md#our-standards) for this project. ## ⏭ Next Steps - Adding attribute bindings - Adding logic for common directives such as `when`
- Loading branch information
Showing
20 changed files
with
582 additions
and
161 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
change/@microsoft-fast-element-a0dc8892-ba16-4f59-8c59-9125aa60be70.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"type": "minor", | ||
"comment": "Expose the fast registry and allow triggering definition updates", | ||
"packageName": "@microsoft/fast-element", | ||
"email": "[email protected]", | ||
"dependentChangeType": "none" | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { TemplateElement } from "@microsoft/fast-btr"; | ||
import { attr, FASTElement } from "@microsoft/fast-element"; | ||
|
||
class CustomElement extends FASTElement { | ||
@attr | ||
text: string = "Hello"; | ||
} | ||
CustomElement.define({ | ||
name: "custom-element", | ||
}); | ||
|
||
TemplateElement.define({ | ||
name: "f-template", | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,5 +5,5 @@ | |
"rootDir": ".", | ||
"outDir": "dist" | ||
}, | ||
"references": [{ "path": "../src"}] | ||
"include": ["./server.ts"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { TemplateElement } from "./template.js"; |
109 changes: 109 additions & 0 deletions
109
packages/web-components/fast-btr/src/components/template.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import { | ||
attr, | ||
FAST, | ||
FASTElement, | ||
FASTElementDefinition, | ||
fastElementRegistry, | ||
ViewTemplate, | ||
} from "@microsoft/fast-element"; | ||
import { DOMPolicy } from "@microsoft/fast-element/dom-policy.js"; | ||
import { Message } from "../interfaces.js"; | ||
|
||
/** | ||
* The <f-template> custom element that will provide view logic to the element | ||
*/ | ||
class TemplateElement extends FASTElement { | ||
/** | ||
* The name of the custom element this template will be applied to | ||
*/ | ||
@attr | ||
public name?: string; | ||
|
||
private bindingRegex: RegExp = /{{(?:.*?)}}/g; | ||
|
||
private openBinding: string = "{{"; | ||
|
||
private closeBinding: string = "}}"; | ||
|
||
connectedCallback(): void { | ||
super.connectedCallback(); | ||
|
||
if (this.name) { | ||
this.$fastController.definition.registry | ||
.whenDefined(this.name) | ||
.then(value => { | ||
const registeredFastElement: FASTElementDefinition | undefined = | ||
fastElementRegistry.getByType(value); | ||
const template = this.getElementsByTagName("template").item(0); | ||
|
||
if (template) { | ||
const childNodes = template.content.childNodes; | ||
const strings: any[] = []; | ||
const values: any[] = []; // these can be bindings, directives, etc. | ||
|
||
childNodes.forEach(childNode => { | ||
switch (childNode.nodeType) { | ||
case 1: // HTMLElement | ||
break; | ||
case 3: // text | ||
this.resolveTextBindings(childNode, strings, values); | ||
break; | ||
default: | ||
break; | ||
} | ||
}); | ||
|
||
strings.push(""); | ||
|
||
(strings as any).raw = strings.map(value => | ||
String.raw({ raw: value }) | ||
); | ||
|
||
if (registeredFastElement) { | ||
// all new elements will get the updated template | ||
registeredFastElement.template = ViewTemplate.create( | ||
strings, | ||
values, | ||
DOMPolicy.create() | ||
); | ||
} | ||
} else { | ||
throw FAST.error(Message.noTemplateProvided, { name: this.name }); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* Resolve a text binding | ||
* @param childNode The child node to interpret. | ||
* @param strings The strings array. | ||
* @param values The interpreted values. | ||
*/ | ||
private resolveTextBindings( | ||
childNode: ChildNode, | ||
strings: Array<string>, | ||
values: Array<any> | ||
) { | ||
const textContent = childNode.textContent || ""; | ||
const bindingArray = textContent.match(this.bindingRegex); | ||
const stringArray = textContent.split(this.bindingRegex); | ||
|
||
if (bindingArray) { | ||
bindingArray.forEach((htmlBindingItem, index) => { | ||
// create a binding | ||
const sansBindingStrings = htmlBindingItem | ||
.replace(this.openBinding, "") | ||
.replace(this.closeBinding, "") | ||
.trim(); | ||
const bindingItem = (x: any) => x[sansBindingStrings]; | ||
strings.push(stringArray[index]); | ||
values.push(bindingItem); | ||
}); | ||
} else { | ||
strings.push(textContent); | ||
} | ||
} | ||
} | ||
|
||
export { TemplateElement }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export const debugMessages = { | ||
[2000 /* noTemplateProvided */]: `The first child of the <f-template> must be a <template>, this is missing from ${name}.`, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,20 @@ | ||
import { expect, test } from "@playwright/test"; | ||
|
||
test("placeholder", async () => { | ||
// TODO: update this with tests against fixtures | ||
expect(1+1).toEqual(2); | ||
test.describe("f-template", async () => { | ||
test("create a binding", async ({ page }) => { | ||
await page.goto("/binding"); | ||
|
||
const customElement = await page.locator("custom-element"); | ||
|
||
await expect(await customElement.getAttribute("text")).toEqual("Hello world"); | ||
await expect((await customElement.textContent()) || "".includes("Hello world")).toBeTruthy(); | ||
|
||
await page.evaluate(() => { | ||
const customElement = document.getElementsByTagName("custom-element"); | ||
customElement.item(0)?.setAttribute("text", "Hello pluto"); | ||
}); | ||
|
||
await expect(await customElement.getAttribute("text")).toEqual("Hello pluto"); | ||
await expect((await customElement.textContent()) || "".includes("Hello pluto")).toBeTruthy(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { FAST } from "@microsoft/fast-element"; | ||
import { debugMessages } from "./debug.js"; | ||
|
||
FAST.addMessages(debugMessages); | ||
|
||
export { TemplateElement } from "./components/index.js"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/** | ||
* Warning and error messages. | ||
* @internal | ||
*/ | ||
export const enum Message { | ||
noTemplateProvided = 2000, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import path from "path"; | ||
import { fileURLToPath } from "url"; | ||
|
||
const __filename = fileURLToPath(import.meta.url); | ||
const __dirname = path.resolve(path.dirname(__filename), "./"); | ||
|
||
export default { | ||
entry: "./server/main.ts", | ||
mode: "production", | ||
output: { | ||
filename: "main.js", | ||
path: path.resolve(__dirname, "./server/dist"), | ||
}, | ||
devServer: { | ||
static: "./public", | ||
port: 3001 | ||
}, | ||
resolve: { | ||
extensions: [".ts", ".js"], | ||
extensionAlias: { | ||
".js": [".js", ".ts"], | ||
} | ||
}, | ||
module: { | ||
rules: [ | ||
{ test: /\.([cm]?ts)$/, loader: "ts-loader" } | ||
] | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.