@microsoft/fast-element 2.0.0-beta.5 → 2.0.0-beta.7

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 (80) hide show
  1. package/CHANGELOG.json +72 -0
  2. package/CHANGELOG.md +24 -1
  3. package/dist/dts/components/attributes.d.ts +10 -0
  4. package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +24 -25
  5. package/dist/dts/components/fast-definitions.d.ts +28 -3
  6. package/dist/dts/components/fast-element.d.ts +2 -2
  7. package/dist/dts/di/di.d.ts +41 -0
  8. package/dist/dts/index.d.ts +2 -2
  9. package/dist/dts/interfaces.d.ts +4 -0
  10. package/dist/dts/observation/observable.d.ts +86 -47
  11. package/dist/dts/pending-task.d.ts +20 -0
  12. package/dist/dts/platform.d.ts +6 -0
  13. package/dist/dts/state/exports.d.ts +3 -0
  14. package/dist/dts/state/reactive.d.ts +8 -0
  15. package/dist/dts/state/state.d.ts +141 -0
  16. package/dist/dts/state/visitor.d.ts +6 -0
  17. package/dist/dts/state/watch.d.ts +10 -0
  18. package/dist/dts/styles/css-directive.d.ts +2 -2
  19. package/dist/dts/styles/element-styles.d.ts +3 -3
  20. package/dist/dts/styles/host.d.ts +68 -0
  21. package/dist/dts/templating/binding-signal.d.ts +2 -2
  22. package/dist/dts/templating/binding-two-way.d.ts +11 -3
  23. package/dist/dts/templating/binding.d.ts +21 -119
  24. package/dist/dts/templating/children.d.ts +1 -1
  25. package/dist/dts/templating/html-directive.d.ts +69 -39
  26. package/dist/dts/templating/node-observation.d.ts +4 -5
  27. package/dist/dts/templating/ref.d.ts +5 -13
  28. package/dist/dts/templating/render.d.ts +15 -20
  29. package/dist/dts/templating/repeat.d.ts +11 -16
  30. package/dist/dts/templating/slotted.d.ts +1 -1
  31. package/dist/dts/templating/template.d.ts +4 -4
  32. package/dist/dts/templating/view.d.ts +68 -9
  33. package/dist/dts/templating/when.d.ts +1 -1
  34. package/dist/dts/testing/exports.d.ts +1 -0
  35. package/dist/dts/testing/fakes.d.ts +4 -0
  36. package/dist/dts/testing/fixture.d.ts +0 -6
  37. package/dist/dts/utilities.d.ts +0 -18
  38. package/dist/esm/components/attributes.js +13 -4
  39. package/dist/esm/components/{controller.js → element-controller.js} +95 -105
  40. package/dist/esm/components/fast-definitions.js +3 -1
  41. package/dist/esm/components/fast-element.js +4 -4
  42. package/dist/esm/di/di.js +87 -3
  43. package/dist/esm/index.js +2 -1
  44. package/dist/esm/interfaces.js +4 -0
  45. package/dist/esm/observation/observable.js +59 -126
  46. package/dist/esm/pending-task.js +16 -0
  47. package/dist/esm/platform.js +21 -0
  48. package/dist/esm/state/exports.js +3 -0
  49. package/dist/esm/state/reactive.js +34 -0
  50. package/dist/esm/state/state.js +148 -0
  51. package/dist/esm/state/visitor.js +28 -0
  52. package/dist/esm/state/watch.js +36 -0
  53. package/dist/esm/styles/css.js +4 -4
  54. package/dist/esm/{observation/behavior.js → styles/host.js} +0 -0
  55. package/dist/esm/templating/binding-signal.js +21 -17
  56. package/dist/esm/templating/binding-two-way.js +32 -27
  57. package/dist/esm/templating/binding.js +73 -177
  58. package/dist/esm/templating/html-directive.js +78 -7
  59. package/dist/esm/templating/node-observation.js +9 -8
  60. package/dist/esm/templating/ref.js +4 -12
  61. package/dist/esm/templating/render.js +30 -31
  62. package/dist/esm/templating/repeat.js +37 -38
  63. package/dist/esm/templating/template.js +3 -4
  64. package/dist/esm/templating/view.js +96 -24
  65. package/dist/esm/testing/exports.js +1 -0
  66. package/dist/esm/testing/fakes.js +76 -0
  67. package/dist/esm/testing/fixture.js +1 -3
  68. package/dist/esm/utilities.js +0 -95
  69. package/dist/fast-element.api.json +5720 -5385
  70. package/dist/fast-element.d.ts +510 -399
  71. package/dist/fast-element.debug.js +492 -509
  72. package/dist/fast-element.debug.min.js +1 -1
  73. package/dist/fast-element.js +492 -509
  74. package/dist/fast-element.min.js +1 -1
  75. package/dist/fast-element.untrimmed.d.ts +519 -405
  76. package/docs/api-report.md +197 -129
  77. package/package.json +8 -4
  78. package/dist/dts/hooks.d.ts +0 -20
  79. package/dist/dts/observation/behavior.d.ts +0 -19
  80. package/dist/esm/hooks.js +0 -32
@@ -10,31 +10,43 @@ let twoWaySettings = {
10
10
  return "change";
11
11
  },
12
12
  };
13
+ export const TwoWaySettings = Object.freeze({
14
+ /**
15
+ * Configures two-way binding.
16
+ * @param settings - The settings to use for the two-way binding system.
17
+ */
18
+ configure(settings) {
19
+ twoWaySettings = settings;
20
+ },
21
+ });
13
22
  class TwoWayObserver {
14
23
  constructor(directive, subscriber, dataBinding) {
15
24
  this.directive = directive;
16
25
  this.subscriber = subscriber;
17
26
  this.dataBinding = dataBinding;
27
+ this.isNotBound = true;
18
28
  this.notifier = Observable.binding(dataBinding.evaluate, this, dataBinding.isVolatile);
19
29
  }
20
- observe(source, context) {
30
+ bind(controller) {
21
31
  var _a;
22
32
  if (!this.changeEvent) {
23
33
  this.changeEvent =
24
34
  (_a = this.dataBinding.options.changeEvent) !== null && _a !== void 0 ? _a : twoWaySettings.determineChangeEvent(this.directive, this.target);
25
35
  }
26
- this.target.addEventListener(this.changeEvent, this);
27
- return this.notifier.observe(source, context);
36
+ if (this.isNotBound) {
37
+ this.target.addEventListener(this.changeEvent, this);
38
+ controller.onUnbind(this);
39
+ this.isNotBound = false;
40
+ }
41
+ return this.notifier.bind(controller);
28
42
  }
29
- dispose() {
30
- this.notifier.dispose();
43
+ unbind(controller) {
44
+ this.isNotBound = true;
31
45
  this.target.removeEventListener(this.changeEvent, this);
32
46
  }
33
- /** @internal */
34
47
  handleChange(subject, args) {
35
48
  this.subscriber.handleChange(this.dataBinding.evaluate, this);
36
49
  }
37
- /** @internal */
38
50
  handleEvent(event) {
39
51
  const directive = this.directive;
40
52
  const target = event.currentTarget;
@@ -63,36 +75,29 @@ class TwoWayObserver {
63
75
  }
64
76
  }
65
77
  class TwoWayBinding extends Binding {
66
- constructor(evaluate, isVolatile, options = defaultOptions) {
67
- super();
68
- this.evaluate = evaluate;
69
- this.isVolatile = isVolatile;
70
- this.options = options;
71
- if (!options.fromView) {
72
- options.fromView = defaultOptions.fromView;
73
- }
74
- }
75
78
  createObserver(directive, subscriber) {
76
79
  return new TwoWayObserver(directive, subscriber, this);
77
80
  }
78
- /**
79
- * Configures two-way binding.
80
- * @param settings - The settings to use for the two-way binding system.
81
- */
82
- static configure(settings) {
83
- twoWaySettings = settings;
84
- }
85
81
  }
86
82
  /**
87
83
  * Creates a default binding.
88
- * @param binding - The binding to refresh when changed.
84
+ * @param expression - The binding to refresh when changed.
85
+ * @param optionsOrChangeEvent - The binding options or the name of the change event to use.
89
86
  * @param isBindingVolatile - Indicates whether the binding is volatile or not.
90
- * @returns A binding configuration.
87
+ * @returns A binding.
91
88
  * @public
92
89
  */
93
- export function twoWay(binding, optionsOrChangeEvent, isBindingVolatile = Observable.isVolatileBinding(binding)) {
90
+ export function twoWay(expression, optionsOrChangeEvent, isBindingVolatile = Observable.isVolatileBinding(expression)) {
94
91
  if (isString(optionsOrChangeEvent)) {
95
92
  optionsOrChangeEvent = { changeEvent: optionsOrChangeEvent };
96
93
  }
97
- return new TwoWayBinding(binding, isBindingVolatile, optionsOrChangeEvent);
94
+ if (!optionsOrChangeEvent) {
95
+ optionsOrChangeEvent = defaultOptions;
96
+ }
97
+ else if (!optionsOrChangeEvent.fromView) {
98
+ optionsOrChangeEvent.fromView = defaultOptions.fromView;
99
+ }
100
+ const binding = new TwoWayBinding(expression, isBindingVolatile);
101
+ binding.options = optionsOrChangeEvent;
102
+ return binding;
98
103
  }
@@ -14,29 +14,19 @@ const createInnerHTMLBinding = globalThis.TrustedHTML
14
14
  }
15
15
  : (binding) => binding;
16
16
  class OnChangeBinding extends Binding {
17
- constructor(evaluate, isVolatile) {
18
- super();
19
- this.evaluate = evaluate;
20
- this.isVolatile = isVolatile;
21
- }
22
17
  createObserver(_, subscriber) {
23
18
  return Observable.binding(this.evaluate, subscriber, this.isVolatile);
24
19
  }
25
20
  }
26
21
  class OneTimeBinding extends Binding {
27
- constructor(evaluate) {
28
- super();
29
- this.evaluate = evaluate;
30
- }
31
22
  createObserver() {
32
23
  return this;
33
24
  }
34
- observe(source, context) {
35
- return this.evaluate(source, context);
25
+ bind(controller) {
26
+ return this.evaluate(controller.source, controller.context);
36
27
  }
37
- dispose() { }
38
28
  }
39
- function updateContentTarget(target, aspect, value, source, context) {
29
+ function updateContent(target, aspect, value, controller) {
40
30
  // If there's no actual value, then this equates to the
41
31
  // empty string for the purposes of content bindings.
42
32
  if (value === null || value === undefined) {
@@ -68,14 +58,14 @@ function updateContentTarget(target, aspect, value, source, context) {
68
58
  // and that there's actually no need to compose it.
69
59
  if (!view.isComposed) {
70
60
  view.isComposed = true;
71
- view.bind(source, context);
61
+ view.bind(controller.source);
72
62
  view.insertBefore(target);
73
63
  target.$fastView = view;
74
64
  target.$fastTemplate = value;
75
65
  }
76
66
  else if (view.needsBindOnly) {
77
67
  view.needsBindOnly = false;
78
- view.bind(source, context);
68
+ view.bind(controller.source);
79
69
  }
80
70
  }
81
71
  else {
@@ -95,10 +85,9 @@ function updateContentTarget(target, aspect, value, source, context) {
95
85
  target.textContent = value;
96
86
  }
97
87
  }
98
- function updateTokenListTarget(target, aspect, value) {
88
+ function updateTokenList(target, aspect, value) {
99
89
  var _a;
100
- const directive = this.directive;
101
- const lookup = `${directive.id}-t`;
90
+ const lookup = `${this.id}-t`;
102
91
  const state = (_a = target[lookup]) !== null && _a !== void 0 ? _a : (target[lookup] = { c: 0, v: Object.create(null) });
103
92
  const versions = state.v;
104
93
  let currentVersion = state.c;
@@ -128,154 +117,8 @@ function updateTokenListTarget(target, aspect, value) {
128
117
  }
129
118
  }
130
119
  }
131
- /**
132
- * A binding behavior for bindings that change.
133
- * @public
134
- */
135
- export class BindingBehavior {
136
- /**
137
- * Creates an instance of ChangeBinding.
138
- * @param directive - The directive that has the configuration for this behavior.
139
- * @param updateTarget - The function used to update the target with the latest value.
140
- */
141
- constructor(directive, updateTarget) {
142
- this.directive = directive;
143
- this.updateTarget = updateTarget;
144
- this.observerProperty = `${directive.id}-o`;
145
- }
146
- /**
147
- * Bind this behavior to the source.
148
- * @param source - The source to bind to.
149
- * @param context - The execution context that the binding is operating within.
150
- * @param targets - The targets that behaviors in a view can attach to.
151
- */
152
- bind(source, context, targets) {
153
- const directive = this.directive;
154
- const target = targets[directive.nodeId];
155
- const observer = this.getObserver(target);
156
- observer.target = target;
157
- observer.source = source;
158
- observer.context = context;
159
- this.updateTarget(target, directive.targetAspect, observer.observe(source, context), source, context);
160
- }
161
- /**
162
- * Unbinds this behavior from the source.
163
- * @param source - The source to unbind from.
164
- * @param context - The execution context that the binding is operating within.
165
- * @param targets - The targets that behaviors in a view can attach to.
166
- */
167
- unbind(source, context, targets) {
168
- const target = targets[this.directive.nodeId];
169
- const observer = this.getObserver(target);
170
- observer.dispose();
171
- observer.target = null;
172
- observer.source = null;
173
- observer.context = null;
174
- }
175
- /** @internal */
176
- handleChange(binding, observer) {
177
- const target = observer.target;
178
- const source = observer.source;
179
- const context = observer.context;
180
- this.updateTarget(target, this.directive.targetAspect, observer.observe(source, context), source, context);
181
- }
182
- /**
183
- * Returns the binding observer used to update the node.
184
- * @param target - The target node.
185
- * @returns A BindingObserver.
186
- */
187
- getObserver(target) {
188
- var _a;
189
- return ((_a = target[this.observerProperty]) !== null && _a !== void 0 ? _a : (target[this.observerProperty] = this.directive.dataBinding.createObserver(this.directive, this)));
190
- }
191
- /**
192
- * Creates a behavior.
193
- * @param targets - The targets available for behaviors to be attached to.
194
- */
195
- createBehavior(targets) {
196
- return this;
197
- }
198
- }
199
- /**
200
- * A special binding behavior that can bind node content.
201
- * @public
202
- */
203
- export class ContentBehavior extends BindingBehavior {
204
- /**
205
- * Unbinds this behavior from the source.
206
- * @param source - The source to unbind from.
207
- * @param context - The execution context that the binding is operating within.
208
- * @param targets - The targets that behaviors in a view can attach to.
209
- */
210
- unbind(source, context, targets) {
211
- super.unbind(source, context, targets);
212
- const target = targets[this.directive.nodeId];
213
- const view = target.$fastView;
214
- if (view !== void 0 && view.isComposed) {
215
- view.unbind();
216
- view.needsBindOnly = true;
217
- }
218
- }
219
- }
220
- /**
221
- * A binding behavior for handling events.
222
- * @public
223
- */
224
- export class EventBehavior {
225
- /**
226
- * Creates an instance of EventBinding.
227
- * @param directive - The directive that has the configuration for this behavior.
228
- */
229
- constructor(directive) {
230
- this.directive = directive;
231
- this.sourceProperty = `${directive.id}-s`;
232
- this.contextProperty = `${directive.id}-c`;
233
- }
234
- /**
235
- * Bind this behavior to the source.
236
- * @param source - The source to bind to.
237
- * @param context - The execution context that the binding is operating within.
238
- * @param targets - The targets that behaviors in a view can attach to.
239
- */
240
- bind(source, context, targets) {
241
- const directive = this.directive;
242
- const target = targets[directive.nodeId];
243
- target[this.sourceProperty] = source;
244
- target[this.contextProperty] = context;
245
- target.addEventListener(directive.targetAspect, this, directive.dataBinding.options);
246
- }
247
- /**
248
- * Unbinds this behavior from the source.
249
- * @param source - The source to unbind from.
250
- * @param context - The execution context that the binding is operating within.
251
- * @param targets - The targets that behaviors in a view can attach to.
252
- */
253
- unbind(source, context, targets) {
254
- const directive = this.directive;
255
- const target = targets[directive.nodeId];
256
- target[this.sourceProperty] = target[this.contextProperty] = null;
257
- target.removeEventListener(directive.targetAspect, this, directive.dataBinding.options);
258
- }
259
- /**
260
- * Creates a behavior.
261
- * @param targets - The targets available for behaviors to be attached to.
262
- */
263
- createBehavior(targets) {
264
- return this;
265
- }
266
- /**
267
- * @internal
268
- */
269
- handleEvent(event) {
270
- const target = event.currentTarget;
271
- ExecutionContext.setEvent(event);
272
- const result = this.directive.dataBinding.evaluate(target[this.sourceProperty], target[this.contextProperty]);
273
- ExecutionContext.setEvent(null);
274
- if (result !== true) {
275
- event.preventDefault();
276
- }
277
- }
278
- }
120
+ const setProperty = (t, a, v) => (t[a] = v);
121
+ const eventTarget = () => void 0;
279
122
  /**
280
123
  * A directive that applies bindings.
281
124
  * @public
@@ -287,7 +130,7 @@ export class HTMLBindingDirective {
287
130
  */
288
131
  constructor(dataBinding) {
289
132
  this.dataBinding = dataBinding;
290
- this.factory = null;
133
+ this.updateTarget = null;
291
134
  /**
292
135
  * The unique id of the factory.
293
136
  */
@@ -296,6 +139,9 @@ export class HTMLBindingDirective {
296
139
  * The type of aspect to target.
297
140
  */
298
141
  this.aspectType = Aspect.content;
142
+ /** @internal */
143
+ this.bind = this.bindDefault;
144
+ this.data = `${this.id}-d`;
299
145
  }
300
146
  /**
301
147
  * Creates HTML to be used within a template.
@@ -306,37 +152,87 @@ export class HTMLBindingDirective {
306
152
  }
307
153
  /**
308
154
  * Creates a behavior.
309
- * @param targets - The targets available for behaviors to be attached to.
310
155
  */
311
- createBehavior(targets) {
312
- if (this.factory == null) {
156
+ createBehavior() {
157
+ if (this.updateTarget === null) {
313
158
  if (this.targetAspect === "innerHTML") {
314
159
  this.dataBinding.evaluate = createInnerHTMLBinding(this.dataBinding.evaluate);
315
160
  }
316
161
  switch (this.aspectType) {
317
162
  case 1:
318
- this.factory = new BindingBehavior(this, DOM.setAttribute);
163
+ this.updateTarget = DOM.setAttribute;
319
164
  break;
320
165
  case 2:
321
- this.factory = new BindingBehavior(this, DOM.setBooleanAttribute);
166
+ this.updateTarget = DOM.setBooleanAttribute;
322
167
  break;
323
168
  case 3:
324
- this.factory = new BindingBehavior(this, (t, a, v) => (t[a] = v));
169
+ this.updateTarget = setProperty;
325
170
  break;
326
171
  case 4:
327
- this.factory = new ContentBehavior(this, updateContentTarget);
172
+ this.bind = this.bindContent;
173
+ this.updateTarget = updateContent;
328
174
  break;
329
175
  case 5:
330
- this.factory = new BindingBehavior(this, updateTokenListTarget);
176
+ this.updateTarget = updateTokenList;
331
177
  break;
332
178
  case 6:
333
- this.factory = new EventBehavior(this);
179
+ this.bind = this.bindEvent;
180
+ this.updateTarget = eventTarget;
334
181
  break;
335
182
  default:
336
183
  throw FAST.error(1205 /* Message.unsupportedBindingBehavior */);
337
184
  }
338
185
  }
339
- return this.factory.createBehavior(targets);
186
+ return this;
187
+ }
188
+ /** @internal */
189
+ bindDefault(controller) {
190
+ var _a;
191
+ const target = controller.targets[this.nodeId];
192
+ const observer = (_a = target[this.data]) !== null && _a !== void 0 ? _a : (target[this.data] = this.dataBinding.createObserver(this, this));
193
+ observer.target = target;
194
+ observer.controller = controller;
195
+ this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
196
+ if (this.updateTarget === updateContent) {
197
+ controller.onUnbind(this);
198
+ }
199
+ }
200
+ /** @internal */
201
+ bindContent(controller) {
202
+ this.bindDefault(controller);
203
+ controller.onUnbind(this);
204
+ }
205
+ /** @internal */
206
+ bindEvent(controller) {
207
+ const target = controller.targets[this.nodeId];
208
+ target[this.data] = controller;
209
+ target.addEventListener(this.targetAspect, this, this.dataBinding.options);
210
+ }
211
+ /** @internal */
212
+ unbind(controller) {
213
+ const target = controller.targets[this.nodeId];
214
+ const view = target.$fastView;
215
+ if (view !== void 0 && view.isComposed) {
216
+ view.unbind();
217
+ view.needsBindOnly = true;
218
+ }
219
+ }
220
+ /** @internal */
221
+ handleEvent(event) {
222
+ const target = event.currentTarget;
223
+ ExecutionContext.setEvent(event);
224
+ const controller = target[this.data];
225
+ const result = this.dataBinding.evaluate(controller.source, controller.context);
226
+ ExecutionContext.setEvent(null);
227
+ if (result !== true) {
228
+ event.preventDefault();
229
+ }
230
+ }
231
+ /** @internal */
232
+ handleChange(binding, observer) {
233
+ const target = observer.target;
234
+ const controller = observer.controller;
235
+ this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
340
236
  }
341
237
  }
342
238
  HTMLDirective.define(HTMLBindingDirective, { aspected: true });
@@ -1,5 +1,67 @@
1
+ import { ExecutionContext, } from "../observation/observable.js";
1
2
  import { createTypeRegistry } from "../platform.js";
2
3
  import { Markup, nextId } from "./markup.js";
4
+ /**
5
+ * Bridges between ViewBehaviors and HostBehaviors, enabling a host to
6
+ * control ViewBehaviors.
7
+ * @public
8
+ */
9
+ export const ViewBehaviorOrchestrator = Object.freeze({
10
+ /**
11
+ * Creates a ViewBehaviorOrchestrator.
12
+ * @param source - The source to to associate behaviors with.
13
+ * @returns A ViewBehaviorOrchestrator.
14
+ */
15
+ create(source) {
16
+ const behaviors = [];
17
+ const targets = {};
18
+ let unbindables = null;
19
+ let isConnected = false;
20
+ return {
21
+ source,
22
+ context: ExecutionContext.default,
23
+ targets,
24
+ get isBound() {
25
+ return isConnected;
26
+ },
27
+ addBehaviorFactory(factory, target) {
28
+ const nodeId = factory.nodeId || (factory.nodeId = nextId());
29
+ factory.id || (factory.id = nextId());
30
+ this.addTarget(nodeId, target);
31
+ this.addBehavior(factory.createBehavior());
32
+ },
33
+ addTarget(nodeId, target) {
34
+ targets[nodeId] = target;
35
+ },
36
+ addBehavior(behavior) {
37
+ behaviors.push(behavior);
38
+ if (isConnected) {
39
+ behavior.bind(this);
40
+ }
41
+ },
42
+ onUnbind(unbindable) {
43
+ if (unbindables === null) {
44
+ unbindables = [];
45
+ }
46
+ unbindables.push(unbindable);
47
+ },
48
+ connectedCallback(controller) {
49
+ if (!isConnected) {
50
+ isConnected = true;
51
+ behaviors.forEach(x => x.bind(this));
52
+ }
53
+ },
54
+ disconnectedCallback(controller) {
55
+ if (isConnected) {
56
+ isConnected = false;
57
+ if (unbindables !== null) {
58
+ unbindables.forEach(x => x.unbind(this));
59
+ }
60
+ }
61
+ },
62
+ };
63
+ },
64
+ });
3
65
  const registry = createTypeRegistry();
4
66
  /**
5
67
  * Instructs the template engine to apply behavior to a node.
@@ -45,6 +107,15 @@ export function htmlDirective(options) {
45
107
  * @public
46
108
  */
47
109
  export class Binding {
110
+ /**
111
+ * Creates a binding.
112
+ * @param evaluate - Evaluates the binding.
113
+ * @param isVolatile - Indicates whether the binding is volatile.
114
+ */
115
+ constructor(evaluate, isVolatile = false) {
116
+ this.evaluate = evaluate;
117
+ this.isVolatile = isVolatile;
118
+ }
48
119
  }
49
120
  /**
50
121
  * The type of HTML aspect to target.
@@ -144,13 +215,6 @@ export class StatelessAttachedAttributeDirective {
144
215
  */
145
216
  this.id = nextId();
146
217
  }
147
- /**
148
- * Creates a behavior.
149
- * @param targets - The targets available for behaviors to be attached to.
150
- */
151
- createBehavior(targets) {
152
- return this;
153
- }
154
218
  /**
155
219
  * Creates a placeholder string based on the directive's index within the template.
156
220
  * @param index - The index of the directive within the template.
@@ -160,4 +224,11 @@ export class StatelessAttachedAttributeDirective {
160
224
  createHTML(add) {
161
225
  return Markup.attribute(add(this));
162
226
  }
227
+ /**
228
+ * Creates a behavior.
229
+ * @param targets - The targets available for behaviors to be attached to.
230
+ */
231
+ createBehavior() {
232
+ return this;
233
+ }
163
234
  }
@@ -1,5 +1,5 @@
1
1
  import { emptyArray } from "../platform.js";
2
- import { StatelessAttachedAttributeDirective, } from "./html-directive.js";
2
+ import { StatelessAttachedAttributeDirective } from "./html-directive.js";
3
3
  const selectElements = (value) => value.nodeType === 1;
4
4
  /**
5
5
  * Creates a function that can be used to filter a Node array, selecting only elements.
@@ -26,11 +26,12 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
26
26
  * @param context - The execution context that the binding is operating within.
27
27
  * @param targets - The targets that behaviors in a view can attach to.
28
28
  */
29
- bind(source, context, targets) {
30
- const target = targets[this.nodeId];
31
- target[this.sourceProperty] = source;
32
- this.updateTarget(source, this.computeNodes(target));
29
+ bind(controller) {
30
+ const target = controller.targets[this.nodeId];
31
+ target[this.sourceProperty] = controller.source;
32
+ this.updateTarget(controller.source, this.computeNodes(target));
33
33
  this.observe(target);
34
+ controller.onUnbind(this);
34
35
  }
35
36
  /**
36
37
  * Unbinds this behavior from the source.
@@ -38,9 +39,9 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
38
39
  * @param context - The execution context that the binding is operating within.
39
40
  * @param targets - The targets that behaviors in a view can attach to.
40
41
  */
41
- unbind(source, context, targets) {
42
- const target = targets[this.nodeId];
43
- this.updateTarget(source, emptyArray);
42
+ unbind(controller) {
43
+ const target = controller.targets[this.nodeId];
44
+ this.updateTarget(controller.source, emptyArray);
44
45
  this.disconnect(target);
45
46
  target[this.sourceProperty] = null;
46
47
  }
@@ -5,20 +5,12 @@ import { HTMLDirective, StatelessAttachedAttributeDirective, } from "./html-dire
5
5
  */
6
6
  export class RefDirective extends StatelessAttachedAttributeDirective {
7
7
  /**
8
- * Bind this behavior to the source.
9
- * @param source - The source to bind to.
10
- * @param context - The execution context that the binding is operating within.
11
- * @param targets - The targets that behaviors in a view can attach to.
8
+ * Bind this behavior.
9
+ * @param controller - The view controller that manages the lifecycle of this behavior.
12
10
  */
13
- bind(source, context, targets) {
14
- source[this.options] = targets[this.nodeId];
11
+ bind(controller) {
12
+ controller.source[this.options] = controller.targets[this.nodeId];
15
13
  }
16
- /**
17
- * Unbinds this behavior from the source.
18
- * @param source - The source to unbind from.
19
- */
20
- /* eslint-disable-next-line @typescript-eslint/no-empty-function */
21
- unbind() { }
22
14
  }
23
15
  HTMLDirective.define(RefDirective);
24
16
  /**