ember-material-icons
Version:
Google Material icons for your ember-cli app
121 lines (97 loc) • 5.19 kB
text/typescript
import { EvaluatedArgs } from '../compiled/expressions/args';
import { FunctionExpression } from '../compiled/expressions/function';
import { CompiledProgram } from '../compiled/blocks';
import { Layout } from '../scanner';
import Environment, { DynamicScope } from '../environment';
import { ElementOperations } from '../builder';
import Bounds from '../bounds';
import * as Simple from '../dom/interfaces';
import { Destroyable, Opaque } from '@glimmer/util';
import { PathReference, RevisionTag } from '@glimmer/reference';
export type Component = Opaque;
export type ComponentClass = any;
export interface ComponentManager<T extends Component> {
// First, the component manager is asked to prepare the arguments needed
// for `create`. This allows for things like closure components where the
// args need to be curried before constructing the instance of the state
// bucket.
prepareArgs(definition: ComponentDefinition<T>, args: EvaluatedArgs, dynamicScope: DynamicScope): EvaluatedArgs;
// Then, the component manager is asked to create a bucket of state for
// the supplied arguments. From the perspective of Glimmer, this is
// an opaque token, but in practice it is probably a component object.
create(env: Environment, definition: ComponentDefinition<T>, args: EvaluatedArgs, dynamicScope: DynamicScope, caller: PathReference<Opaque>, hasDefaultBlock: boolean): T;
// Return the compiled layout to use for this component. This is called
// *after* the component instance has been created, because you might
// want to return a different layout per-instance for optimization reasons
// or to implement features like Ember's "late-bound" layouts.
layoutFor(definition: ComponentDefinition<T>, component: T, env: Environment): CompiledProgram;
// Next, Glimmer asks the manager to create a reference for the `self`
// it should use in the layout.
getSelf(component: T): PathReference<Opaque>;
// The `didCreateElement` hook is run for non-tagless components after the
// element as been created, but before it has been appended ("flushed") to
// the DOM. This hook allows the manager to save off the element, as well as
// install other dynamic attributes via the ElementOperations object.
//
// Hosts should use `didCreate`, which runs asynchronously after the rendering
// process, to provide hooks for user code.
didCreateElement(component: T, element: Simple.Element, operations: ElementOperations): void;
// This hook is run after the entire layout has been rendered.
//
// Hosts should use `didCreate`, which runs asynchronously after the rendering
// process, to provide hooks for user code.
didRenderLayout(component: T, bounds: Bounds): void;
// Once the whole top-down rendering process is complete, Glimmer invokes
// the `didCreate` callbacks.
didCreate(component: T): void;
// Convert the opaque component into a `RevisionTag` that determins when
// the component's update hooks need to be called, in addition to any
// outside changes captured in the input arguments. If it returns null,
// the update hooks will only be called when one or more of the input
// arguments has changed.
getTag(component: T): RevisionTag;
// When the input arguments have changed, and top-down revalidation has
// begun, the manager's `update` hook is called.
update(component: T, args: EvaluatedArgs, dynamicScope: DynamicScope): void;
// This hook is run after the entire layout has been updated.
//
// Hosts should use `didUpdate`, which runs asynchronously after the rendering
// process, to provide hooks for user code.
didUpdateLayout(component: T, bounds: Bounds): void;
// Finally, once top-down revalidation has completed, Glimmer invokes
// the `didUpdate` callbacks on components that changed.
didUpdate(component: T): void;
// Convert the opaque component into an object that implements Destroyable.
// If it returns null, the component will not be destroyed.
getDestructor(component: T): Destroyable;
}
export interface ComponentLayoutBuilder {
env: Environment;
tag: ComponentTagBuilder;
attrs: ComponentAttrsBuilder;
wrapLayout(layout: Layout): void;
fromLayout(layout: Layout): void;
}
export interface ComponentTagBuilder {
static(tagName: string): void;
dynamic(tagName: FunctionExpression<string>): void;
}
export interface ComponentAttrsBuilder {
static(name: string, value: string): void;
dynamic(name: string, value: FunctionExpression<string>): void;
}
const COMPONENT_DEFINITION_BRAND = 'COMPONENT DEFINITION [id=e59c754e-61eb-4392-8c4a-2c0ac72bfcd4]';
export function isComponentDefinition(obj: any): obj is ComponentDefinition<Opaque> {
return typeof obj === 'object' && obj && obj[COMPONENT_DEFINITION_BRAND];
}
export abstract class ComponentDefinition<T> {
public name: string; // for debugging
public manager: ComponentManager<T>;
public ComponentClass: ComponentClass;
constructor(name: string, manager: ComponentManager<T>, ComponentClass: ComponentClass) {
this[COMPONENT_DEFINITION_BRAND] = true;
this.name = name;
this.manager = manager;
this.ComponentClass = ComponentClass;
}
}