@microsoft/fast-element
Advanced tools
Comparing version 0.9.0 to 0.10.0
@@ -6,2 +6,14 @@ # Change Log | ||
# [0.10.0](https://github.com/Microsoft/fast-dna/compare/@microsoft/fast-element@0.9.0...@microsoft/fast-element@0.10.0) (2020-06-05) | ||
### Features | ||
* **fast-element:** add content composition ([#3182](https://github.com/Microsoft/fast-dna/issues/3182)) ([26c59ea](https://github.com/Microsoft/fast-dna/commit/26c59ead7829f9e54f827811cd6aabfb92d0391b)) | ||
* **website:** new docusaurus v2 setup with launch toc configuration ([#3159](https://github.com/Microsoft/fast-dna/issues/3159)) ([f12ba16](https://github.com/Microsoft/fast-dna/commit/f12ba1687bb46fd3f6717790b1687b441363671e)) | ||
# [0.9.0](https://github.com/Microsoft/fast-dna/compare/@microsoft/fast-element@0.8.1...@microsoft/fast-element@0.9.0) (2020-05-18) | ||
@@ -8,0 +20,0 @@ |
@@ -1,3 +0,2 @@ | ||
import { ExecutionContext, Expression } from "../observation/observable"; | ||
import { ObservableExpression } from "../observation/observable"; | ||
import { ExecutionContext, Binding, BindingObserver } from "../observation/observable"; | ||
import { Directive } from "./directive"; | ||
@@ -8,4 +7,7 @@ import { Behavior } from "./behavior"; | ||
declare function updatePropertyTarget(this: BindingBehavior, value: unknown): void; | ||
/** | ||
* A directive that configures data binding to element content and attributes. | ||
*/ | ||
export declare class BindingDirective extends Directive { | ||
expression: Expression; | ||
binding: Binding; | ||
private cleanedTargetName?; | ||
@@ -17,11 +19,36 @@ private originalTargetName?; | ||
private updateTarget; | ||
constructor(expression: Expression); | ||
/** | ||
* Creates an instance of BindingDirective. | ||
* @param binding A binding that returns the data used to update the DOM. | ||
*/ | ||
constructor(binding: Binding); | ||
/** | ||
* Gets the name of the attribute or property that this | ||
* binding is targeting. | ||
*/ | ||
get targetName(): string | undefined; | ||
/** | ||
* Sets the name of the attribute or property tha this | ||
* binding is targeting. | ||
*/ | ||
set targetName(value: string | undefined); | ||
/** | ||
* Makes this binding target the content of an element rather than | ||
* a particular attribute or property. | ||
*/ | ||
targetAtContent(): void; | ||
/** | ||
* Creates the runtime BindingBehavior instance based on the configuration | ||
* information stored in the BindingDirective. | ||
* @param target The target node that the binding behavior should attach to. | ||
*/ | ||
createBehavior(target: any): BindingBehavior; | ||
} | ||
/** | ||
* A behavior that updates content and attributes based on a configured | ||
* BindingDirective. | ||
*/ | ||
export declare class BindingBehavior implements Behavior { | ||
target: any; | ||
expression: Expression; | ||
binding: Binding; | ||
bind: typeof normalBind; | ||
@@ -33,9 +60,24 @@ unbind: typeof normalUnbind; | ||
context: ExecutionContext | null; | ||
observableExpression: ObservableExpression | null; | ||
bindingObserver: BindingObserver | null; | ||
classVersions: Record<string, number>; | ||
version: number; | ||
constructor(target: any, expression: Expression, bind: typeof normalBind, unbind: typeof normalUnbind, updateTarget: typeof updatePropertyTarget, targetName?: string | undefined); | ||
handleExpressionChange(): void; | ||
/** | ||
* | ||
* @param target The target of the data updates. | ||
* @param binding The binding that returns the latest value for an update. | ||
* @param bind The operation to perform during binding. | ||
* @param unbind The operation to perform during unbinding. | ||
* @param updateTarget The operation to perform when updating. | ||
* @param targetName The name of the target attribute or property to update. | ||
*/ | ||
constructor(target: any, binding: Binding, bind: typeof normalBind, unbind: typeof normalUnbind, updateTarget: typeof updatePropertyTarget, targetName?: string | undefined); | ||
/** | ||
* @internal | ||
*/ | ||
handleChange(): void; | ||
/** | ||
* @internal | ||
*/ | ||
handleEvent(event: Event): void; | ||
} | ||
export {}; |
import { CaptureType, SyntheticViewTemplate, ViewTemplate } from "../template"; | ||
import { ExecutionContext, Expression } from "../observation/observable"; | ||
import { ExecutionContext, Binding } from "../observation/observable"; | ||
import { Subscriber } from "../observation/notifier"; | ||
@@ -12,2 +12,3 @@ import { Splice } from "../observation/array-change-records"; | ||
private location; | ||
private binding; | ||
private template; | ||
@@ -19,10 +20,9 @@ private options; | ||
private itemsObserver?; | ||
private observableExpression; | ||
private bindingObserver; | ||
private originalContext; | ||
private childContext; | ||
private bindView; | ||
constructor(location: Node, expression: Expression, template: SyntheticViewTemplate, options: RepeatOptions); | ||
constructor(location: Node, binding: Binding, template: SyntheticViewTemplate, options: RepeatOptions); | ||
bind(source: unknown, context: ExecutionContext): void; | ||
unbind(): void; | ||
handleExpressionChange(): void; | ||
handleChange(source: any, args: Splice[]): void; | ||
@@ -35,9 +35,9 @@ private observeItems; | ||
export declare class RepeatDirective extends Directive { | ||
expression: Expression; | ||
binding: Binding; | ||
template: SyntheticViewTemplate; | ||
options: RepeatOptions; | ||
createPlaceholder: (index: number) => string; | ||
constructor(expression: Expression, template: SyntheticViewTemplate, options: RepeatOptions); | ||
constructor(binding: Binding, template: SyntheticViewTemplate, options: RepeatOptions); | ||
createBehavior(target: any): RepeatBehavior; | ||
} | ||
export declare function repeat<TScope = any, TItem = any>(expression: Expression<TScope, TItem[]>, template: ViewTemplate<Partial<TItem>, TScope>, options?: RepeatOptions): CaptureType<TScope>; | ||
export declare function repeat<TScope = any, TItem = any>(binding: Binding<TScope, TItem[]>, template: ViewTemplate<Partial<TItem>, TScope>, options?: RepeatOptions): CaptureType<TScope>; |
import { CaptureType, SyntheticViewTemplate } from "../template"; | ||
import { ExecutionContext, Expression } from "../observation/observable"; | ||
import { Behavior } from "./behavior"; | ||
import { Directive } from "./directive"; | ||
export declare class WhenBehavior implements Behavior { | ||
private location; | ||
private template; | ||
private view; | ||
private cachedView?; | ||
private source; | ||
private observableExpression; | ||
private context; | ||
constructor(location: Node, expression: Expression, template: SyntheticViewTemplate); | ||
bind(source: unknown, context: ExecutionContext): void; | ||
unbind(): void; | ||
handleExpressionChange(): void; | ||
updateTarget(show: boolean): void; | ||
} | ||
export declare class WhenDirective extends Directive { | ||
expression: Expression; | ||
template: SyntheticViewTemplate; | ||
createPlaceholder: (index: number) => string; | ||
constructor(expression: Expression, template: SyntheticViewTemplate); | ||
createBehavior(target: any): WhenBehavior; | ||
} | ||
export declare function when<T = any, K = any>(expression: Expression<T, K>, template: SyntheticViewTemplate): CaptureType<T>; | ||
import { Binding } from "../observation/observable"; | ||
/** | ||
* A directive that enables basic conditional rendering in a template. | ||
* @param binding The condition to test for rendering. | ||
* @param templateOrTemplateBinding The template or a binding that gets | ||
* the template to render when the condition is true. | ||
*/ | ||
export declare function when<TSource = any, TReturn = any>(binding: Binding<TSource, TReturn>, templateOrTemplateBinding: SyntheticViewTemplate | Binding<TSource, SyntheticViewTemplate>): CaptureType<TSource>; |
@@ -5,2 +5,5 @@ import { Callable } from "./interfaces"; | ||
}; | ||
/** | ||
* Common DOM APIs. | ||
*/ | ||
export declare const DOM: Readonly<{ | ||
@@ -14,3 +17,11 @@ setHTMLPolicy(policy: TrustedTypesPolicy): void; | ||
createBlockPlaceholder(index: number): string; | ||
/** | ||
* Schedules DOM update work in the next async batch. | ||
* @param callable The callable function or object to queue. | ||
*/ | ||
queueUpdate(callable: Callable): void; | ||
/** | ||
* Resolves with the next DOM update. | ||
*/ | ||
nextUpdate(): Promise<void>; | ||
setAttribute(element: HTMLElement, attributeName: string, value: any): void; | ||
@@ -17,0 +28,0 @@ setBooleanAttribute(element: HTMLElement, attributeName: string, value: boolean): void; |
@@ -23,3 +23,9 @@ import { ElementViewTemplate } from "./template"; | ||
}; | ||
/** | ||
* @internal | ||
*/ | ||
export declare const fastDefinitions: Map<Function, FASTElementDefinition>; | ||
/** | ||
* @internal | ||
*/ | ||
export declare function getDefinition<T extends Function>(Type: T): FASTElementDefinition | undefined; |
@@ -0,4 +1,13 @@ | ||
/** | ||
* Represents a callable type such as a function or an object with a "call" method. | ||
*/ | ||
export declare type Callable = typeof Function.prototype.call | { | ||
call(): void; | ||
}; | ||
/** | ||
* A readonly, empty array. | ||
* @remarks | ||
* Typically returned by APIs that return arrays when there are | ||
* no actual items to return. | ||
*/ | ||
export declare const emptyArray: readonly never[]; |
@@ -0,6 +1,21 @@ | ||
/** | ||
* Represents a set of splice-based changes against an Array. | ||
*/ | ||
export interface Splice { | ||
/** | ||
* The index that the splice occurs at. | ||
*/ | ||
index: number; | ||
/** | ||
* The items that were removed. | ||
*/ | ||
removed: any[]; | ||
/** | ||
* The number of items that were added. | ||
*/ | ||
addedCount: number; | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
export declare function newSplice(index: number, removed: any[], addedCount: number): Splice; | ||
@@ -21,2 +36,4 @@ /** | ||
/** | ||
* @internal | ||
* @remarks | ||
* Lacking individual splice mutation information, the minimal set of | ||
@@ -32,2 +49,5 @@ * splices can be synthesized given the previous state and final state of an | ||
export declare function calcSplices(current: any[], currentStart: number, currentEnd: number, old: any[], oldStart: number, oldEnd: number): ReadonlyArray<never> | Splice[]; | ||
/** | ||
* @internal | ||
*/ | ||
export declare function projectArraySplices(array: any[], changeRecords: any[]): Splice[]; |
@@ -1,13 +0,8 @@ | ||
import { SubscriberSet } from "./notifier"; | ||
import { Splice } from "./array-change-records"; | ||
export declare class ArrayObserver extends SubscriberSet { | ||
private oldCollection; | ||
private splices; | ||
private needsQueue; | ||
call: () => void; | ||
constructor(source: any[]); | ||
addSplice(splice: Splice): void; | ||
reset(oldCollection: any[] | undefined): void; | ||
flush(): void; | ||
} | ||
/** | ||
* Enables the array observation mechanism. | ||
* @remarks | ||
* Array observation is enabled automatically when using the | ||
* {@link RepeatDirective}, so calling this API manually is | ||
* not typically necessary. | ||
*/ | ||
export declare function enableArrayObservation(): void; |
@@ -46,4 +46,5 @@ /** | ||
/** | ||
* An implementation of Notifier that efficiently keeps track of subscribers interested | ||
* in a specific change notification on an observable source. | ||
* An implementation of {@link Notifier} that efficiently keeps track of | ||
* subscribers interested in a specific change notification on an | ||
* observable source. | ||
* | ||
@@ -56,3 +57,2 @@ * @remarks | ||
export declare class SubscriberSet implements Notifier { | ||
readonly source: any; | ||
private sub1; | ||
@@ -62,6 +62,11 @@ private sub2; | ||
/** | ||
* The source that this subscriber set is reporting changes for. | ||
*/ | ||
readonly source: any; | ||
/** | ||
* Creates an instance of SubscriberSet for the specified source. | ||
* @param source The object source that subscribers will receive notifications from. | ||
* @param initialSubscriber An initial subscriber to changes. | ||
*/ | ||
constructor(source: any); | ||
constructor(source: any, initialSubscriber?: Subscriber); | ||
/** | ||
@@ -89,8 +94,12 @@ * Checks whether the provided subscriber has been added to this set. | ||
/** | ||
* An implementation of Notifier that allows subscribers to be notified of individual property changes on an object. | ||
* An implementation of Notifier that allows subscribers to be notified | ||
* of individual property changes on an object. | ||
*/ | ||
export declare class PropertyChangeNotifier implements Notifier { | ||
readonly source: any; | ||
private subscribers; | ||
/** | ||
* The source that property changes are being notified for. | ||
*/ | ||
readonly source: any; | ||
/** | ||
* Creates an instance of PropertyChangeNotifier for the specified source. | ||
@@ -97,0 +106,0 @@ * @param source The object source that subscribers will receive notifications from. |
@@ -1,16 +0,79 @@ | ||
import { Notifier } from "./notifier"; | ||
import { Notifier, Subscriber } from "./notifier"; | ||
/** | ||
* Represents a getter/setter property accessor on an object. | ||
*/ | ||
export interface Accessor { | ||
/** | ||
* The name of the property. | ||
*/ | ||
name: string; | ||
/** | ||
* Gets the value of the property on the source object. | ||
* @param source The source object to access. | ||
*/ | ||
getValue(source: any): any; | ||
/** | ||
* Sets the value of the property on the source object. | ||
* @param source The source object to access. | ||
* @param value The value to set the property to. | ||
*/ | ||
setValue(source: any, value: any): void; | ||
} | ||
export declare const Observable: { | ||
createArrayObserver(array: any[]): Notifier; | ||
getNotifier<T extends Notifier = Notifier>(source: any): T; | ||
/** | ||
* Common Observable APIs. | ||
*/ | ||
export declare const Observable: Readonly<{ | ||
/** | ||
* @internal | ||
* @param factory The factory used to create array observers. | ||
*/ | ||
setArrayObserverFactory(factory: (collection: any[]) => Notifier): void; | ||
/** | ||
* Gets a notifier for an object or Array. | ||
* @param source The object or Array to get the notifier for. | ||
*/ | ||
getNotifier(source: any): Notifier; | ||
/** | ||
* Records a property change for a source object. | ||
* @param source The object to record the change against. | ||
* @param propertyName The property to track as changed. | ||
*/ | ||
track(source: unknown, propertyName: string): void; | ||
/** | ||
* Notifies subscribers of a source object of changes. | ||
* @param source the object to notify of changes. | ||
* @param args The change args to pass to subscribers. | ||
*/ | ||
notify(source: unknown, args: any): void; | ||
/** | ||
* Defines an observable property on an object or prototype. | ||
* @param target The target object to define the observable on. | ||
* @param nameOrAccessor The name of the property to define as observable; | ||
* or a custom accessor that specifies the property name and accessor implementation. | ||
*/ | ||
defineProperty(target: {}, nameOrAccessor: string | Accessor): void; | ||
/** | ||
* Finds all the observable accessors defined on the target, | ||
* including its prototype chain. | ||
* @param target The target object to search for accessor on. | ||
*/ | ||
getAccessors(target: {}): Accessor[]; | ||
}; | ||
export declare function observable($target: {}, $prop: string): void; | ||
/** | ||
* Creates a {@link BindingObserver} that can watch the | ||
* provided {@link Binding} for changes. | ||
* @param binding The binding to observe. | ||
* @param initialSubscriber An initial subscriber to changes in the binding value. | ||
*/ | ||
binding<TScope = any, TReturn = any, TParent = any>(binding: Binding<any, any, any>, initialSubscriber?: Subscriber | undefined): BindingObserver<TScope, TReturn, TParent>; | ||
}>; | ||
/** | ||
* Decorator: Defines an observable property on the target. | ||
* @param target The target to define the observable on. | ||
* @param nameOrAccessor The property name or accessor to define the observable as. | ||
*/ | ||
export declare function observable(target: {}, nameOrAccessor: string | Accessor): void; | ||
/** | ||
* @internal | ||
* @param event The event to set as current for the context. | ||
*/ | ||
export declare function setCurrentEvent(event: Event | null): void; | ||
@@ -21,40 +84,68 @@ /** | ||
export declare class ExecutionContext<TParent = any> { | ||
/** | ||
* The index of the current item within a repeat context. | ||
*/ | ||
index: number; | ||
/** | ||
* The length of the current collection within a repeat context. | ||
*/ | ||
length: number; | ||
/** | ||
* The parent data object within a repeat context. | ||
*/ | ||
parent: TParent; | ||
/** | ||
* The current event within an event handler. | ||
*/ | ||
get event(): Event; | ||
get even(): boolean; | ||
get odd(): boolean; | ||
get first(): boolean; | ||
get middle(): boolean; | ||
get last(): boolean; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* has an even index. | ||
*/ | ||
get isEven(): boolean; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* has an odd index. | ||
*/ | ||
get isOdd(): boolean; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* is the first item in the collection. | ||
*/ | ||
get isFirst(): boolean; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* is somewhere in the middle of the collection. | ||
*/ | ||
get isInMiddle(): boolean; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* is the last item in the collection. | ||
*/ | ||
get isLast(): boolean; | ||
} | ||
/** | ||
* The default execution context used in binding expressions. | ||
*/ | ||
export declare const defaultExecutionContext: ExecutionContext<any>; | ||
/** | ||
* The signature of an arrow function capable of being evaluated as part of a template update. | ||
* The signature of an arrow function capable of being evaluated | ||
* as part of a template binding update. | ||
*/ | ||
export declare type Expression<TScope = any, TReturn = any, TParent = any> = (scope: TScope, context: ExecutionContext<TParent>) => TReturn; | ||
export interface ExpressionObserver { | ||
handleExpressionChange(expression: ObservableExpression): void; | ||
export declare type Binding<TSource = any, TReturn = any, TParent = any> = (source: TSource, context: ExecutionContext<TParent>) => TReturn; | ||
/** | ||
* Enables evaluation of and subscription to a binding. | ||
*/ | ||
export interface BindingObserver<TSource = any, TReturn = any, TParent = any> extends Notifier { | ||
/** | ||
* Begins observing the binding for the source and returns the current value. | ||
* @param source The source that the binding is based on. | ||
* @param context The execution context to execute the binding within. | ||
* @returns The value of the binding. | ||
*/ | ||
observe(source: TSource, context: ExecutionContext): TReturn; | ||
/** | ||
* Unsubscribe from all dependent observables of the binding. | ||
*/ | ||
disconnect(): void; | ||
} | ||
export declare class ObservableExpression { | ||
private expression; | ||
private observer; | ||
private needsRefresh; | ||
private needsQueue; | ||
private first; | ||
private last; | ||
private source; | ||
private propertyName; | ||
private notifier; | ||
private next; | ||
constructor(expression: Expression, observer: ExpressionObserver); | ||
evaluate(scope: unknown, context: ExecutionContext): any; | ||
dispose(): void; | ||
/** @internal */ | ||
observe(source: unknown, propertyName: string): void; | ||
/** @internal */ | ||
handleChange(): void; | ||
/** @internal */ | ||
call(): void; | ||
} |
import { ElementView, HTMLView, SyntheticView } from "./view"; | ||
import { Behavior } from "./directives/behavior"; | ||
import { Directive } from "./directives/directive"; | ||
import { ExecutionContext, Expression } from "./observation/observable"; | ||
import { Binding } from "./observation/observable"; | ||
/** | ||
@@ -24,15 +23,8 @@ * A template capable of creating views specifically for rendering custom elements. | ||
} | ||
export declare class HTMLTemplateBehavior implements Behavior { | ||
private view; | ||
constructor(template: SyntheticViewTemplate, location: HTMLElement); | ||
bind(source: unknown, context: ExecutionContext): void; | ||
unbind(): void; | ||
} | ||
/** | ||
* A template capable of creating HTMLView instances or rendering directly to DOM. | ||
*/ | ||
export declare class ViewTemplate<TSource = any, TParent = any> extends Directive implements ElementViewTemplate, SyntheticViewTemplate { | ||
export declare class ViewTemplate<TSource = any, TParent = any> implements ElementViewTemplate, SyntheticViewTemplate { | ||
readonly html: string | HTMLTemplateElement; | ||
readonly directives: ReadonlyArray<Directive>; | ||
createPlaceholder: (index: number) => string; | ||
private behaviorCount; | ||
@@ -61,8 +53,14 @@ private hasHostBehaviors; | ||
render(source: TSource, host: HTMLElement | string): HTMLView; | ||
createBehavior(target: any): HTMLTemplateBehavior; | ||
} | ||
/** | ||
* A marker interface used to capture types when interpolating Directive helpers | ||
* into templates. | ||
*/ | ||
export interface CaptureType<TSource> { | ||
} | ||
declare type TemplateValue<TScope, TParent = any> = Expression<TScope, any, TParent> | string | number | Directive | CaptureType<TScope>; | ||
/** | ||
* Represents the types of values that can be interpolated into a template. | ||
*/ | ||
export declare type TemplateValue<TScope, TParent = any> = Binding<TScope, any, TParent> | string | number | Directive | CaptureType<TScope>; | ||
/** | ||
* Transforms a template literal string into a renderable ViewTemplate. | ||
@@ -76,2 +74,1 @@ * @param strings The string fragments that interpolated with the values. | ||
export declare function html<TSource = any, TParent = any>(strings: TemplateStringsArray, ...values: TemplateValue<TSource, TParent>[]): ViewTemplate<TSource, TParent>; | ||
export {}; |
@@ -12,2 +12,6 @@ import { Behavior } from "./directives/behavior"; | ||
/** | ||
* The data that the view is bound to. | ||
*/ | ||
readonly source: any | null; | ||
/** | ||
* Binds a view's behaviors to its binding source. | ||
@@ -66,6 +70,11 @@ * @param source The binding source for the view's binding behaviors. | ||
private behaviors; | ||
private source; | ||
source: any | null; | ||
context: ExecutionContext | null; | ||
firstChild: Node; | ||
lastChild: Node; | ||
/** | ||
* | ||
* @param fragment The html fragment that contains the nodes for this view. | ||
* @param behaviors The behaviors to be applied to this view. | ||
*/ | ||
constructor(fragment: DocumentFragment, behaviors: Behavior[]); | ||
@@ -72,0 +81,0 @@ /** |
@@ -1,3 +0,3 @@ | ||
import { setCurrentEvent } from "../observation/observable"; | ||
import { ObservableExpression } from "../observation/observable"; | ||
import { setCurrentEvent, } from "../observation/observable"; | ||
import { Observable } from "../observation/observable"; | ||
import { DOM } from "../dom"; | ||
@@ -8,6 +8,6 @@ import { Directive } from "./directive"; | ||
this.context = context; | ||
if (this.observableExpression === null) { | ||
this.observableExpression = new ObservableExpression(this.expression, this); | ||
if (this.bindingObserver === null) { | ||
this.bindingObserver = Observable.binding(this.binding, this); | ||
} | ||
this.updateTarget(this.observableExpression.evaluate(source, context)); | ||
this.updateTarget(this.bindingObserver.observe(source, context)); | ||
} | ||
@@ -20,6 +20,16 @@ function triggerBind(source, context) { | ||
function normalUnbind() { | ||
this.observableExpression.dispose(); | ||
this.bindingObserver.disconnect(); | ||
this.source = null; | ||
this.context = null; | ||
} | ||
function contentUnbind() { | ||
this.bindingObserver.disconnect(); | ||
this.source = null; | ||
this.context = null; | ||
const view = this.target.$fastView; | ||
if (view !== void 0 && view.isComposed) { | ||
view.unbind(); | ||
view.needsBindOnly = true; | ||
} | ||
} | ||
function triggerUnbind() { | ||
@@ -36,4 +46,60 @@ this.target.removeEventListener(this.targetName, this, true); | ||
} | ||
function updateTextTarget(value) { | ||
this.target.textContent = value; | ||
function updateContentTarget(value) { | ||
// If there's no actual value, then this equates to the | ||
// empty string for the purposes of content bindings. | ||
if (value === null || value === undefined) { | ||
value = ""; | ||
} | ||
// If the value has a "create" method, then it's a template-like. | ||
if (value.create) { | ||
this.target.textContent = ""; | ||
let view = this.target.$fastView; | ||
// If there's no previous view that we might be able to | ||
// reuse then create a new view from the template. | ||
if (view === void 0) { | ||
view = value.create(); | ||
} | ||
else { | ||
// If there is a previous view, but it wasn't created | ||
// from the same template as the new value, then we | ||
// need to remove the old view if it's still in the DOM | ||
// and create a new view from the template. | ||
if (this.target.$fastTemplate !== value) { | ||
if (view.isComposed) { | ||
view.remove(); | ||
view.unbind(); | ||
} | ||
view = value.create(); | ||
} | ||
} | ||
// It's possible that the value is the same as the previous template | ||
// and that there's actually no need to compose it. | ||
if (!view.isComposed) { | ||
view.isComposed = true; | ||
view.bind(this.source, this.context); | ||
view.insertBefore(this.target); | ||
this.target.$fastView = view; | ||
this.target.$fastTemplate = value; | ||
} | ||
else if (view.needsBindOnly) { | ||
view.needsBindOnly = false; | ||
view.bind(this.source, this.context); | ||
} | ||
} | ||
else { | ||
const view = this.target.$fastView; | ||
// If there is a view and it's currently composed into | ||
// the DOM, then we need to remove it. | ||
if (view !== void 0 && view.isComposed) { | ||
view.isComposed = false; | ||
view.remove(); | ||
if (view.needsBindOnly) { | ||
view.needsBindOnly = false; | ||
} | ||
else { | ||
view.unbind(); | ||
} | ||
} | ||
this.target.textContent = value; | ||
} | ||
} | ||
@@ -73,6 +139,13 @@ function updatePropertyTarget(value) { | ||
} | ||
/** | ||
* A directive that configures data binding to element content and attributes. | ||
*/ | ||
export class BindingDirective extends Directive { | ||
constructor(expression) { | ||
/** | ||
* Creates an instance of BindingDirective. | ||
* @param binding A binding that returns the data used to update the DOM. | ||
*/ | ||
constructor(binding) { | ||
super(); | ||
this.expression = expression; | ||
this.binding = binding; | ||
this.createPlaceholder = DOM.createInterpolationPlaceholder; | ||
@@ -83,5 +156,13 @@ this.bind = normalBind; | ||
} | ||
/** | ||
* Gets the name of the attribute or property that this | ||
* binding is targeting. | ||
*/ | ||
get targetName() { | ||
return this.originalTargetName; | ||
} | ||
/** | ||
* Sets the name of the attribute or property tha this | ||
* binding is targeting. | ||
*/ | ||
set targetName(value) { | ||
@@ -97,5 +178,5 @@ this.originalTargetName = value; | ||
if (this.cleanedTargetName === "innerHTML") { | ||
const expression = this.expression; | ||
const binding = this.binding; | ||
/* eslint-disable-next-line */ | ||
this.expression = (s, c) => DOM.createHTML(expression(s, c)); | ||
this.binding = (s, c) => DOM.createHTML(binding(s, c)); | ||
} | ||
@@ -120,14 +201,37 @@ break; | ||
} | ||
/** | ||
* Makes this binding target the content of an element rather than | ||
* a particular attribute or property. | ||
*/ | ||
targetAtContent() { | ||
this.updateTarget = updateTextTarget; | ||
this.updateTarget = updateContentTarget; | ||
this.unbind = contentUnbind; | ||
} | ||
/** | ||
* Creates the runtime BindingBehavior instance based on the configuration | ||
* information stored in the BindingDirective. | ||
* @param target The target node that the binding behavior should attach to. | ||
*/ | ||
createBehavior(target) { | ||
/* eslint-disable-next-line @typescript-eslint/no-use-before-define */ | ||
return new BindingBehavior(target, this.expression, this.bind, this.unbind, this.updateTarget, this.cleanedTargetName); | ||
return new BindingBehavior(target, this.binding, this.bind, this.unbind, this.updateTarget, this.cleanedTargetName); | ||
} | ||
} | ||
/** | ||
* A behavior that updates content and attributes based on a configured | ||
* BindingDirective. | ||
*/ | ||
export class BindingBehavior { | ||
constructor(target, expression, bind, unbind, updateTarget, targetName) { | ||
/** | ||
* | ||
* @param target The target of the data updates. | ||
* @param binding The binding that returns the latest value for an update. | ||
* @param bind The operation to perform during binding. | ||
* @param unbind The operation to perform during unbinding. | ||
* @param updateTarget The operation to perform when updating. | ||
* @param targetName The name of the target attribute or property to update. | ||
*/ | ||
constructor(target, binding, bind, unbind, updateTarget, targetName) { | ||
this.target = target; | ||
this.expression = expression; | ||
this.binding = binding; | ||
this.bind = bind; | ||
@@ -139,10 +243,16 @@ this.unbind = unbind; | ||
this.context = null; | ||
this.observableExpression = null; | ||
this.bindingObserver = null; | ||
} | ||
handleExpressionChange() { | ||
this.updateTarget(this.observableExpression.evaluate(this.source, this.context)); | ||
/** | ||
* @internal | ||
*/ | ||
handleChange() { | ||
this.updateTarget(this.bindingObserver.observe(this.source, this.context)); | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
handleEvent(event) { | ||
setCurrentEvent(event); | ||
const result = this.expression(this.source, this.context); | ||
const result = this.binding(this.source, this.context); | ||
setCurrentEvent(null); | ||
@@ -149,0 +259,0 @@ if (result !== true) { |
import { DOM } from "../dom"; | ||
import { Observable, ObservableExpression, } from "../observation/observable"; | ||
import { Observable, } from "../observation/observable"; | ||
import { HTMLView } from "../view"; | ||
@@ -19,4 +19,5 @@ import { enableArrayObservation } from "../observation/array-observer"; | ||
export class RepeatBehavior { | ||
constructor(location, expression, template, options) { | ||
constructor(location, binding, template, options) { | ||
this.location = location; | ||
this.binding = binding; | ||
this.template = template; | ||
@@ -31,3 +32,3 @@ this.options = options; | ||
this.bindView = bindWithoutPositioning; | ||
this.observableExpression = new ObservableExpression(expression, this); | ||
this.bindingObserver = Observable.binding(binding, this); | ||
if (options.positioning) { | ||
@@ -42,3 +43,3 @@ this.bindView = bindWithPositioning; | ||
this.childContext.parent = source; | ||
this.items = this.observableExpression.evaluate(source, this.originalContext); | ||
this.items = this.bindingObserver.observe(source, this.originalContext); | ||
this.observeItems(); | ||
@@ -54,11 +55,13 @@ this.refreshAllViews(); | ||
this.unbindAllViews(); | ||
this.observableExpression.dispose(); | ||
this.bindingObserver.disconnect(); | ||
} | ||
handleExpressionChange() { | ||
this.items = this.observableExpression.evaluate(this.source, this.originalContext); | ||
this.observeItems(); | ||
this.refreshAllViews(); | ||
} | ||
handleChange(source, args) { | ||
this.updateViews(args); | ||
if (source === this.binding) { | ||
this.items = this.bindingObserver.observe(this.source, this.originalContext); | ||
this.observeItems(); | ||
this.refreshAllViews(); | ||
} | ||
else { | ||
this.updateViews(args); | ||
} | ||
} | ||
@@ -169,5 +172,5 @@ observeItems() { | ||
export class RepeatDirective extends Directive { | ||
constructor(expression, template, options) { | ||
constructor(binding, template, options) { | ||
super(); | ||
this.expression = expression; | ||
this.binding = binding; | ||
this.template = template; | ||
@@ -179,7 +182,7 @@ this.options = options; | ||
createBehavior(target) { | ||
return new RepeatBehavior(target, this.expression, this.template, this.options); | ||
return new RepeatBehavior(target, this.binding, this.template, this.options); | ||
} | ||
} | ||
export function repeat(expression, template, options = defaultRepeatOptions) { | ||
return new RepeatDirective(expression, template, options); | ||
export function repeat(binding, template, options = defaultRepeatOptions) { | ||
return new RepeatDirective(binding, template, options); | ||
} |
@@ -1,54 +0,12 @@ | ||
import { DOM } from "../dom"; | ||
import { ObservableExpression, } from "../observation/observable"; | ||
import { Directive } from "./directive"; | ||
export class WhenBehavior { | ||
constructor(location, expression, template) { | ||
this.location = location; | ||
this.template = template; | ||
this.view = null; | ||
this.context = void 0; | ||
this.observableExpression = new ObservableExpression(expression, this); | ||
} | ||
bind(source, context) { | ||
this.source = source; | ||
this.context = context; | ||
this.updateTarget(this.observableExpression.evaluate(source, context)); | ||
} | ||
unbind() { | ||
if (this.view !== null) { | ||
this.view.unbind(); | ||
} | ||
this.observableExpression.dispose(); | ||
this.source = null; | ||
} | ||
handleExpressionChange() { | ||
this.updateTarget(this.observableExpression.evaluate(this.source, this.context)); | ||
} | ||
updateTarget(show) { | ||
if (show && this.view == null) { | ||
this.view = this.cachedView || (this.cachedView = this.template.create()); | ||
this.view.bind(this.source, this.context); | ||
this.view.insertBefore(this.location); | ||
} | ||
else if (!show && this.view !== null) { | ||
// do not dispose, since we may want to use the view again | ||
this.view.remove(); | ||
this.view.unbind(); | ||
this.view = null; | ||
} | ||
} | ||
/** | ||
* A directive that enables basic conditional rendering in a template. | ||
* @param binding The condition to test for rendering. | ||
* @param templateOrTemplateBinding The template or a binding that gets | ||
* the template to render when the condition is true. | ||
*/ | ||
export function when(binding, templateOrTemplateBinding) { | ||
const getTemplate = typeof templateOrTemplateBinding === "function" | ||
? templateOrTemplateBinding | ||
: () => templateOrTemplateBinding; | ||
return (source, context) => binding(source, context) ? getTemplate(source, context) : null; | ||
} | ||
export class WhenDirective extends Directive { | ||
constructor(expression, template) { | ||
super(); | ||
this.expression = expression; | ||
this.template = template; | ||
this.createPlaceholder = DOM.createBlockPlaceholder; | ||
} | ||
createBehavior(target) { | ||
return new WhenBehavior(target, this.expression, this.template); | ||
} | ||
} | ||
export function when(expression, template) { | ||
return new WhenDirective(expression, template); | ||
} |
@@ -1,2 +0,2 @@ | ||
const markerClass = `fast-${Math.random().toString(36).substring(7)}`; | ||
const marker = `fast-${Math.random().toString(36).substring(7)}`; | ||
const updateQueue = []; | ||
@@ -37,2 +37,5 @@ // Tiny API-only polyfill for trustedTypes | ||
} | ||
/** | ||
* Common DOM APIs. | ||
*/ | ||
export const DOM = Object.freeze({ | ||
@@ -49,6 +52,6 @@ setHTMLPolicy(policy) { | ||
isMarker(node) { | ||
return (node && node.nodeType === 8 && node.data.startsWith(markerClass)); | ||
return node && node.nodeType === 8 && node.data.startsWith(marker); | ||
}, | ||
extractDirectiveIndexFromMarker(node) { | ||
return parseInt(node.data.replace(`${markerClass}:`, "")); | ||
return parseInt(node.data.replace(`${marker}:`, "")); | ||
}, | ||
@@ -62,4 +65,8 @@ createInterpolationPlaceholder(index) { | ||
createBlockPlaceholder(index) { | ||
return `<!--${markerClass}:${index}-->`; | ||
return `<!--${marker}:${index}-->`; | ||
}, | ||
/** | ||
* Schedules DOM update work in the next async batch. | ||
* @param callable The callable function or object to queue. | ||
*/ | ||
queueUpdate(callable) { | ||
@@ -71,2 +78,10 @@ if (updateQueue.length < 1) { | ||
}, | ||
/** | ||
* Resolves with the next DOM update. | ||
*/ | ||
nextUpdate() { | ||
return new Promise((resolve) => { | ||
DOM.queueUpdate(resolve); | ||
}); | ||
}, | ||
setAttribute(element, attributeName, value) { | ||
@@ -73,0 +88,0 @@ if (value === null || value === undefined) { |
@@ -13,5 +13,11 @@ export class FASTElementDefinition { | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
export const fastDefinitions = new Map(); | ||
/** | ||
* @internal | ||
*/ | ||
export function getDefinition(Type) { | ||
return fastDefinitions.get(Type); | ||
} |
@@ -0,1 +1,7 @@ | ||
/** | ||
* A readonly, empty array. | ||
* @remarks | ||
* Typically returned by APIs that return arrays when there are | ||
* no actual items to return. | ||
*/ | ||
export const emptyArray = Object.freeze([]); |
import { emptyArray } from "../interfaces"; | ||
/** | ||
* @internal | ||
*/ | ||
export function newSplice(index, removed, addedCount) { | ||
@@ -161,2 +164,4 @@ return { | ||
/** | ||
* @internal | ||
* @remarks | ||
* Lacking individual splice mutation information, the minimal set of | ||
@@ -309,2 +314,5 @@ * splices can be synthesized given the previous state and final state of an | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
export function projectArraySplices(array, changeRecords) { | ||
@@ -311,0 +319,0 @@ let splices = []; |
@@ -22,3 +22,3 @@ import { DOM } from "../dom"; | ||
} | ||
export class ArrayObserver extends SubscriberSet { | ||
class ArrayObserver extends SubscriberSet { | ||
constructor(source) { | ||
@@ -68,2 +68,9 @@ super(source); | ||
/* eslint-disable @typescript-eslint/explicit-function-return-type */ | ||
/** | ||
* Enables the array observation mechanism. | ||
* @remarks | ||
* Array observation is enabled automatically when using the | ||
* {@link RepeatDirective}, so calling this API manually is | ||
* not typically necessary. | ||
*/ | ||
export function enableArrayObservation() { | ||
@@ -74,5 +81,5 @@ if (arrayObservationEnabled) { | ||
arrayObservationEnabled = true; | ||
Observable.createArrayObserver = (collection) => { | ||
Observable.setArrayObserverFactory((collection) => { | ||
return new ArrayObserver(collection); | ||
}; | ||
}); | ||
const arrayProto = Array.prototype; | ||
@@ -79,0 +86,0 @@ const pop = arrayProto.pop; |
@@ -26,4 +26,5 @@ function spilloverSubscribe(subscriber) { | ||
/** | ||
* An implementation of Notifier that efficiently keeps track of subscribers interested | ||
* in a specific change notification on an observable source. | ||
* An implementation of {@link Notifier} that efficiently keeps track of | ||
* subscribers interested in a specific change notification on an | ||
* observable source. | ||
* | ||
@@ -39,8 +40,10 @@ * @remarks | ||
* @param source The object source that subscribers will receive notifications from. | ||
* @param initialSubscriber An initial subscriber to changes. | ||
*/ | ||
constructor(source) { | ||
this.source = source; | ||
constructor(source, initialSubscriber) { | ||
this.sub1 = void 0; | ||
this.sub2 = void 0; | ||
this.spillover = void 0; | ||
this.source = source; | ||
this.sub1 = initialSubscriber; | ||
} | ||
@@ -107,3 +110,4 @@ /** | ||
/** | ||
* An implementation of Notifier that allows subscribers to be notified of individual property changes on an object. | ||
* An implementation of Notifier that allows subscribers to be notified | ||
* of individual property changes on an object. | ||
*/ | ||
@@ -116,4 +120,4 @@ export class PropertyChangeNotifier { | ||
constructor(source) { | ||
this.subscribers = {}; | ||
this.source = source; | ||
this.subscribers = {}; | ||
} | ||
@@ -120,0 +124,0 @@ /** |
import { DOM } from "../dom"; | ||
import { PropertyChangeNotifier } from "./notifier"; | ||
import { PropertyChangeNotifier, SubscriberSet } from "./notifier"; | ||
const notifierLookup = new WeakMap(); | ||
const accessorLookup = new WeakMap(); | ||
let watcher = void 0; | ||
let createArrayObserver = (array) => { | ||
throw new Error("Must call enableArrayObservation before observing arrays."); | ||
}; | ||
class DefaultObservableAccessor { | ||
@@ -15,3 +18,3 @@ constructor(name, target) { | ||
if (watcher !== void 0) { | ||
watcher.observe(source, this.name); | ||
watcher.watch(source, this.name); | ||
} | ||
@@ -33,7 +36,17 @@ return source[this.field]; | ||
} | ||
export const Observable = { | ||
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ | ||
createArrayObserver(array) { | ||
throw new Error("Must call enableArrayObservation before observing arrays."); | ||
/** | ||
* Common Observable APIs. | ||
*/ | ||
export const Observable = Object.freeze({ | ||
/** | ||
* @internal | ||
* @param factory The factory used to create array observers. | ||
*/ | ||
setArrayObserverFactory(factory) { | ||
createArrayObserver = factory; | ||
}, | ||
/** | ||
* Gets a notifier for an object or Array. | ||
* @param source The object or Array to get the notifier for. | ||
*/ | ||
getNotifier(source) { | ||
@@ -43,3 +56,3 @@ let found = source.$fastController || notifierLookup.get(source); | ||
if (Array.isArray(source)) { | ||
found = Observable.createArrayObserver(source); | ||
found = createArrayObserver(source); | ||
} | ||
@@ -52,7 +65,17 @@ else { | ||
}, | ||
/** | ||
* Records a property change for a source object. | ||
* @param source The object to record the change against. | ||
* @param propertyName The property to track as changed. | ||
*/ | ||
track(source, propertyName) { | ||
if (watcher !== void 0) { | ||
watcher.observe(source, propertyName); | ||
watcher.watch(source, propertyName); | ||
} | ||
}, | ||
/** | ||
* Notifies subscribers of a source object of changes. | ||
* @param source the object to notify of changes. | ||
* @param args The change args to pass to subscribers. | ||
*/ | ||
notify(source, args) { | ||
@@ -62,2 +85,8 @@ /* eslint-disable-next-line @typescript-eslint/no-use-before-define */ | ||
}, | ||
/** | ||
* Defines an observable property on an object or prototype. | ||
* @param target The target object to define the observable on. | ||
* @param nameOrAccessor The name of the property to define as observable; | ||
* or a custom accessor that specifies the property name and accessor implementation. | ||
*/ | ||
defineProperty(target, nameOrAccessor) { | ||
@@ -78,2 +107,7 @@ if (typeof nameOrAccessor === "string") { | ||
}, | ||
/** | ||
* Finds all the observable accessors defined on the target, | ||
* including its prototype chain. | ||
* @param target The target object to search for accessor on. | ||
*/ | ||
getAccessors(target) { | ||
@@ -97,9 +131,27 @@ let accessors = accessorLookup.get(target); | ||
}, | ||
}; | ||
/** | ||
* Creates a {@link BindingObserver} that can watch the | ||
* provided {@link Binding} for changes. | ||
* @param binding The binding to observe. | ||
* @param initialSubscriber An initial subscriber to changes in the binding value. | ||
*/ | ||
binding(binding, initialSubscriber) { | ||
return new BindingObserverImplementation(binding, initialSubscriber); | ||
}, | ||
}); | ||
const getNotifier = Observable.getNotifier; | ||
const queueUpdate = DOM.queueUpdate; | ||
export function observable($target, $prop) { | ||
Observable.defineProperty($target, $prop); | ||
/** | ||
* Decorator: Defines an observable property on the target. | ||
* @param target The target to define the observable on. | ||
* @param nameOrAccessor The property name or accessor to define the observable as. | ||
*/ | ||
export function observable(target, nameOrAccessor) { | ||
Observable.defineProperty(target, nameOrAccessor); | ||
} | ||
let currentEvent = null; | ||
/** | ||
* @internal | ||
* @param event The event to set as current for the context. | ||
*/ | ||
export function setCurrentEvent(event) { | ||
@@ -113,22 +165,54 @@ currentEvent = event; | ||
constructor() { | ||
/** | ||
* The index of the current item within a repeat context. | ||
*/ | ||
this.index = 0; | ||
/** | ||
* The length of the current collection within a repeat context. | ||
*/ | ||
this.length = 0; | ||
/** | ||
* The parent data object within a repeat context. | ||
*/ | ||
this.parent = null; | ||
} | ||
/** | ||
* The current event within an event handler. | ||
*/ | ||
get event() { | ||
return currentEvent; | ||
} | ||
get even() { | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* has an even index. | ||
*/ | ||
get isEven() { | ||
return this.index % 2 === 0; | ||
} | ||
get odd() { | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* has an odd index. | ||
*/ | ||
get isOdd() { | ||
return this.index % 2 !== 0; | ||
} | ||
get first() { | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* is the first item in the collection. | ||
*/ | ||
get isFirst() { | ||
return this.index === 0; | ||
} | ||
get middle() { | ||
return !this.first && !this.last; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* is somewhere in the middle of the collection. | ||
*/ | ||
get isInMiddle() { | ||
return !this.isFirst && !this.isLast; | ||
} | ||
get last() { | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* is the last item in the collection. | ||
*/ | ||
get isLast() { | ||
return this.index === this.length - 1; | ||
@@ -139,7 +223,10 @@ } | ||
Observable.defineProperty(ExecutionContext.prototype, "length"); | ||
/** | ||
* The default execution context used in binding expressions. | ||
*/ | ||
export const defaultExecutionContext = new ExecutionContext(); | ||
export class ObservableExpression { | ||
constructor(expression, observer) { | ||
this.expression = expression; | ||
this.observer = observer; | ||
class BindingObserverImplementation extends SubscriberSet { | ||
constructor(binding, initialSubscriber) { | ||
super(binding, initialSubscriber); | ||
this.binding = binding; | ||
this.needsRefresh = true; | ||
@@ -149,3 +236,3 @@ this.needsQueue = true; | ||
this.last = null; | ||
this.source = void 0; | ||
this.propertySource = void 0; | ||
this.propertyName = void 0; | ||
@@ -155,13 +242,14 @@ this.notifier = void 0; | ||
} | ||
evaluate(scope, context) { | ||
observe(source, context) { | ||
if (this.needsRefresh && this.last !== null) { | ||
this.dispose(); | ||
this.disconnect(); | ||
} | ||
const previousWatcher = watcher; | ||
watcher = this.needsRefresh ? this : void 0; | ||
this.needsRefresh = false; | ||
const result = this.expression(scope, context); | ||
watcher = void 0; | ||
const result = this.binding(source, context); | ||
watcher = previousWatcher; | ||
return result; | ||
} | ||
dispose() { | ||
disconnect() { | ||
if (this.last !== null) { | ||
@@ -178,7 +266,7 @@ let current = this.first; | ||
/** @internal */ | ||
observe(source, propertyName) { | ||
watch(propertySource, propertyName) { | ||
const prev = this.last; | ||
const notifier = getNotifier(source); | ||
const notifier = getNotifier(propertySource); | ||
const current = prev === null ? this.first : {}; | ||
current.source = source; | ||
current.propertySource = propertySource; | ||
current.propertyName = propertyName; | ||
@@ -190,5 +278,5 @@ current.notifier = notifier; | ||
watcher = void 0; | ||
const prevValue = prev.source[prev.propertyName]; | ||
const prevValue = prev.propertySource[prev.propertyName]; | ||
watcher = this; | ||
if (source === prevValue) { | ||
if (propertySource === prevValue) { | ||
this.needsRefresh = true; | ||
@@ -211,4 +299,4 @@ } | ||
this.needsQueue = true; | ||
this.observer.handleExpressionChange(this); | ||
this.notify(this); | ||
} | ||
} |
@@ -13,5 +13,5 @@ import { DOM } from "./dom"; | ||
compilationContext.locatedDirectives++; | ||
return x.expression; | ||
return x.binding; | ||
}); | ||
const expression = (scope, context) => { | ||
const binding = (scope, context) => { | ||
let output = ""; | ||
@@ -23,5 +23,5 @@ for (let i = 0; i < partCount; ++i) { | ||
}; | ||
const binding = new BindingDirective(expression); | ||
binding.targetName = targetName; | ||
return binding; | ||
const directive = new BindingDirective(binding); | ||
directive.targetName = targetName; | ||
return directive; | ||
} | ||
@@ -134,6 +134,6 @@ function parseContent(value, directives) { | ||
} | ||
function captureContentBinding(binding, viewBehaviorFactories) { | ||
binding.targetAtContent(); | ||
binding.targetIndex = compilationContext.targetIndex; | ||
viewBehaviorFactories.push(binding); | ||
function captureContentBinding(directive, viewBehaviorFactories) { | ||
directive.targetAtContent(); | ||
directive.targetIndex = compilationContext.targetIndex; | ||
viewBehaviorFactories.push(directive); | ||
compilationContext.locatedDirectives++; | ||
@@ -140,0 +140,0 @@ } |
@@ -6,19 +6,7 @@ import { compileTemplate } from "./template-compiler"; | ||
import { BindingDirective } from "./directives/binding"; | ||
import { defaultExecutionContext, } from "./observation/observable"; | ||
export class HTMLTemplateBehavior { | ||
constructor(template, location) { | ||
this.view = template.create(); | ||
this.view.insertBefore(location); | ||
} | ||
bind(source, context) { | ||
this.view.bind(source, context); | ||
} | ||
unbind() { | ||
this.view.unbind(); | ||
} | ||
} | ||
import { defaultExecutionContext } from "./observation/observable"; | ||
/** | ||
* A template capable of creating HTMLView instances or rendering directly to DOM. | ||
*/ | ||
export class ViewTemplate extends Directive { | ||
export class ViewTemplate { | ||
/** | ||
@@ -30,6 +18,4 @@ * Creates an instance of ViewTemplate. | ||
constructor(html, directives) { | ||
super(); | ||
this.html = html; | ||
this.directives = directives; | ||
this.createPlaceholder = DOM.createBlockPlaceholder; | ||
this.behaviorCount = 0; | ||
@@ -114,5 +100,2 @@ this.hasHostBehaviors = false; | ||
} | ||
createBehavior(target) { | ||
return new HTMLTemplateBehavior(this, target); | ||
} | ||
} | ||
@@ -138,2 +121,6 @@ // Much thanks to LitHTML for working this out! | ||
html += currentString; | ||
if (value instanceof ViewTemplate) { | ||
const template = value; | ||
value = () => template; | ||
} | ||
if (typeof value === "function") { | ||
@@ -140,0 +127,0 @@ value = new BindingDirective(value); |
@@ -8,6 +8,11 @@ // A singleton Range instance used to efficiently remove ranges of DOM nodes. | ||
export class HTMLView { | ||
/** | ||
* | ||
* @param fragment The html fragment that contains the nodes for this view. | ||
* @param behaviors The behaviors to be applied to this view. | ||
*/ | ||
constructor(fragment, behaviors) { | ||
this.fragment = fragment; | ||
this.behaviors = behaviors; | ||
this.source = void 0; | ||
this.source = null; | ||
this.context = null; | ||
@@ -92,3 +97,3 @@ this.firstChild = fragment.firstChild; | ||
} | ||
else if (this.source !== void 0) { | ||
else if (this.source !== null) { | ||
const oldSource = this.source; | ||
@@ -115,3 +120,3 @@ this.source = source; | ||
unbind() { | ||
if (this.source === void 0) { | ||
if (this.source === null) { | ||
return; | ||
@@ -124,3 +129,3 @@ } | ||
} | ||
this.source = void 0; | ||
this.source = null; | ||
} | ||
@@ -127,0 +132,0 @@ /** |
/** | ||
* Represents a getter/setter property accessor on an object. | ||
*/ | ||
export declare interface Accessor { | ||
/** | ||
* The name of the property. | ||
*/ | ||
name: string; | ||
/** | ||
* Gets the value of the property on the source object. | ||
* @param source The source object to access. | ||
*/ | ||
getValue(source: any): any; | ||
/** | ||
* Sets the value of the property on the source object. | ||
* @param source The source object to access. | ||
* @param value The value to set the property to. | ||
*/ | ||
setValue(source: any, value: any): void; | ||
@@ -80,5 +95,15 @@ } | ||
/** | ||
* The signature of an arrow function capable of being evaluated | ||
* as part of a template binding update. | ||
*/ | ||
export declare type Binding<TSource = any, TReturn = any, TParent = any> = (source: TSource, context: ExecutionContext<TParent>) => TReturn; | ||
/** | ||
* A behavior that updates content and attributes based on a configured | ||
* BindingDirective. | ||
*/ | ||
export declare class BindingBehavior implements Behavior { | ||
target: any; | ||
expression: Expression; | ||
binding: Binding; | ||
bind: typeof normalBind; | ||
@@ -90,12 +115,30 @@ unbind: typeof normalUnbind; | ||
context: ExecutionContext | null; | ||
observableExpression: ObservableExpression | null; | ||
bindingObserver: BindingObserver | null; | ||
classVersions: Record<string, number>; | ||
version: number; | ||
constructor(target: any, expression: Expression, bind: typeof normalBind, unbind: typeof normalUnbind, updateTarget: typeof updatePropertyTarget, targetName?: string | undefined); | ||
handleExpressionChange(): void; | ||
/** | ||
* | ||
* @param target The target of the data updates. | ||
* @param binding The binding that returns the latest value for an update. | ||
* @param bind The operation to perform during binding. | ||
* @param unbind The operation to perform during unbinding. | ||
* @param updateTarget The operation to perform when updating. | ||
* @param targetName The name of the target attribute or property to update. | ||
*/ | ||
constructor(target: any, binding: Binding, bind: typeof normalBind, unbind: typeof normalUnbind, updateTarget: typeof updatePropertyTarget, targetName?: string | undefined); | ||
/** | ||
* @internal | ||
*/ | ||
handleChange(): void; | ||
/** | ||
* @internal | ||
*/ | ||
handleEvent(event: Event): void; | ||
} | ||
/** | ||
* A directive that configures data binding to element content and attributes. | ||
*/ | ||
export declare class BindingDirective extends Directive { | ||
expression: Expression; | ||
binding: Binding; | ||
private cleanedTargetName?; | ||
@@ -107,11 +150,52 @@ private originalTargetName?; | ||
private updateTarget; | ||
constructor(expression: Expression); | ||
/** | ||
* Creates an instance of BindingDirective. | ||
* @param binding A binding that returns the data used to update the DOM. | ||
*/ | ||
constructor(binding: Binding); | ||
/** | ||
* Gets the name of the attribute or property that this | ||
* binding is targeting. | ||
*/ | ||
get targetName(): string | undefined; | ||
/** | ||
* Sets the name of the attribute or property tha this | ||
* binding is targeting. | ||
*/ | ||
set targetName(value: string | undefined); | ||
/** | ||
* Makes this binding target the content of an element rather than | ||
* a particular attribute or property. | ||
*/ | ||
targetAtContent(): void; | ||
/** | ||
* Creates the runtime BindingBehavior instance based on the configuration | ||
* information stored in the BindingDirective. | ||
* @param target The target node that the binding behavior should attach to. | ||
*/ | ||
createBehavior(target: any): BindingBehavior; | ||
} | ||
/** | ||
* Enables evaluation of and subscription to a binding. | ||
*/ | ||
export declare interface BindingObserver<TSource = any, TReturn = any, TParent = any> extends Notifier { | ||
/** | ||
* Begins observing the binding for the source and returns the current value. | ||
* @param source The source that the binding is based on. | ||
* @param context The execution context to execute the binding within. | ||
* @returns The value of the binding. | ||
*/ | ||
observe(source: TSource, context: ExecutionContext): TReturn; | ||
/** | ||
* Unsubscribe from all dependent observables of the binding. | ||
*/ | ||
disconnect(): void; | ||
} | ||
export declare const booleanConverter: ValueConverter; | ||
/** | ||
* Represents a callable type such as a function or an object with a "call" method. | ||
*/ | ||
export declare type Callable = typeof Function.prototype.call | { | ||
@@ -121,2 +205,6 @@ call(): void; | ||
/** | ||
* A marker interface used to capture types when interpolating Directive helpers | ||
* into templates. | ||
*/ | ||
export declare interface CaptureType<TSource> { | ||
@@ -202,2 +290,5 @@ } | ||
/** | ||
* The default execution context used in binding expressions. | ||
*/ | ||
export declare const defaultExecutionContext: ExecutionContext<any>; | ||
@@ -211,2 +302,5 @@ | ||
/** | ||
* Common DOM APIs. | ||
*/ | ||
export declare const DOM: Readonly<{ | ||
@@ -220,3 +314,11 @@ setHTMLPolicy(policy: TrustedTypesPolicy): void; | ||
createBlockPlaceholder(index: number): string; | ||
/** | ||
* Schedules DOM update work in the next async batch. | ||
* @param callable The callable function or object to queue. | ||
*/ | ||
queueUpdate(callable: Callable): void; | ||
/** | ||
* Resolves with the next DOM update. | ||
*/ | ||
nextUpdate(): Promise<void>; | ||
setAttribute(element: HTMLElement, attributeName: string, value: any): void; | ||
@@ -264,2 +366,8 @@ setBooleanAttribute(element: HTMLElement, attributeName: string, value: boolean): void; | ||
/** | ||
* A readonly, empty array. | ||
* @remarks | ||
* Typically returned by APIs that return arrays when there are | ||
* no actual items to return. | ||
*/ | ||
export declare const emptyArray: readonly never[]; | ||
@@ -271,22 +379,45 @@ | ||
export declare class ExecutionContext<TParent = any> { | ||
/** | ||
* The index of the current item within a repeat context. | ||
*/ | ||
index: number; | ||
/** | ||
* The length of the current collection within a repeat context. | ||
*/ | ||
length: number; | ||
/** | ||
* The parent data object within a repeat context. | ||
*/ | ||
parent: TParent; | ||
/** | ||
* The current event within an event handler. | ||
*/ | ||
get event(): Event; | ||
get even(): boolean; | ||
get odd(): boolean; | ||
get first(): boolean; | ||
get middle(): boolean; | ||
get last(): boolean; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* has an even index. | ||
*/ | ||
get isEven(): boolean; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* has an odd index. | ||
*/ | ||
get isOdd(): boolean; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* is the first item in the collection. | ||
*/ | ||
get isFirst(): boolean; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* is somewhere in the middle of the collection. | ||
*/ | ||
get isInMiddle(): boolean; | ||
/** | ||
* Indicates whether the current item within a repeat context | ||
* is the last item in the collection. | ||
*/ | ||
get isLast(): boolean; | ||
} | ||
/** | ||
* The signature of an arrow function capable of being evaluated as part of a template update. | ||
*/ | ||
export declare type Expression<TScope = any, TReturn = any, TParent = any> = (scope: TScope, context: ExecutionContext<TParent>) => TReturn; | ||
export declare interface ExpressionObserver { | ||
handleExpressionChange(expression: ObservableExpression): void; | ||
} | ||
export declare interface FASTElement { | ||
@@ -321,2 +452,5 @@ $fastController: Controller; | ||
/** | ||
* @internal | ||
*/ | ||
declare function getDefinition<T extends Function>(Type: T): FASTElementDefinition | undefined; | ||
@@ -334,9 +468,2 @@ | ||
export declare class HTMLTemplateBehavior implements Behavior { | ||
private view; | ||
constructor(template: SyntheticViewTemplate, location: HTMLElement); | ||
bind(source: unknown, context: ExecutionContext): void; | ||
unbind(): void; | ||
} | ||
/** | ||
@@ -348,6 +475,11 @@ * The standard View implementation, which also implements ElementView and SyntheticView. | ||
private behaviors; | ||
private source; | ||
source: any | null; | ||
context: ExecutionContext | null; | ||
firstChild: Node; | ||
lastChild: Node; | ||
/** | ||
* | ||
* @param fragment The html fragment that contains the nodes for this view. | ||
* @param behaviors The behaviors to be applied to this view. | ||
*/ | ||
constructor(fragment: DocumentFragment, behaviors: Behavior[]); | ||
@@ -452,35 +584,57 @@ /** | ||
export declare const Observable: { | ||
createArrayObserver(array: any[]): Notifier; | ||
getNotifier<T extends Notifier = Notifier>(source: any): T; | ||
/** | ||
* Common Observable APIs. | ||
*/ | ||
export declare const Observable: Readonly<{ | ||
/** | ||
* @internal | ||
* @param factory The factory used to create array observers. | ||
*/ | ||
setArrayObserverFactory(factory: (collection: any[]) => Notifier): void; | ||
/** | ||
* Gets a notifier for an object or Array. | ||
* @param source The object or Array to get the notifier for. | ||
*/ | ||
getNotifier(source: any): Notifier; | ||
/** | ||
* Records a property change for a source object. | ||
* @param source The object to record the change against. | ||
* @param propertyName The property to track as changed. | ||
*/ | ||
track(source: unknown, propertyName: string): void; | ||
/** | ||
* Notifies subscribers of a source object of changes. | ||
* @param source the object to notify of changes. | ||
* @param args The change args to pass to subscribers. | ||
*/ | ||
notify(source: unknown, args: any): void; | ||
/** | ||
* Defines an observable property on an object or prototype. | ||
* @param target The target object to define the observable on. | ||
* @param nameOrAccessor The name of the property to define as observable; | ||
* or a custom accessor that specifies the property name and accessor implementation. | ||
*/ | ||
defineProperty(target: {}, nameOrAccessor: string | Accessor): void; | ||
/** | ||
* Finds all the observable accessors defined on the target, | ||
* including its prototype chain. | ||
* @param target The target object to search for accessor on. | ||
*/ | ||
getAccessors(target: {}): Accessor[]; | ||
}; | ||
/** | ||
* Creates a {@link BindingObserver} that can watch the | ||
* provided {@link Binding} for changes. | ||
* @param binding The binding to observe. | ||
* @param initialSubscriber An initial subscriber to changes in the binding value. | ||
*/ | ||
binding<TScope = any, TReturn = any, TParent = any>(binding: Binding<any, any, any>, initialSubscriber?: Subscriber | undefined): BindingObserver<TScope, TReturn, TParent>; | ||
}>; | ||
export declare function observable($target: {}, $prop: string): void; | ||
/** | ||
* Decorator: Defines an observable property on the target. | ||
* @param target The target to define the observable on. | ||
* @param nameOrAccessor The property name or accessor to define the observable as. | ||
*/ | ||
export declare function observable(target: {}, nameOrAccessor: string | Accessor): void; | ||
export declare class ObservableExpression { | ||
private expression; | ||
private observer; | ||
private needsRefresh; | ||
private needsQueue; | ||
private first; | ||
private last; | ||
private source; | ||
private propertyName; | ||
private notifier; | ||
private next; | ||
constructor(expression: Expression, observer: ExpressionObserver); | ||
evaluate(scope: unknown, context: ExecutionContext): any; | ||
dispose(): void; | ||
/** @internal */ | ||
observe(source: unknown, propertyName: string): void; | ||
/** @internal */ | ||
handleChange(): void; | ||
/** @internal */ | ||
call(): void; | ||
} | ||
export declare type PartialFASTElementDefinition = { | ||
@@ -496,8 +650,12 @@ readonly name: string; | ||
/** | ||
* An implementation of Notifier that allows subscribers to be notified of individual property changes on an object. | ||
* An implementation of Notifier that allows subscribers to be notified | ||
* of individual property changes on an object. | ||
*/ | ||
export declare class PropertyChangeNotifier implements Notifier { | ||
readonly source: any; | ||
private subscribers; | ||
/** | ||
* The source that property changes are being notified for. | ||
*/ | ||
readonly source: any; | ||
/** | ||
* Creates an instance of PropertyChangeNotifier for the specified source. | ||
@@ -536,6 +694,7 @@ * @param source The object source that subscribers will receive notifications from. | ||
export declare function repeat<TScope = any, TItem = any>(expression: Expression<TScope, TItem[]>, template: ViewTemplate<Partial<TItem>, TScope>, options?: RepeatOptions): CaptureType<TScope>; | ||
export declare function repeat<TScope = any, TItem = any>(binding: Binding<TScope, TItem[]>, template: ViewTemplate<Partial<TItem>, TScope>, options?: RepeatOptions): CaptureType<TScope>; | ||
export declare class RepeatBehavior implements Behavior, Subscriber { | ||
private location; | ||
private binding; | ||
private template; | ||
@@ -547,10 +706,9 @@ private options; | ||
private itemsObserver?; | ||
private observableExpression; | ||
private bindingObserver; | ||
private originalContext; | ||
private childContext; | ||
private bindView; | ||
constructor(location: Node, expression: Expression, template: SyntheticViewTemplate, options: RepeatOptions); | ||
constructor(location: Node, binding: Binding, template: SyntheticViewTemplate, options: RepeatOptions); | ||
bind(source: unknown, context: ExecutionContext): void; | ||
unbind(): void; | ||
handleExpressionChange(): void; | ||
handleChange(source: any, args: Splice[]): void; | ||
@@ -564,7 +722,7 @@ private observeItems; | ||
export declare class RepeatDirective extends Directive { | ||
expression: Expression; | ||
binding: Binding; | ||
template: SyntheticViewTemplate; | ||
options: RepeatOptions; | ||
createPlaceholder: (index: number) => string; | ||
constructor(expression: Expression, template: SyntheticViewTemplate, options: RepeatOptions); | ||
constructor(binding: Binding, template: SyntheticViewTemplate, options: RepeatOptions); | ||
createBehavior(target: any): RepeatBehavior; | ||
@@ -577,2 +735,6 @@ } | ||
/** | ||
* @internal | ||
* @param event The event to set as current for the context. | ||
*/ | ||
export declare function setCurrentEvent(event: Event | null): void; | ||
@@ -592,5 +754,17 @@ | ||
/** | ||
* Represents a set of splice-based changes against an Array. | ||
*/ | ||
declare interface Splice { | ||
/** | ||
* The index that the splice occurs at. | ||
*/ | ||
index: number; | ||
/** | ||
* The items that were removed. | ||
*/ | ||
removed: any[]; | ||
/** | ||
* The number of items that were added. | ||
*/ | ||
addedCount: number; | ||
@@ -629,4 +803,5 @@ } | ||
/** | ||
* An implementation of Notifier that efficiently keeps track of subscribers interested | ||
* in a specific change notification on an observable source. | ||
* An implementation of {@link Notifier} that efficiently keeps track of | ||
* subscribers interested in a specific change notification on an | ||
* observable source. | ||
* | ||
@@ -639,3 +814,2 @@ * @remarks | ||
export declare class SubscriberSet implements Notifier { | ||
readonly source: any; | ||
private sub1; | ||
@@ -645,6 +819,11 @@ private sub2; | ||
/** | ||
* The source that this subscriber set is reporting changes for. | ||
*/ | ||
readonly source: any; | ||
/** | ||
* Creates an instance of SubscriberSet for the specified source. | ||
* @param source The object source that subscribers will receive notifications from. | ||
* @param initialSubscriber An initial subscriber to changes. | ||
*/ | ||
constructor(source: any); | ||
constructor(source: any, initialSubscriber?: Subscriber); | ||
/** | ||
@@ -711,3 +890,6 @@ * Checks whether the provided subscriber has been added to this set. | ||
declare type TemplateValue<TScope, TParent = any> = Expression<TScope, any, TParent> | string | number | Directive | CaptureType<TScope>; | ||
/** | ||
* Represents the types of values that can be interpolated into a template. | ||
*/ | ||
export declare type TemplateValue<TScope, TParent = any> = Binding<TScope, any, TParent> | string | number | Directive | CaptureType<TScope>; | ||
@@ -734,2 +916,6 @@ declare type TrustedTypesPolicy = { | ||
/** | ||
* The data that the view is bound to. | ||
*/ | ||
readonly source: any | null; | ||
/** | ||
* Binds a view's behaviors to its binding source. | ||
@@ -748,6 +934,5 @@ * @param source The binding source for the view's binding behaviors. | ||
*/ | ||
export declare class ViewTemplate<TSource = any, TParent = any> extends Directive implements ElementViewTemplate, SyntheticViewTemplate { | ||
export declare class ViewTemplate<TSource = any, TParent = any> implements ElementViewTemplate, SyntheticViewTemplate { | ||
readonly html: string | HTMLTemplateElement; | ||
readonly directives: ReadonlyArray<Directive>; | ||
createPlaceholder: (index: number) => string; | ||
private behaviorCount; | ||
@@ -776,30 +961,12 @@ private hasHostBehaviors; | ||
render(source: TSource, host: HTMLElement | string): HTMLView; | ||
createBehavior(target: any): HTMLTemplateBehavior; | ||
} | ||
export declare function when<T = any, K = any>(expression: Expression<T, K>, template: SyntheticViewTemplate): CaptureType<T>; | ||
/** | ||
* A directive that enables basic conditional rendering in a template. | ||
* @param binding The condition to test for rendering. | ||
* @param templateOrTemplateBinding The template or a binding that gets | ||
* the template to render when the condition is true. | ||
*/ | ||
export declare function when<TSource = any, TReturn = any>(binding: Binding<TSource, TReturn>, templateOrTemplateBinding: SyntheticViewTemplate | Binding<TSource, SyntheticViewTemplate>): CaptureType<TSource>; | ||
export declare class WhenBehavior implements Behavior { | ||
private location; | ||
private template; | ||
private view; | ||
private cachedView?; | ||
private source; | ||
private observableExpression; | ||
private context; | ||
constructor(location: Node, expression: Expression, template: SyntheticViewTemplate); | ||
bind(source: unknown, context: ExecutionContext): void; | ||
unbind(): void; | ||
handleExpressionChange(): void; | ||
updateTarget(show: boolean): void; | ||
} | ||
export declare class WhenDirective extends Directive { | ||
expression: Expression; | ||
template: SyntheticViewTemplate; | ||
createPlaceholder: (index: number) => string; | ||
constructor(expression: Expression, template: SyntheticViewTemplate); | ||
createBehavior(target: any): WhenBehavior; | ||
} | ||
export { } |
@@ -8,3 +8,4 @@ # Acknowledgements | ||
* [Knockout](https://knockoutjs.com/) - One of the first JavaScript libraries (if not the first) to implement an observer system. The original techniques for observables and computed observables have influenced many libraries over the years. Re-interpreting these ideas in terms of modern JavaScript and DOM has helped us to build a powerful and robust system. | ||
* [lit-html](https://lit-html.polymer-project.org/) - One of the first libraries to leverage standard JavaScript tagged template literals for HTML templates. We were inspired by this technique and wanted to explore whether it could be combined with our idea of arrow function expressions. | ||
* [Polymer](https://www.polymer-project.org/) - One of the first libraries (if not the first) to embrace Web Components. | ||
* [lit-html](https://lit-html.polymer-project.org/) - One of the first libraries to leverage standard JavaScript tagged template literals for HTML templates. We were inspired by this technique and wanted to explore whether it could be combined with our idea of arrow function binding expressions. | ||
* [Polymer](https://www.polymer-project.org/) - One of the first libraries (if not the first) to embrace Web Components. | ||
* [Vue](https://vuejs.org/) - We liked the terseness of the `:` and `@` syntax in templates, so we adapted it with some modifications in our own templates. |
@@ -7,9 +7,6 @@ ## API Report File for "@microsoft/fast-element" | ||
// @public (undocumented) | ||
// @public | ||
export interface Accessor { | ||
// (undocumented) | ||
getValue(source: any): any; | ||
// (undocumented) | ||
name: string; | ||
// (undocumented) | ||
setValue(source: any, value: any): void; | ||
@@ -101,5 +98,8 @@ } | ||
// @public (undocumented) | ||
// @public | ||
export type Binding<TSource = any, TReturn = any, TParent = any> = (source: TSource, context: ExecutionContext<TParent>) => TReturn; | ||
// @public | ||
export class BindingBehavior implements Behavior { | ||
constructor(target: any, expression: Expression, bind: typeof normalBind, unbind: typeof normalUnbind, updateTarget: typeof updatePropertyTarget, targetName?: string | undefined); | ||
constructor(target: any, binding: Binding, bind: typeof normalBind, unbind: typeof normalUnbind, updateTarget: typeof updatePropertyTarget, targetName?: string | undefined); | ||
// Warning: (ae-forgotten-export) The symbol "normalBind" needs to be exported by the entry point index.d.ts | ||
@@ -110,14 +110,14 @@ // | ||
// (undocumented) | ||
binding: Binding; | ||
// (undocumented) | ||
bindingObserver: BindingObserver | null; | ||
// (undocumented) | ||
classVersions: Record<string, number>; | ||
// (undocumented) | ||
context: ExecutionContext | null; | ||
// (undocumented) | ||
expression: Expression; | ||
// (undocumented) | ||
// @internal (undocumented) | ||
handleChange(): void; | ||
// @internal (undocumented) | ||
handleEvent(event: Event): void; | ||
// (undocumented) | ||
handleExpressionChange(): void; | ||
// (undocumented) | ||
observableExpression: ObservableExpression | null; | ||
// (undocumented) | ||
source: unknown; | ||
@@ -140,14 +140,11 @@ // (undocumented) | ||
// @public (undocumented) | ||
// @public | ||
export class BindingDirective extends Directive { | ||
constructor(expression: Expression); | ||
constructor(binding: Binding); | ||
// (undocumented) | ||
binding: Binding; | ||
createBehavior(target: any): BindingBehavior; | ||
// (undocumented) | ||
createPlaceholder: (index: number) => string; | ||
// (undocumented) | ||
expression: Expression; | ||
// (undocumented) | ||
targetAtContent(): void; | ||
// (undocumented) | ||
get targetName(): string | undefined; | ||
@@ -157,6 +154,12 @@ set targetName(value: string | undefined); | ||
// @public | ||
export interface BindingObserver<TSource = any, TReturn = any, TParent = any> extends Notifier { | ||
disconnect(): void; | ||
observe(source: TSource, context: ExecutionContext): TReturn; | ||
} | ||
// @public (undocumented) | ||
export const booleanConverter: ValueConverter; | ||
// @public (undocumented) | ||
// @public | ||
export type Callable = typeof Function.prototype.call | { | ||
@@ -166,3 +169,3 @@ call(): void; | ||
// @public (undocumented) | ||
// @public | ||
export interface CaptureType<TSource> { | ||
@@ -249,3 +252,3 @@ } | ||
// @public (undocumented) | ||
// @public | ||
export const defaultExecutionContext: ExecutionContext<any>; | ||
@@ -263,3 +266,3 @@ | ||
// @public (undocumented) | ||
// @public | ||
export const DOM: Readonly<{ | ||
@@ -274,2 +277,3 @@ setHTMLPolicy(policy: TrustedTypesPolicy): void; | ||
queueUpdate(callable: Callable): void; | ||
nextUpdate(): Promise<void>; | ||
setAttribute(element: HTMLElement, attributeName: string, value: any): void; | ||
@@ -307,3 +311,3 @@ setBooleanAttribute(element: HTMLElement, attributeName: string, value: boolean): void; | ||
// @public (undocumented) | ||
// @public | ||
export const emptyArray: readonly never[]; | ||
@@ -313,32 +317,14 @@ | ||
export class ExecutionContext<TParent = any> { | ||
// (undocumented) | ||
get even(): boolean; | ||
// (undocumented) | ||
get event(): Event; | ||
// (undocumented) | ||
get first(): boolean; | ||
// (undocumented) | ||
index: number; | ||
// (undocumented) | ||
get last(): boolean; | ||
// (undocumented) | ||
get isEven(): boolean; | ||
get isFirst(): boolean; | ||
get isInMiddle(): boolean; | ||
get isLast(): boolean; | ||
get isOdd(): boolean; | ||
length: number; | ||
// (undocumented) | ||
get middle(): boolean; | ||
// (undocumented) | ||
get odd(): boolean; | ||
// (undocumented) | ||
parent: TParent; | ||
} | ||
// @public | ||
export type Expression<TScope = any, TReturn = any, TParent = any> = (scope: TScope, context: ExecutionContext<TParent>) => TReturn; | ||
// @public (undocumented) | ||
export interface ExpressionObserver { | ||
// (undocumented) | ||
handleExpressionChange(expression: ObservableExpression): void; | ||
} | ||
// @public (undocumented) | ||
export interface FASTElement { | ||
@@ -388,16 +374,5 @@ // (undocumented) | ||
// Warning: (ae-forgotten-export) The symbol "TemplateValue" needs to be exported by the entry point index.d.ts | ||
// | ||
// @public | ||
export function html<TSource = any, TParent = any>(strings: TemplateStringsArray, ...values: TemplateValue<TSource, TParent>[]): ViewTemplate<TSource, TParent>; | ||
// @public (undocumented) | ||
export class HTMLTemplateBehavior implements Behavior { | ||
constructor(template: SyntheticViewTemplate, location: HTMLElement); | ||
// (undocumented) | ||
bind(source: unknown, context: ExecutionContext): void; | ||
// (undocumented) | ||
unbind(): void; | ||
} | ||
// @public | ||
@@ -418,2 +393,4 @@ export class HTMLView implements ElementView, SyntheticView { | ||
remove(): void; | ||
// (undocumented) | ||
source: any | null; | ||
unbind(): void; | ||
@@ -433,6 +410,6 @@ } | ||
// @public (undocumented) | ||
export const Observable: { | ||
createArrayObserver(array: any[]): Notifier; | ||
getNotifier<T extends Notifier = Notifier>(source: any): T; | ||
// @public | ||
export const Observable: Readonly<{ | ||
setArrayObserverFactory(factory: (collection: any[]) => Notifier): void; | ||
getNotifier(source: any): Notifier; | ||
track(source: unknown, propertyName: string): void; | ||
@@ -442,23 +419,9 @@ notify(source: unknown, args: any): void; | ||
getAccessors(target: {}): Accessor[]; | ||
}; | ||
binding<TScope = any, TReturn = any, TParent = any>(binding: Binding<any, any, any>, initialSubscriber?: Subscriber | undefined): BindingObserver<TScope, TReturn, TParent>; | ||
}>; | ||
// @public (undocumented) | ||
export function observable($target: {}, $prop: string): void; | ||
// @public | ||
export function observable(target: {}, nameOrAccessor: string | Accessor): void; | ||
// @public (undocumented) | ||
export class ObservableExpression { | ||
constructor(expression: Expression, observer: ExpressionObserver); | ||
// @internal (undocumented) | ||
call(): void; | ||
// (undocumented) | ||
dispose(): void; | ||
// (undocumented) | ||
evaluate(scope: unknown, context: ExecutionContext): any; | ||
// @internal (undocumented) | ||
handleChange(): void; | ||
// @internal (undocumented) | ||
observe(source: unknown, propertyName: string): void; | ||
} | ||
// @public (undocumented) | ||
export type PartialFASTElementDefinition = { | ||
@@ -477,3 +440,2 @@ readonly name: string; | ||
notify(propertyName: string): void; | ||
// (undocumented) | ||
readonly source: any; | ||
@@ -497,7 +459,7 @@ subscribe(subscriber: Subscriber, propertyToWatch: string): void; | ||
// @public (undocumented) | ||
export function repeat<TScope = any, TItem = any>(expression: Expression<TScope, TItem[]>, template: ViewTemplate<Partial<TItem>, TScope>, options?: RepeatOptions): CaptureType<TScope>; | ||
export function repeat<TScope = any, TItem = any>(binding: Binding<TScope, TItem[]>, template: ViewTemplate<Partial<TItem>, TScope>, options?: RepeatOptions): CaptureType<TScope>; | ||
// @public (undocumented) | ||
export class RepeatBehavior implements Behavior, Subscriber { | ||
constructor(location: Node, expression: Expression, template: SyntheticViewTemplate, options: RepeatOptions); | ||
constructor(location: Node, binding: Binding, template: SyntheticViewTemplate, options: RepeatOptions); | ||
// (undocumented) | ||
@@ -510,4 +472,2 @@ bind(source: unknown, context: ExecutionContext): void; | ||
// (undocumented) | ||
handleExpressionChange(): void; | ||
// (undocumented) | ||
unbind(): void; | ||
@@ -518,4 +478,6 @@ } | ||
export class RepeatDirective extends Directive { | ||
constructor(expression: Expression, template: SyntheticViewTemplate, options: RepeatOptions); | ||
constructor(binding: Binding, template: SyntheticViewTemplate, options: RepeatOptions); | ||
// (undocumented) | ||
binding: Binding; | ||
// (undocumented) | ||
createBehavior(target: any): RepeatBehavior; | ||
@@ -525,4 +487,2 @@ // (undocumented) | ||
// (undocumented) | ||
expression: Expression; | ||
// (undocumented) | ||
options: RepeatOptions; | ||
@@ -539,3 +499,5 @@ // (undocumented) | ||
// @public (undocumented) | ||
// Warning: (ae-internal-missing-underscore) The name "setCurrentEvent" should be prefixed with an underscore because the declaration is marked as @internal | ||
// | ||
// @internal (undocumented) | ||
export function setCurrentEvent(event: Event | null): void; | ||
@@ -593,6 +555,5 @@ | ||
export class SubscriberSet implements Notifier { | ||
constructor(source: any); | ||
constructor(source: any, initialSubscriber?: Subscriber); | ||
has(subscriber: Subscriber): boolean; | ||
notify(args: any): void; | ||
// (undocumented) | ||
readonly source: any; | ||
@@ -617,2 +578,5 @@ subscribe(subscriber: Subscriber): void; | ||
// @public | ||
export type TemplateValue<TScope, TParent = any> = Binding<TScope, any, TParent> | string | number | Directive | CaptureType<TScope>; | ||
// @public (undocumented) | ||
@@ -630,2 +594,3 @@ export interface ValueConverter { | ||
readonly context: ExecutionContext | null; | ||
readonly source: any | null; | ||
unbind(): void; | ||
@@ -635,10 +600,6 @@ } | ||
// @public | ||
export class ViewTemplate<TSource = any, TParent = any> extends Directive implements ElementViewTemplate, SyntheticViewTemplate { | ||
export class ViewTemplate<TSource = any, TParent = any> implements ElementViewTemplate, SyntheticViewTemplate { | ||
constructor(html: string | HTMLTemplateElement, directives: ReadonlyArray<Directive>); | ||
create(host?: Element): HTMLView; | ||
// (undocumented) | ||
createBehavior(target: any): HTMLTemplateBehavior; | ||
// (undocumented) | ||
createPlaceholder: (index: number) => string; | ||
// (undocumented) | ||
readonly directives: ReadonlyArray<Directive>; | ||
@@ -650,35 +611,9 @@ // (undocumented) | ||
// @public (undocumented) | ||
export function when<T = any, K = any>(expression: Expression<T, K>, template: SyntheticViewTemplate): CaptureType<T>; | ||
// @public | ||
export function when<TSource = any, TReturn = any>(binding: Binding<TSource, TReturn>, templateOrTemplateBinding: SyntheticViewTemplate | Binding<TSource, SyntheticViewTemplate>): CaptureType<TSource>; | ||
// @public (undocumented) | ||
export class WhenBehavior implements Behavior { | ||
constructor(location: Node, expression: Expression, template: SyntheticViewTemplate); | ||
// (undocumented) | ||
bind(source: unknown, context: ExecutionContext): void; | ||
// (undocumented) | ||
handleExpressionChange(): void; | ||
// (undocumented) | ||
unbind(): void; | ||
// (undocumented) | ||
updateTarget(show: boolean): void; | ||
} | ||
// @public (undocumented) | ||
export class WhenDirective extends Directive { | ||
constructor(expression: Expression, template: SyntheticViewTemplate); | ||
// (undocumented) | ||
createBehavior(target: any): WhenBehavior; | ||
// (undocumented) | ||
createPlaceholder: (index: number) => string; | ||
// (undocumented) | ||
expression: Expression; | ||
// (undocumented) | ||
template: SyntheticViewTemplate; | ||
} | ||
// Warnings were encountered during analysis: | ||
// | ||
// dist/dts/dom.d.ts:6:5 - (ae-forgotten-export) The symbol "TrustedTypesPolicy" needs to be exported by the entry point index.d.ts | ||
// dist/dts/dom.d.ts:9:5 - (ae-forgotten-export) The symbol "TrustedTypesPolicy" needs to be exported by the entry point index.d.ts | ||
// dist/dts/fast-element.d.ts:16:5 - (ae-forgotten-export) The symbol "getDefinition" needs to be exported by the entry point index.d.ts | ||
@@ -685,0 +620,0 @@ |
@@ -5,3 +5,3 @@ { | ||
"sideEffects": false, | ||
"version": "0.9.0", | ||
"version": "0.10.0", | ||
"author": { | ||
@@ -32,3 +32,3 @@ "name": "Microsoft", | ||
"eslint:fix": "eslint . --ext .ts --fix", | ||
"test": "npm run test-node:verbose", | ||
"test": "npm run test-chrome:verbose", | ||
"test-node": "mocha --reporter min --exit dist/esm/__test__/setup-node.js './dist/esm/**/*.spec.js'", | ||
@@ -83,3 +83,3 @@ "test-node:verbose": "mocha --reporter spec --exit dist/esm/__test__/setup-node.js './dist/esm/**/*.spec.js'", | ||
}, | ||
"gitHead": "a508de4e24fc96f34291df8984f4c55ed5942db4" | ||
"gitHead": "cb339f92824034d048f5e840633ed3d7ded6b009" | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
718835
69
17356
0