From 7b0030542dc5ab897f30ba46403edbc86fa990df Mon Sep 17 00:00:00 2001 From: nicholasrice Date: Wed, 18 Nov 2020 10:47:08 -0800 Subject: [PATCH] wire in registry --- .../src/configuration/configuration.ts | 51 ++++++----- .../custom-property-manager.ts | 37 ++------ .../src/custom-properties/manager.ts | 4 +- .../design-system-provider.ts | 8 +- .../src/design-tokens/configuration.ts | 16 ---- .../src/design-tokens/index.ts | 1 - .../src/design-tokens/library.ts | 13 ++- .../src/design-tokens/provider.ts | 31 ++++--- .../src/design-tokens/registration.ts | 84 +++++++++++++++++++ .../src/design-tokens/tokens.ts | 9 -- .../fast-foundation/src/di/di.ts | 13 +-- .../src/foundation/foundation.ts | 4 +- 12 files changed, 159 insertions(+), 112 deletions(-) delete mode 100644 packages/web-components/fast-foundation/src/design-tokens/configuration.ts create mode 100644 packages/web-components/fast-foundation/src/design-tokens/registration.ts delete mode 100644 packages/web-components/fast-foundation/src/design-tokens/tokens.ts diff --git a/packages/web-components/fast-foundation/src/configuration/configuration.ts b/packages/web-components/fast-foundation/src/configuration/configuration.ts index f7559e62e64..446a26c09fd 100644 --- a/packages/web-components/fast-foundation/src/configuration/configuration.ts +++ b/packages/web-components/fast-foundation/src/configuration/configuration.ts @@ -5,11 +5,15 @@ import { PartialFASTElementDefinition, } from "@microsoft/fast-element"; import { - CSSCustomPropertyManager, CustomPropertyManagerImpl, + DICustomPropertyManager, } from "../css-custom-property-manager"; -import { DesignTokenLibraryImpl, DesignTokens } from "../design-tokens"; -import { DesignTokenDefinition } from "../design-tokens/configuration"; +import { DesignTokenLibraryImpl, DIDesignTokens } from "../design-tokens"; +import { + DesignTokenDefinition, + DesignTokenRegistryImpl, + DIDesignTokenRegistry, +} from "../design-tokens/registration"; import { DI, InterfaceSymbol, Key, Registration } from "../di"; import { supportsAdoptedStylesheets } from "../feature-detection"; @@ -147,20 +151,26 @@ export class ConfigurationImpl implements Configuration { private designTokens = new DesignTokenLibraryImpl(); private customPropertyManager = new CustomPropertyManagerImpl(); private customPropertySheet = new CSSStyleSheet(); + private designTokenRegistration = new DesignTokenRegistryImpl(); + private templateRegistry = new Map(); + private stylesRegistry = new Map(); + private elementRegistry = new Map(); private designTokenTarget: CSSStyleRule; constructor(options: ConfigurationOptions = {}) { this.prefix = options.prefix || "fast"; - DI.getOrCreateDOMContainer().register( - Registration.instance(ConfigurationInterface, this), - Registration.callback(DesignTokens, () => { + const container = DI.getOrCreateDOMContainer(); + container.register( + Registration.instance(DIConfiguration, this), + Registration.instance(DIDesignTokenRegistry, this.designTokenRegistration), + Registration.instance(DICustomPropertyManager, this.customPropertyManager), + Registration.callback(DIDesignTokens, () => { const tokens = new DesignTokenLibraryImpl(); tokens.upstream = this.designTokens; return tokens; - }), - Registration.instance(CSSCustomPropertyManager, this.customPropertyManager) + }) ); this.designTokenTarget = this.customPropertySheet.cssRules[ @@ -240,13 +250,9 @@ export class ConfigurationImpl implements Configuration { } /** {@inheritdoc Configuration.registerDesignToken} */ - public registerDesignToken(registration: DesignTokenDefinition) { - const { key, value, customProperty } = registration; - this.designTokenRegistry.set(key, registration); - - if (customProperty && key !== customProperty) { - this.customPropertyManager.alias(key, customProperty); - } + public registerDesignToken(registration: DesignTokenDefinition) { + const { key, value } = registration; + this.designTokenRegistration.register(registration); if (value) { this.designTokens.set(key, value); @@ -275,28 +281,27 @@ export class ConfigurationImpl implements Configuration { this.designTokens.set(key, value); } + /** + * Reacts to changes to Design Tokens, setting + * the CSSCustomProperty if it is defined. + */ private designTokenChangeHandler = { handleChange: (source, keys: string[]) => { keys.forEach(key => { - const def = this.designTokenRegistry.get(key); + const def = this.designTokenRegistration.get(key); const value = this.designTokens.get(key); if (def && def.customProperty && value) { this.designTokenTarget.style.setProperty( - this.customPropertyManager.name(key), + CustomPropertyManagerImpl.format(def.customProperty), value as any ); } }); }, }; - - private templateRegistry = new Map(); - private stylesRegistry = new Map(); - private elementRegistry = new Map(); - private designTokenRegistry = new Map>(); } -export const ConfigurationInterface: InterfaceSymbol = DI.createInterface( +export const DIConfiguration: InterfaceSymbol = DI.createInterface( "Configuration" ).noDefault(); diff --git a/packages/web-components/fast-foundation/src/css-custom-property-manager/custom-property-manager.ts b/packages/web-components/fast-foundation/src/css-custom-property-manager/custom-property-manager.ts index 210d6002537..01d7fc2454d 100644 --- a/packages/web-components/fast-foundation/src/css-custom-property-manager/custom-property-manager.ts +++ b/packages/web-components/fast-foundation/src/css-custom-property-manager/custom-property-manager.ts @@ -1,6 +1,6 @@ import { css, ElementStyles } from "@microsoft/fast-element"; import { DI, InterfaceSymbol, Key } from "../di"; -export interface CSSCustomPropertyManagerInterface { +export interface CustomPropertyManager { /** * Retrieves an {@link @microsoft/fast-element#ElementStyles} by key and value. If * no entry for the provided key and value exist, one will be created. The returned @@ -10,24 +10,10 @@ export interface CSSCustomPropertyManagerInterface { * @param value The value of the key being resolved. */ get(key: string, value: any): ElementStyles; - - /** - * Aliases a key to a new name. The name will be the name of the CSS custom property. - * @param key The key to alias - * @param name The new to alias the key too - */ - alias(key: string, name: string): void; - - /** - * Returns the CSS custom property name (including the '--' prefix) of a key. - * @param key The key to get the name of - */ - - name(key: string): string; } + export class CustomPropertyManagerImpl { private static cache = new Map>(); - private names = new Map(); private selector = ":host"; /** @@ -49,33 +35,20 @@ export class CustomPropertyManagerImpl { return v; } - /** - * {@inheritdoc CustomPropertyManager.alias} - */ - public alias(key: string, name: string) { - this.names.set(key, name); - } - - /** - * {@inheritdoc CustomPropertyManager.name} - */ - public name(key: string) { - return CustomPropertyManagerImpl.format(this.names.get(key) || key); - } /** * Creates an ElementStyles with the key/value CSS custom property * on the host */ private create(key, value): ElementStyles { - return css`${this.selector}{${this.name(key)}:${value};}`; + return css`${this.selector}{${CustomPropertyManagerImpl.format(key)}:${value};}`; } /** * Formats a name as a CSS custom property * @param name The name to format */ - private static format(name: string) { + public static format(name: string) { return `--${name}`; } } @@ -83,6 +56,6 @@ export class CustomPropertyManagerImpl { /** * DI decorator to get the app CustomPropertyManager */ -export const CSSCustomPropertyManager: InterfaceSymbol = DI.createInterface( +export const DICustomPropertyManager: InterfaceSymbol = DI.createInterface( "custom-property-manager" ).noDefault(); diff --git a/packages/web-components/fast-foundation/src/custom-properties/manager.ts b/packages/web-components/fast-foundation/src/custom-properties/manager.ts index 6ae39388a2c..11e1f4af9fc 100644 --- a/packages/web-components/fast-foundation/src/custom-properties/manager.ts +++ b/packages/web-components/fast-foundation/src/custom-properties/manager.ts @@ -38,7 +38,7 @@ export interface CustomPropertyManagerClient extends FASTElement, HTMLElement { * * @public */ -export interface CustomPropertyManager { +export interface CSSCustomPropertyManager { /** * The CustomPropertyManagerTarget responsible for evaluating CSSCustomPropertyDefinitions */ @@ -92,7 +92,7 @@ export interface CustomPropertyManager { isSubscribed?(provider: CustomPropertyManagerClient): boolean; } -abstract class CustomPropertyManagerBase implements CustomPropertyManager { +abstract class CustomPropertyManagerBase implements CSSCustomPropertyManager { /** * A queue of additions and deletions. Operations will be queued when customPropertyTarget is null */ diff --git a/packages/web-components/fast-foundation/src/design-system-provider/design-system-provider.ts b/packages/web-components/fast-foundation/src/design-system-provider/design-system-provider.ts index a709c4dc78d..626b7cb71bd 100644 --- a/packages/web-components/fast-foundation/src/design-system-provider/design-system-provider.ts +++ b/packages/web-components/fast-foundation/src/design-system-provider/design-system-provider.ts @@ -13,7 +13,7 @@ import { } from "../custom-properties/index"; import { ConstructableStylesCustomPropertyManager, - CustomPropertyManager, + CSSCustomPropertyManager, CustomPropertyManagerClient, StyleElementCustomPropertyManager, } from "../custom-properties/manager"; @@ -223,10 +223,10 @@ export class DesignSystemProvider extends FASTElement * the DesignSystemProvider depends on. */ @observable - public customPropertyManager: CustomPropertyManager; + public customPropertyManager: CSSCustomPropertyManager; private customPropertyManagerChanged( - prev: CustomPropertyManager | void, - next: CustomPropertyManager + prev: CSSCustomPropertyManager | void, + next: CSSCustomPropertyManager ) { if (prev && prev.unsubscribe) { prev.unsubscribe(this); diff --git a/packages/web-components/fast-foundation/src/design-tokens/configuration.ts b/packages/web-components/fast-foundation/src/design-tokens/configuration.ts deleted file mode 100644 index f264e779d13..00000000000 --- a/packages/web-components/fast-foundation/src/design-tokens/configuration.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface DesignTokenDefinition { - /** - * The key for which the token can be accessed. - */ - key: string; - - /** - * The CSS custom property name - */ - customProperty?: string; - - /** - * The default value. - */ - value?: T; -} diff --git a/packages/web-components/fast-foundation/src/design-tokens/index.ts b/packages/web-components/fast-foundation/src/design-tokens/index.ts index c5670da3a15..cd48ed05471 100644 --- a/packages/web-components/fast-foundation/src/design-tokens/index.ts +++ b/packages/web-components/fast-foundation/src/design-tokens/index.ts @@ -1,4 +1,3 @@ export * from "./library"; -export * from "./tokens"; import DesignTokenProvider from "./provider"; export { DesignTokenProvider }; diff --git a/packages/web-components/fast-foundation/src/design-tokens/library.ts b/packages/web-components/fast-foundation/src/design-tokens/library.ts index e6fb18653ac..6cf74322053 100644 --- a/packages/web-components/fast-foundation/src/design-tokens/library.ts +++ b/packages/web-components/fast-foundation/src/design-tokens/library.ts @@ -1,6 +1,7 @@ import { Subscriber } from "@microsoft/fast-element"; +import { DI, InterfaceSymbol } from "../di"; -interface DesignTokenLibrary { +export interface DesignTokenLibrary { /** * Gets the composed value associated to a key. This method will ask any * upstream DesignSystem for the value if a local value does not exist. @@ -46,7 +47,8 @@ interface DesignTokenLibrary { keys(): Array; } -interface InheritableDesignTokenLibrary extends DesignTokenLibrary { +export interface InheritableDesignTokenLibrary + extends DesignTokenLibrary { /** * The upstream object an InheritableDesignTokenLibrary should inherit from. */ @@ -210,3 +212,10 @@ export class DesignTokenLibraryImpl implements InheritableDesignTokenLibrary< } } } + +export const DIDesignTokens: InterfaceSymbol> = DI.createInterface>({ + friendlyName: "DesignTokens", + respectConnection: true, +}).noDefault(); diff --git a/packages/web-components/fast-foundation/src/design-tokens/provider.ts b/packages/web-components/fast-foundation/src/design-tokens/provider.ts index 1f7e761477b..3f2b2162fba 100644 --- a/packages/web-components/fast-foundation/src/design-tokens/provider.ts +++ b/packages/web-components/fast-foundation/src/design-tokens/provider.ts @@ -1,23 +1,28 @@ import { Constructable, ElementStyles, FASTElement } from "@microsoft/fast-element"; import { - CSSCustomPropertyManager, - CustomPropertyManagerImpl, + CustomPropertyManager, + DICustomPropertyManager, } from "../css-custom-property-manager"; -import { DesignTokenLibraryImpl } from "../design-tokens/library"; +import { + DesignTokenLibraryImpl, + InheritableDesignTokenLibrary, +} from "../design-tokens/library"; import { DI, Registration } from "../di"; -import { DesignTokens } from "./tokens"; +import { DesignTokenRegistry, DIDesignTokenRegistry } from "./registration"; +import { DIDesignTokens } from "./library"; export default >(Base: TBase) => { const C = class extends Base { - public designTokens: DesignTokenLibraryImpl; - private customPropertyManager: CustomPropertyManagerImpl; + public designTokens: InheritableDesignTokenLibrary; + private customPropertyManager: CustomPropertyManager; private localSheets = new Map(); + private designTokenRegistry: DesignTokenRegistry; constructor(...args: any[]) { super(...args); DI.getOrCreateDOMContainer(this).register( - Registration.callback(DesignTokens, () => { + Registration.callback(DIDesignTokens, () => { const tokens = new DesignTokenLibraryImpl(); tokens.upstream = this.designTokens; @@ -29,7 +34,6 @@ export default >(Base: TB connectedCallback() { super.connectedCallback(); this.designTokens.subscribe(this); - // How do I know what should be reflected to CSS custom properties? } /** @@ -41,9 +45,11 @@ export default >(Base: TB */ public handleChange(source: DesignTokenLibraryImpl, keys: Array) { keys.forEach(key => { - if (source.hasLocal(key)) { + const customProperty = this.designTokenRegistry.customProperty(key); + + if (source.hasLocal(key) && customProperty) { const sheet = this.customPropertyManager.get( - key, + customProperty, this.designTokens.get(key) ); const prevSheet = this.localSheets.get(key); @@ -59,8 +65,9 @@ export default >(Base: TB } }; - DesignTokens(C.prototype, "designTokens"); - CSSCustomPropertyManager(C.prototype, "customPropertyManager"); + DIDesignTokenRegistry(C.prototype, "designTokenRegistry"); + DIDesignTokens(C.prototype, "designTokens"); + DICustomPropertyManager(C.prototype, "customPropertyManager"); return C; }; diff --git a/packages/web-components/fast-foundation/src/design-tokens/registration.ts b/packages/web-components/fast-foundation/src/design-tokens/registration.ts new file mode 100644 index 00000000000..e26acd15625 --- /dev/null +++ b/packages/web-components/fast-foundation/src/design-tokens/registration.ts @@ -0,0 +1,84 @@ +import { DI } from "../di"; + +export interface DesignTokenDefinition { + /** + * The key for which the token can be accessed. + */ + readonly key: K; + + /** + * The CSS custom property name + */ + readonly customProperty?: string; + + /** + * The default value. + */ + readonly value?: V; +} + +export interface DesignTokenRegistry { + /** + * Register a Design Token definition + * @param definition - The definition to register + */ + register(definition: DesignTokenDefinition); + + /** + * Gets the CSS custom property name of a Design Token, or undefined if the Token is + * not associated to CSS custom property. + * @param key - The Design Token key to get the CSS custom property name of + */ + customProperty(key: string): string | undefined; + + /** + * Gets the value a property key was registered with, or otherwise undefined. + * @param key - THe key for which to get the value of + */ + value(key: string): string | undefined; + + /** + * Determines if a Design Token has been registered + * @param key - The key for which to check if a Design Token has been registered + */ + has(key: string): boolean; + + /** + * Returns a {@link DesignTokenDefinition} for a key, or undefined if one does not exist. + * @param key - The key for which to get a {@link DesignTokenDefinition } + */ + get(key: string): DesignTokenDefinition | undefined; +} + +export class DesignTokenRegistryImpl implements DesignTokenRegistry { + #definitions = new Map>(); + + /** @inheritdoc DesignTokenRegistry.register */ + public register(definition: DesignTokenDefinition) { + this.#definitions.set(definition.key, definition); + } + + /** @inheritdoc DesignTokenRegistry.customProperty */ + public customProperty(key: string): string | undefined { + return this.get(key)?.customProperty || undefined; + } + + /** @inheritdoc DesignTokenRegistry.value */ + public value(key: string): string | undefined { + return this.get(key)?.value || undefined; + } + + /** @inheritdoc DesignTokenRegistry.has */ + public has(key: string): boolean { + return this.#definitions.has(key); + } + + /** @inheritdoc DesignTokenRegistry.get */ + public get(key: string): DesignTokenDefinition | undefined { + return this.#definitions.get(key); + } +} + +export const DIDesignTokenRegistry = DI.createInterface( + "DesignTokenRegistration" +).noDefault(); diff --git a/packages/web-components/fast-foundation/src/design-tokens/tokens.ts b/packages/web-components/fast-foundation/src/design-tokens/tokens.ts deleted file mode 100644 index 0ac002ccee6..00000000000 --- a/packages/web-components/fast-foundation/src/design-tokens/tokens.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { DI, InterfaceSymbol } from "../di"; -import { DesignTokenLibraryImpl } from "./library"; - -export const DesignTokens: InterfaceSymbol> = DI.createInterface>({ - friendlyName: "DesignTokens", - respectConnection: true, -}).noDefault(); diff --git a/packages/web-components/fast-foundation/src/di/di.ts b/packages/web-components/fast-foundation/src/di/di.ts index e2866c08e74..23bca3fe8dc 100644 --- a/packages/web-components/fast-foundation/src/di/di.ts +++ b/packages/web-components/fast-foundation/src/di/di.ts @@ -324,15 +324,10 @@ function createInterface(nameOrConfig?: any) { let value = this[diPropertyKey]; if (value === void 0) { - let container: Container | undefined; - - if (this instanceof HTMLElement) { - container = domParentLocator(this); - } else { - throw new Error( - "Could not locate container to use during property injection" - ); - } + const container: Container = + this instanceof HTMLElement + ? domParentLocator(this) + : DI.getOrCreateDOMContainer(); value = container.get(Interface); this[diPropertyKey] = value; diff --git a/packages/web-components/fast-foundation/src/foundation/foundation.ts b/packages/web-components/fast-foundation/src/foundation/foundation.ts index 47b29f71232..d288acc5997 100644 --- a/packages/web-components/fast-foundation/src/foundation/foundation.ts +++ b/packages/web-components/fast-foundation/src/foundation/foundation.ts @@ -4,7 +4,7 @@ import { FASTElement, observable, } from "@microsoft/fast-element"; -import { Configuration, ConfigurationInterface, unprefix } from "../configuration"; +import { Configuration, DIConfiguration, unprefix } from "../configuration"; /** * Defines a foundation element class that: @@ -13,7 +13,7 @@ import { Configuration, ConfigurationInterface, unprefix } from "../configuratio * 3. Allows resolving the element styles from the instance or the FASTProvider */ export class FoundationElement extends FASTElement { - @ConfigurationInterface + @DIConfiguration private configuration: Configuration; /**