Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Add a registry path export for FAST element definition lookups.",
"packageName": "@microsoft/fast-element",
"email": "7559015+janechu@users.noreply.github.com",
"dependentChangeType": "none"
}
7 changes: 5 additions & 2 deletions packages/fast-element/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ For deep dives into specific areas, see the linked detailed documents.
The library's kernel is module-scoped rather than stored on `globalThis`: import `FAST` from `@microsoft/fast-element`, `Updates` from `@microsoft/fast-element`, and `Observable` from `@microsoft/fast-element`.

The root entrypoint exports the FAST Element implementation APIs. Focused package
path exports remain available when a consumer wants a narrower entrypoint.
path exports remain available when a consumer wants a narrower entrypoint,
including `@microsoft/fast-element/registry.js` for FAST element definition
lookups.

---

Expand Down Expand Up @@ -99,7 +101,7 @@ The previous `FAST.getById()` slot registry, `FASTGlobal` type, and `KernelServi
- `onAttributeChangedCallback()` is the standard handler that processes attribute changes. During the prerendered bind, it is temporarily swapped to a no-op (see above) to avoid redundant processing of server-rendered attribute values.
- Exposes `addBehavior` / `removeBehavior` for dynamic `HostBehavior` management (used by `ElementStyles`).

`FASTElementDefinition` wraps all the metadata for a custom element class: its tag name, template, styles, and observed attribute list. It is created by `FASTElement.compose()` (which returns `Promise<FASTElementDefinition>`, always resolving immediately) and registered globally via `fastElementRegistry`. `PartialFASTElementDefinition.template` may be either a concrete `ElementViewTemplate<InstanceType<TType>>` or a `FASTElementTemplateResolver<TType>` function that receives the composed definition and returns the concrete template (sync or async). `FASTElementDefinition.template` always stores the concrete `ElementViewTemplate<InstanceType<TType>>` after composition or resolver settlement. `FASTElement.define()` returns `Promise<TType>` β€” resolving immediately for complete definitions or definitions without an initial template, and resolving async template resolver functions only after extensions have had a chance to update the definition. `FASTElementDefinition.register()` returns `Promise<Function>` β€” resolving when a definition with the given name has been registered.
`FASTElementDefinition` wraps all the metadata for a custom element class: its tag name, template, styles, and observed attribute list. It is created by `FASTElement.compose()` (which returns `Promise<FASTElementDefinition>`, always resolving immediately) and registered globally via `fastElementRegistry`. Consumers that need focused access to definition lookup can import `fastElementRegistry` from `@microsoft/fast-element/registry.js`. `PartialFASTElementDefinition.template` may be either a concrete `ElementViewTemplate<InstanceType<TType>>` or a `FASTElementTemplateResolver<TType>` function that receives the composed definition and returns the concrete template (sync or async). `FASTElementDefinition.template` always stores the concrete `ElementViewTemplate<InstanceType<TType>>` after composition or resolver settlement. `FASTElement.define()` returns `Promise<TType>` β€” resolving immediately for complete definitions or definitions without an initial template, and resolving async template resolver functions only after extensions have had a chance to update the definition. `FASTElementDefinition.register()` returns `Promise<Function>` β€” resolving when a definition with the given name has been registered.

#### Extensions

Expand Down Expand Up @@ -535,6 +537,7 @@ src/
β”œβ”€β”€ metadata.ts # Reflect-based metadata helpers
β”œβ”€β”€ utilities.ts # UnobservableMutationObserver and other helpers
β”œβ”€β”€ debug.ts # Exports enableDebug() for human-readable FAST errors
β”œβ”€β”€ registry.ts # fastElementRegistry focused path export
β”œβ”€β”€ observation/
β”‚ β”œβ”€β”€ observable.ts # Observable, @observable, ExpressionNotifier, ExecutionContext
β”‚ β”œβ”€β”€ notifier.ts # Subscriber, Notifier, SubscriberSet, PropertyChangeNotifier
Expand Down
6 changes: 4 additions & 2 deletions packages/fast-element/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ Bundle sizes for each tree-shakeable export are tracked in [`SIZES.md`](./SIZES.
The root `@microsoft/fast-element` entrypoint exports the FAST Element
implementation APIs, including the element base class, kernel, controller,
definition APIs, template APIs, binding helpers, directives, styles, and schema
helpers. Declarative, hydration, context, and dependency injection APIs are
available from their focused path exports.
helpers. The FAST element registry is also available from
`@microsoft/fast-element/registry.js` for focused definition lookups.
Declarative, hydration, context, and dependency injection APIs are available
from their focused path exports.

Focused package path exports remain available for consumers that want to import
a narrower entrypoint directly. The website's
Expand Down
17 changes: 7 additions & 10 deletions packages/fast-element/docs/api-report.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -571,9 +571,7 @@ export class FASTElementDefinition<TType extends Constructable<HTMLElement> = Co
// @public
export type FASTElementExtension = (definition: FASTElementDefinition) => void;

// Warning: (ae-internal-missing-underscore) The name "fastElementRegistry" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal
// @public
export const fastElementRegistry: TypeRegistry<FASTElementDefinition>;

// @public
Expand Down Expand Up @@ -1177,16 +1175,15 @@ export const TwoWaySettings: Readonly<{
configure(settings: TwoWaySettings): void;
}>;

// Warning: (ae-forgotten-export) The symbol "TypeDefinition" needs to be exported by the entry point index.d.ts
// Warning: (ae-internal-missing-underscore) The name "TypeRegistry" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal
// @public
export interface TypeDefinition {
type: Function;
}

// @public
export interface TypeRegistry<TDefinition extends TypeDefinition> {
// (undocumented)
getByType(key: Function): TDefinition | undefined;
// (undocumented)
getForInstance(object: any): TDefinition | undefined;
// (undocumented)
register(definition: TDefinition): boolean;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ The DOM after hydration should look like this:

### Fast Element Registry

The `fastElementRegistry` serves as the central coordination point between the two packages:
The `fastElementRegistry` serves as the central coordination point between the
two packages and is available to consumers from
`@microsoft/fast-element/registry.js`:

- Stores partial element definitions created by `define()`
- Provides lookup mechanism via `register()` for template attachment
Expand Down
5 changes: 5 additions & 0 deletions packages/fast-element/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
"test": "./src/components/fast-element.ts",
"default": "./dist/esm/components/fast-element.js"
},
"./registry.js": {
"types": "./dist/dts/registry.d.ts",
"test": "./src/registry.ts",
"default": "./dist/esm/registry.js"
},
"./declarative.js": {
"types": "./dist/dts/declarative/index.d.ts",
"test": "./src/declarative/index.ts",
Expand Down
15 changes: 11 additions & 4 deletions packages/fast-element/src/components/fast-definitions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { type Constructable, isFunction, isString } from "../interfaces.js";
import { Observable } from "../observation/observable.js";
import { createTypeRegistry, type TypeRegistry } from "../platform.js";
import {
createTypeRegistry,
type TypeDefinition,
type TypeRegistry,
} from "../platform.js";
import { type ComposableStyles, ElementStyles } from "../styles/element-styles.js";
import type { ElementViewTemplate } from "../templating/template.js";
import { type AttributeConfiguration, AttributeDefinition } from "./attributes.js";
Expand All @@ -11,13 +15,16 @@ const defaultElementOptions: ElementDefinitionOptions = {};
const fastElementBaseTypes = new Set<Function>();

/**
* The FAST custom element registry
* @internal
* The FAST custom element registry.
* @remarks
* This registry stores FAST element definitions by constructor so consumers can
* look up the `FASTElementDefinition` associated with an element type or instance.
* @public
*/
export const fastElementRegistry: TypeRegistry<FASTElementDefinition> =
createTypeRegistry<FASTElementDefinition>();

export type { TypeRegistry };
export type { TypeDefinition, TypeRegistry };

/**
* Shadow root initialization options.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,41 @@ test.describe("extension subpaths", () => {
expect(result.hasSchema).toBe(true);
});

test("exports the FAST element registry from the registry subpath", async ({
page,
}) => {
await page.goto("/");

const result = await page.evaluate(async () => {
// @ts-expect-error: Client module.
const { FASTElementDefinition, fastElementRegistry } = await import(
"/extension-subpaths-main.js"
);

class RegistrySubpathElement extends HTMLElement {}

const name = `registry-subpath-element-${crypto.randomUUID()}`;
const definition = await FASTElementDefinition.compose(
RegistrySubpathElement,
{ name },
);
definition.define();
const instance = document.createElement(name);

return {
hasRegistry: typeof fastElementRegistry.getByType === "function",
getByTypeReturnsDefinition:
fastElementRegistry.getByType(RegistrySubpathElement) === definition,
getForInstanceReturnsDefinition:
fastElementRegistry.getForInstance(instance) === definition,
};
});

expect(result.hasRegistry).toBe(true);
expect(result.getByTypeReturnsDefinition).toBe(true);
expect(result.getForInstanceReturnsDefinition).toBe(true);
});

test("observerMap accepts a schema for non-declarative use", async ({ page }) => {
await page.goto("/");

Expand Down
1 change: 1 addition & 0 deletions packages/fast-element/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type {
FASTElementTemplateResolver,
PartialFASTElementDefinition,
ShadowRootOptions,
TypeDefinition,
TypeRegistry,
} from "./components/fast-definitions.js";
export {
Expand Down
26 changes: 22 additions & 4 deletions packages/fast-element/src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,38 @@ export function getDebugMessageLookup(): Record<number, string> {
export const emptyArray = Object.freeze([]);

/**
* Do not change. Part of shared kernel contract.
* @internal
* A type that can be registered with a `TypeRegistry`.
* @public
*/
export interface TypeDefinition {
/**
* The registered type constructor.
*/
type: Function;
}

/**
* Do not change. Part of shared kernel contract.
* @internal
* A registry that stores definitions by type.
* @public
*/
export interface TypeRegistry<TDefinition extends TypeDefinition> {
/**
* Registers a type definition.
* @param definition - The type definition to register.
* @returns `true` when the definition was registered, otherwise `false`.
*/
register(definition: TDefinition): boolean;

/**
* Gets a definition by type.
* @param key - The type to retrieve the definition for.
*/
getByType(key: Function): TDefinition | undefined;

/**
* Gets a definition by instance.
* @param object - The instance to retrieve the definition for.
*/
getForInstance(object: any): TDefinition | undefined;
}

Expand Down
6 changes: 6 additions & 0 deletions packages/fast-element/src/registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export {
FASTElementDefinition,
fastElementRegistry,
type TypeDefinition,
type TypeRegistry,
} from "./components/fast-definitions.js";
4 changes: 4 additions & 0 deletions packages/fast-element/test/extension-subpaths-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ export {
ObserverMap,
observerMap,
} from "@microsoft/fast-element/observer-map.js";
export {
FASTElementDefinition,
fastElementRegistry,
} from "@microsoft/fast-element/registry.js";
export { Schema } from "../src/components/schema.js";
1 change: 1 addition & 0 deletions sites/website/src/docs/3.x/advanced/path-exports.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ This table is generated from the `exports` field in `@microsoft/fast-element/pac
| `@microsoft/fast-element` | Root implementation export for FAST Element APIs. | `./dist/esm/index.js` | `./dist/dts/index.d.ts` |
| `@microsoft/fast-element/debug.js` | Debug message helpers. | `./dist/esm/debug.js` | `./dist/dts/debug.d.ts` |
| `@microsoft/fast-element/fast-element.js` | FASTElement and the customElement decorator. | `./dist/esm/components/fast-element.js` | `./dist/dts/components/fast-element.d.ts` |
| `@microsoft/fast-element/registry.js` | FAST element definition registry APIs. | `./dist/esm/registry.js` | `./dist/dts/registry.d.ts` |
| `@microsoft/fast-element/declarative.js` | Path-only declarative template APIs. | `./dist/esm/declarative/index.js` | `./dist/dts/declarative/index.d.ts` |
| `@microsoft/fast-element/declarative-utilities.js` | Declarative parser and observer-map utilities. | `./dist/esm/declarative/utilities.js` | `./dist/dts/declarative/utilities.d.ts` |
| `@microsoft/fast-element/attribute-map.js` | Schema-driven attribute map extension. | `./dist/esm/declarative/attribute-map.js` | `./dist/dts/declarative/attribute-map.d.ts` |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
id: "fast-element.fastelementregistry"
title: "fastElementRegistry variable"
layout: 3x-api
eleventyNavigation:
key: "api3xfast-element.fastelementregistry"
parent: "api3xfast-element"
title: "fastElementRegistry variable"
navigationOptions:
activeKey: "api3xfast-element.fastelementregistry"
---
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[@microsoft/fast-element](../fast-element/index.html) &gt; [fastElementRegistry](../fast-element.fastelementregistry/index.html)

## fastElementRegistry variable

The FAST custom element registry.

**Signature:**

```typescript
fastElementRegistry: TypeRegistry<FASTElementDefinition>
```

## Remarks

This registry stores FAST element definitions by constructor so consumers can look up the `FASTElementDefinition` associated with an element type or instance.
33 changes: 33 additions & 0 deletions sites/website/src/docs/3.x/api/fast-element.md
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,28 @@ Lifecycle callbacks for template events.
The settings required to enable two-way binding.


</td></tr>
<tr><td>

[TypeDefinition](../fast-element.typedefinition/)


</td><td>

A type that can be registered with a `TypeRegistry`<!-- -->.


</td></tr>
<tr><td>

[TypeRegistry](../fast-element.typeregistry/)


</td><td>

A registry that stores definitions by type.


</td></tr>
<tr><td>

Expand Down Expand Up @@ -1519,6 +1541,17 @@ The FAST messaging API for warnings and errors.
A minimal base class for FASTElements that also provides static helpers for working with FASTElements.


</td></tr>
<tr><td>

[fastElementRegistry](../fast-element.fastelementregistry/)


</td><td>

The FAST custom element registry.


</td></tr>
<tr><td>

Expand Down
68 changes: 68 additions & 0 deletions sites/website/src/docs/3.x/api/fast-element.typedefinition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
id: "fast-element.typedefinition"
title: "TypeDefinition interface"
layout: 3x-api
eleventyNavigation:
key: "api3xfast-element.typedefinition"
parent: "api3xfast-element"
title: "TypeDefinition interface"
navigationOptions:
activeKey: "api3xfast-element.typedefinition"
---
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[@microsoft/fast-element](../fast-element/index.html) &gt; [TypeDefinition](../fast-element.typedefinition/index.html)

## TypeDefinition interface

A type that can be registered with a `TypeRegistry`<!-- -->.

**Signature:**

```typescript
export interface TypeDefinition
```

## Properties

<table><thead><tr><th>

Property


</th><th>

Modifiers


</th><th>

Type


</th><th>

Description


</th></tr></thead>
<tbody><tr><td>

[type](../fast-element.typedefinition.type/)


</td><td>


</td><td>

Function


</td><td>

The registered type constructor.


</td></tr>
</tbody></table>
Loading