Skip to content

Commit

Permalink
feat: new HTMLDirective design (#5826)
Browse files Browse the repository at this point in the history
* refactor: clean up array observer

* refactor: modernize the splice code

* chore: set up SSR package (#5589)

* project files and starting to set up test infrastructure

* incorporating ts project references and getting tests working

* adding .npmignore to ingore tests and server

* adding readmes

* Update packages/web-components/fast-ssr/package.json

Co-authored-by: Chris Holt <[email protected]>

Co-authored-by: nicholasrice <[email protected]>
Co-authored-by: Chris Holt <[email protected]>

* feat: enable multiple instances of fast-element on a page at once (#5718)

* feat: enable multiple instances of fast-element on a page at once

* Change files

Co-authored-by: EisenbergEffect <[email protected]>

* refactor: extract polyfill and polyfill-like code to an optional module (#5752)

* refactor: extract polyfill and polyfill-like code to an optional module

* Change files

* fix: correct build break in fast-foundation from removing $global

* fix: update templates to use classList and fix classList bug

* Change files

* feat: require trusted types for bindings to innerHtml & move core policy

* fix: bug that arises when there are real trusted types

* refactor: minor internal cleanup in the polyfills

* fix: remove polyfill external module dependency

Co-authored-by: EisenbergEffect <[email protected]>

* feat: implement template renderer infrastructure  (#5698)

* implement factory fn to create TemplateRenderer and ElementRenderer

* rename index to exports

* adding default render info object

* adding initial directive rendering

* adds initial custom element rendering

* add directive renderers

* add renderInfo to DirectiveRenderer

* use default directive renderers

* adding attribute binding tests

* ensure attributes don't get emitted twice for custom elements

* Adding internal function to render op codes so that we can omit template elements when rendering custom element templates

* emit template open and close codes from template parser

* implement FAST parser changes and fix tests

* working AspectedHTMLDirective changes into branch

* naive implementation of custom element template rendering

* adds rendering of template op code

* progress on elmeent rendering

* fixing custom element attribute rendering bug

* Change files

* adding boolean and property binding test

* fix bug preventing template elements from being parsed

* add failing template nesting test

* update parsing of content nodes to correctly render interpolated templates

* fix API report and formatting

* adding repeater rendering

* adding directive implementations for Ref, Slotted, and Children

* clean up op types to reduce rendant information

* remove commented code that is no longer needed

* adding tests for ref, slotted, and children

* re-use noop function for noop directives

* cache length of arrays in for loops

* adding style tests

* implementing style renderer

* remove 'data' from style id name

* adding tests

* renaming files to align with current conventions

* update attachShadow signature

* adding classList support

* fixing tests and supporting string types

* removing comment that is a non-concern

* add playwright install step to ci

* add browser path to ci script

* change install script to install at the package level

* update playwright

* Change files

* fixing test

Co-authored-by: nicholasrice <[email protected]>

* feat: new execution context design (#5800)

* refactor: new design for execution context

* feat: add two new event helpers to the execution context and tests

* fix: wip update types to match new context apis

* fix: update foundation and components template types

* Change files

* fix: update template type in fast-website

* fix: update site components for new template types

* fix: add missing api updates

Co-authored-by: EisenbergEffect <[email protected]>

* feat: new HTMLDirective API

* feat: new directive registration/identification model

* refactor: refine design/implementation of new directive aproach

* refactor: clean up comments, interfaces, types for directives/registries

* fix: update foundation to new APIs

* fix: update router to new directive APIs.

* fix: update ssr to new directive APIs

* refactor: clean up ssr switch to new directive APIs

* fix: update React wrapper lib to use latest APIs

* Change files

* fix: post rebase issues

* fix: update reflectAttributes directive to new directive APIs

* test: add more tests to capture new html/directive aspect scenarios

* Change files

* chore: run prettier on foundation

* Update packages/web-components/fast-ssr/src/template-parser/template-parser.spec.ts

Co-authored-by: Nicholas Rice <[email protected]>

* Update packages/web-components/fast-ssr/src/template-parser/template-parser.spec.ts

Co-authored-by: Nicholas Rice <[email protected]>

* Update packages/web-components/fast-foundation/src/directives/reflect-attributes.ts

Co-authored-by: Nicholas Rice <[email protected]>

* Update packages/web-components/fast-foundation/src/directives/reflect-attributes.ts

Co-authored-by: Nicholas Rice <[email protected]>

* chore: cleanup tests after rebase

Co-authored-by: Nicholas Rice <[email protected]>
Co-authored-by: nicholasrice <[email protected]>
Co-authored-by: Chris Holt <[email protected]>
Co-authored-by: EisenbergEffect <[email protected]>
  • Loading branch information
5 people authored Apr 13, 2022
1 parent 7036e33 commit 87ad6d0
Show file tree
Hide file tree
Showing 52 changed files with 1,168 additions and 682 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "major",
"comment": "feat: new directive registration/identification model",
"packageName": "@microsoft/fast-element",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "major",
"comment": "fix: update foundation to new APIs",
"packageName": "@microsoft/fast-foundation",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "major",
"comment": "fix: update React wrapper lib to use latest APIs",
"packageName": "@microsoft/fast-react-wrapper",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "major",
"comment": "fix: update router to new directive APIs.",
"packageName": "@microsoft/fast-router",
"email": "[email protected]",
"dependentChangeType": "patch"
}
2 changes: 1 addition & 1 deletion packages/utilities/fast-react-wrapper/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function getTagName<TElement, TEvents>(
) {
if (!config.name) {
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
const definition = FASTElementDefinition.forType(type)!;
const definition = FASTElementDefinition.getByType(type)!;

if (definition) {
config.name = definition.name;
Expand Down
129 changes: 90 additions & 39 deletions packages/web-components/fast-element/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export interface Accessor {
setValue(source: any, value: any): void;
}

// @public
export type AddViewBehaviorFactory = (factory: ViewBehaviorFactory) => string;

// Warning: (ae-internal-missing-underscore) The name "AdoptedStyleSheetsStrategy" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal
Expand All @@ -25,23 +28,23 @@ export class AdoptedStyleSheetsStrategy implements StyleStrategy {
}

// @public
export enum Aspect {
attribute = 0,
booleanAttribute = 1,
content = 3,
event = 5,
property = 2,
tokenList = 4
}
export const Aspect: Readonly<{
none: number;
attribute: number;
booleanAttribute: number;
property: number;
content: number;
tokenList: number;
event: number;
assign(directive: Aspected, value: string): void;
}>;

// @public
export abstract class AspectedHTMLDirective extends HTMLDirective {
abstract readonly aspect: Aspect;
abstract readonly binding?: Binding;
abstract captureSource(source: string): void;
createPlaceholder: (index: number) => string;
abstract readonly source: string;
abstract readonly target: string;
export interface Aspected {
aspectType: number;
binding?: Binding;
sourceAspect: string;
targetAspect: string;
}

// @public
Expand Down Expand Up @@ -106,7 +109,7 @@ export interface BindingConfig<T = any> {
}

// @alpha (undocumented)
export type BindingMode = Record<Aspect, BindingType>;
export type BindingMode = Record<number, BindingType>;

// @public
export interface BindingObserver<TSource = any, TReturn = any, TParent = any> extends Notifier {
Expand Down Expand Up @@ -172,14 +175,14 @@ export interface ChildViewTemplate<TSource = any, TParent = any> {
// @public
export type CompilationStrategy = (
html: string | HTMLTemplateElement,
directives: readonly HTMLDirective[]) => HTMLTemplateCompilationResult;
factories: Record<string, ViewBehaviorFactory>) => HTMLTemplateCompilationResult;

// @public
export const Compiler: {
setHTMLPolicy(policy: TrustedTypesPolicy): void;
compile<TSource = any, TParent = any, TContext extends ExecutionContext<TParent> = ExecutionContext<TParent>>(html: string | HTMLTemplateElement, directives: ReadonlyArray<HTMLDirective>): HTMLTemplateCompilationResult<TSource, TParent, TContext>;
compile<TSource = any, TParent = any, TContext extends ExecutionContext<TParent> = ExecutionContext<TParent>>(html: string | HTMLTemplateElement, directives: Record<string, ViewBehaviorFactory>): HTMLTemplateCompilationResult<TSource, TParent, TContext>;
setDefaultStrategy(strategy: CompilationStrategy): void;
aggregate(parts: (string | HTMLDirective)[]): HTMLDirective;
aggregate(parts: (string | ViewBehaviorFactory)[]): ViewBehaviorFactory;
};

// @public
Expand Down Expand Up @@ -218,6 +221,11 @@ export class Controller<TElement extends HTMLElement = HTMLElement> extends Prop
readonly view: ElementView<TElement> | null;
}

// Warning: (ae-internal-missing-underscore) The name "createTypeRegistry" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal
export function createTypeRegistry<TDefinition extends TypeDefinition>(): TypeRegistry<TDefinition>;

// @public
export function css(strings: TemplateStringsArray, ...values: (ComposableStyles | CSSDirective)[]): ElementStyles;

Expand All @@ -231,7 +239,7 @@ export class CSSDirective {
export function cssPartial(strings: TemplateStringsArray, ...values: (ComposableStyles | CSSDirective)[]): CSSDirective;

// @public
export function customElement(nameOrDef: string | PartialFASTElementDefinition): (type: Function) => void;
export function customElement(nameOrDef: string | PartialFASTElementDefinition): (type: Constructable<HTMLElement>) => void;

// @public
export type DecoratorAttributeConfiguration = Omit<AttributeConfiguration, "property">;
Expand Down Expand Up @@ -329,17 +337,18 @@ export const FASTElement: (new () => HTMLElement & FASTElement) & {
new (): HTMLElement;
prototype: HTMLElement;
}>(BaseType: TBase): new () => InstanceType<TBase> & FASTElement;
define<TType extends Function>(type: TType, nameOrDef?: string | PartialFASTElementDefinition | undefined): TType;
define<TType extends Constructable<HTMLElement>>(type: TType, nameOrDef?: string | PartialFASTElementDefinition | undefined): TType;
};

// @public
export class FASTElementDefinition<TType extends Function = Function> {
export class FASTElementDefinition<TType extends Constructable<HTMLElement> = Constructable<HTMLElement>> {
constructor(type: TType, nameOrConfig?: PartialFASTElementDefinition | string);
readonly attributeLookup: Record<string, AttributeDefinition>;
readonly attributes: ReadonlyArray<AttributeDefinition>;
define(registry?: CustomElementRegistry): this;
readonly elementOptions?: ElementDefinitionOptions;
static readonly forType: <TType_1 extends Function>(key: TType_1) => FASTElementDefinition<Function> | undefined;
static readonly getByType: (key: Function) => FASTElementDefinition<Constructable<HTMLElement>> | undefined;
static readonly getForInstance: (object: any) => FASTElementDefinition<Constructable<HTMLElement>> | undefined;
get isDefined(): boolean;
readonly name: string;
readonly propertyLookup: Record<string, AttributeDefinition>;
Expand All @@ -366,11 +375,23 @@ export interface FASTGlobal {
export function html<TSource = any, TParent = any, TContext extends ExecutionContext<TParent> = ExecutionContext<TParent>>(strings: TemplateStringsArray, ...values: TemplateValue<TSource, TParent, TContext>[]): ViewTemplate<TSource, TParent>;

// @public
export abstract class HTMLDirective implements ViewBehaviorFactory {
abstract createBehavior(targets: ViewBehaviorTargets): Behavior | ViewBehavior;
abstract createPlaceholder(index: number): string;
targetId: string;
readonly uniqueId: string;
export interface HTMLDirective {
createHTML(add: AddViewBehaviorFactory): string;
}

// @public
export const HTMLDirective: Readonly<{
getForInstance: (object: any) => HTMLDirectiveDefinition<Constructable<HTMLDirective>> | undefined;
getByType: (key: Function) => HTMLDirectiveDefinition<Constructable<HTMLDirective>> | undefined;
define<TType extends Constructable<HTMLDirective>>(type: TType, options?: PartialHTMLDirectiveDefinition | undefined): TType;
}>;

// @public
export function htmlDirective(options?: PartialHTMLDirectiveDefinition): (type: Constructable<HTMLDirective>) => void;

// @public
export interface HTMLDirectiveDefinition<TType extends Constructable<HTMLDirective> = Constructable<HTMLDirective>> extends Required<PartialHTMLDirectiveDefinition> {
readonly type: TType;
}

// @public
Expand Down Expand Up @@ -418,9 +439,9 @@ export interface ItemViewTemplate<TSource = any, TParent = any> {

// @public
export const Markup: Readonly<{
interpolation: (index: number) => string;
attribute: (index: number) => string;
comment: (index: number) => string;
interpolation: (id: string) => string;
attribute: (id: string) => string;
comment: (id: string) => string;
}>;

// Warning: (ae-internal-missing-underscore) The name "Mutable" should be prefixed with an underscore because the declaration is marked as @internal
Expand Down Expand Up @@ -492,7 +513,7 @@ export const oneTime: BindingConfig<DefaultBindingOptions> & BindingConfigResolv

// @public
export const Parser: Readonly<{
parse(value: string, directives: readonly HTMLDirective[]): (string | HTMLDirective)[] | null;
parse(value: string, factories: Record<string, ViewBehaviorFactory>): (string | ViewBehaviorFactory)[] | null;
}>;

// @public
Expand All @@ -505,6 +526,11 @@ export interface PartialFASTElementDefinition {
readonly template?: ElementViewTemplate;
}

// @public
export interface PartialHTMLDirectiveDefinition {
aspected?: boolean;
}

// @public
export class PropertyChangeNotifier implements Notifier {
constructor(subject: any);
Expand Down Expand Up @@ -572,12 +598,14 @@ export class RepeatBehavior<TSource = any> implements Behavior, Subscriber {
}

// @public
export class RepeatDirective<TSource = any> extends HTMLDirective {
export class RepeatDirective<TSource = any> implements HTMLDirective, ViewBehaviorFactory {
constructor(itemsBinding: Binding, templateBinding: Binding<TSource, SyntheticViewTemplate>, options: RepeatOptions);
createBehavior(targets: ViewBehaviorTargets): RepeatBehavior<TSource>;
createPlaceholder: (index: number) => string;
createHTML(add: AddViewBehaviorFactory): string;
id: string;
// (undocumented)
readonly itemsBinding: Binding;
nodeId: string;
// (undocumented)
readonly options: RepeatOptions;
// (undocumented)
Expand Down Expand Up @@ -630,11 +658,13 @@ export class Splice {
}

// @public
export abstract class StatelessAttachedAttributeDirective<T> extends HTMLDirective implements ViewBehavior {
export abstract class StatelessAttachedAttributeDirective<T> implements HTMLDirective, ViewBehaviorFactory, ViewBehavior {
constructor(options: T);
abstract bind(source: any, context: ExecutionContext, targets: ViewBehaviorTargets): void;
createBehavior(targets: ViewBehaviorTargets): ViewBehavior;
createPlaceholder: (index: number) => string;
createHTML(add: AddViewBehaviorFactory): string;
id: string;
nodeId: string;
// (undocumented)
protected options: T;
abstract unbind(source: any, context: ExecutionContext, targets: ViewBehaviorTargets): void;
Expand Down Expand Up @@ -704,6 +734,26 @@ export type TrustedTypesPolicy = {
createHTML(html: string): string;
};

// Warning: (ae-internal-missing-underscore) The name "TypeDefinition" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal
export interface TypeDefinition {
// (undocumented)
type: Function;
}

// Warning: (ae-internal-missing-underscore) The name "TypeRegistry" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal
export interface TypeRegistry<TDefinition extends TypeDefinition> {
// (undocumented)
getByType(key: Function): TDefinition | undefined;
// (undocumented)
getForInstance(object: any): TDefinition | undefined;
// (undocumented)
register(definition: TDefinition): boolean;
}

// @public
export interface ValueConverter {
fromView(value: any): any;
Expand All @@ -728,7 +778,8 @@ export interface ViewBehavior<TSource = any, TParent = any> {
// @public
export interface ViewBehaviorFactory {
createBehavior(targets: ViewBehaviorTargets): Behavior | ViewBehavior;
targetId: string;
id: string;
nodeId: string;
}

// @public
Expand All @@ -738,9 +789,9 @@ export type ViewBehaviorTargets = {

// @public
export class ViewTemplate<TSource = any, TParent = any, TContext extends ExecutionContext<TParent> = ExecutionContext> implements ElementViewTemplate<TSource, TParent>, SyntheticViewTemplate<TSource, TParent, TContext> {
constructor(html: string | HTMLTemplateElement, directives: ReadonlyArray<HTMLDirective>);
constructor(html: string | HTMLTemplateElement, factories: Record<string, ViewBehaviorFactory>);
create(hostBindingTarget?: Element): HTMLView<TSource, TParent, TContext>;
readonly directives: ReadonlyArray<HTMLDirective>;
readonly factories: Record<string, ViewBehaviorFactory>;
readonly html: string | HTMLTemplateElement;
render(source: TSource, host: Node, hostBindingTarget?: Element, context?: TContext): HTMLView<TSource, TParent, TContext>;
type: any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ export class Controller<
return controller;
}

const definition = FASTElementDefinition.forType(element.constructor);
const definition = FASTElementDefinition.getForInstance(element);

if (definition === void 0) {
throw FAST.error(Message.missingElementDefinition);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { FASTElementDefinition } from "./fast-definitions";
import { ElementStyles } from "../styles/element-styles";

describe("FASTElementDefinition", () => {
class MyElement {}
class MyElement extends HTMLElement {}

context("styles", () => {
it("can accept a string", () => {
Expand Down
Loading

0 comments on commit 87ad6d0

Please sign in to comment.