Skip to content

Commit

Permalink
wire in registry
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasrice committed Nov 18, 2020
1 parent 70aea4e commit 7b00305
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -147,20 +151,26 @@ export class ConfigurationImpl implements Configuration {
private designTokens = new DesignTokenLibraryImpl<any>();
private customPropertyManager = new CustomPropertyManagerImpl();
private customPropertySheet = new CSSStyleSheet();
private designTokenRegistration = new DesignTokenRegistryImpl();
private templateRegistry = new Map<string, ElementViewTemplate | null>();
private stylesRegistry = new Map<string, ElementStyles | null>();
private elementRegistry = new Map<typeof FASTElement, PartialFASTElementDefinition>();
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<any>();
tokens.upstream = this.designTokens;

return tokens;
}),
Registration.instance(CSSCustomPropertyManager, this.customPropertyManager)
})
);

this.designTokenTarget = this.customPropertySheet.cssRules[
Expand Down Expand Up @@ -240,13 +250,9 @@ export class ConfigurationImpl implements Configuration {
}

/** {@inheritdoc Configuration.registerDesignToken} */
public registerDesignToken<T>(registration: DesignTokenDefinition<T>) {
const { key, value, customProperty } = registration;
this.designTokenRegistry.set(key, registration);

if (customProperty && key !== customProperty) {
this.customPropertyManager.alias(key, customProperty);
}
public registerDesignToken(registration: DesignTokenDefinition<any>) {
const { key, value } = registration;
this.designTokenRegistration.register(registration);

if (value) {
this.designTokens.set(key, value);
Expand Down Expand Up @@ -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<string, ElementViewTemplate | null>();
private stylesRegistry = new Map<string, ElementStyles | null>();
private elementRegistry = new Map<typeof FASTElement, PartialFASTElementDefinition>();
private designTokenRegistry = new Map<string, DesignTokenDefinition<any>>();
}

export const ConfigurationInterface: InterfaceSymbol<Key, any> = DI.createInterface(
export const DIConfiguration: InterfaceSymbol<Key, any> = DI.createInterface(
"Configuration"
).noDefault();
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<string, Map<any, ElementStyles>>();
private names = new Map<string, string>();
private selector = ":host";

/**
Expand All @@ -49,40 +35,27 @@ 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}`;
}
}

/**
* DI decorator to get the app CustomPropertyManager
*/
export const CSSCustomPropertyManager: InterfaceSymbol<Key, any> = DI.createInterface(
export const DICustomPropertyManager: InterfaceSymbol<Key, any> = DI.createInterface(
"custom-property-manager"
).noDefault();
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export interface CustomPropertyManagerClient extends FASTElement, HTMLElement {
*
* @public
*/
export interface CustomPropertyManager {
export interface CSSCustomPropertyManager {
/**
* The CustomPropertyManagerTarget responsible for evaluating CSSCustomPropertyDefinitions
*/
Expand Down Expand Up @@ -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
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from "../custom-properties/index";
import {
ConstructableStylesCustomPropertyManager,
CustomPropertyManager,
CSSCustomPropertyManager,
CustomPropertyManagerClient,
StyleElementCustomPropertyManager,
} from "../custom-properties/manager";
Expand Down Expand Up @@ -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);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from "./library";
export * from "./tokens";
import DesignTokenProvider from "./provider";
export { DesignTokenProvider };
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Subscriber } from "@microsoft/fast-element";
import { DI, InterfaceSymbol } from "../di";

interface DesignTokenLibrary<T extends {}> {
export interface DesignTokenLibrary<T extends {}> {
/**
* 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.
Expand Down Expand Up @@ -46,7 +47,8 @@ interface DesignTokenLibrary<T extends {}> {
keys<K extends keyof T>(): Array<K>;
}

interface InheritableDesignTokenLibrary<T extends {}> extends DesignTokenLibrary<T> {
export interface InheritableDesignTokenLibrary<T extends {}>
extends DesignTokenLibrary<T> {
/**
* The upstream object an InheritableDesignTokenLibrary should inherit from.
*/
Expand Down Expand Up @@ -210,3 +212,10 @@ export class DesignTokenLibraryImpl<T> implements InheritableDesignTokenLibrary<
}
}
}

export const DIDesignTokens: InterfaceSymbol<DesignTokenLibraryImpl<
any
>> = DI.createInterface<DesignTokenLibraryImpl<any>>({
friendlyName: "DesignTokens",
respectConnection: true,
}).noDefault();
Original file line number Diff line number Diff line change
@@ -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 <TBase extends Constructable<FASTElement & HTMLElement>>(Base: TBase) => {
const C = class extends Base {
public designTokens: DesignTokenLibraryImpl<any>;
private customPropertyManager: CustomPropertyManagerImpl;
public designTokens: InheritableDesignTokenLibrary<any>;
private customPropertyManager: CustomPropertyManager;
private localSheets = new Map<string, ElementStyles>();
private designTokenRegistry: DesignTokenRegistry;

constructor(...args: any[]) {
super(...args);

DI.getOrCreateDOMContainer(this).register(
Registration.callback(DesignTokens, () => {
Registration.callback(DIDesignTokens, () => {
const tokens = new DesignTokenLibraryImpl<any>();
tokens.upstream = this.designTokens;

Expand All @@ -29,7 +34,6 @@ export default <TBase extends Constructable<FASTElement & HTMLElement>>(Base: TB
connectedCallback() {
super.connectedCallback();
this.designTokens.subscribe(this);
// How do I know what should be reflected to CSS custom properties?
}

/**
Expand All @@ -41,9 +45,11 @@ export default <TBase extends Constructable<FASTElement & HTMLElement>>(Base: TB
*/
public handleChange(source: DesignTokenLibraryImpl<any>, keys: Array<any>) {
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);
Expand All @@ -59,8 +65,9 @@ export default <TBase extends Constructable<FASTElement & HTMLElement>>(Base: TB
}
};

DesignTokens(C.prototype, "designTokens");
CSSCustomPropertyManager(C.prototype, "customPropertyManager");
DIDesignTokenRegistry(C.prototype, "designTokenRegistry");
DIDesignTokens(C.prototype, "designTokens");
DICustomPropertyManager(C.prototype, "customPropertyManager");

return C;
};
Loading

0 comments on commit 7b00305

Please sign in to comment.