From 71c2fda6e4c9f342e1e341f5a61c9966ea4147de Mon Sep 17 00:00:00 2001
From: Jane Chu <7559015+janechu@users.noreply.github.com>
Date: Wed, 27 Nov 2024 15:13:51 -0800
Subject: [PATCH] Split architecture doc into multiple explainers
---
.../fast-element/ARCHITECTURE.md | 136 ------------------
.../fast-element/ARCHITECTURE_FASTELEMENT.md | 63 ++++++++
...CHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md | 32 +++++
.../fast-element/ARCHITECTURE_INTRO.md | 10 ++
.../fast-element/ARCHITECTURE_OVERVIEW.md | 52 +++++++
.../fast-element/ARCHITECTURE_UPDATES.md | 11 ++
6 files changed, 168 insertions(+), 136 deletions(-)
delete mode 100644 packages/web-components/fast-element/ARCHITECTURE.md
create mode 100644 packages/web-components/fast-element/ARCHITECTURE_FASTELEMENT.md
create mode 100644 packages/web-components/fast-element/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md
create mode 100644 packages/web-components/fast-element/ARCHITECTURE_INTRO.md
create mode 100644 packages/web-components/fast-element/ARCHITECTURE_OVERVIEW.md
create mode 100644 packages/web-components/fast-element/ARCHITECTURE_UPDATES.md
diff --git a/packages/web-components/fast-element/ARCHITECTURE.md b/packages/web-components/fast-element/ARCHITECTURE.md
deleted file mode 100644
index 3b98cfc19af..00000000000
--- a/packages/web-components/fast-element/ARCHITECTURE.md
+++ /dev/null
@@ -1,136 +0,0 @@
-# Architecture
-
-This document explains various logical flows for how a `FASTElement` is composed, defined, rendered, and updated.
-
-## What is FASTElement?
-
-`FASTElement` is an extension of `HTMLElement` which makes use of Custom Element APIs native to the browser. It also supplies the following methods:
-
-- The `compose` method combines the Custom Element name, template, style, and other options to create the definition for the Custom Element.
-- The `define` method makes use of the native Custom Element [`define()`](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define) to register the Custom Element with a Custom Element Registry.
-- The `from` method allows the use of Customized Built-in elements, which extend from native elements such as `HTMLButtonElement`.
-
-### Creating a Custom Element from FASTElement
-
-A basic developer flow for defining a custom element looks like this:
-
-```mermaid
-flowchart TD
- A[Create a FASTElement
web component by extending the FASTElement
class] --> F
- F[Compose with FASTElement.compose
to include template and styles] --> G[Define the component in the browser with FASTElement.define
]
-```
-
-Let's take a look at the compose step to see what the FAST architecture is doing at this stage.
-
-### Composing a Custom Element
-
-The `FASTElement.compose()` function creates a new `FASTElementDefinition`, which includes all metadata needed for the element (such as templates, attributes, and styles). The element definition is registered with the global `FAST` for re-use, and the `FASTElementDefinition` is returned. The resulting object can be retrieved via `ElementController.definition`.
-
-## A Custom Element in JavaScript sent to the Browser
-
-Let's step back from defining the Custom Element and consider what is happening when we import from the `@microsoft/fast-element` package.
-
-First, a global `FAST` property will be created if one does not already exist, typically in browser on the `window`.
-
-Additionally, when Custom Elements are included in a script a few things might happen even before a Custom Element gets detected by the browser. First, there are initial side effects caused by the use of decorators. These include the `attr` and `observable` decorators made available by the `@microsoft/fast-element` package.
-
-```mermaid
-flowchart TD
- A[The browser loads the JavaScript file containing FAST]
- A --> B[The FAST global is added]
- B --> C[Any defined observable decorators are added to the FAST global]
- A --> D[Any defined attribute decorators are attached to the constructor of the FAST Custom Element]
-```
-
-### Pre-render Template
-
-The `html` tagged template function creates a `ViewTemplate` object via the `ViewTemplate.create()` method. This is then used during the `compose` step, before `FASTElement` is instantiated.
-
-During the `Compiler.compile()` method triggered by `ViewTemplate.create()` method, the following happens for each string:
-- Factories with unique IDs are created for each tag template literal argument (or `TemplateValue`) which matches with the corresponding string
-- A binding is created from the `TemplateValue`
-
-A resulting string using a `createHTML()` function is produced using the `HTMLDirective`s executed for each factory. The behavior is augmented by the previous string from the `html` tag template which determines the aspect if one exists, these aspects are the `@`, `:`, or other binding aspect attached to attributes.
-
-The `createHTML()` function utilizes a `Markup` attribute which is assigned to a factory's unique ID. The strings are concatenated and passed to a new `ViewTemplate` with all the factories (empty until one is assigned) that act as a dictionary with the unique IDs as the key to look up each factory once it has been created. The string this creates is injected into a `` as `innerHTML`, which allows the browser to create the nodes and placeholder factory IDs, with the only `DOM` node that is explicitly created being the wrapping `` element.
-
-#### HTML Binding Directives
-
-The `HTMLBindingDirective` applies bindings to items identified as various `TemplateValue`s within the `html` tagged template. The `createHTML` step uses the factory associated with the binding to create strings in the markup using the factory's ID.
-
-```mermaid
-flowchart TD
- A[A new HTMLBindingDirective
is created with a data binding which has a policy, options, createObserver
, and an evaluate method assigned to the passed arrow function such as x => x.foo
]
- B[oneTime
binding passes the corresponding tag template argument, an arrow function]
- C[oneWay
binding passes a copy of the corresponding tag template argument, an arrow function]
- D[An already specified binding such as a repeat
or when
directive is passed]
- A --> B
- A --> C
- A --> D
- E[When a createObserver
is called, an Observable.binding
is created passing the arrow function to be evaluated and the subscriber to be notified]
- C --> E
- F[When a createObserver
is called, the instance of the one time binding is returned which includes a bind method returning the arrow function executed against the controller source and context]
- B --> F
-```
-
-## A Custom Element is Detected by the Browser
-
-Because the `FASTElement` is an extension of the `HTMLElement`, it makes use of the same lifecycle hooks and extends them with `$fastController`. It also initializes using another class `ElementController`, the methods this are called during the custom elements native `constructor`, `connectedCallback`, `disconnectedCallback`, and `attributeChangedCallback` lifecycle hooks.
-
-### 🔄 **Lifecycle**: Initialization
-
-```mermaid
-flowchart TD
- A[A FASTElement
web component is added to the DOM
] --> B
- B[FASTElement
initializes the ElementController.forCustomElement
passing the Custom Element instance] --> C
- B --> F[Observables applied to the FASTElement
are updated on the FAST global without values]
- C{Is an ElementController
available?}
- C --> |yes|E
- C --> |no|D
- D[Initialize a new ElementController
referred to as setting an element controller strategy]
- D --> F
- E[ElementController
captures the Custom Element instance and the definition and attaches them to the $fastController
which is then attached to the instance]
-```
-
-### 🔄 **Lifecycle**: Component is connected
-
-```mermaid
-flowchart TD
- A[browser HTMLElement
's connectedCallback
is called] --> B
- B[this.$fastController.connect
in FASTElement is called] --> C
- B --> D
- B --> E
- B --> F
- C[bind observables by capturing the Custom Elements properties and setting the values from the bound observables on the Custom Element]
- D[connect behaviors by call the connectedCallback
on all behaviors]
- E[render template, execute an ElementViewTemplate
's render method]
- F[add styles either as an appended StyleElement
node or an adoptedStylesheet
which may include and attach behaviors]
-```
-
-#### Render Template
-
-The rendering of the template on the `ElementController` is by the `renderTemplate` method which is called during the `ElementController.connect` method which is triggered by `HTMLElement`s `connectedCallback` lifecycle.
-
-The `renderTemplate` identifies the Custom Element, and the shadow root associated with the Custom Element. This then places a rendering of the template (an `ElementView`) onto the internal `view` of the controller. When creating the `ElementView`/`HTMLView` using the `ViewTemplate.render`, the `Compile.compile()` method identifies a `DocumentFragment` either by using an existing `` tag, or creating one to wrap the contents of the shadow root. A new `CompilationContext` is created and the `compileAttributes` function is called, this results in the replacement of the placeholder attributes initally set-up during the pre-render step with their values if a value has been assigned. The factories with the associated nodes identified are then passed to the context. The view then binds all behaviors to the source element. The `CompilationContext.createView` is executed with the `DocumentFragment` as the root, and returns an `HTMLView`. This `HTMLView` includes an `appendTo` method to attach the fragment to the host element, which it then does. It should be noted that the compiled HTML is a `string`, which when set on the `DocumentFragment` as `innerHTML`, this allows the browser to dictate the creation of HTML nodes.
-
-### 🔄 **Lifecycle**: Component is disconnected
-
-When a component is disconnected, a cleanup step is created to remove associated behaviors.
-
-### 🔄 **Lifecycle**: Attribute has been changed
-
-Attributes have an `AttributeDefinition` which allows for converters, attachment of the `Changed` aspect of the `@attr` decorator among other capabilities.
-
-```mermaid
-flowchart TD
- A[The browser HTMLElement
's attributeChangedCallback
is called] --> B
- B[this.$fastController.onAttributeChangedCallback
in FASTElement
is called] --> C
- C[calls the attribute definitions onAttributeChangedCallback
method with the updated value] --> D
- D[An Updates.enqueue
is called which places the update in the task queue which is then executed, these are performed async unless otherwise specified]
-```
-
-These changes are observed and similar to the way `Observables` work, they utilize an `Accessor` pattern which has a `getValue` and `setValue` in which DOM updates are applied.
-
-### Observables are updated
-
-The `Reflect` API is used to override `defineProperty` in order to observe a property on an Custom Element, this overrides the getter and setter, which allows subscribers to be notified of changes. Any changes which `set` the value are passed to the `Updates` queue which has been added to the FAST Global.
\ No newline at end of file
diff --git a/packages/web-components/fast-element/ARCHITECTURE_FASTELEMENT.md b/packages/web-components/fast-element/ARCHITECTURE_FASTELEMENT.md
new file mode 100644
index 00000000000..e227474a2bf
--- /dev/null
+++ b/packages/web-components/fast-element/ARCHITECTURE_FASTELEMENT.md
@@ -0,0 +1,63 @@
+# FASTElement
+
+The `FASTElement` is our extension of the `HTMLElement`. As such it leverages the lifecycles but also requires additional setup before before the class `constructor` or the `connectedCallback` method is executed which are explained in the [overview](./ARCHITECTURE_OVERVIEW.md). This document explains specifically what `FASTElement` leverages inside the `HTMLElement`s lifecycle hooks.
+
+For an explanation into `HTMLElement` lifecycle hooks refer to the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks).
+
+## A Custom Element is Detected by the Browser
+
+Because the `FASTElement` is an extension of the `HTMLElement`, it makes use of the same lifecycle hooks and extends them with `$fastController`. It also initializes using another class `ElementController`, the methods this are called during the custom elements native `constructor`, `connectedCallback`, `disconnectedCallback`, and `attributeChangedCallback` lifecycle hooks.
+
+### 🔄 **Lifecycle**: Initialization
+
+```mermaid
+flowchart TD
+ A[A FASTElement
web component is added to the DOM
] --> B
+ B[FASTElement
initializes the ElementController.forCustomElement
passing the Custom Element instance] --> C
+ B --> F[Observables applied to the FASTElement
are updated on the FAST global without values]
+ C{Is an ElementController
available?}
+ C --> |yes|E
+ C --> |no|D
+ D[Initialize a new ElementController
referred to as setting an element controller strategy]
+ D --> F
+ E[ElementController
captures the Custom Element instance and the definition and attaches them to the $fastController
which is then attached to the instance]
+```
+
+### 🔄 **Lifecycle**: Component is connected
+
+```mermaid
+flowchart TD
+ A[browser HTMLElement
's connectedCallback
is called] --> B
+ B[this.$fastController.connect
in FASTElement is called] --> C
+ B --> D
+ B --> E
+ B --> F
+ C[bind observables by capturing the Custom Elements properties and setting the values from the bound observables on the Custom Element]
+ D[connect behaviors by call the connectedCallback
on all behaviors]
+ E[render template, execute an ElementViewTemplate
's render method]
+ F[add styles either as an appended StyleElement
node or an adoptedStylesheet
which may include and attach behaviors]
+```
+
+#### Render Template
+
+The rendering of the template on the `ElementController` is by the `renderTemplate` method which is called during the `ElementController.connect` method which is triggered by `HTMLElement`s `connectedCallback` lifecycle.
+
+The `renderTemplate` identifies the Custom Element, and the shadow root associated with the Custom Element. This then places a rendering of the template (an `ElementView`) onto the internal `view` of the controller. When creating the `ElementView`/`HTMLView` using the `ViewTemplate.render`, the `Compile.compile()` method identifies a `DocumentFragment` either by using an existing `` tag, or creating one to wrap the contents of the shadow root. A new `CompilationContext` is created and the `compileAttributes` function is called, this results in the replacement of the placeholder attributes initally set-up during the pre-render step with their values if a value has been assigned. The factories with the associated nodes identified are then passed to the context. The view then binds all behaviors to the source element. The `CompilationContext.createView` is executed with the `DocumentFragment` as the root, and returns an `HTMLView`. This `HTMLView` includes an `appendTo` method to attach the fragment to the host element, which it then does. It should be noted that the compiled HTML is a `string`, which when set on the `DocumentFragment` as `innerHTML`, this allows the browser to dictate the creation of HTML nodes.
+
+### 🔄 **Lifecycle**: Component is disconnected
+
+When a component is disconnected, a cleanup step is created to remove associated behaviors.
+
+### 🔄 **Lifecycle**: Attribute has been changed
+
+Attributes have an `AttributeDefinition` which allows for converters, attachment of the `Changed` aspect of the `@attr` decorator among other capabilities.
+
+```mermaid
+flowchart TD
+ A[The browser HTMLElement
's attributeChangedCallback
is called] --> B
+ B[this.$fastController.onAttributeChangedCallback
in FASTElement
is called] --> C
+ C[calls the attribute definitions onAttributeChangedCallback
method with the updated value] --> D
+ D[An Updates.enqueue
is called which places the update in the task queue which is then executed, these are performed async unless otherwise specified]
+```
+
+These changes are observed and similar to the way `Observables` work, they utilize an `Accessor` pattern which has a `getValue` and `setValue` in which DOM updates are applied.
\ No newline at end of file
diff --git a/packages/web-components/fast-element/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md b/packages/web-components/fast-element/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md
new file mode 100644
index 00000000000..730c1060d94
--- /dev/null
+++ b/packages/web-components/fast-element/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md
@@ -0,0 +1,32 @@
+# `html` tagged template literal
+
+## Pre-render Template
+
+The `html` tagged template function creates a `ViewTemplate` object via the `ViewTemplate.create()` method. This is then used during the `compose` step, before `FASTElement` is instantiated.
+
+During the `Compiler.compile()` method triggered by `ViewTemplate.create()` method, the following happens for each string:
+- Factories with unique IDs are created for each tag template literal argument (or `TemplateValue`) which matches with the corresponding string
+- A binding is created from the `TemplateValue`
+
+A resulting string using a `createHTML()` function is produced using the `HTMLDirective`s executed for each factory. The behavior is augmented by the previous string from the `html` tag template which determines the aspect if one exists, these aspects are the `@`, `:`, or other binding aspect attached to attributes.
+
+The `createHTML()` function utilizes a `Markup` attribute which is assigned to a factory's unique ID. The strings are concatenated and passed to a new `ViewTemplate` with all the factories (empty until one is assigned) that act as a dictionary with the unique IDs as the key to look up each factory once it has been created. The string this creates is injected into a `` as `innerHTML`, which allows the browser to create the nodes and placeholder factory IDs, with the only `DOM` node that is explicitly created being the wrapping `` element.
+
+## Directives
+
+The `HTMLBindingDirective` applies bindings to items identified as various `TemplateValue`s within the `html` tagged template. The `createHTML` step uses the factory associated with the binding to create strings in the markup using the factory's ID.
+
+```mermaid
+flowchart TD
+ A[A new HTMLBindingDirective
is created with a data binding which has a policy, options, createObserver
, and an evaluate method assigned to the passed arrow function such as x => x.foo
]
+ B[oneTime
binding passes the corresponding tag template argument, an arrow function]
+ C[oneWay
binding passes a copy of the corresponding tag template argument, an arrow function]
+ D[An already specified binding such as a repeat
or when
directive is passed]
+ A --> B
+ A --> C
+ A --> D
+ E[When a createObserver
is called, an Observable.binding
is created passing the arrow function to be evaluated and the subscriber to be notified]
+ C --> E
+ F[When a createObserver
is called, the instance of the one time binding is returned which includes a bind method returning the arrow function executed against the controller source and context]
+ B --> F
+```
\ No newline at end of file
diff --git a/packages/web-components/fast-element/ARCHITECTURE_INTRO.md b/packages/web-components/fast-element/ARCHITECTURE_INTRO.md
new file mode 100644
index 00000000000..b260a28ef46
--- /dev/null
+++ b/packages/web-components/fast-element/ARCHITECTURE_INTRO.md
@@ -0,0 +1,10 @@
+# Introduction
+
+This document (and the linked documents) explains how the exports and side effects of `@microsoft/fast-element` are used to create custom elements.
+
+## Glossary
+
+- [Overview](./ARCHITECTURE_OVERVIEW.md): How the `@microsoft/fast-element` should be used by a developer and what code is executed during the first render.
+- [`FASTElement`](./ARCHITECTURE_FASTELEMENT.md): How the `FASTElement` is architected.
+- [`html` tagged template literal](./ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md): How the `html` tagged template literal takes and converts the contents into a `VIEWTemplate`.
+- [`Updates` queue](./ARCHITECTURE_UPDATES.md): How updates to attributes and observables are processed.
\ No newline at end of file
diff --git a/packages/web-components/fast-element/ARCHITECTURE_OVERVIEW.md b/packages/web-components/fast-element/ARCHITECTURE_OVERVIEW.md
new file mode 100644
index 00000000000..68e609acbd8
--- /dev/null
+++ b/packages/web-components/fast-element/ARCHITECTURE_OVERVIEW.md
@@ -0,0 +1,52 @@
+# General FAST usage
+
+`FASTElement` is an extension of `HTMLElement` which makes use of Custom Element APIs native to the browser. It also supplies the following methods:
+
+- The `compose` method combines the Custom Element name, template, style, and other options to create the definition for the Custom Element.
+- The `define` method makes use of the native Custom Element [`define()`](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define) to register the Custom Element with a Custom Element Registry.
+- The `from` method allows the use of Customized Built-in elements, which extend from native elements such as `HTMLButtonElement`.
+
+### Creating a Custom Element from FASTElement
+
+A basic developer flow for defining a custom element looks like this:
+
+```mermaid
+flowchart TD
+ A[Create a FASTElement
web component by extending the FASTElement
class] --> F
+ F[Compose with FASTElement.compose
to include template and styles] --> G[Define the component in the browser with FASTElement.define
]
+```
+
+Let's take a look at the compose step to see what the FAST architecture is doing at this stage.
+
+### Composing a Custom Element
+
+The `FASTElement.compose()` function creates a new `FASTElementDefinition`, which includes all metadata needed for the element (such as templates, attributes, and styles). The element definition is registered with the global `FAST` for re-use, and the `FASTElementDefinition` is returned. The resulting object can be retrieved via `ElementController.definition`.
+
+## A Custom Element in JavaScript is sent to the Browser
+
+Let's step back from defining the Custom Element and consider what is happening when we import from the `@microsoft/fast-element` package.
+
+First, a global `FAST` property will be created if one does not already exist, typically in browser on the `window`.
+
+Additionally, when Custom Elements are included in a script a few things might happen even before a Custom Element gets detected by the browser. First, there are initial side effects caused by the use of decorators. These include the `attr` and `observable` decorators made available by the `@microsoft/fast-element` package.
+
+Here is a basic flow of what code is executed and when during initial load of a script that contains a FAST defined Custom Element:
+
+```mermaid
+flowchart TD
+ A@{ shape: circle, label: "The browser loads the JavaScript file containing FAST and FAST Custom Element definitions" }
+ B@{ shape: rect, label: "The FAST global is added to the window" }
+ A --> B
+ C@{ shape: rect, label: "A Custom Element executes the compose
step"}
+ B --> C
+ D@{ shape: procs, label: "- Any defined observable decorators are added to the FAST global
- An attribute decorator locates the associated Custom Elements constructor which it uses to push itself to the Custom Elements attribute collection
"}
+ C --> D
+ F@{ shape: rect, label: "An HTML tagged template literal is executed for the FAST Custom Element and applied to the definition" }
+ D --> F
+ G@{ shape: rect, label: "The define
step is hit and the customElement
is registered with the Custom Element Registry" }
+ F --> G
+ H@{ shape: rect, label: "A Custom Element is detected on the page and the browser initializes it" }
+ I@{ shape: dbl-circ, label: "The lifecycle steps for FASTElement
are executed" }
+ G --> H
+ H --> I
+```
\ No newline at end of file
diff --git a/packages/web-components/fast-element/ARCHITECTURE_UPDATES.md b/packages/web-components/fast-element/ARCHITECTURE_UPDATES.md
new file mode 100644
index 00000000000..6d2502d3d18
--- /dev/null
+++ b/packages/web-components/fast-element/ARCHITECTURE_UPDATES.md
@@ -0,0 +1,11 @@
+# `Updates`
+
+The `Updates` API is part of the `FAST` global. The updates that are queued include updates to attributes, observables, and observed arrays.
+
+## Attributes
+
+An attribute change may be queued when the value of the attribute is updated. This change is triggered by `HTMLElement` lifecycle hook `attributeChangedCallback`. The `Updates` queue is used to try to reflect the attribute with the updated value onto the element using `DOM` APIs.
+
+## Observables
+
+The `Reflect` API is used to override `defineProperty` in order to observe a property on an Custom Element, this overrides the getter and setter, which allows subscribers to be notified of changes. Any changes which `set` the value are passed to the `Updates` queue.
\ No newline at end of file