@microsoft/fast-element 2.0.0-beta.20 → 2.0.0-beta.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.json +54 -0
  2. package/CHANGELOG.md +21 -1
  3. package/dist/dts/binding/binding.d.ts +49 -0
  4. package/dist/dts/binding/normalize.d.ts +9 -0
  5. package/dist/dts/binding/one-time.d.ts +11 -0
  6. package/dist/dts/binding/one-way.d.ts +20 -0
  7. package/dist/dts/{templating/binding-signal.d.ts → binding/signal.d.ts} +1 -1
  8. package/dist/dts/{templating/binding-two-way.d.ts → binding/two-way.d.ts} +3 -4
  9. package/dist/dts/components/element-controller.d.ts +20 -5
  10. package/dist/dts/context.d.ts +26 -13
  11. package/dist/dts/dom-policy.d.ts +15 -0
  12. package/dist/dts/index.d.ts +6 -2
  13. package/dist/dts/interfaces.d.ts +6 -5
  14. package/dist/dts/metadata.d.ts +6 -5
  15. package/dist/dts/pending-task.d.ts +19 -7
  16. package/dist/dts/platform.d.ts +10 -2
  17. package/dist/dts/styles/css-binding-directive.d.ts +60 -0
  18. package/dist/dts/styles/css.d.ts +9 -2
  19. package/dist/dts/styles/host.d.ts +2 -5
  20. package/dist/dts/templating/{binding.d.ts → html-binding-directive.d.ts} +3 -34
  21. package/dist/dts/templating/html-directive.d.ts +3 -35
  22. package/dist/dts/templating/render.d.ts +19 -5
  23. package/dist/dts/templating/repeat.d.ts +3 -2
  24. package/dist/dts/templating/template.d.ts +2 -6
  25. package/dist/dts/templating/view.d.ts +16 -6
  26. package/dist/dts/testing/fakes.d.ts +2 -1
  27. package/dist/dts/utilities.d.ts +3 -2
  28. package/dist/esm/binding/binding.js +18 -0
  29. package/dist/esm/binding/normalize.js +17 -0
  30. package/dist/esm/binding/one-time.js +21 -0
  31. package/dist/esm/binding/one-way.js +30 -0
  32. package/dist/esm/{templating/binding-signal.js → binding/signal.js} +5 -8
  33. package/dist/esm/{templating/binding-two-way.js → binding/two-way.js} +11 -15
  34. package/dist/esm/components/element-controller.js +33 -9
  35. package/dist/esm/context.js +24 -3
  36. package/dist/esm/debug.js +1 -0
  37. package/dist/esm/di/di.js +5 -5
  38. package/dist/esm/dom-policy.js +9 -1
  39. package/dist/esm/index.js +8 -2
  40. package/dist/esm/interfaces.js +3 -3
  41. package/dist/esm/metadata.js +11 -8
  42. package/dist/esm/observation/observable.js +3 -6
  43. package/dist/esm/pending-task.js +13 -1
  44. package/dist/esm/platform.js +10 -1
  45. package/dist/esm/styles/css-binding-directive.js +76 -0
  46. package/dist/esm/styles/css.js +14 -2
  47. package/dist/esm/templating/compiler.js +2 -1
  48. package/dist/esm/templating/{binding.js → html-binding-directive.js} +3 -70
  49. package/dist/esm/templating/html-directive.js +2 -25
  50. package/dist/esm/templating/render.js +25 -12
  51. package/dist/esm/templating/repeat.js +3 -3
  52. package/dist/esm/templating/template.js +9 -10
  53. package/dist/esm/templating/view.js +2 -6
  54. package/dist/esm/testing/fakes.js +1 -1
  55. package/dist/esm/utilities.js +3 -2
  56. package/dist/fast-element.api.json +1827 -663
  57. package/dist/fast-element.d.ts +167 -43
  58. package/dist/fast-element.debug.js +227 -120
  59. package/dist/fast-element.debug.min.js +1 -1
  60. package/dist/fast-element.js +226 -120
  61. package/dist/fast-element.min.js +1 -1
  62. package/dist/fast-element.untrimmed.d.ts +134 -82
  63. package/docs/api-report.md +54 -57
  64. package/package.json +5 -5
@@ -1,17 +1,32 @@
1
1
  import "./interfaces.js";
2
2
  import { Metadata } from "./metadata.js";
3
3
  import { FAST } from "./platform.js";
4
+ const contextsByName = new Map();
4
5
  const contextEventType = "context-request";
5
6
  let requestStrategy;
6
7
  /**
7
8
  * Enables using the {@link https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md | W3C Community Context protocol.}
8
- * @beta
9
+ * @public
9
10
  */
10
11
  export const Context = Object.freeze({
11
12
  /**
12
13
  * The event type used for W3C Context Protocol requests.
13
14
  */
14
15
  eventType: contextEventType,
16
+ /**
17
+ * Returns a FASTContext object from the global context registry matching the given name if found.
18
+ * Otherwise, returns a new FASTContext with this name.
19
+ * @param name - The name of the FASTContext to get or create.
20
+ * @returns A FASTContext object.
21
+ */
22
+ for(name) {
23
+ let c = contextsByName.get(name);
24
+ if (c === void 0) {
25
+ c = Context.create(name);
26
+ contextsByName.set(name, c);
27
+ }
28
+ return c;
29
+ },
15
30
  /**
16
31
  * Creates a W3C Community Protocol-based Context object to use in requesting/providing
17
32
  * context through the DOM.
@@ -94,8 +109,14 @@ export const Context = Object.freeze({
94
109
  dispatch(target, context, callback, multiple = false) {
95
110
  target.dispatchEvent(new ContextEvent(context, callback, multiple));
96
111
  },
112
+ /**
113
+ * Enables an event target to provide a context value.
114
+ * @param target The target to provide the context value for.
115
+ * @param context The context to provide the value for.
116
+ * @param value The value to provide for the context.
117
+ */
97
118
  provide(target, context, value) {
98
- this.handle(target, (event) => {
119
+ Context.handle(target, (event) => {
99
120
  event.stopImmediatePropagation();
100
121
  event.callback(value);
101
122
  }, context);
@@ -132,7 +153,7 @@ export const Context = Object.freeze({
132
153
  * initialValue if the context isn't handled.
133
154
  */
134
155
  defineProperty(target, propertyName, context) {
135
- const field = `$di_${propertyName}`;
156
+ const field = Symbol.for(`fast:di:${propertyName}`);
136
157
  Reflect.defineProperty(target, propertyName, {
137
158
  get: function () {
138
159
  var _a;
package/dist/esm/debug.js CHANGED
@@ -17,6 +17,7 @@ const debugMessages = {
17
17
  [1206 /* directCallToHTMLTagNotAllowed */]: "Calling html`` as a normal function invalidates the security guarantees provided by FAST.",
18
18
  [1207 /* onlySetTemplatePolicyOnce */]: "The DOM Policy for an HTML template can only be set once.",
19
19
  [1208 /* cannotSetTemplatePolicyAfterCompilation */]: "The DOM Policy cannot be set after a template is compiled.",
20
+ [1209 /* blockedByDOMPolicy */]: "'${aspectName}' on '${tagName}' is blocked by the current DOMPolicy.",
20
21
  [1401 /* missingElementDefinition */]: "Missing FASTElement definition.",
21
22
  [1501 /* noRegistrationForContext */]: "No registration for Context/Interface '${name}'.",
22
23
  [1502 /* noFactoryForResolver */]: "Dependency injection resolver for '${key}' returned a null factory.",
package/dist/esm/di/di.js CHANGED
@@ -371,16 +371,16 @@ export const DI = Object.freeze({
371
371
  * The respectConnection option is only applicable to elements that descend from FASTElement.
372
372
  */
373
373
  defineProperty(target, propertyName, key, respectConnection = false) {
374
- const diPropertyKey = `$di_${propertyName}`;
374
+ const field = Symbol.for(`fast:di:${propertyName}`);
375
375
  Reflect.defineProperty(target, propertyName, {
376
376
  get: function () {
377
- let value = this[diPropertyKey];
377
+ let value = this[field];
378
378
  if (value === void 0) {
379
379
  const container = this instanceof Node
380
380
  ? DI.findResponsibleContainer(this)
381
381
  : DI.getOrCreateDOMContainer();
382
382
  value = container.get(key);
383
- this[diPropertyKey] = value;
383
+ this[field] = value;
384
384
  if (respectConnection) {
385
385
  const notifier = this.$fastController;
386
386
  if (!notifier) {
@@ -389,9 +389,9 @@ export const DI = Object.freeze({
389
389
  const handleChange = () => {
390
390
  const newContainer = DI.findResponsibleContainer(this);
391
391
  const newValue = newContainer.get(key);
392
- const oldValue = this[diPropertyKey];
392
+ const oldValue = this[field];
393
393
  if (newValue !== oldValue) {
394
- this[diPropertyKey] = value;
394
+ this[field] = value;
395
395
  notifier.notify(propertyName);
396
396
  }
397
397
  };
@@ -1,5 +1,6 @@
1
1
  import { DOMAspect } from "./dom.js";
2
2
  import { isString } from "./interfaces.js";
3
+ import { FAST } from "./platform.js";
3
4
  function safeURL(tagName, aspect, aspectName, sink) {
4
5
  return (target, name, value, ...rest) => {
5
6
  if (isString(value)) {
@@ -9,7 +10,10 @@ function safeURL(tagName, aspect, aspectName, sink) {
9
10
  };
10
11
  }
11
12
  function block(tagName, aspect, aspectName, sink) {
12
- throw new Error(`${aspectName} on ${tagName !== null && tagName !== void 0 ? tagName : "text"} is blocked by the current DOMPolicy.`);
13
+ throw FAST.error(1209 /* Message.blockedByDOMPolicy */, {
14
+ aspectName,
15
+ tagName: tagName !== null && tagName !== void 0 ? tagName : "text",
16
+ });
13
17
  }
14
18
  const defaultDOMElementGuards = {
15
19
  a: {
@@ -303,6 +307,10 @@ function tryGuard(aspectGuards, tagName, aspect, aspectName, sink) {
303
307
  }
304
308
  }
305
309
  }
310
+ /**
311
+ * A helper for creating DOM policies.
312
+ * @public
313
+ */
306
314
  const DOMPolicy = Object.freeze({
307
315
  /**
308
316
  * Creates a new DOM Policy object.
package/dist/esm/index.js CHANGED
@@ -1,21 +1,27 @@
1
- export * from "./platform.js";
1
+ export { FAST, emptyArray } from "./platform.js";
2
+ // DOM
2
3
  export * from "./dom.js";
3
4
  // Observation
4
5
  export * from "./observation/observable.js";
5
6
  export * from "./observation/notifier.js";
6
7
  export * from "./observation/arrays.js";
7
8
  export * from "./observation/update-queue.js";
9
+ // Binding
10
+ export * from "./binding/binding.js";
11
+ export * from "./binding/one-way.js";
12
+ export * from "./binding/one-time.js";
8
13
  // Styles
9
14
  export * from "./styles/element-styles.js";
10
15
  export * from "./styles/css.js";
11
16
  export * from "./styles/css-directive.js";
12
17
  export * from "./styles/host.js";
13
18
  export * from "./styles/style-strategy.js";
19
+ export * from "./styles/css-binding-directive.js";
14
20
  // Templating
15
21
  export * from "./templating/template.js";
16
22
  export * from "./templating/compiler.js";
17
23
  export { Markup, Parser } from "./templating/markup.js";
18
- export * from "./templating/binding.js";
24
+ export * from "./templating/html-binding-directive.js";
19
25
  export * from "./templating/html-directive.js";
20
26
  export * from "./templating/ref.js";
21
27
  export * from "./templating/when.js";
@@ -45,16 +45,16 @@ switch (kernelMode) {
45
45
  export { KernelServiceId };
46
46
  /**
47
47
  * Determines whether or not an object is a function.
48
- * @internal
48
+ * @public
49
49
  */
50
50
  export const isFunction = (object) => typeof object === "function";
51
51
  /**
52
52
  * Determines whether or not an object is a string.
53
- * @internal
53
+ * @public
54
54
  */
55
55
  export const isString = (object) => typeof object === "string";
56
56
  /**
57
57
  * A function which does nothing.
58
- * @internal
58
+ * @public
59
59
  */
60
60
  export const noop = () => void 0;
@@ -22,8 +22,11 @@ if (!("metadata" in Reflect)) {
22
22
  return void 0;
23
23
  };
24
24
  }
25
+ const annotationParamTypesKey = "annotation:paramtypes";
26
+ const designParamTypesKey = "design:paramtypes";
25
27
  /**
26
28
  * Provides basic metadata capabilities used by Context and Dependency Injection.
29
+ * @public
27
30
  */
28
31
  export const Metadata = Object.freeze({
29
32
  /**
@@ -31,29 +34,29 @@ export const Metadata = Object.freeze({
31
34
  * @param Type - The type to get the metadata for.
32
35
  * @returns The metadata array or a frozen empty array if no metadata is found.
33
36
  */
34
- getDesignParamTypes: Type => {
37
+ getDesignParamTypes: (Type) => {
35
38
  var _a;
36
- return (_a = Reflect.getOwnMetadata("design:paramtypes", Type)) !== null && _a !== void 0 ? _a : emptyArray;
39
+ return ((_a = Reflect.getOwnMetadata(designParamTypesKey, Type)) !== null && _a !== void 0 ? _a : emptyArray);
37
40
  },
38
41
  /**
39
42
  * Gets the "annotation:paramtypes" metadata for the specified type.
40
43
  * @param Type - The type to get the metadata for.
41
44
  * @returns The metadata array or a frozen empty array if no metadata is found.
42
45
  */
43
- getAnnotationParamTypes: Type => {
46
+ getAnnotationParamTypes: (Type) => {
44
47
  var _a;
45
- return (_a = Reflect.getOwnMetadata("annotation:paramtypes", Type)) !== null && _a !== void 0 ? _a : emptyArray;
48
+ return ((_a = Reflect.getOwnMetadata(annotationParamTypesKey, Type)) !== null && _a !== void 0 ? _a : emptyArray);
46
49
  },
47
50
  /**
48
- *
49
- * @param Type - Gets the "annotation:paramtypes" metadata for the specified type. If none is found,
51
+ * Gets the "annotation:paramtypes" metadata for the specified type. If none is found,
50
52
  * an empty, mutable metadata array is created and added.
51
- * @returns The metadata array.
53
+ * @param Type - The type to get or create the metadata for.
54
+ * @returns A mutable metadata array.
52
55
  */
53
56
  getOrCreateAnnotationParamTypes(Type) {
54
57
  let types = this.getAnnotationParamTypes(Type);
55
58
  if (types === emptyArray) {
56
- Reflect.defineMetadata("annotation:paramtypes", (types = []), Type);
59
+ Reflect.defineMetadata(annotationParamTypesKey, (types = []), Type);
57
60
  }
58
61
  return types;
59
62
  },
@@ -1,5 +1,5 @@
1
- import { isFunction, isString, KernelServiceId, noop, } from "../interfaces.js";
2
- import { createMetadataLocator, FAST } from "../platform.js";
1
+ import { isFunction, isString, KernelServiceId, } from "../interfaces.js";
2
+ import { createMetadataLocator, FAST, makeSerializationNoop } from "../platform.js";
3
3
  import { Updates } from "./update-queue.js";
4
4
  import { PropertyChangeNotifier, SubscriberSet } from "./notifier.js";
5
5
  /**
@@ -79,10 +79,6 @@ export const Observable = FAST.getById(KernelServiceId.observable, () => {
79
79
  this.propertyName = void 0;
80
80
  this.notifier = void 0;
81
81
  this.next = void 0;
82
- /**
83
- * Opts out of JSON stringification.
84
- */
85
- this.toJSON = noop;
86
82
  }
87
83
  setMode(isAsync) {
88
84
  this.isAsync = this.needsQueue = isAsync;
@@ -184,6 +180,7 @@ export const Observable = FAST.getById(KernelServiceId.observable, () => {
184
180
  }
185
181
  }
186
182
  }
183
+ makeSerializationNoop(ExpressionNotifierImplementation);
187
184
  return Object.freeze({
188
185
  /**
189
186
  * @internal
@@ -1,16 +1,28 @@
1
1
  /**
2
2
  * A concrete implementation of {@link PendingTask}
3
- * @beta
3
+ * @public
4
4
  */
5
5
  export class PendingTaskEvent extends Event {
6
+ /**
7
+ * Creates an instance of PendingTaskEvent.
8
+ * @param complete - A promise that resolves when the pending task is complete.
9
+ */
6
10
  constructor(complete) {
7
11
  super(PendingTaskEvent.type, { bubbles: true, composed: true });
8
12
  this.complete = complete;
9
13
  }
14
+ /**
15
+ * Determines whether a value is a PendingTaskEvent.
16
+ * @param value - The value to check.
17
+ * @returns True if the value is a PendingTaskEvent; false otherwise.
18
+ */
10
19
  static isPendingTask(value) {
11
20
  var _a;
12
21
  return (value.type === PendingTaskEvent.type &&
13
22
  typeof ((_a = value.complete) === null || _a === void 0 ? void 0 : _a.then) === "function");
14
23
  }
15
24
  }
25
+ /**
26
+ * The type of the pending task event.
27
+ */
16
28
  PendingTaskEvent.type = "pending-task";
@@ -1,3 +1,4 @@
1
+ import { noop } from "./interfaces.js";
1
2
  import "./polyfills.js";
2
3
  // ensure FAST global - duplicated debug.ts
3
4
  const propConfig = {
@@ -10,7 +11,7 @@ if (globalThis.FAST === void 0) {
10
11
  }
11
12
  /**
12
13
  * The FAST global.
13
- * @internal
14
+ * @public
14
15
  */
15
16
  export const FAST = globalThis.FAST;
16
17
  if (FAST.getById === void 0) {
@@ -86,3 +87,11 @@ export function createMetadataLocator() {
86
87
  return metadata;
87
88
  };
88
89
  }
90
+ /**
91
+ * Makes a type noop for JSON serialization.
92
+ * @param type - The type to make noop for JSON serialization.
93
+ * @internal
94
+ */
95
+ export function makeSerializationNoop(type) {
96
+ type.prototype.toJSON = noop;
97
+ }
@@ -0,0 +1,76 @@
1
+ import { CSSDirective } from "./css-directive.js";
2
+ function handleChange(directive, controller, observer) {
3
+ controller.source.style.setProperty(directive.targetAspect, observer.bind(controller));
4
+ }
5
+ /**
6
+ * Enables bindings in CSS.
7
+ *
8
+ * @public
9
+ */
10
+ export class CSSBindingDirective {
11
+ /**
12
+ * Creates an instance of CSSBindingDirective.
13
+ * @param dataBinding - The binding to use in CSS.
14
+ * @param targetAspect - The CSS property to target.
15
+ */
16
+ constructor(dataBinding, targetAspect) {
17
+ this.dataBinding = dataBinding;
18
+ this.targetAspect = targetAspect;
19
+ }
20
+ /**
21
+ * Creates a CSS fragment to interpolate into the CSS document.
22
+ * @returns - the string to interpolate into CSS
23
+ */
24
+ createCSS(add) {
25
+ add(this);
26
+ return `var(${this.targetAspect})`;
27
+ }
28
+ /**
29
+ * Executed when this behavior is attached to a controller.
30
+ * @param controller - Controls the behavior lifecycle.
31
+ */
32
+ addedCallback(controller) {
33
+ var _a;
34
+ const element = controller.source;
35
+ if (!element.$cssBindings) {
36
+ element.$cssBindings = new Map();
37
+ const setAttribute = element.setAttribute;
38
+ element.setAttribute = (attr, value) => {
39
+ setAttribute.call(element, attr, value);
40
+ if (attr === "style") {
41
+ element.$cssBindings.forEach((v, k) => handleChange(k, v.controller, v.observer));
42
+ }
43
+ };
44
+ }
45
+ const observer = (_a = controller[this.targetAspect]) !== null && _a !== void 0 ? _a : (controller[this.targetAspect] = this.dataBinding.createObserver(this, this));
46
+ observer.controller = controller;
47
+ controller.source.$cssBindings.set(this, { controller, observer });
48
+ }
49
+ /**
50
+ * Executed when this behavior's host is connected.
51
+ * @param controller - Controls the behavior lifecycle.
52
+ */
53
+ connectedCallback(controller) {
54
+ handleChange(this, controller, controller[this.targetAspect]);
55
+ }
56
+ /**
57
+ * Executed when this behavior is detached from a controller.
58
+ * @param controller - Controls the behavior lifecycle.
59
+ */
60
+ removedCallback(controller) {
61
+ if (controller.source.$cssBindings) {
62
+ controller.source.$cssBindings.delete(this);
63
+ }
64
+ }
65
+ /**
66
+ * Called when a subject this instance has subscribed to changes.
67
+ * @param subject - The subject of the change.
68
+ * @param args - The event args detailing the change that occurred.
69
+ *
70
+ * @internal
71
+ */
72
+ handleChange(_, observer) {
73
+ handleChange(this, observer.controller, observer);
74
+ }
75
+ }
76
+ CSSDirective.define(CSSBindingDirective);
@@ -1,6 +1,12 @@
1
- import { isString } from "../interfaces.js";
1
+ import { isFunction, isString } from "../interfaces.js";
2
+ import { Binding } from "../binding/binding.js";
3
+ import { oneWay } from "../binding/one-way.js";
2
4
  import { CSSDirective } from "./css-directive.js";
3
5
  import { ElementStyles } from "./element-styles.js";
6
+ import { CSSBindingDirective } from "./css-binding-directive.js";
7
+ const marker = `${Math.random().toString(36).substring(2, 8)}`;
8
+ let varId = 0;
9
+ const nextCSSVariable = () => `--v${marker}${++varId}`;
4
10
  function collectStyles(strings, values) {
5
11
  const styles = [];
6
12
  let cssString = "";
@@ -11,7 +17,13 @@ function collectStyles(strings, values) {
11
17
  for (let i = 0, ii = strings.length - 1; i < ii; ++i) {
12
18
  cssString += strings[i];
13
19
  let value = values[i];
14
- if (CSSDirective.getForInstance(value) !== void 0) {
20
+ if (isFunction(value)) {
21
+ value = new CSSBindingDirective(oneWay(value), nextCSSVariable()).createCSS(add);
22
+ }
23
+ else if (value instanceof Binding) {
24
+ value = new CSSBindingDirective(value, nextCSSVariable()).createCSS(add);
25
+ }
26
+ else if (CSSDirective.getForInstance(value) !== void 0) {
15
27
  value = value.createCSS(add);
16
28
  }
17
29
  if (value instanceof ElementStyles || value instanceof CSSStyleSheet) {
@@ -1,8 +1,9 @@
1
1
  import { isFunction, isString } from "../interfaces.js";
2
2
  import { FAST } from "../platform.js";
3
3
  import { DOM } from "../dom.js";
4
+ import { oneTime } from "../binding/one-time.js";
4
5
  import { nextId, Parser } from "./markup.js";
5
- import { HTMLBindingDirective, oneTime } from "./binding.js";
6
+ import { HTMLBindingDirective } from "./html-binding-directive.js";
6
7
  import { HTMLDirective, } from "./html-directive.js";
7
8
  import { HTMLView } from "./view.js";
8
9
  const targetIdFrom = (parentId, nodeIndex) => `${parentId}.${nodeIndex}`;
@@ -1,30 +1,9 @@
1
- import { isFunction, noop } from "../interfaces.js";
2
- import { ExecutionContext, Observable, } from "../observation/observable.js";
1
+ import "../interfaces.js";
2
+ import { ExecutionContext, } from "../observation/observable.js";
3
3
  import { FAST } from "../platform.js";
4
4
  import { DOM, DOMAspect } from "../dom.js";
5
- import { Binding, HTMLDirective, } from "./html-directive.js";
5
+ import { HTMLDirective, } from "./html-directive.js";
6
6
  import { Markup } from "./markup.js";
7
- class OnChangeBinding extends Binding {
8
- createObserver(_, subscriber) {
9
- return Observable.binding(this.evaluate, subscriber, this.isVolatile);
10
- }
11
- }
12
- class OneTimeBinding extends Binding {
13
- constructor() {
14
- super(...arguments);
15
- /**
16
- * Opts out of JSON stringification.
17
- * @internal
18
- */
19
- this.toJSON = noop;
20
- }
21
- createObserver() {
22
- return this;
23
- }
24
- bind(controller) {
25
- return this.evaluate(controller.source, controller.context);
26
- }
27
- }
28
7
  function updateContent(target, aspect, value, controller) {
29
8
  // If there's no actual value, then this equates to the
30
9
  // empty string for the purposes of content bindings.
@@ -213,49 +192,3 @@ export class HTMLBindingDirective {
213
192
  }
214
193
  }
215
194
  HTMLDirective.define(HTMLBindingDirective, { aspected: true });
216
- /**
217
- * Creates an standard binding.
218
- * @param expression - The binding to refresh when changed.
219
- * @param policy - The security policy to associate with th binding.
220
- * @param isVolatile - Indicates whether the binding is volatile or not.
221
- * @returns A binding configuration.
222
- * @public
223
- */
224
- export function bind(expression, policy, isVolatile = Observable.isVolatileBinding(expression)) {
225
- return new OnChangeBinding(expression, policy, isVolatile);
226
- }
227
- /**
228
- * Creates a one time binding
229
- * @param expression - The binding to refresh when signaled.
230
- * @param policy - The security policy to associate with th binding.
231
- * @returns A binding configuration.
232
- * @public
233
- */
234
- export function oneTime(expression, policy) {
235
- return new OneTimeBinding(expression, policy);
236
- }
237
- /**
238
- * Creates an event listener binding.
239
- * @param expression - The binding to invoke when the event is raised.
240
- * @param options - Event listener options.
241
- * @returns A binding configuration.
242
- * @public
243
- */
244
- export function listener(expression, options) {
245
- const config = new OnChangeBinding(expression);
246
- config.options = options;
247
- return config;
248
- }
249
- /**
250
- * Normalizes the input value into a binding.
251
- * @param value - The value to create the default binding for.
252
- * @returns A binding configuration for the provided value.
253
- * @public
254
- */
255
- export function normalizeBinding(value) {
256
- return isFunction(value)
257
- ? bind(value)
258
- : value instanceof Binding
259
- ? value
260
- : oneTime(() => value);
261
- }
@@ -1,6 +1,5 @@
1
1
  import { DOMAspect } from "../dom.js";
2
- import { noop } from "../interfaces.js";
3
- import { createTypeRegistry } from "../platform.js";
2
+ import { createTypeRegistry, makeSerializationNoop } from "../platform.js";
4
3
  import { Markup } from "./markup.js";
5
4
  const registry = createTypeRegistry();
6
5
  /**
@@ -76,24 +75,6 @@ export function htmlDirective(options) {
76
75
  HTMLDirective.define(type, options);
77
76
  };
78
77
  }
79
- /**
80
- * Captures a binding expression along with related information and capabilities.
81
- *
82
- * @public
83
- */
84
- export class Binding {
85
- /**
86
- * Creates a binding.
87
- * @param evaluate - Evaluates the binding.
88
- * @param policy - The security policy to associate with this binding.
89
- * @param isVolatile - Indicates whether the binding is volatile.
90
- */
91
- constructor(evaluate, policy, isVolatile = false) {
92
- this.evaluate = evaluate;
93
- this.policy = policy;
94
- this.isVolatile = isVolatile;
95
- }
96
- }
97
78
  /**
98
79
  * A base class used for attribute directives that don't need internal state.
99
80
  * @public
@@ -105,11 +86,6 @@ export class StatelessAttachedAttributeDirective {
105
86
  */
106
87
  constructor(options) {
107
88
  this.options = options;
108
- /**
109
- * Opts out of JSON stringification.
110
- * @internal
111
- */
112
- this.toJSON = noop;
113
89
  }
114
90
  /**
115
91
  * Creates a placeholder string based on the directive's index within the template.
@@ -128,3 +104,4 @@ export class StatelessAttachedAttributeDirective {
128
104
  return this;
129
105
  }
130
106
  }
107
+ makeSerializationNoop(StatelessAttachedAttributeDirective);
@@ -1,7 +1,10 @@
1
1
  import { FASTElementDefinition } from "../components/fast-definitions.js";
2
2
  import { isFunction, isString } from "../interfaces.js";
3
- import { bind, normalizeBinding, oneTime, } from "./binding.js";
4
- import { Binding, HTMLDirective, } from "./html-directive.js";
3
+ import { Binding } from "../binding/binding.js";
4
+ import { oneTime } from "../binding/one-time.js";
5
+ import { oneWay } from "../binding/one-way.js";
6
+ import { normalizeBinding } from "../binding/normalize.js";
7
+ import { HTMLDirective, } from "./html-directive.js";
5
8
  import { Markup } from "./markup.js";
6
9
  import { html, ViewTemplate, } from "./template.js";
7
10
  /**
@@ -19,8 +22,8 @@ export class RenderBehavior {
19
22
  this.controller = null;
20
23
  this.view = null;
21
24
  this.data = null;
22
- this.dataBindingObserver = directive.dataBinding.createObserver(directive, this);
23
- this.templateBindingObserver = directive.templateBinding.createObserver(directive, this);
25
+ this.dataBindingObserver = directive.dataBinding.createObserver(this, directive);
26
+ this.templateBindingObserver = directive.templateBinding.createObserver(this, directive);
24
27
  }
25
28
  /**
26
29
  * Bind this behavior.
@@ -141,12 +144,13 @@ function instructionToTemplate(def) {
141
144
  }
142
145
  return def.template;
143
146
  }
144
- function createElementTemplate(tagName, attributes, content, policy) {
147
+ function createElementTemplate(tagName, options) {
145
148
  const markup = [];
146
149
  const values = [];
150
+ const { attributes, directives, content, policy } = options !== null && options !== void 0 ? options : {};
151
+ markup.push(`<${tagName}`);
147
152
  if (attributes) {
148
153
  const attrNames = Object.getOwnPropertyNames(attributes);
149
- markup.push(`<${tagName}`);
150
154
  for (let i = 0, ii = attrNames.length; i < ii; ++i) {
151
155
  const name = attrNames[i];
152
156
  if (i === 0) {
@@ -157,11 +161,17 @@ function createElementTemplate(tagName, attributes, content, policy) {
157
161
  }
158
162
  values.push(attributes[name]);
159
163
  }
160
- markup.push(`">`);
164
+ markup.push(`"`);
161
165
  }
162
- else {
163
- markup.push(`<${tagName}>`);
166
+ if (directives) {
167
+ markup[markup.length - 1] += " ";
168
+ for (let i = 0, ii = directives.length; i < ii; ++i) {
169
+ const directive = directives[i];
170
+ markup.push(i > 0 ? "" : " ");
171
+ values.push(directive);
172
+ }
164
173
  }
174
+ markup[markup.length - 1] += ">";
165
175
  if (content && isFunction(content.create)) {
166
176
  values.push(content);
167
177
  markup.push(`</${tagName}>`);
@@ -173,7 +183,7 @@ function createElementTemplate(tagName, attributes, content, policy) {
173
183
  return ViewTemplate.create(markup, values, policy);
174
184
  }
175
185
  function create(options) {
176
- var _a, _b;
186
+ var _a;
177
187
  const name = (_a = options.name) !== null && _a !== void 0 ? _a : defaultViewName;
178
188
  let template;
179
189
  if (isElementRenderOptions(options)) {
@@ -187,7 +197,10 @@ function create(options) {
187
197
  throw new Error("Invalid element for model rendering.");
188
198
  }
189
199
  }
190
- template = createElementTemplate(tagName, (_b = options.attributes) !== null && _b !== void 0 ? _b : defaultAttributes, options.content, options.policy);
200
+ if (!options.attributes) {
201
+ options.attributes = defaultAttributes;
202
+ }
203
+ template = createElementTemplate(tagName, options);
191
204
  }
192
205
  else {
193
206
  template = options.template;
@@ -357,7 +370,7 @@ export function render(value, template) {
357
370
  });
358
371
  }
359
372
  else if (isFunction(template)) {
360
- templateBinding = bind((s, c) => {
373
+ templateBinding = oneWay((s, c) => {
361
374
  var _a;
362
375
  let result = template(s, c);
363
376
  if (isString(result)) {