Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@microsoft/fast-element

Package Overview
Dependencies
Maintainers
5
Versions
83
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@microsoft/fast-element - npm Package Compare versions

Comparing version 0.7.0 to 0.8.0

16

CHANGELOG.md

@@ -6,2 +6,18 @@ # Change Log

# [0.8.0](https://github.com/Microsoft/fast-dna/compare/@microsoft/fast-element@0.7.0...@microsoft/fast-element@0.8.0) (2020-04-27)
### Bug Fixes
* **fast-element:** attr bindings preserved during upgrade ([#3010](https://github.com/Microsoft/fast-dna/issues/3010)) ([e9b14cc](https://github.com/Microsoft/fast-dna/commit/e9b14ccf70efa7eac4b055d7a34fc4e2d775fa0c))
### Features
* **fast-element:** add a render method to templates for pure templating ([#3018](https://github.com/Microsoft/fast-dna/issues/3018)) ([c4ac6b2](https://github.com/Microsoft/fast-dna/commit/c4ac6b2a20d67992d5d820e9ae56eb75db7e2e3a))
# [0.7.0](https://github.com/Microsoft/fast-dna/compare/@microsoft/fast-element@0.6.0...@microsoft/fast-element@0.7.0) (2020-04-22)

@@ -8,0 +24,0 @@

11

dist/attributes.d.ts

@@ -0,1 +1,2 @@

import { Accessor } from "./observation/observable";
export interface ValueConverter {

@@ -15,5 +16,5 @@ toView(value: any): string | null;

export declare const nullableNumberConverter: ValueConverter;
export declare class AttributeDefinition {
export declare class AttributeDefinition implements Accessor {
readonly Owner: Function;
readonly property: string;
readonly name: string;
readonly attribute: string;

@@ -26,5 +27,5 @@ readonly mode: AttributeMode;

private readonly guards;
constructor(Owner: Function, property: string, attribute?: string, mode?: AttributeMode, converter?: ValueConverter | undefined);
setValue(element: HTMLElement, newValue: any): void;
getValue(element: HTMLElement): any;
constructor(Owner: Function, name: string, attribute?: string, mode?: AttributeMode, converter?: ValueConverter | undefined);
setValue(source: HTMLElement, newValue: any): void;
getValue(source: HTMLElement): any;
onAttributeChangedCallback(element: HTMLElement, value: any): void;

@@ -31,0 +32,0 @@ private tryReflectToAttribute;

@@ -35,5 +35,5 @@ import { Observable } from "./observation/observable";

export class AttributeDefinition {
constructor(Owner, property, attribute = property.toLowerCase(), mode = "reflect", converter) {
constructor(Owner, name, attribute = name.toLowerCase(), mode = "reflect", converter) {
this.Owner = Owner;
this.property = property;
this.name = name;
this.attribute = attribute;

@@ -43,4 +43,4 @@ this.mode = mode;

this.guards = new Set();
this.fieldName = `_${property}`;
this.callbackName = `${property}Changed`;
this.fieldName = `_${name}`;
this.callbackName = `${name}Changed`;
this.hasCallback = this.callbackName in Owner.prototype;

@@ -51,4 +51,4 @@ if (mode === "boolean" && converter === void 0) {

}
setValue(element, newValue) {
const oldValue = element[this.fieldName];
setValue(source, newValue) {
const oldValue = source[this.fieldName];
const converter = this.converter;

@@ -59,13 +59,13 @@ if (converter !== void 0) {

if (oldValue !== newValue) {
element[this.fieldName] = newValue;
this.tryReflectToAttribute(element);
source[this.fieldName] = newValue;
this.tryReflectToAttribute(source);
if (this.hasCallback) {
element[this.callbackName](oldValue, newValue);
source[this.callbackName](oldValue, newValue);
}
element.$fastController.notify(element, this.property);
source.$fastController.notify(source, this.name);
}
}
getValue(element) {
Observable.track(element, this.property);
return element[this.fieldName];
getValue(source) {
Observable.track(source, this.name);
return source[this.fieldName];
}

@@ -72,0 +72,0 @@ onAttributeChangedCallback(element, value) {

@@ -36,9 +36,9 @@ import { FASTElement } from "./fast-element";

// the browser upgraded the element. Then delete the property since it will
// shadow the getter/setter that is required to make the observable function.
// shadow the getter/setter that is required to make the observable operate.
// Later, in the connect callback, we'll re-apply the values.
const observedProps = Observable.getObservedProperties(element);
if (observedProps.length > 0) {
const accessors = Observable.getAccessors(element);
if (accessors.length > 0) {
const boundObservables = (this.boundObservables = Object.create(null));
for (let i = 0, ii = observedProps.length; i < ii; ++i) {
const propertyName = observedProps[i];
for (let i = 0, ii = accessors.length; i < ii; ++i) {
const propertyName = accessors[i].name;
const value = element[propertyName];

@@ -45,0 +45,0 @@ if (value !== void 0) {

@@ -10,5 +10,4 @@ import { Observable } from "../observation/observable";

bind(source) {
this.shouldUpdate =
Observable.getObservedProperties(source).indexOf(this.options.property) !==
-1;
const name = this.options.property;
this.shouldUpdate = Observable.getAccessors(source).some((x) => x.name === name);
this.source = source;

@@ -15,0 +14,0 @@ this.updateTarget(this.getNodes());

import { CaptureType, SyntheticViewTemplate, ViewTemplate } from "../template";
import { ExecutionContext, Expression } from "../observation/observable";
import { Subscriber } from "../observation/subscriber-collection";
import { Subscriber } from "../observation/notifier";
import { Splice } from "../observation/array-change-records";

@@ -5,0 +5,0 @@ import { Behavior } from "./behavior";

@@ -48,3 +48,3 @@ import { DOM } from "../dom";

if (this.itemsObserver !== void 0) {
this.itemsObserver.removeSubscriber(this);
this.itemsObserver.unsubscribe(this);
}

@@ -70,5 +70,5 @@ this.unbindAllViews();

if (oldObserver !== void 0) {
oldObserver.removeSubscriber(this);
oldObserver.unsubscribe(this);
}
newObserver.addSubscriber(this);
newObserver.subscribe(this);
}

@@ -75,0 +75,0 @@ }

import { Controller } from "./controller";
import { AttributeDefinition } from "./attributes";
import { Observable } from "./observation/observable";
const defaultShadowOptions = { mode: "open" };

@@ -64,13 +65,5 @@ const defaultElementOptions = {};

observedAttributes[i] = current.attribute;
propertyLookup[current.property] = current;
propertyLookup[current.name] = current;
attributeLookup[current.attribute] = current;
Reflect.defineProperty(proto, current.property, {
enumerable: true,
get: function () {
return current.getValue(this);
},
set: function (value) {
return current.setValue(this, value);
},
});
Observable.defineProperty(proto, current);
}

@@ -77,0 +70,0 @@ Reflect.defineProperty(Type, "observedAttributes", {

@@ -10,2 +10,3 @@ export * from "./template";

export * from "./observation/observable";
export * from "./observation/notifier";
export * from "./dom";

@@ -12,0 +13,0 @@ export * from "./directives/behavior";

@@ -10,2 +10,3 @@ export * from "./template";

export * from "./observation/observable";
export * from "./observation/notifier";
export * from "./dom";

@@ -12,0 +13,0 @@ export * from "./directives/binding";

@@ -1,5 +0,4 @@

import { Subscriber, SubscriberCollection } from "./subscriber-collection";
import { Notifier } from "./notifier";
import { SubscriberCollection } from "./notifier";
import { Splice } from "./array-change-records";
export declare class ArrayObserver extends SubscriberCollection implements Notifier {
export declare class ArrayObserver extends SubscriberCollection {
private collection;

@@ -9,10 +8,8 @@ private oldCollection;

private needsQueue;
subscribe: (subscriber: Subscriber) => void;
unsubscribe: (subscriber: Subscriber) => void;
call: () => void;
constructor(collection: any[]);
addSplice(splice: Splice): void;
reset(oldCollection: any[] | undefined): void;
notify(): void;
call(): void;
flush(): void;
}
export declare function enableArrayObservation(): void;
import { DOM } from "../dom";
import { Observable } from "./observable";
import { SubscriberCollection } from "./subscriber-collection";
import { SubscriberCollection } from "./notifier";
import { calcSplices, newSplice, projectArraySplices, } from "./array-change-records";

@@ -28,4 +28,3 @@ let arrayObservationEnabled = false;

this.needsQueue = true;
this.subscribe = this.addSubscriber;
this.unsubscribe = this.removeSubscriber;
this.call = this.flush;
collection.$fastController = this;

@@ -35,18 +34,16 @@ this.collection = collection;

addSplice(splice) {
if (this.hasSubscribers()) {
if (this.splices === void 0) {
this.splices = [splice];
}
else {
this.splices.push(splice);
}
if (this.needsQueue) {
this.needsQueue = false;
DOM.queueUpdate(this);
}
if (this.splices === void 0) {
this.splices = [splice];
}
else {
this.splices.push(splice);
}
if (this.needsQueue) {
this.needsQueue = false;
DOM.queueUpdate(this);
}
}
reset(oldCollection) {
this.oldCollection = oldCollection;
if (this.hasSubscribers() && this.needsQueue) {
if (this.needsQueue) {
this.needsQueue = false;

@@ -56,19 +53,15 @@ DOM.queueUpdate(this);

}
notify() {
if (this.splices !== void 0 || this.oldCollection !== void 0) {
this.call();
}
}
call() {
flush() {
const splices = this.splices;
const oldCollection = this.oldCollection;
if (splices === void 0 && oldCollection === void 0) {
return;
}
this.needsQueue = true;
this.splices = void 0;
this.oldCollection = void 0;
if (this.hasSubscribers()) {
const finalSplices = oldCollection === void 0
? projectArraySplices(this.collection, splices)
: calcSplices(this.collection, 0, this.collection.length, oldCollection, 0, oldCollection.length);
this.notifySubscribers(this, finalSplices);
}
const finalSplices = oldCollection === void 0
? projectArraySplices(this.collection, splices)
: calcSplices(this.collection, 0, this.collection.length, oldCollection, 0, oldCollection.length);
this.notify(this, finalSplices);
}

@@ -115,3 +108,3 @@ }

if (o !== void 0) {
o.notify();
o.flush();
oldArray = this.slice();

@@ -138,3 +131,3 @@ }

if (o !== void 0) {
o.notify();
o.flush();
oldArray = this.slice();

@@ -141,0 +134,0 @@ }

@@ -1,2 +0,7 @@

import { Subscriber } from "./subscriber-collection";
/**
* Implemented by objects that are interested in change notifications.
*/
export interface Subscriber {
handleChange(source: any, args: any): void;
}
export interface Notifier {

@@ -7,2 +12,18 @@ notify(source: any, args: any): void;

}
/**
* Efficiently keeps track of subscribers interested in change notifications.
*
* @remarks
* This collection is optimized for the most common scenario of 1 or 2 subscribers.
* With this in mind, it can store a subscriber in an internal field, allowing it to avoid Array#push operations.
* If the collection ever exceeds two subscribers, it upgrade to an array.
*/
export declare class SubscriberCollection implements Notifier {
private sub1;
private sub2;
private spillover;
subscribe(subscriber: Subscriber): void;
unsubscribe(subscriber: Subscriber): void;
notify(source: any, args: any): void;
}
export declare class PropertyChangeNotifier implements Notifier {

@@ -9,0 +30,0 @@ private subscribers;

@@ -1,2 +0,75 @@

import { SubscriberCollection } from "./subscriber-collection";
function spilloverSubscribe(subscriber) {
const spillover = this.spillover;
const index = spillover.indexOf(subscriber);
if (index === -1) {
spillover.push(subscriber);
}
}
function spilloverUnsubscribe(subscriber) {
const spillover = this.spillover;
const index = spillover.indexOf(subscriber);
if (index !== -1) {
spillover.splice(index, 1);
}
}
function spilloverNotifySubscribers(source, args) {
const spillover = this.spillover;
for (let i = 0, ii = spillover.length; i < ii; ++i) {
spillover[i].handleChange(source, args);
}
}
/**
* Efficiently keeps track of subscribers interested in change notifications.
*
* @remarks
* This collection is optimized for the most common scenario of 1 or 2 subscribers.
* With this in mind, it can store a subscriber in an internal field, allowing it to avoid Array#push operations.
* If the collection ever exceeds two subscribers, it upgrade to an array.
*/
export class SubscriberCollection {
constructor() {
this.sub1 = void 0;
this.sub2 = void 0;
this.spillover = void 0;
}
subscribe(subscriber) {
if (this.sub1 === subscriber || this.sub2 === subscriber) {
return;
}
if (this.sub1 === void 0) {
this.sub1 = subscriber;
return;
}
if (this.sub2 === void 0) {
this.sub2 = subscriber;
return;
}
this.spillover = [this.sub1, this.sub2];
this.subscribe = spilloverSubscribe;
this.unsubscribe = spilloverUnsubscribe;
this.notify = spilloverNotifySubscribers;
this.sub1 = void 0;
this.sub2 = void 0;
}
unsubscribe(subscriber) {
if (this.sub1 === subscriber) {
this.sub1 = void 0;
return;
}
if (this.sub2 === subscriber) {
this.sub2 = void 0;
return;
}
}
notify(source, args) {
const sub1 = this.sub1;
const sub2 = this.sub2;
if (sub1 !== void 0) {
sub1.handleChange(source, args);
}
if (sub2 !== void 0) {
sub2.handleChange(source, args);
}
}
}
export class PropertyChangeNotifier {

@@ -9,9 +82,11 @@ constructor() {

if (subscribers !== void 0) {
subscribers.notifySubscribers(source, propertyName);
subscribers.notify(source, propertyName);
}
}
subscribe(subscriber, propertyName) {
const subscribers = this.subscribers[propertyName] ||
(this.subscribers[propertyName] = new SubscriberCollection());
subscribers.addSubscriber(subscriber);
let subscribers = this.subscribers[propertyName];
if (subscribers === void 0) {
this.subscribers[propertyName] = subscribers = new SubscriberCollection();
}
subscribers.subscribe(subscriber);
}

@@ -23,4 +98,4 @@ unsubscribe(subscriber, propertyName) {

}
subscribers.removeSubscriber(subscriber);
subscribers.unsubscribe(subscriber);
}
}
import { Notifier } from "./notifier";
export interface Accessor {
name: string;
getValue(source: any): any;
setValue(source: any, value: any): void;
}
export declare const Observable: {

@@ -7,4 +12,4 @@ createArrayObserver(array: any[]): Notifier;

notify(source: unknown, args: any): void;
define(target: {}, propertyName: string): void;
getObservedProperties(target: {}): string[];
defineProperty(target: {}, nameOrAccessor: string | Accessor): void;
getAccessors(target: {}): Accessor[];
};

@@ -11,0 +16,0 @@ export declare function observable($target: {}, $prop: string): void;

@@ -1,6 +0,32 @@

import { emptyArray } from "../interfaces";
import { DOM } from "../dom";
import { PropertyChangeNotifier } from "./notifier";
const notifierLookup = new WeakMap();
const accessorLookup = new WeakMap();
let watcher = void 0;
class DefaultObservableAccessor {
constructor(name, target) {
this.name = name;
this.field = `_${name}`;
this.callback = `${name}Changed`;
this.hasCallback = this.callback in target;
}
getValue(source) {
if (watcher !== void 0) {
watcher.observe(source, this.name);
}
return source[this.field];
}
setValue(source, newValue) {
const field = this.field;
const oldValue = source[field];
if (oldValue !== newValue) {
source[field] = newValue;
if (this.hasCallback) {
source[this.callback](oldValue, newValue);
}
/* eslint-disable-next-line @typescript-eslint/no-use-before-define */
getNotifier(source).notify(source, this.name);
}
}
}
export const Observable = {

@@ -32,32 +58,34 @@ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */

},
define(target, propertyName) {
const fieldName = `_${propertyName}`;
const callbackName = `${propertyName}Changed`;
const hasCallback = callbackName in target;
const observedProperties = target.observedProperties ||
(target.observedProperties = []);
observedProperties.push(propertyName);
Reflect.defineProperty(target, propertyName, {
defineProperty(target, nameOrAccessor) {
if (typeof nameOrAccessor === "string") {
nameOrAccessor = new DefaultObservableAccessor(nameOrAccessor, target);
}
this.getAccessors(target).push(nameOrAccessor);
Reflect.defineProperty(target, nameOrAccessor.name, {
enumerable: true,
get: function () {
if (watcher !== void 0) {
watcher.observe(this, propertyName);
}
return this[fieldName];
return nameOrAccessor.getValue(this);
},
set: function (newValue) {
const oldValue = this[fieldName];
if (oldValue !== newValue) {
this[fieldName] = newValue;
if (hasCallback) {
this[callbackName](oldValue, newValue);
}
/* eslint-disable-next-line @typescript-eslint/no-use-before-define */
getNotifier(this).notify(this, propertyName);
}
nameOrAccessor.setValue(this, newValue);
},
});
},
getObservedProperties(target) {
return target.observedProperties || emptyArray;
getAccessors(target) {
let accessors = accessorLookup.get(target);
if (accessors === void 0) {
let currentTarget = Reflect.getPrototypeOf(target);
while (accessors === void 0 && currentTarget !== null) {
accessors = accessorLookup.get(currentTarget);
currentTarget = Reflect.getPrototypeOf(currentTarget);
}
if (accessors === void 0) {
accessors = [];
}
else {
accessors = accessors.slice(0);
}
accessorLookup.set(target, accessors);
}
return accessors;
},

@@ -68,3 +96,3 @@ };

export function observable($target, $prop) {
Observable.define($target, $prop);
Observable.defineProperty($target, $prop);
}

@@ -103,4 +131,4 @@ let currentEvent = null;

}
Observable.define(ExecutionContext.prototype, "index");
Observable.define(ExecutionContext.prototype, "length");
Observable.defineProperty(ExecutionContext.prototype, "index");
Observable.defineProperty(ExecutionContext.prototype, "length");
export const defaultExecutionContext = new ExecutionContext();

@@ -107,0 +135,0 @@ export class ObservableExpression {

@@ -8,3 +8,3 @@ import { ElementView, HTMLView, SyntheticView } from "./view";

}
export interface SyntheticViewTemplate<TScope = any, TParent = any> {
export interface SyntheticViewTemplate<TSource = any, TParent = any> {
create(): SyntheticView;

@@ -18,3 +18,3 @@ }

}
export declare class ViewTemplate<TScope = any, TParent = any> extends Directive implements ElementViewTemplate, SyntheticViewTemplate {
export declare class ViewTemplate<TSource = any, TParent = any> extends Directive implements ElementViewTemplate, SyntheticViewTemplate {
private html;

@@ -31,9 +31,10 @@ private directives;

create(host?: Element): HTMLView;
render(source: TSource, host: HTMLElement | string): HTMLView;
createBehavior(target: any): HTMLTemplateBehavior;
}
export declare const lastAttributeNameRegex: RegExp;
export interface CaptureType<TScope> {
export interface CaptureType<TSource> {
}
declare type TemplateValue<TScope, TParent = any> = Expression<TScope, any, TParent> | string | number | Directive | CaptureType<TScope>;
export declare function html<TScope = any, TParent = any>(strings: TemplateStringsArray, ...values: TemplateValue<TScope, TParent>[]): ViewTemplate<TScope, TParent>;
export declare function html<TSource = any, TParent = any>(strings: TemplateStringsArray, ...values: TemplateValue<TSource, TParent>[]): ViewTemplate<TSource, TParent>;
export {};

@@ -6,2 +6,3 @@ import { compileTemplate } from "./template-compiler";

import { BindingDirective } from "./directives/binding";
import { defaultExecutionContext, } from "./observation/observable";
export class HTMLTemplateBehavior {

@@ -86,2 +87,11 @@ constructor(template, location) {

}
render(source, host) {
if (typeof host === "string") {
host = document.getElementById(host);
}
const view = this.create(host);
view.bind(source, defaultExecutionContext);
view.appendTo(host);
return view;
}
createBehavior(target) {

@@ -88,0 +98,0 @@ return new HTMLTemplateBehavior(this, target);

@@ -5,3 +5,3 @@ {

"sideEffects": false,
"version": "0.7.0",
"version": "0.8.0",
"author": {

@@ -34,3 +34,3 @@ "name": "Microsoft",

},
"gitHead": "d23405bdc1b1bd3b2c278443d22a469b1283c598"
"gitHead": "526e002ac76d999f6ab3acea249e63bbc4d79173"
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc