@microsoft/fast-element 2.0.0-beta.1 → 2.0.0-beta.10

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 (96) hide show
  1. package/CHANGELOG.json +333 -0
  2. package/CHANGELOG.md +106 -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 +43 -9
  6. package/dist/dts/components/fast-element.d.ts +15 -21
  7. package/dist/dts/context.d.ts +157 -0
  8. package/dist/dts/di/di.d.ts +899 -0
  9. package/dist/dts/index.d.ts +2 -2
  10. package/dist/dts/interfaces.d.ts +44 -12
  11. package/dist/dts/metadata.d.ts +25 -0
  12. package/dist/dts/observation/arrays.d.ts +1 -1
  13. package/dist/dts/observation/observable.d.ts +101 -75
  14. package/dist/dts/pending-task.d.ts +20 -0
  15. package/dist/dts/platform.d.ts +6 -0
  16. package/dist/dts/state/exports.d.ts +3 -0
  17. package/dist/dts/state/reactive.d.ts +8 -0
  18. package/dist/dts/state/state.d.ts +141 -0
  19. package/dist/dts/state/visitor.d.ts +6 -0
  20. package/dist/dts/state/watch.d.ts +10 -0
  21. package/dist/dts/styles/css-directive.d.ts +2 -2
  22. package/dist/dts/styles/element-styles.d.ts +9 -3
  23. package/dist/dts/styles/host.d.ts +68 -0
  24. package/dist/dts/templating/binding-signal.d.ts +21 -0
  25. package/dist/dts/templating/binding-two-way.d.ts +39 -0
  26. package/dist/dts/templating/binding.d.ts +69 -294
  27. package/dist/dts/templating/children.d.ts +1 -1
  28. package/dist/dts/templating/compiler.d.ts +1 -2
  29. package/dist/dts/templating/html-directive.d.ts +93 -35
  30. package/dist/dts/templating/node-observation.d.ts +4 -5
  31. package/dist/dts/templating/ref.d.ts +5 -13
  32. package/dist/dts/templating/render.d.ts +272 -0
  33. package/dist/dts/templating/repeat.d.ts +20 -75
  34. package/dist/dts/templating/slotted.d.ts +1 -1
  35. package/dist/dts/templating/template.d.ts +12 -61
  36. package/dist/dts/templating/view.d.ts +77 -12
  37. package/dist/dts/templating/when.d.ts +3 -3
  38. package/dist/dts/testing/exports.d.ts +3 -0
  39. package/dist/dts/testing/fakes.d.ts +4 -0
  40. package/dist/dts/testing/fixture.d.ts +84 -0
  41. package/dist/dts/testing/timeout.d.ts +7 -0
  42. package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +0 -0
  43. package/dist/dts/utilities.d.ts +0 -18
  44. package/dist/esm/components/attributes.js +13 -4
  45. package/dist/esm/components/{controller.js → element-controller.js} +95 -105
  46. package/dist/esm/components/fast-definitions.js +38 -28
  47. package/dist/esm/components/fast-element.js +31 -12
  48. package/dist/esm/context.js +163 -0
  49. package/dist/esm/debug.js +36 -4
  50. package/dist/esm/di/di.js +1435 -0
  51. package/dist/esm/index.js +2 -1
  52. package/dist/esm/interfaces.js +4 -0
  53. package/dist/esm/metadata.js +60 -0
  54. package/dist/esm/observation/arrays.js +304 -3
  55. package/dist/esm/observation/observable.js +81 -87
  56. package/dist/esm/pending-task.js +16 -0
  57. package/dist/esm/platform.js +25 -1
  58. package/dist/esm/state/exports.js +3 -0
  59. package/dist/esm/state/reactive.js +34 -0
  60. package/dist/esm/state/state.js +148 -0
  61. package/dist/esm/state/visitor.js +28 -0
  62. package/dist/esm/state/watch.js +36 -0
  63. package/dist/esm/styles/css.js +4 -4
  64. package/dist/esm/styles/element-styles.js +14 -0
  65. package/dist/esm/{observation/behavior.js → styles/host.js} +0 -0
  66. package/dist/esm/templating/binding-signal.js +83 -0
  67. package/dist/esm/templating/binding-two-way.js +103 -0
  68. package/dist/esm/templating/binding.js +134 -414
  69. package/dist/esm/templating/compiler.js +30 -7
  70. package/dist/esm/templating/html-directive.js +100 -28
  71. package/dist/esm/templating/node-observation.js +9 -8
  72. package/dist/esm/templating/ref.js +4 -12
  73. package/dist/esm/templating/render.js +391 -0
  74. package/dist/esm/templating/repeat.js +96 -72
  75. package/dist/esm/templating/template.js +11 -29
  76. package/dist/esm/templating/view.js +107 -29
  77. package/dist/esm/templating/when.js +5 -4
  78. package/dist/esm/testing/exports.js +3 -0
  79. package/dist/esm/testing/fakes.js +76 -0
  80. package/dist/esm/testing/fixture.js +86 -0
  81. package/dist/esm/testing/timeout.js +24 -0
  82. package/dist/esm/utilities.js +0 -95
  83. package/dist/fast-element.api.json +9034 -10524
  84. package/dist/fast-element.d.ts +707 -811
  85. package/dist/fast-element.debug.js +1133 -850
  86. package/dist/fast-element.debug.min.js +1 -1
  87. package/dist/fast-element.js +1097 -846
  88. package/dist/fast-element.min.js +1 -1
  89. package/dist/fast-element.untrimmed.d.ts +724 -818
  90. package/docs/api-report.md +264 -305
  91. package/package.json +39 -10
  92. package/dist/dts/hooks.d.ts +0 -20
  93. package/dist/dts/observation/behavior.d.ts +0 -19
  94. package/dist/dts/observation/splice-strategies.d.ts +0 -13
  95. package/dist/esm/hooks.js +0 -32
  96. package/dist/esm/observation/splice-strategies.js +0 -400
@@ -97,19 +97,51 @@ const debugMessages = {
97
97
  [1101 /* needsArrayObservation */]: "Must call enableArrayObservation before observing arrays.",
98
98
  [1201 /* onlySetHTMLPolicyOnce */]: "The HTML policy can only be set once.",
99
99
  [1202 /* bindingInnerHTMLRequiresTrustedTypes */]: "To bind innerHTML, you must use a TrustedTypesPolicy.",
100
+ [1203 /* twoWayBindingRequiresObservables */]: "View=>Model update skipped. To use twoWay binding, the target property must be observable.",
101
+ [1204 /* hostBindingWithoutHost */]: "No host element is present. Cannot bind host with ${name}.",
102
+ [1205 /* unsupportedBindingBehavior */]: "The requested binding behavior is not supported by the binding engine.",
100
103
  [1401 /* missingElementDefinition */]: "Missing FASTElement definition.",
104
+ [1501 /* noRegistrationForContext */]: "No registration for Context/Interface '${name}'.",
105
+ [1502 /* noFactoryForResolver */]: "Dependency injection resolver for '${key}' returned a null factory.",
106
+ [1503 /* invalidResolverStrategy */]: "Invalid dependency injection resolver strategy specified '${strategy}'.",
107
+ [1504 /* cannotAutoregisterDependency */]: "Unable to autoregister dependency.",
108
+ [1505 /* cannotResolveKey */]: "Unable to resolve dependency injection key '${key}'.",
109
+ [1506 /* cannotConstructNativeFunction */]: "'${name}' is a native function and therefore cannot be safely constructed by DI. If this is intentional, please use a callback or cachedCallback resolver.",
110
+ [1507 /* cannotJITRegisterNonConstructor */]: "Attempted to jitRegister something that is not a constructor '${value}'. Did you forget to register this dependency?",
111
+ [1508 /* cannotJITRegisterIntrinsic */]: "Attempted to jitRegister an intrinsic type '${value}'. Did you forget to add @inject(Key)?",
112
+ [1509 /* cannotJITRegisterInterface */]: "Attempted to jitRegister an interface '${value}'.",
113
+ [1510 /* invalidResolver */]: "A valid resolver was not returned from the register method.",
114
+ [1511 /* invalidKey */]: "Key/value cannot be null or undefined. Are you trying to inject/register something that doesn't exist with DI?",
115
+ [1512 /* noDefaultResolver */]: "'${key}' not registered. Did you forget to add @singleton()?",
116
+ [1513 /* cyclicDependency */]: "Cyclic dependency found '${name}'.",
117
+ [1514 /* connectUpdateRequiresController */]: "Injected properties that are updated on changes to DOM connectivity require the target object to be an instance of FASTElement.",
101
118
  };
119
+ const allPlaceholders = /(\$\{\w+?})/g;
120
+ const placeholder = /\$\{(\w+?)}/g;
121
+ const noValues = Object.freeze({});
122
+ function formatMessage(message, values) {
123
+ return message
124
+ .split(allPlaceholders)
125
+ .map(v => {
126
+ var _a;
127
+ const replaced = v.replace(placeholder, "$1");
128
+ return String((_a = values[replaced]) !== null && _a !== void 0 ? _a : v);
129
+ })
130
+ .join("");
131
+ }
102
132
  Object.assign(FAST$1, {
103
133
  addMessages(messages) {
104
134
  Object.assign(debugMessages, messages);
105
135
  },
106
- warn(code, ...args) {
136
+ warn(code, values = noValues) {
107
137
  var _a;
108
- console.warn((_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Warning");
138
+ const message = (_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Warning";
139
+ console.warn(formatMessage(message, values));
109
140
  },
110
- error(code, ...args) {
141
+ error(code, values = noValues) {
111
142
  var _a;
112
- return new Error((_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Error");
143
+ const message = (_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Error";
144
+ return new Error(formatMessage(message, values));
113
145
  },
114
146
  });
115
147
 
@@ -141,7 +173,7 @@ if (FAST.error === void 0) {
141
173
  Object.assign(FAST, {
142
174
  warn() { },
143
175
  error(code) {
144
- return new Error(`Code ${code}`);
176
+ return new Error(`Error ${code}`);
145
177
  },
146
178
  addMessages() { },
147
179
  });
@@ -172,10 +204,34 @@ function createTypeRegistry() {
172
204
  return typeToDefinition.get(key);
173
205
  },
174
206
  getForInstance(object) {
207
+ if (object === null || object === void 0) {
208
+ return void 0;
209
+ }
175
210
  return typeToDefinition.get(object.constructor);
176
211
  },
177
212
  });
178
213
  }
214
+ /**
215
+ * Creates a function capable of locating metadata associated with a type.
216
+ * @returns A metadata locator function.
217
+ * @internal
218
+ */
219
+ function createMetadataLocator() {
220
+ const metadataLookup = new WeakMap();
221
+ return function (target) {
222
+ let metadata = metadataLookup.get(target);
223
+ if (metadata === void 0) {
224
+ let currentTarget = Reflect.getPrototypeOf(target);
225
+ while (metadata === void 0 && currentTarget !== null) {
226
+ metadata = metadataLookup.get(currentTarget);
227
+ currentTarget = Reflect.getPrototypeOf(currentTarget);
228
+ }
229
+ metadata = metadata === void 0 ? [] : metadata.slice(0);
230
+ metadataLookup.set(target, metadata);
231
+ }
232
+ return metadata;
233
+ };
234
+ }
179
235
 
180
236
  /**
181
237
  * @internal
@@ -417,6 +473,21 @@ class PropertyChangeNotifier {
417
473
  }
418
474
  }
419
475
 
476
+ /**
477
+ * Describes how the source's lifetime relates to its controller's lifetime.
478
+ * @public
479
+ */
480
+ const SourceLifetime = Object.freeze({
481
+ /**
482
+ * The source to controller lifetime relationship is unknown.
483
+ */
484
+ unknown: void 0,
485
+ /**
486
+ * The source and controller lifetimes are coupled to one another.
487
+ * They can/will be GC'd together.
488
+ */
489
+ coupled: 1,
490
+ });
420
491
  /**
421
492
  * Common Observable APIs.
422
493
  * @public
@@ -425,7 +496,6 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
425
496
  const queueUpdate = Updates.enqueue;
426
497
  const volatileRegex = /(:|&&|\|\||if)/;
427
498
  const notifierLookup = new WeakMap();
428
- const accessorLookup = new WeakMap();
429
499
  let watcher = void 0;
430
500
  let createArrayObserver = (array) => {
431
501
  throw FAST.error(1101 /* Message.needsArrayObservation */);
@@ -440,19 +510,7 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
440
510
  }
441
511
  return found;
442
512
  }
443
- function getAccessors(target) {
444
- let accessors = accessorLookup.get(target);
445
- if (accessors === void 0) {
446
- let currentTarget = Reflect.getPrototypeOf(target);
447
- while (accessors === void 0 && currentTarget !== null) {
448
- accessors = accessorLookup.get(currentTarget);
449
- currentTarget = Reflect.getPrototypeOf(currentTarget);
450
- }
451
- accessors = accessors === void 0 ? [] : accessors.slice(0);
452
- accessorLookup.set(target, accessors);
453
- }
454
- return accessors;
455
- }
513
+ const getAccessors = createMetadataLocator();
456
514
  class DefaultObservableAccessor {
457
515
  constructor(name) {
458
516
  this.name = name;
@@ -478,10 +536,10 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
478
536
  }
479
537
  }
480
538
  }
481
- class BindingObserverImplementation extends SubscriberSet {
482
- constructor(binding, initialSubscriber, isVolatileBinding = false) {
483
- super(binding, initialSubscriber);
484
- this.binding = binding;
539
+ class ExpressionNotifierImplementation extends SubscriberSet {
540
+ constructor(expression, initialSubscriber, isVolatileBinding = false) {
541
+ super(expression, initialSubscriber);
542
+ this.expression = expression;
485
543
  this.isVolatileBinding = isVolatileBinding;
486
544
  this.needsRefresh = true;
487
545
  this.needsQueue = true;
@@ -496,6 +554,22 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
496
554
  setMode(isAsync) {
497
555
  this.isAsync = this.needsQueue = isAsync;
498
556
  }
557
+ bind(controller) {
558
+ this.controller = controller;
559
+ const value = this.observe(controller.source, controller.context);
560
+ if (!controller.isBound && this.requiresUnbind(controller)) {
561
+ controller.onUnbind(this);
562
+ }
563
+ return value;
564
+ }
565
+ requiresUnbind(controller) {
566
+ return (controller.sourceLifetime !== SourceLifetime.coupled ||
567
+ this.first !== this.last ||
568
+ this.first.propertySource !== controller.source);
569
+ }
570
+ unbind(controller) {
571
+ this.dispose();
572
+ }
499
573
  observe(source, context) {
500
574
  if (this.needsRefresh && this.last !== null) {
501
575
  this.dispose();
@@ -503,10 +577,19 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
503
577
  const previousWatcher = watcher;
504
578
  watcher = this.needsRefresh ? this : void 0;
505
579
  this.needsRefresh = this.isVolatileBinding;
506
- const result = this.binding(source, context !== null && context !== void 0 ? context : ExecutionContext.default);
507
- watcher = previousWatcher;
580
+ let result;
581
+ try {
582
+ result = this.expression(source, context);
583
+ }
584
+ finally {
585
+ watcher = previousWatcher;
586
+ }
508
587
  return result;
509
588
  }
589
+ // backwards compat with v1 kernel
590
+ disconnect() {
591
+ this.dispose();
592
+ }
510
593
  dispose() {
511
594
  if (this.last !== null) {
512
595
  let current = this.first;
@@ -633,22 +716,22 @@ const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
633
716
  */
634
717
  getAccessors,
635
718
  /**
636
- * Creates a {@link BindingObserver} that can watch the
637
- * provided {@link Binding} for changes.
638
- * @param binding - The binding to observe.
719
+ * Creates a {@link ExpressionNotifier} that can watch the
720
+ * provided {@link Expression} for changes.
721
+ * @param expression - The binding to observe.
639
722
  * @param initialSubscriber - An initial subscriber to changes in the binding value.
640
723
  * @param isVolatileBinding - Indicates whether the binding's dependency list must be re-evaluated on every value evaluation.
641
724
  */
642
- binding(binding, initialSubscriber, isVolatileBinding = this.isVolatileBinding(binding)) {
643
- return new BindingObserverImplementation(binding, initialSubscriber, isVolatileBinding);
725
+ binding(expression, initialSubscriber, isVolatileBinding = this.isVolatileBinding(expression)) {
726
+ return new ExpressionNotifierImplementation(expression, initialSubscriber, isVolatileBinding);
644
727
  },
645
728
  /**
646
729
  * Determines whether a binding expression is volatile and needs to have its dependency list re-evaluated
647
730
  * on every evaluation of the value.
648
- * @param binding - The binding to inspect.
731
+ * @param expression - The binding to inspect.
649
732
  */
650
- isVolatileBinding(binding) {
651
- return volatileRegex.test(binding.toString());
733
+ isVolatileBinding(expression) {
734
+ return volatileRegex.test(expression.toString());
652
735
  },
653
736
  });
654
737
  });
@@ -687,73 +770,40 @@ const contextEvent = FAST.getById(3 /* KernelServiceId.contextEvent */, () => {
687
770
  },
688
771
  };
689
772
  });
690
- class DefaultExecutionContext {
691
- constructor(parentSource = null, parentContext = null) {
692
- this.index = 0;
693
- this.length = 0;
694
- this.parent = parentSource;
695
- this.parentContext = parentContext;
696
- }
697
- get event() {
698
- return contextEvent.get();
699
- }
700
- get isEven() {
701
- return this.index % 2 === 0;
702
- }
703
- get isOdd() {
704
- return this.index % 2 !== 0;
705
- }
706
- get isFirst() {
707
- return this.index === 0;
708
- }
709
- get isInMiddle() {
710
- return !this.isFirst && !this.isLast;
711
- }
712
- get isLast() {
713
- return this.index === this.length - 1;
714
- }
715
- eventDetail() {
716
- return this.event.detail;
717
- }
718
- eventTarget() {
719
- return this.event.target;
720
- }
721
- updatePosition(index, length) {
722
- this.index = index;
723
- this.length = length;
724
- }
725
- createChildContext(parentSource) {
726
- return new DefaultExecutionContext(parentSource, this);
727
- }
728
- createItemContext(index, length) {
729
- const childContext = Object.create(this);
730
- childContext.index = index;
731
- childContext.length = length;
732
- return childContext;
733
- }
734
- }
735
- Observable.defineProperty(DefaultExecutionContext.prototype, "index");
736
- Observable.defineProperty(DefaultExecutionContext.prototype, "length");
737
773
  /**
738
- * The common execution context APIs.
774
+ * Provides additional contextual information available to behaviors and expressions.
739
775
  * @public
740
776
  */
741
777
  const ExecutionContext = Object.freeze({
742
- default: new DefaultExecutionContext(),
743
778
  /**
744
- * Sets the event for the current execution context.
745
- * @param event - The event to set.
746
- * @internal
779
+ * A default execution context.
747
780
  */
748
- setEvent(event) {
749
- contextEvent.set(event);
781
+ default: {
782
+ index: 0,
783
+ length: 0,
784
+ get event() {
785
+ return ExecutionContext.getEvent();
786
+ },
787
+ eventDetail() {
788
+ return this.event.detail;
789
+ },
790
+ eventTarget() {
791
+ return this.event.target;
792
+ },
750
793
  },
751
794
  /**
752
- * Creates a new root execution context.
753
- * @returns A new execution context.
795
+ * Gets the current event.
796
+ * @returns An event object.
754
797
  */
755
- create() {
756
- return new DefaultExecutionContext();
798
+ getEvent() {
799
+ return contextEvent.get();
800
+ },
801
+ /**
802
+ * Sets the current event.
803
+ * @param event - An event object.
804
+ */
805
+ setEvent(event) {
806
+ contextEvent.set(event);
757
807
  },
758
808
  });
759
809
 
@@ -822,10 +872,311 @@ const SpliceStrategySupport = Object.freeze({
822
872
  const reset = new Splice(0, emptyArray, 0);
823
873
  reset.reset = true;
824
874
  const resetSplices = [reset];
875
+ // Note: This function is *based* on the computation of the Levenshtein
876
+ // "edit" distance. The one change is that "updates" are treated as two
877
+ // edits - not one. With Array splices, an update is really a delete
878
+ // followed by an add. By retaining this, we optimize for "keeping" the
879
+ // maximum array items in the original array. For example:
880
+ //
881
+ // 'xxxx123' to '123yyyy'
882
+ //
883
+ // With 1-edit updates, the shortest path would be just to update all seven
884
+ // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
885
+ // leaves the substring '123' intact.
886
+ function calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd) {
887
+ // "Deletion" columns
888
+ const rowCount = oldEnd - oldStart + 1;
889
+ const columnCount = currentEnd - currentStart + 1;
890
+ const distances = new Array(rowCount);
891
+ let north;
892
+ let west;
893
+ // "Addition" rows. Initialize null column.
894
+ for (let i = 0; i < rowCount; ++i) {
895
+ distances[i] = new Array(columnCount);
896
+ distances[i][0] = i;
897
+ }
898
+ // Initialize null row
899
+ for (let j = 0; j < columnCount; ++j) {
900
+ distances[0][j] = j;
901
+ }
902
+ for (let i = 1; i < rowCount; ++i) {
903
+ for (let j = 1; j < columnCount; ++j) {
904
+ if (current[currentStart + j - 1] === old[oldStart + i - 1]) {
905
+ distances[i][j] = distances[i - 1][j - 1];
906
+ }
907
+ else {
908
+ north = distances[i - 1][j] + 1;
909
+ west = distances[i][j - 1] + 1;
910
+ distances[i][j] = north < west ? north : west;
911
+ }
912
+ }
913
+ }
914
+ return distances;
915
+ }
916
+ // This starts at the final weight, and walks "backward" by finding
917
+ // the minimum previous weight recursively until the origin of the weight
918
+ // matrix.
919
+ function spliceOperationsFromEditDistances(distances) {
920
+ let i = distances.length - 1;
921
+ let j = distances[0].length - 1;
922
+ let current = distances[i][j];
923
+ const edits = [];
924
+ while (i > 0 || j > 0) {
925
+ if (i === 0) {
926
+ edits.push(2 /* Edit.add */);
927
+ j--;
928
+ continue;
929
+ }
930
+ if (j === 0) {
931
+ edits.push(3 /* Edit.delete */);
932
+ i--;
933
+ continue;
934
+ }
935
+ const northWest = distances[i - 1][j - 1];
936
+ const west = distances[i - 1][j];
937
+ const north = distances[i][j - 1];
938
+ let min;
939
+ if (west < north) {
940
+ min = west < northWest ? west : northWest;
941
+ }
942
+ else {
943
+ min = north < northWest ? north : northWest;
944
+ }
945
+ if (min === northWest) {
946
+ if (northWest === current) {
947
+ edits.push(0 /* Edit.leave */);
948
+ }
949
+ else {
950
+ edits.push(1 /* Edit.update */);
951
+ current = northWest;
952
+ }
953
+ i--;
954
+ j--;
955
+ }
956
+ else if (min === west) {
957
+ edits.push(3 /* Edit.delete */);
958
+ i--;
959
+ current = west;
960
+ }
961
+ else {
962
+ edits.push(2 /* Edit.add */);
963
+ j--;
964
+ current = north;
965
+ }
966
+ }
967
+ return edits.reverse();
968
+ }
969
+ function sharedPrefix(current, old, searchLength) {
970
+ for (let i = 0; i < searchLength; ++i) {
971
+ if (current[i] !== old[i]) {
972
+ return i;
973
+ }
974
+ }
975
+ return searchLength;
976
+ }
977
+ function sharedSuffix(current, old, searchLength) {
978
+ let index1 = current.length;
979
+ let index2 = old.length;
980
+ let count = 0;
981
+ while (count < searchLength && current[--index1] === old[--index2]) {
982
+ count++;
983
+ }
984
+ return count;
985
+ }
986
+ function intersect(start1, end1, start2, end2) {
987
+ // Disjoint
988
+ if (end1 < start2 || end2 < start1) {
989
+ return -1;
990
+ }
991
+ // Adjacent
992
+ if (end1 === start2 || end2 === start1) {
993
+ return 0;
994
+ }
995
+ // Non-zero intersect, span1 first
996
+ if (start1 < start2) {
997
+ if (end1 < end2) {
998
+ return end1 - start2; // Overlap
999
+ }
1000
+ return end2 - start2; // Contained
1001
+ }
1002
+ // Non-zero intersect, span2 first
1003
+ if (end2 < end1) {
1004
+ return end2 - start1; // Overlap
1005
+ }
1006
+ return end1 - start1; // Contained
1007
+ }
1008
+ /**
1009
+ * @remarks
1010
+ * Lacking individual splice mutation information, the minimal set of
1011
+ * splices can be synthesized given the previous state and final state of an
1012
+ * array. The basic approach is to calculate the edit distance matrix and
1013
+ * choose the shortest path through it.
1014
+ *
1015
+ * Complexity: O(l * p)
1016
+ * l: The length of the current array
1017
+ * p: The length of the old array
1018
+ */
1019
+ function calc(current, currentStart, currentEnd, old, oldStart, oldEnd) {
1020
+ let prefixCount = 0;
1021
+ let suffixCount = 0;
1022
+ const minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
1023
+ if (currentStart === 0 && oldStart === 0) {
1024
+ prefixCount = sharedPrefix(current, old, minLength);
1025
+ }
1026
+ if (currentEnd === current.length && oldEnd === old.length) {
1027
+ suffixCount = sharedSuffix(current, old, minLength - prefixCount);
1028
+ }
1029
+ currentStart += prefixCount;
1030
+ oldStart += prefixCount;
1031
+ currentEnd -= suffixCount;
1032
+ oldEnd -= suffixCount;
1033
+ if (currentEnd - currentStart === 0 && oldEnd - oldStart === 0) {
1034
+ return emptyArray;
1035
+ }
1036
+ if (currentStart === currentEnd) {
1037
+ const splice = new Splice(currentStart, [], 0);
1038
+ while (oldStart < oldEnd) {
1039
+ splice.removed.push(old[oldStart++]);
1040
+ }
1041
+ return [splice];
1042
+ }
1043
+ else if (oldStart === oldEnd) {
1044
+ return [new Splice(currentStart, [], currentEnd - currentStart)];
1045
+ }
1046
+ const ops = spliceOperationsFromEditDistances(calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
1047
+ const splices = [];
1048
+ let splice = void 0;
1049
+ let index = currentStart;
1050
+ let oldIndex = oldStart;
1051
+ for (let i = 0; i < ops.length; ++i) {
1052
+ switch (ops[i]) {
1053
+ case 0 /* Edit.leave */:
1054
+ if (splice !== void 0) {
1055
+ splices.push(splice);
1056
+ splice = void 0;
1057
+ }
1058
+ index++;
1059
+ oldIndex++;
1060
+ break;
1061
+ case 1 /* Edit.update */:
1062
+ if (splice === void 0) {
1063
+ splice = new Splice(index, [], 0);
1064
+ }
1065
+ splice.addedCount++;
1066
+ index++;
1067
+ splice.removed.push(old[oldIndex]);
1068
+ oldIndex++;
1069
+ break;
1070
+ case 2 /* Edit.add */:
1071
+ if (splice === void 0) {
1072
+ splice = new Splice(index, [], 0);
1073
+ }
1074
+ splice.addedCount++;
1075
+ index++;
1076
+ break;
1077
+ case 3 /* Edit.delete */:
1078
+ if (splice === void 0) {
1079
+ splice = new Splice(index, [], 0);
1080
+ }
1081
+ splice.removed.push(old[oldIndex]);
1082
+ oldIndex++;
1083
+ break;
1084
+ // no default
1085
+ }
1086
+ }
1087
+ if (splice !== void 0) {
1088
+ splices.push(splice);
1089
+ }
1090
+ return splices;
1091
+ }
1092
+ function merge(splice, splices) {
1093
+ let inserted = false;
1094
+ let insertionOffset = 0;
1095
+ for (let i = 0; i < splices.length; i++) {
1096
+ const current = splices[i];
1097
+ current.index += insertionOffset;
1098
+ if (inserted) {
1099
+ continue;
1100
+ }
1101
+ const intersectCount = intersect(splice.index, splice.index + splice.removed.length, current.index, current.index + current.addedCount);
1102
+ if (intersectCount >= 0) {
1103
+ // Merge the two splices
1104
+ splices.splice(i, 1);
1105
+ i--;
1106
+ insertionOffset -= current.addedCount - current.removed.length;
1107
+ splice.addedCount += current.addedCount - intersectCount;
1108
+ const deleteCount = splice.removed.length + current.removed.length - intersectCount;
1109
+ if (!splice.addedCount && !deleteCount) {
1110
+ // merged splice is a noop. discard.
1111
+ inserted = true;
1112
+ }
1113
+ else {
1114
+ let currentRemoved = current.removed;
1115
+ if (splice.index < current.index) {
1116
+ // some prefix of splice.removed is prepended to current.removed.
1117
+ const prepend = splice.removed.slice(0, current.index - splice.index);
1118
+ prepend.push(...currentRemoved);
1119
+ currentRemoved = prepend;
1120
+ }
1121
+ if (splice.index + splice.removed.length >
1122
+ current.index + current.addedCount) {
1123
+ // some suffix of splice.removed is appended to current.removed.
1124
+ const append = splice.removed.slice(current.index + current.addedCount - splice.index);
1125
+ currentRemoved.push(...append);
1126
+ }
1127
+ splice.removed = currentRemoved;
1128
+ if (current.index < splice.index) {
1129
+ splice.index = current.index;
1130
+ }
1131
+ }
1132
+ }
1133
+ else if (splice.index < current.index) {
1134
+ // Insert splice here.
1135
+ inserted = true;
1136
+ splices.splice(i, 0, splice);
1137
+ i++;
1138
+ const offset = splice.addedCount - splice.removed.length;
1139
+ current.index += offset;
1140
+ insertionOffset += offset;
1141
+ }
1142
+ }
1143
+ if (!inserted) {
1144
+ splices.push(splice);
1145
+ }
1146
+ }
1147
+ function project(array, changes) {
1148
+ let splices = [];
1149
+ const initialSplices = [];
1150
+ for (let i = 0, ii = changes.length; i < ii; i++) {
1151
+ merge(changes[i], initialSplices);
1152
+ }
1153
+ for (let i = 0, ii = initialSplices.length; i < ii; ++i) {
1154
+ const splice = initialSplices[i];
1155
+ if (splice.addedCount === 1 && splice.removed.length === 1) {
1156
+ if (splice.removed[0] !== array[splice.index]) {
1157
+ splices.push(splice);
1158
+ }
1159
+ continue;
1160
+ }
1161
+ splices = splices.concat(calc(array, splice.index, splice.index + splice.addedCount, splice.removed, 0, splice.removed.length));
1162
+ }
1163
+ return splices;
1164
+ }
1165
+ /**
1166
+ * A SpliceStrategy that attempts to merge all splices into the minimal set of
1167
+ * splices needed to represent the change from the old array to the new array.
1168
+ * @public
1169
+ */
825
1170
  let defaultSpliceStrategy = Object.freeze({
826
- support: SpliceStrategySupport.splice,
1171
+ support: SpliceStrategySupport.optimized,
827
1172
  normalize(previous, current, changes) {
828
- return previous === void 0 ? changes !== null && changes !== void 0 ? changes : emptyArray : resetSplices;
1173
+ if (previous === void 0) {
1174
+ if (changes === void 0) {
1175
+ return emptyArray;
1176
+ }
1177
+ return changes.length > 1 ? project(current, changes) : changes;
1178
+ }
1179
+ return resetSplices;
829
1180
  },
830
1181
  pop(array, observer, pop, args) {
831
1182
  const notEmpty = array.length > 0;
@@ -1010,7 +1361,7 @@ const ArrayObserver = Object.freeze({
1010
1361
  * @returns The length of the array.
1011
1362
  * @public
1012
1363
  */
1013
- function length(array) {
1364
+ function lengthOf(array) {
1014
1365
  if (!array) {
1015
1366
  return 0;
1016
1367
  }
@@ -1094,6 +1445,20 @@ class ElementStyles {
1094
1445
  static setDefaultStrategy(Strategy) {
1095
1446
  DefaultStyleStrategy = Strategy;
1096
1447
  }
1448
+ /**
1449
+ * Normalizes a set of composable style options.
1450
+ * @param styles - The style options to normalize.
1451
+ * @returns A singular ElementStyles instance or undefined.
1452
+ */
1453
+ static normalize(styles) {
1454
+ return styles === void 0
1455
+ ? void 0
1456
+ : Array.isArray(styles)
1457
+ ? new ElementStyles(styles)
1458
+ : styles instanceof ElementStyles
1459
+ ? styles
1460
+ : new ElementStyles([styles]);
1461
+ }
1097
1462
  }
1098
1463
  /**
1099
1464
  * Indicates whether the DOM supports the adoptedStyleSheets feature.
@@ -1238,11 +1603,11 @@ class CSSPartial {
1238
1603
  }
1239
1604
  return this.css;
1240
1605
  }
1241
- bind(el) {
1242
- el.$fastController.addStyles(this.styles);
1606
+ addedCallback(controller) {
1607
+ controller.addStyles(this.styles);
1243
1608
  }
1244
- unbind(el) {
1245
- el.$fastController.removeStyles(this.styles);
1609
+ removedCallback(controller) {
1610
+ controller.removeStyles(this.styles);
1246
1611
  }
1247
1612
  }
1248
1613
  CSSDirective.define(CSSPartial);
@@ -1381,6 +1746,67 @@ const Parser = Object.freeze({
1381
1746
  },
1382
1747
  });
1383
1748
 
1749
+ /**
1750
+ * Bridges between ViewBehaviors and HostBehaviors, enabling a host to
1751
+ * control ViewBehaviors.
1752
+ * @public
1753
+ */
1754
+ const ViewBehaviorOrchestrator = Object.freeze({
1755
+ /**
1756
+ * Creates a ViewBehaviorOrchestrator.
1757
+ * @param source - The source to to associate behaviors with.
1758
+ * @returns A ViewBehaviorOrchestrator.
1759
+ */
1760
+ create(source) {
1761
+ const behaviors = [];
1762
+ const targets = {};
1763
+ let unbindables = null;
1764
+ let isConnected = false;
1765
+ return {
1766
+ source,
1767
+ context: ExecutionContext.default,
1768
+ targets,
1769
+ get isBound() {
1770
+ return isConnected;
1771
+ },
1772
+ addBehaviorFactory(factory, target) {
1773
+ const nodeId = factory.nodeId || (factory.nodeId = nextId());
1774
+ factory.id || (factory.id = nextId());
1775
+ this.addTarget(nodeId, target);
1776
+ this.addBehavior(factory.createBehavior());
1777
+ },
1778
+ addTarget(nodeId, target) {
1779
+ targets[nodeId] = target;
1780
+ },
1781
+ addBehavior(behavior) {
1782
+ behaviors.push(behavior);
1783
+ if (isConnected) {
1784
+ behavior.bind(this);
1785
+ }
1786
+ },
1787
+ onUnbind(unbindable) {
1788
+ if (unbindables === null) {
1789
+ unbindables = [];
1790
+ }
1791
+ unbindables.push(unbindable);
1792
+ },
1793
+ connectedCallback(controller) {
1794
+ if (!isConnected) {
1795
+ isConnected = true;
1796
+ behaviors.forEach(x => x.bind(this));
1797
+ }
1798
+ },
1799
+ disconnectedCallback(controller) {
1800
+ if (isConnected) {
1801
+ isConnected = false;
1802
+ if (unbindables !== null) {
1803
+ unbindables.forEach(x => x.unbind(this));
1804
+ }
1805
+ }
1806
+ },
1807
+ };
1808
+ },
1809
+ });
1384
1810
  const registry = createTypeRegistry();
1385
1811
  /**
1386
1812
  * Instructs the template engine to apply behavior to a node.
@@ -1420,6 +1846,22 @@ function htmlDirective(options) {
1420
1846
  HTMLDirective.define(type, options);
1421
1847
  };
1422
1848
  }
1849
+ /**
1850
+ * Captures a binding expression along with related information and capabilities.
1851
+ *
1852
+ * @public
1853
+ */
1854
+ class Binding {
1855
+ /**
1856
+ * Creates a binding.
1857
+ * @param evaluate - Evaluates the binding.
1858
+ * @param isVolatile - Indicates whether the binding is volatile.
1859
+ */
1860
+ constructor(evaluate, isVolatile = false) {
1861
+ this.evaluate = evaluate;
1862
+ this.isVolatile = isVolatile;
1863
+ }
1864
+ }
1423
1865
  /**
1424
1866
  * The type of HTML aspect to target.
1425
1867
  * @public
@@ -1457,26 +1899,22 @@ const Aspect = Object.freeze({
1457
1899
  *
1458
1900
  * @param directive - The directive to assign the aspect to.
1459
1901
  * @param value - The value to base the aspect determination on.
1902
+ * @remarks
1903
+ * If a falsy value is provided, then the content aspect will be assigned.
1460
1904
  */
1461
1905
  assign(directive, value) {
1462
- directive.sourceAspect = value;
1463
1906
  if (!value) {
1907
+ directive.aspectType = Aspect.content;
1464
1908
  return;
1465
1909
  }
1910
+ directive.sourceAspect = value;
1466
1911
  switch (value[0]) {
1467
1912
  case ":":
1468
1913
  directive.targetAspect = value.substring(1);
1469
- switch (directive.targetAspect) {
1470
- case "innerHTML":
1471
- directive.aspectType = Aspect.property;
1472
- break;
1473
- case "classList":
1474
- directive.aspectType = Aspect.tokenList;
1475
- break;
1476
- default:
1477
- directive.aspectType = Aspect.property;
1478
- break;
1479
- }
1914
+ directive.aspectType =
1915
+ directive.targetAspect === "classList"
1916
+ ? Aspect.tokenList
1917
+ : Aspect.property;
1480
1918
  break;
1481
1919
  case "?":
1482
1920
  directive.targetAspect = value.substring(1);
@@ -1487,14 +1925,8 @@ const Aspect = Object.freeze({
1487
1925
  directive.aspectType = Aspect.event;
1488
1926
  break;
1489
1927
  default:
1490
- if (value === "class") {
1491
- directive.targetAspect = "className";
1492
- directive.aspectType = Aspect.property;
1493
- }
1494
- else {
1495
- directive.targetAspect = value;
1496
- directive.aspectType = Aspect.attribute;
1497
- }
1928
+ directive.targetAspect = value;
1929
+ directive.aspectType = Aspect.attribute;
1498
1930
  break;
1499
1931
  }
1500
1932
  },
@@ -1510,13 +1942,10 @@ class StatelessAttachedAttributeDirective {
1510
1942
  */
1511
1943
  constructor(options) {
1512
1944
  this.options = options;
1513
- }
1514
- /**
1515
- * Creates a behavior.
1516
- * @param targets - The targets available for behaviors to be attached to.
1517
- */
1518
- createBehavior(targets) {
1519
- return this;
1945
+ /**
1946
+ * The unique id of the factory.
1947
+ */
1948
+ this.id = nextId();
1520
1949
  }
1521
1950
  /**
1522
1951
  * Creates a placeholder string based on the directive's index within the template.
@@ -1527,6 +1956,13 @@ class StatelessAttachedAttributeDirective {
1527
1956
  createHTML(add) {
1528
1957
  return Markup.attribute(add(this));
1529
1958
  }
1959
+ /**
1960
+ * Creates a behavior.
1961
+ * @param targets - The targets available for behaviors to be attached to.
1962
+ */
1963
+ createBehavior() {
1964
+ return this;
1965
+ }
1530
1966
  }
1531
1967
 
1532
1968
  const createInnerHTMLBinding = globalThis.TrustedHTML
@@ -1538,107 +1974,26 @@ const createInnerHTMLBinding = globalThis.TrustedHTML
1538
1974
  throw FAST.error(1202 /* Message.bindingInnerHTMLRequiresTrustedTypes */);
1539
1975
  }
1540
1976
  : (binding) => binding;
1541
- /**
1542
- * Describes how aspects of an HTML element will be affected by bindings.
1543
- * @public
1544
- */
1545
- const BindingMode = Object.freeze({
1546
- /**
1547
- * Creates a binding mode based on the supplied behavior types.
1548
- * @param UpdateType - The base behavior type used to update aspects.
1549
- * @param EventType - The base behavior type used to respond to events.
1550
- * @returns A new binding mode.
1551
- */
1552
- define(UpdateType, EventType = EventBinding) {
1553
- return Object.freeze({
1554
- [1]: d => new UpdateType(d, DOM.setAttribute),
1555
- [2]: d => new UpdateType(d, DOM.setBooleanAttribute),
1556
- [3]: d => new UpdateType(d, (t, a, v) => (t[a] = v)),
1557
- [4]: d => new (createContentBinding(UpdateType))(d, updateContentTarget),
1558
- [5]: d => new UpdateType(d, updateTokenListTarget),
1559
- [6]: d => new EventType(d),
1560
- });
1561
- },
1562
- });
1563
- /**
1564
- * Describes the configuration for a binding expression.
1565
- * @public
1566
- */
1567
- const BindingConfig = Object.freeze({
1568
- /**
1569
- * Creates a binding configuration based on the provided mode and options.
1570
- * @param mode - The mode to use for the configuration.
1571
- * @param defaultOptions - The default options to use for the configuration.
1572
- * @returns A new binding configuration.
1573
- */
1574
- define(mode, defaultOptions) {
1575
- const config = (options) => {
1576
- return {
1577
- mode: config.mode,
1578
- options: Object.assign({}, defaultOptions, options),
1579
- };
1580
- };
1581
- config.options = defaultOptions;
1582
- config.mode = mode;
1583
- return config;
1584
- },
1585
- });
1586
- /**
1587
- * A base binding behavior for DOM updates.
1588
- * @public
1589
- */
1590
- class UpdateBinding {
1591
- /**
1592
- * Creates an instance of UpdateBinding.
1593
- * @param directive - The directive that has the configuration for this behavior.
1594
- * @param updateTarget - The function used to update the target with the latest value.
1595
- */
1596
- constructor(directive, updateTarget) {
1597
- this.directive = directive;
1598
- this.updateTarget = updateTarget;
1977
+ class OnChangeBinding extends Binding {
1978
+ createObserver(_, subscriber) {
1979
+ return Observable.binding(this.evaluate, subscriber, this.isVolatile);
1599
1980
  }
1600
- /**
1601
- * Bind this behavior to the source.
1602
- * @param source - The source to bind to.
1603
- * @param context - The execution context that the binding is operating within.
1604
- * @param targets - The targets that behaviors in a view can attach to.
1605
- */
1606
- bind(source, context, targets) { }
1607
- /**
1608
- * Unbinds this behavior from the source.
1609
- * @param source - The source to unbind from.
1610
- * @param context - The execution context that the binding is operating within.
1611
- * @param targets - The targets that behaviors in a view can attach to.
1612
- */
1613
- unbind(source, context, targets) { }
1614
- /**
1615
- * Creates a behavior.
1616
- * @param targets - The targets available for behaviors to be attached to.
1617
- */
1618
- createBehavior(targets) {
1981
+ }
1982
+ class OneTimeBinding extends Binding {
1983
+ createObserver() {
1619
1984
  return this;
1620
1985
  }
1986
+ bind(controller) {
1987
+ return this.evaluate(controller.source, controller.context);
1988
+ }
1621
1989
  }
1622
- function createContentBinding(Type) {
1623
- return class extends Type {
1624
- unbind(source, context, targets) {
1625
- super.unbind(source, context, targets);
1626
- const target = targets[this.directive.nodeId];
1627
- const view = target.$fastView;
1628
- if (view !== void 0 && view.isComposed) {
1629
- view.unbind();
1630
- view.needsBindOnly = true;
1631
- }
1632
- }
1633
- };
1634
- }
1635
- function updateContentTarget(target, aspect, value, source, context) {
1990
+ function updateContent(target, aspect, value, controller) {
1636
1991
  // If there's no actual value, then this equates to the
1637
1992
  // empty string for the purposes of content bindings.
1638
1993
  if (value === null || value === undefined) {
1639
1994
  value = "";
1640
1995
  }
1641
- // If the value has a "create" method, then it's a template-like.
1996
+ // If the value has a "create" method, then it's a ContentTemplate.
1642
1997
  if (value.create) {
1643
1998
  target.textContent = "";
1644
1999
  let view = target.$fastView;
@@ -1664,14 +2019,14 @@ function updateContentTarget(target, aspect, value, source, context) {
1664
2019
  // and that there's actually no need to compose it.
1665
2020
  if (!view.isComposed) {
1666
2021
  view.isComposed = true;
1667
- view.bind(source, context);
2022
+ view.bind(controller.source, controller.context);
1668
2023
  view.insertBefore(target);
1669
2024
  target.$fastView = view;
1670
2025
  target.$fastTemplate = value;
1671
2026
  }
1672
2027
  else if (view.needsBindOnly) {
1673
2028
  view.needsBindOnly = false;
1674
- view.bind(source, context);
2029
+ view.bind(controller.source, controller.context);
1675
2030
  }
1676
2031
  }
1677
2032
  else {
@@ -1691,10 +2046,9 @@ function updateContentTarget(target, aspect, value, source, context) {
1691
2046
  target.textContent = value;
1692
2047
  }
1693
2048
  }
1694
- function updateTokenListTarget(target, aspect, value) {
2049
+ function updateTokenList(target, aspect, value) {
1695
2050
  var _a;
1696
- const directive = this.directive;
1697
- const lookup = `${directive.id}-t`;
2051
+ const lookup = `${this.id}-t`;
1698
2052
  const state = (_a = target[lookup]) !== null && _a !== void 0 ? _a : (target[lookup] = { c: 0, v: Object.create(null) });
1699
2053
  const versions = state.v;
1700
2054
  let currentVersion = state.c;
@@ -1724,311 +2078,8 @@ function updateTokenListTarget(target, aspect, value) {
1724
2078
  }
1725
2079
  }
1726
2080
  }
1727
- /**
1728
- * A binding behavior for one-time bindings.
1729
- * @public
1730
- */
1731
- class OneTimeBinding extends UpdateBinding {
1732
- /**
1733
- * Bind this behavior to the source.
1734
- * @param source - The source to bind to.
1735
- * @param context - The execution context that the binding is operating within.
1736
- * @param targets - The targets that behaviors in a view can attach to.
1737
- */
1738
- bind(source, context, targets) {
1739
- const directive = this.directive;
1740
- this.updateTarget(targets[directive.nodeId], directive.targetAspect, directive.binding(source, context), source, context);
1741
- }
1742
- }
1743
- const signals = Object.create(null);
1744
- /**
1745
- * A binding behavior for signal bindings.
1746
- * @public
1747
- */
1748
- class SignalBinding extends UpdateBinding {
1749
- constructor() {
1750
- super(...arguments);
1751
- this.handlerProperty = `${this.directive.id}-h`;
1752
- }
1753
- /**
1754
- * Bind this behavior to the source.
1755
- * @param source - The source to bind to.
1756
- * @param context - The execution context that the binding is operating within.
1757
- * @param targets - The targets that behaviors in a view can attach to.
1758
- */
1759
- bind(source, context, targets) {
1760
- const directive = this.directive;
1761
- const target = targets[directive.nodeId];
1762
- const signal = this.getSignal(source, context);
1763
- const handler = (target[this.handlerProperty] = () => {
1764
- this.updateTarget(target, directive.targetAspect, directive.binding(source, context), source, context);
1765
- });
1766
- handler();
1767
- const found = signals[signal];
1768
- if (found) {
1769
- Array.isArray(found)
1770
- ? found.push(handler)
1771
- : (signals[signal] = [found, handler]);
1772
- }
1773
- else {
1774
- signals[signal] = handler;
1775
- }
1776
- }
1777
- /**
1778
- * Unbinds this behavior from the source.
1779
- * @param source - The source to unbind from.
1780
- * @param context - The execution context that the binding is operating within.
1781
- * @param targets - The targets that behaviors in a view can attach to.
1782
- */
1783
- unbind(source, context, targets) {
1784
- const signal = this.getSignal(source, context);
1785
- const found = signals[signal];
1786
- if (found && Array.isArray(found)) {
1787
- const directive = this.directive;
1788
- const target = targets[directive.nodeId];
1789
- const handler = target[this.handlerProperty];
1790
- const index = found.indexOf(handler);
1791
- if (index !== -1) {
1792
- found.splice(index, 1);
1793
- }
1794
- }
1795
- else {
1796
- signals[signal] = void 0;
1797
- }
1798
- }
1799
- getSignal(source, context) {
1800
- const options = this.directive.options;
1801
- return isString(options) ? options : options(source, context);
1802
- }
1803
- /**
1804
- * Sends the specified signal to signaled bindings.
1805
- * @param signal - The signal to send.
1806
- * @public
1807
- */
1808
- static send(signal) {
1809
- const found = signals[signal];
1810
- if (found) {
1811
- Array.isArray(found) ? found.forEach(x => x()) : found();
1812
- }
1813
- }
1814
- }
1815
- /**
1816
- * A binding behavior for bindings that change.
1817
- * @public
1818
- */
1819
- class ChangeBinding extends UpdateBinding {
1820
- /**
1821
- * Creates an instance of ChangeBinding.
1822
- * @param directive - The directive that has the configuration for this behavior.
1823
- * @param updateTarget - The function used to update the target with the latest value.
1824
- */
1825
- constructor(directive, updateTarget) {
1826
- super(directive, updateTarget);
1827
- this.isBindingVolatile = Observable.isVolatileBinding(directive.binding);
1828
- this.observerProperty = `${directive.id}-o`;
1829
- }
1830
- /**
1831
- * Returns the binding observer used to update the node.
1832
- * @param target - The target node.
1833
- * @returns A BindingObserver.
1834
- */
1835
- getObserver(target) {
1836
- var _a;
1837
- return ((_a = target[this.observerProperty]) !== null && _a !== void 0 ? _a : (target[this.observerProperty] = Observable.binding(this.directive.binding, this, this.isBindingVolatile)));
1838
- }
1839
- /**
1840
- * Bind this behavior to the source.
1841
- * @param source - The source to bind to.
1842
- * @param context - The execution context that the binding is operating within.
1843
- * @param targets - The targets that behaviors in a view can attach to.
1844
- */
1845
- bind(source, context, targets) {
1846
- const directive = this.directive;
1847
- const target = targets[directive.nodeId];
1848
- const observer = this.getObserver(target);
1849
- observer.target = target;
1850
- observer.source = source;
1851
- observer.context = context;
1852
- this.updateTarget(target, directive.targetAspect, observer.observe(source, context), source, context);
1853
- }
1854
- /**
1855
- * Unbinds this behavior from the source.
1856
- * @param source - The source to unbind from.
1857
- * @param context - The execution context that the binding is operating within.
1858
- * @param targets - The targets that behaviors in a view can attach to.
1859
- */
1860
- unbind(source, context, targets) {
1861
- const target = targets[this.directive.nodeId];
1862
- const observer = this.getObserver(target);
1863
- observer.dispose();
1864
- observer.target = null;
1865
- observer.source = null;
1866
- observer.context = null;
1867
- }
1868
- /** @internal */
1869
- handleChange(binding, observer) {
1870
- const target = observer.target;
1871
- const source = observer.source;
1872
- const context = observer.context;
1873
- this.updateTarget(target, this.directive.targetAspect, observer.observe(source, context), source, context);
1874
- }
1875
- }
1876
- /**
1877
- * A binding behavior for handling events.
1878
- * @public
1879
- */
1880
- class EventBinding {
1881
- /**
1882
- * Creates an instance of EventBinding.
1883
- * @param directive - The directive that has the configuration for this behavior.
1884
- */
1885
- constructor(directive) {
1886
- this.directive = directive;
1887
- this.sourceProperty = `${directive.id}-s`;
1888
- this.contextProperty = `${directive.id}-c`;
1889
- }
1890
- /**
1891
- * Bind this behavior to the source.
1892
- * @param source - The source to bind to.
1893
- * @param context - The execution context that the binding is operating within.
1894
- * @param targets - The targets that behaviors in a view can attach to.
1895
- */
1896
- bind(source, context, targets) {
1897
- const directive = this.directive;
1898
- const target = targets[directive.nodeId];
1899
- target[this.sourceProperty] = source;
1900
- target[this.contextProperty] = context;
1901
- target.addEventListener(directive.targetAspect, this, directive.options);
1902
- }
1903
- /**
1904
- * Unbinds this behavior from the source.
1905
- * @param source - The source to unbind from.
1906
- * @param context - The execution context that the binding is operating within.
1907
- * @param targets - The targets that behaviors in a view can attach to.
1908
- */
1909
- unbind(source, context, targets) {
1910
- const directive = this.directive;
1911
- const target = targets[directive.nodeId];
1912
- target[this.sourceProperty] = target[this.contextProperty] = null;
1913
- target.removeEventListener(directive.targetAspect, this, directive.options);
1914
- }
1915
- /**
1916
- * Creates a behavior.
1917
- * @param targets - The targets available for behaviors to be attached to.
1918
- */
1919
- createBehavior(targets) {
1920
- return this;
1921
- }
1922
- /**
1923
- * @internal
1924
- */
1925
- handleEvent(event) {
1926
- const target = event.currentTarget;
1927
- ExecutionContext.setEvent(event);
1928
- const result = this.directive.binding(target[this.sourceProperty], target[this.contextProperty]);
1929
- ExecutionContext.setEvent(null);
1930
- if (result !== true) {
1931
- event.preventDefault();
1932
- }
1933
- }
1934
- }
1935
- let twoWaySettings = {
1936
- determineChangeEvent() {
1937
- return "change";
1938
- },
1939
- };
1940
- /**
1941
- * A binding behavior for bindings that update in two directions.
1942
- * @public
1943
- */
1944
- class TwoWayBinding extends ChangeBinding {
1945
- /**
1946
- * Bind this behavior to the source.
1947
- * @param source - The source to bind to.
1948
- * @param context - The execution context that the binding is operating within.
1949
- * @param targets - The targets that behaviors in a view can attach to.
1950
- */
1951
- bind(source, context, targets) {
1952
- var _a;
1953
- super.bind(source, context, targets);
1954
- const directive = this.directive;
1955
- const target = targets[directive.nodeId];
1956
- if (!this.changeEvent) {
1957
- this.changeEvent =
1958
- (_a = directive.options.changeEvent) !== null && _a !== void 0 ? _a : twoWaySettings.determineChangeEvent(directive, target);
1959
- }
1960
- target.addEventListener(this.changeEvent, this);
1961
- }
1962
- /**
1963
- * Unbinds this behavior from the source.
1964
- * @param source - The source to unbind from.
1965
- * @param context - The execution context that the binding is operating within.
1966
- * @param targets - The targets that behaviors in a view can attach to.
1967
- */
1968
- unbind(source, context, targets) {
1969
- super.unbind(source, context, targets);
1970
- targets[this.directive.nodeId].removeEventListener(this.changeEvent, this);
1971
- }
1972
- /** @internal */
1973
- handleEvent(event) {
1974
- const directive = this.directive;
1975
- const target = event.currentTarget;
1976
- let value;
1977
- switch (directive.aspectType) {
1978
- case 1:
1979
- value = target.getAttribute(directive.targetAspect);
1980
- break;
1981
- case 2:
1982
- value = target.hasAttribute(directive.targetAspect);
1983
- break;
1984
- case 4:
1985
- value = target.innerText;
1986
- break;
1987
- default:
1988
- value = target[directive.targetAspect];
1989
- break;
1990
- }
1991
- const observer = this.getObserver(target);
1992
- const last = observer.last; // using internal API!!!
1993
- last.propertySource[last.propertyName] = directive.options.fromView(value);
1994
- }
1995
- /**
1996
- * Configures two-way binding.
1997
- * @param settings - The settings to use for the two-way binding system.
1998
- */
1999
- static configure(settings) {
2000
- twoWaySettings = settings;
2001
- }
2002
- }
2003
- /**
2004
- * The default onChange binding configuration.
2005
- * @public
2006
- */
2007
- const onChange = BindingConfig.define(BindingMode.define(ChangeBinding), {});
2008
- /**
2009
- * The default twoWay binding configuration.
2010
- * @public
2011
- */
2012
- const twoWay = BindingConfig.define(BindingMode.define(TwoWayBinding), {
2013
- fromView: v => v,
2014
- });
2015
- /**
2016
- * The default onTime binding configuration.
2017
- * @public
2018
- */
2019
- const oneTime = BindingConfig.define(BindingMode.define(OneTimeBinding), {
2020
- once: true,
2021
- });
2022
- const signalMode = BindingMode.define(SignalBinding);
2023
- /**
2024
- * Creates a signal binding configuration with the supplied options.
2025
- * @param options - The signal name or a binding to use to retrieve the signal name.
2026
- * @returns A binding configuration.
2027
- * @public
2028
- */
2029
- const signal = (options) => {
2030
- return { mode: signalMode, options };
2031
- };
2081
+ const setProperty = (t, a, v) => (t[a] = v);
2082
+ const eventTarget = () => void 0;
2032
2083
  /**
2033
2084
  * A directive that applies bindings.
2034
2085
  * @public
@@ -2036,19 +2087,22 @@ const signal = (options) => {
2036
2087
  class HTMLBindingDirective {
2037
2088
  /**
2038
2089
  * Creates an instance of HTMLBindingDirective.
2039
- * @param binding - The binding to apply.
2040
- * @param mode - The binding mode to use when applying the binding.
2041
- * @param options - The options to configure the binding with.
2090
+ * @param dataBinding - The binding configuration to apply.
2042
2091
  */
2043
- constructor(binding, mode, options) {
2044
- this.binding = binding;
2045
- this.mode = mode;
2046
- this.options = options;
2047
- this.factory = null;
2092
+ constructor(dataBinding) {
2093
+ this.dataBinding = dataBinding;
2094
+ this.updateTarget = null;
2095
+ /**
2096
+ * The unique id of the factory.
2097
+ */
2098
+ this.id = nextId();
2048
2099
  /**
2049
2100
  * The type of aspect to target.
2050
2101
  */
2051
2102
  this.aspectType = Aspect.content;
2103
+ /** @internal */
2104
+ this.bind = this.bindDefault;
2105
+ this.data = `${this.id}-d`;
2052
2106
  }
2053
2107
  /**
2054
2108
  * Creates HTML to be used within a template.
@@ -2059,31 +2113,133 @@ class HTMLBindingDirective {
2059
2113
  }
2060
2114
  /**
2061
2115
  * Creates a behavior.
2062
- * @param targets - The targets available for behaviors to be attached to.
2063
2116
  */
2064
- createBehavior(targets) {
2065
- if (this.factory == null) {
2117
+ createBehavior() {
2118
+ if (this.updateTarget === null) {
2066
2119
  if (this.targetAspect === "innerHTML") {
2067
- this.binding = createInnerHTMLBinding(this.binding);
2120
+ this.dataBinding.evaluate = createInnerHTMLBinding(this.dataBinding.evaluate);
2068
2121
  }
2069
- this.factory = this.mode[this.aspectType](this);
2122
+ switch (this.aspectType) {
2123
+ case 1:
2124
+ this.updateTarget = DOM.setAttribute;
2125
+ break;
2126
+ case 2:
2127
+ this.updateTarget = DOM.setBooleanAttribute;
2128
+ break;
2129
+ case 3:
2130
+ this.updateTarget = setProperty;
2131
+ break;
2132
+ case 4:
2133
+ this.bind = this.bindContent;
2134
+ this.updateTarget = updateContent;
2135
+ break;
2136
+ case 5:
2137
+ this.updateTarget = updateTokenList;
2138
+ break;
2139
+ case 6:
2140
+ this.bind = this.bindEvent;
2141
+ this.updateTarget = eventTarget;
2142
+ break;
2143
+ default:
2144
+ throw FAST.error(1205 /* Message.unsupportedBindingBehavior */);
2145
+ }
2146
+ }
2147
+ return this;
2148
+ }
2149
+ /** @internal */
2150
+ bindDefault(controller) {
2151
+ var _a;
2152
+ const target = controller.targets[this.nodeId];
2153
+ const observer = (_a = target[this.data]) !== null && _a !== void 0 ? _a : (target[this.data] = this.dataBinding.createObserver(this, this));
2154
+ observer.target = target;
2155
+ observer.controller = controller;
2156
+ this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
2157
+ if (this.updateTarget === updateContent) {
2158
+ controller.onUnbind(this);
2159
+ }
2160
+ }
2161
+ /** @internal */
2162
+ bindContent(controller) {
2163
+ this.bindDefault(controller);
2164
+ controller.onUnbind(this);
2165
+ }
2166
+ /** @internal */
2167
+ bindEvent(controller) {
2168
+ const target = controller.targets[this.nodeId];
2169
+ target[this.data] = controller;
2170
+ target.addEventListener(this.targetAspect, this, this.dataBinding.options);
2171
+ }
2172
+ /** @internal */
2173
+ unbind(controller) {
2174
+ const target = controller.targets[this.nodeId];
2175
+ const view = target.$fastView;
2176
+ if (view !== void 0 && view.isComposed) {
2177
+ view.unbind();
2178
+ view.needsBindOnly = true;
2179
+ }
2180
+ }
2181
+ /** @internal */
2182
+ handleEvent(event) {
2183
+ const target = event.currentTarget;
2184
+ ExecutionContext.setEvent(event);
2185
+ const controller = target[this.data];
2186
+ const result = this.dataBinding.evaluate(controller.source, controller.context);
2187
+ ExecutionContext.setEvent(null);
2188
+ if (result !== true) {
2189
+ event.preventDefault();
2070
2190
  }
2071
- return this.factory.createBehavior(targets);
2191
+ }
2192
+ /** @internal */
2193
+ handleChange(binding, observer) {
2194
+ const target = observer.target;
2195
+ const controller = observer.controller;
2196
+ this.updateTarget(target, this.targetAspect, observer.bind(controller), controller);
2072
2197
  }
2073
2198
  }
2074
2199
  HTMLDirective.define(HTMLBindingDirective, { aspected: true });
2075
2200
  /**
2076
- * Creates a binding directive with the specified configuration.
2077
- * @param binding - The binding expression.
2078
- * @param config - The binding configuration.
2079
- * @returns A binding directive.
2201
+ * Creates an standard binding.
2202
+ * @param binding - The binding to refresh when changed.
2203
+ * @param isVolatile - Indicates whether the binding is volatile or not.
2204
+ * @returns A binding configuration.
2205
+ * @public
2206
+ */
2207
+ function bind(binding, isVolatile = Observable.isVolatileBinding(binding)) {
2208
+ return new OnChangeBinding(binding, isVolatile);
2209
+ }
2210
+ /**
2211
+ * Creates a one time binding
2212
+ * @param binding - The binding to refresh when signaled.
2213
+ * @returns A binding configuration.
2080
2214
  * @public
2081
2215
  */
2082
- function bind(binding, config = onChange) {
2083
- if (!("mode" in config)) {
2084
- config = onChange(config);
2085
- }
2086
- return new HTMLBindingDirective(binding, config.mode, config.options);
2216
+ function oneTime(binding) {
2217
+ return new OneTimeBinding(binding);
2218
+ }
2219
+ /**
2220
+ * Creates an event listener binding.
2221
+ * @param binding - The binding to invoke when the event is raised.
2222
+ * @param options - Event listener options.
2223
+ * @returns A binding configuration.
2224
+ * @public
2225
+ */
2226
+ function listener(binding, options) {
2227
+ const config = new OnChangeBinding(binding, false);
2228
+ config.options = options;
2229
+ return config;
2230
+ }
2231
+ /**
2232
+ * Normalizes the input value into a binding.
2233
+ * @param value - The value to create the default binding for.
2234
+ * @returns A binding configuration for the provided value.
2235
+ * @public
2236
+ */
2237
+ function normalizeBinding(value) {
2238
+ return isFunction(value)
2239
+ ? bind(value)
2240
+ : value instanceof Binding
2241
+ ? value
2242
+ : oneTime(() => value);
2087
2243
  }
2088
2244
 
2089
2245
  function removeNodeSequence(firstNode, lastNode) {
@@ -2112,17 +2268,87 @@ class HTMLView {
2112
2268
  this.factories = factories;
2113
2269
  this.targets = targets;
2114
2270
  this.behaviors = null;
2271
+ this.unbindables = [];
2115
2272
  /**
2116
2273
  * The data that the view is bound to.
2117
2274
  */
2118
2275
  this.source = null;
2276
+ /**
2277
+ * Indicates whether the controller is bound.
2278
+ */
2279
+ this.isBound = false;
2280
+ /**
2281
+ * Indicates how the source's lifetime relates to the controller's lifetime.
2282
+ */
2283
+ this.sourceLifetime = SourceLifetime.unknown;
2119
2284
  /**
2120
2285
  * The execution context the view is running within.
2121
2286
  */
2122
- this.context = null;
2287
+ this.context = this;
2288
+ /**
2289
+ * The index of the current item within a repeat context.
2290
+ */
2291
+ this.index = 0;
2292
+ /**
2293
+ * The length of the current collection within a repeat context.
2294
+ */
2295
+ this.length = 0;
2123
2296
  this.firstChild = fragment.firstChild;
2124
2297
  this.lastChild = fragment.lastChild;
2125
2298
  }
2299
+ /**
2300
+ * The current event within an event handler.
2301
+ */
2302
+ get event() {
2303
+ return ExecutionContext.getEvent();
2304
+ }
2305
+ /**
2306
+ * Indicates whether the current item within a repeat context
2307
+ * has an even index.
2308
+ */
2309
+ get isEven() {
2310
+ return this.index % 2 === 0;
2311
+ }
2312
+ /**
2313
+ * Indicates whether the current item within a repeat context
2314
+ * has an odd index.
2315
+ */
2316
+ get isOdd() {
2317
+ return this.index % 2 !== 0;
2318
+ }
2319
+ /**
2320
+ * Indicates whether the current item within a repeat context
2321
+ * is the first item in the collection.
2322
+ */
2323
+ get isFirst() {
2324
+ return this.index === 0;
2325
+ }
2326
+ /**
2327
+ * Indicates whether the current item within a repeat context
2328
+ * is somewhere in the middle of the collection.
2329
+ */
2330
+ get isInMiddle() {
2331
+ return !this.isFirst && !this.isLast;
2332
+ }
2333
+ /**
2334
+ * Indicates whether the current item within a repeat context
2335
+ * is the last item in the collection.
2336
+ */
2337
+ get isLast() {
2338
+ return this.index === this.length - 1;
2339
+ }
2340
+ /**
2341
+ * Returns the typed event detail of a custom event.
2342
+ */
2343
+ eventDetail() {
2344
+ return this.event.detail;
2345
+ }
2346
+ /**
2347
+ * Returns the typed event target of the event.
2348
+ */
2349
+ eventTarget() {
2350
+ return this.event.target;
2351
+ }
2126
2352
  /**
2127
2353
  * Appends the view's DOM nodes to the referenced node.
2128
2354
  * @param node - The parent node to append the view's DOM nodes to.
@@ -2139,8 +2365,10 @@ class HTMLView {
2139
2365
  node.parentNode.insertBefore(this.fragment, node);
2140
2366
  }
2141
2367
  else {
2142
- const parentNode = node.parentNode;
2143
2368
  const end = this.lastChild;
2369
+ if (node.previousSibling === end)
2370
+ return;
2371
+ const parentNode = node.parentNode;
2144
2372
  let current = this.firstChild;
2145
2373
  let next;
2146
2374
  while (current !== end) {
@@ -2175,58 +2403,61 @@ class HTMLView {
2175
2403
  removeNodeSequence(this.firstChild, this.lastChild);
2176
2404
  this.unbind();
2177
2405
  }
2406
+ onUnbind(behavior) {
2407
+ this.unbindables.push(behavior);
2408
+ }
2178
2409
  /**
2179
2410
  * Binds a view's behaviors to its binding source.
2180
2411
  * @param source - The binding source for the view's binding behaviors.
2181
2412
  * @param context - The execution context to run the behaviors within.
2182
2413
  */
2183
- bind(source, context) {
2184
- let behaviors = this.behaviors;
2185
- const oldSource = this.source;
2186
- if (oldSource === source) {
2414
+ bind(source, context = this) {
2415
+ if (this.source === source) {
2187
2416
  return;
2188
2417
  }
2189
- this.source = source;
2190
- this.context = context;
2191
- const targets = this.targets;
2192
- if (oldSource !== null) {
2193
- for (let i = 0, ii = behaviors.length; i < ii; ++i) {
2194
- const current = behaviors[i];
2195
- current.unbind(oldSource, context, targets);
2196
- current.bind(source, context, targets);
2197
- }
2198
- }
2199
- else if (behaviors === null) {
2418
+ let behaviors = this.behaviors;
2419
+ if (behaviors === null) {
2420
+ this.source = source;
2421
+ this.context = context;
2200
2422
  this.behaviors = behaviors = new Array(this.factories.length);
2201
2423
  const factories = this.factories;
2202
2424
  for (let i = 0, ii = factories.length; i < ii; ++i) {
2203
- const behavior = factories[i].createBehavior(targets);
2204
- behavior.bind(source, context, targets);
2425
+ const behavior = factories[i].createBehavior();
2426
+ behavior.bind(this);
2205
2427
  behaviors[i] = behavior;
2206
2428
  }
2207
2429
  }
2208
2430
  else {
2431
+ if (this.source !== null) {
2432
+ this.evaluateUnbindables();
2433
+ }
2434
+ this.isBound = false;
2435
+ this.source = source;
2436
+ this.context = context;
2209
2437
  for (let i = 0, ii = behaviors.length; i < ii; ++i) {
2210
- behaviors[i].bind(source, context, targets);
2438
+ behaviors[i].bind(this);
2211
2439
  }
2212
2440
  }
2441
+ this.isBound = true;
2213
2442
  }
2214
2443
  /**
2215
2444
  * Unbinds a view's behaviors from its binding source.
2216
2445
  */
2217
2446
  unbind() {
2218
- const oldSource = this.source;
2219
- if (oldSource === null) {
2447
+ if (!this.isBound || this.source === null) {
2220
2448
  return;
2221
2449
  }
2222
- const targets = this.targets;
2223
- const context = this.context;
2224
- const behaviors = this.behaviors;
2225
- for (let i = 0, ii = behaviors.length; i < ii; ++i) {
2226
- behaviors[i].unbind(oldSource, context, targets);
2227
- }
2450
+ this.evaluateUnbindables();
2228
2451
  this.source = null;
2229
- this.context = null;
2452
+ this.context = this;
2453
+ this.isBound = false;
2454
+ }
2455
+ evaluateUnbindables() {
2456
+ const unbindables = this.unbindables;
2457
+ for (let i = 0, ii = unbindables.length; i < ii; ++i) {
2458
+ unbindables[i].unbind(this);
2459
+ }
2460
+ unbindables.length = 0;
2230
2461
  }
2231
2462
  /**
2232
2463
  * Efficiently disposes of a contiguous range of synthetic view instances.
@@ -2242,6 +2473,8 @@ class HTMLView {
2242
2473
  }
2243
2474
  }
2244
2475
  }
2476
+ Observable.defineProperty(HTMLView.prototype, "index");
2477
+ Observable.defineProperty(HTMLView.prototype, "length");
2245
2478
 
2246
2479
  const targetIdFrom = (parentId, nodeIndex) => `${parentId}.${nodeIndex}`;
2247
2480
  const descriptorCache = {};
@@ -2250,6 +2483,22 @@ const next = {
2250
2483
  index: 0,
2251
2484
  node: null,
2252
2485
  };
2486
+ function tryWarn(name) {
2487
+ if (!name.startsWith("fast-")) {
2488
+ FAST.warn(1204 /* Message.hostBindingWithoutHost */, { name });
2489
+ }
2490
+ }
2491
+ const warningHost = new Proxy(document.createElement("div"), {
2492
+ get(target, property) {
2493
+ tryWarn(property);
2494
+ const value = Reflect.get(target, property);
2495
+ return isFunction(value) ? value.bind(target) : value;
2496
+ },
2497
+ set(target, property, value) {
2498
+ tryWarn(property);
2499
+ return Reflect.set(target, property, value);
2500
+ },
2501
+ });
2253
2502
  class CompilationContext {
2254
2503
  constructor(fragment, directives) {
2255
2504
  this.fragment = fragment;
@@ -2300,7 +2549,7 @@ class CompilationContext {
2300
2549
  const fragment = this.fragment.cloneNode(true);
2301
2550
  const targets = Object.create(this.proto);
2302
2551
  targets.r = fragment;
2303
- targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget : fragment;
2552
+ targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget : warningHost;
2304
2553
  for (const id of this.nodeIds) {
2305
2554
  targets[id]; // trigger locator
2306
2555
  }
@@ -2317,7 +2566,7 @@ function compileAttributes(context, parentId, node, nodeId, nodeIndex, includeBa
2317
2566
  let result = null;
2318
2567
  if (parseResult === null) {
2319
2568
  if (includeBasicValues) {
2320
- result = bind(() => attrValue, oneTime);
2569
+ result = new HTMLBindingDirective(oneTime(() => attrValue));
2321
2570
  Aspect.assign(result, attr.name);
2322
2571
  }
2323
2572
  }
@@ -2354,6 +2603,7 @@ function compileContent(context, node, parentId, nodeId, nodeIndex) {
2354
2603
  }
2355
2604
  else {
2356
2605
  currentNode.textContent = " ";
2606
+ Aspect.assign(currentPart);
2357
2607
  context.addFactory(currentPart, parentId, nodeId, nodeIndex);
2358
2608
  }
2359
2609
  lastNode = currentNode;
@@ -2486,22 +2736,28 @@ const Compiler = {
2486
2736
  return parts[0];
2487
2737
  }
2488
2738
  let sourceAspect;
2739
+ let binding;
2740
+ let isVolatile = false;
2489
2741
  const partCount = parts.length;
2490
2742
  const finalParts = parts.map((x) => {
2491
2743
  if (isString(x)) {
2492
2744
  return () => x;
2493
2745
  }
2494
2746
  sourceAspect = x.sourceAspect || sourceAspect;
2495
- return x.binding;
2747
+ binding = x.dataBinding || binding;
2748
+ isVolatile = isVolatile || x.dataBinding.isVolatile;
2749
+ return x.dataBinding.evaluate;
2496
2750
  });
2497
- const binding = (scope, context) => {
2751
+ const expression = (scope, context) => {
2498
2752
  let output = "";
2499
2753
  for (let i = 0; i < partCount; ++i) {
2500
2754
  output += finalParts[i](scope, context);
2501
2755
  }
2502
2756
  return output;
2503
2757
  };
2504
- const directive = bind(binding);
2758
+ binding.evaluate = expression;
2759
+ binding.isVolatile = isVolatile;
2760
+ const directive = new HTMLBindingDirective(binding);
2505
2761
  Aspect.assign(directive, sourceAspect);
2506
2762
  return directive;
2507
2763
  },
@@ -2539,9 +2795,9 @@ class ViewTemplate {
2539
2795
  * @param hostBindingTarget - An HTML element to target the host bindings at if different from the
2540
2796
  * host that the template is being attached to.
2541
2797
  */
2542
- render(source, host, hostBindingTarget, context) {
2543
- const view = this.create(hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget : host);
2544
- view.bind(source, context !== null && context !== void 0 ? context : ExecutionContext.default);
2798
+ render(source, host, hostBindingTarget) {
2799
+ const view = this.create(hostBindingTarget);
2800
+ view.bind(source);
2545
2801
  view.appendTo(host);
2546
2802
  return view;
2547
2803
  }
@@ -2581,12 +2837,12 @@ function html(strings, ...values) {
2581
2837
  let definition;
2582
2838
  html += currentString;
2583
2839
  if (isFunction(currentValue)) {
2584
- html += createAspectedHTML(bind(currentValue), currentString, add);
2840
+ html += createAspectedHTML(new HTMLBindingDirective(bind(currentValue)), currentString, add);
2585
2841
  }
2586
2842
  else if (isString(currentValue)) {
2587
2843
  const match = lastAttributeNameRegex.exec(currentString);
2588
2844
  if (match !== null) {
2589
- const directive = bind(() => currentValue, oneTime);
2845
+ const directive = new HTMLBindingDirective(oneTime(() => currentValue));
2590
2846
  Aspect.assign(directive, match[2]);
2591
2847
  html += directive.createHTML(add);
2592
2848
  }
@@ -2594,8 +2850,11 @@ function html(strings, ...values) {
2594
2850
  html += currentValue;
2595
2851
  }
2596
2852
  }
2853
+ else if (currentValue instanceof Binding) {
2854
+ html += createAspectedHTML(new HTMLBindingDirective(currentValue), currentString, add);
2855
+ }
2597
2856
  else if ((definition = HTMLDirective.getForInstance(currentValue)) === void 0) {
2598
- html += createAspectedHTML(bind(() => currentValue, oneTime), currentString, add);
2857
+ html += createAspectedHTML(new HTMLBindingDirective(oneTime(() => currentValue)), currentString, add);
2599
2858
  }
2600
2859
  else {
2601
2860
  if (definition.aspected) {
@@ -2608,26 +2867,6 @@ function html(strings, ...values) {
2608
2867
  }
2609
2868
  return new ViewTemplate(html + strings[strings.length - 1], factories);
2610
2869
  }
2611
- /**
2612
- * Transforms a template literal string into a ChildViewTemplate.
2613
- * @param strings - The string fragments that are interpolated with the values.
2614
- * @param values - The values that are interpolated with the string fragments.
2615
- * @remarks
2616
- * The html helper supports interpolation of strings, numbers, binding expressions,
2617
- * other template instances, and Directive instances.
2618
- * @public
2619
- */
2620
- const child = html;
2621
- /**
2622
- * Transforms a template literal string into an ItemViewTemplate.
2623
- * @param strings - The string fragments that are interpolated with the values.
2624
- * @param values - The values that are interpolated with the string fragments.
2625
- * @remarks
2626
- * The html helper supports interpolation of strings, numbers, binding expressions,
2627
- * other template instances, and Directive instances.
2628
- * @public
2629
- */
2630
- const item = html;
2631
2870
 
2632
2871
  /**
2633
2872
  * The runtime behavior for template references.
@@ -2635,20 +2874,12 @@ const item = html;
2635
2874
  */
2636
2875
  class RefDirective extends StatelessAttachedAttributeDirective {
2637
2876
  /**
2638
- * Bind this behavior to the source.
2639
- * @param source - The source to bind to.
2640
- * @param context - The execution context that the binding is operating within.
2641
- * @param targets - The targets that behaviors in a view can attach to.
2877
+ * Bind this behavior.
2878
+ * @param controller - The view controller that manages the lifecycle of this behavior.
2642
2879
  */
2643
- bind(source, context, targets) {
2644
- source[this.options] = targets[this.nodeId];
2880
+ bind(controller) {
2881
+ controller.source[this.options] = controller.targets[this.nodeId];
2645
2882
  }
2646
- /**
2647
- * Unbinds this behavior from the source.
2648
- * @param source - The source to unbind from.
2649
- */
2650
- /* eslint-disable-next-line @typescript-eslint/no-empty-function */
2651
- unbind() { }
2652
2883
  }
2653
2884
  HTMLDirective.define(RefDirective);
2654
2885
  /**
@@ -2660,27 +2891,34 @@ const ref = (propertyName) => new RefDirective(propertyName);
2660
2891
 
2661
2892
  /**
2662
2893
  * A directive that enables basic conditional rendering in a template.
2663
- * @param binding - The condition to test for rendering.
2894
+ * @param condition - The condition to test for rendering.
2664
2895
  * @param templateOrTemplateBinding - The template or a binding that gets
2665
2896
  * the template to render when the condition is true.
2666
2897
  * @public
2667
2898
  */
2668
- function when(binding, templateOrTemplateBinding) {
2669
- const getTemplate = isFunction(templateOrTemplateBinding)
2899
+ function when(condition, templateOrTemplateBinding) {
2900
+ const dataBinding = isFunction(condition) ? condition : () => condition;
2901
+ const templateBinding = isFunction(templateOrTemplateBinding)
2670
2902
  ? templateOrTemplateBinding
2671
2903
  : () => templateOrTemplateBinding;
2672
- return (source, context) => binding(source, context) ? getTemplate(source, context) : null;
2904
+ return (source, context) => dataBinding(source, context) ? templateBinding(source, context) : null;
2673
2905
  }
2674
2906
 
2675
2907
  const defaultRepeatOptions = Object.freeze({
2676
2908
  positioning: false,
2677
2909
  recycle: true,
2678
2910
  });
2679
- function bindWithoutPositioning(view, items, index, context) {
2680
- view.bind(items[index], context);
2911
+ function bindWithoutPositioning(view, items, index, controller) {
2912
+ view.context.parent = controller.source;
2913
+ view.context.parentContext = controller.context;
2914
+ view.bind(items[index]);
2681
2915
  }
2682
- function bindWithPositioning(view, items, index, context) {
2683
- view.bind(items[index], context.createItemContext(index, items.length));
2916
+ function bindWithPositioning(view, items, index, controller) {
2917
+ view.context.parent = controller.source;
2918
+ view.context.parentContext = controller.context;
2919
+ view.context.length = items.length;
2920
+ view.context.index = index;
2921
+ view.bind(items[index]);
2684
2922
  }
2685
2923
  /**
2686
2924
  * A behavior that renders a template for each item in an array.
@@ -2690,57 +2928,45 @@ class RepeatBehavior {
2690
2928
  /**
2691
2929
  * Creates an instance of RepeatBehavior.
2692
2930
  * @param location - The location in the DOM to render the repeat.
2693
- * @param itemsBinding - The array to render.
2931
+ * @param dataBinding - The array to render.
2694
2932
  * @param isItemsBindingVolatile - Indicates whether the items binding has volatile dependencies.
2695
2933
  * @param templateBinding - The template to render for each item.
2696
2934
  * @param isTemplateBindingVolatile - Indicates whether the template binding has volatile dependencies.
2697
2935
  * @param options - Options used to turn on special repeat features.
2698
2936
  */
2699
- constructor(location, itemsBinding, isItemsBindingVolatile, templateBinding, isTemplateBindingVolatile, options) {
2700
- this.location = location;
2701
- this.itemsBinding = itemsBinding;
2702
- this.templateBinding = templateBinding;
2703
- this.options = options;
2704
- this.source = null;
2937
+ constructor(directive) {
2938
+ this.directive = directive;
2705
2939
  this.views = [];
2706
2940
  this.items = null;
2707
2941
  this.itemsObserver = null;
2708
- this.context = void 0;
2709
- this.childContext = void 0;
2710
2942
  this.bindView = bindWithoutPositioning;
2711
- this.itemsBindingObserver = Observable.binding(itemsBinding, this, isItemsBindingVolatile);
2712
- this.templateBindingObserver = Observable.binding(templateBinding, this, isTemplateBindingVolatile);
2713
- if (options.positioning) {
2943
+ this.itemsBindingObserver = directive.dataBinding.createObserver(directive, this);
2944
+ this.templateBindingObserver = directive.templateBinding.createObserver(directive, this);
2945
+ if (directive.options.positioning) {
2714
2946
  this.bindView = bindWithPositioning;
2715
2947
  }
2716
2948
  }
2717
2949
  /**
2718
- * Bind this behavior to the source.
2719
- * @param source - The source to bind to.
2720
- * @param context - The execution context that the binding is operating within.
2950
+ * Bind this behavior.
2951
+ * @param controller - The view controller that manages the lifecycle of this behavior.
2721
2952
  */
2722
- bind(source, context) {
2723
- this.source = source;
2724
- this.context = context;
2725
- this.childContext = context.createChildContext(source);
2726
- this.items = this.itemsBindingObserver.observe(source, this.context);
2727
- this.template = this.templateBindingObserver.observe(source, this.context);
2953
+ bind(controller) {
2954
+ this.location = controller.targets[this.directive.nodeId];
2955
+ this.controller = controller;
2956
+ this.items = this.itemsBindingObserver.bind(controller);
2957
+ this.template = this.templateBindingObserver.bind(controller);
2728
2958
  this.observeItems(true);
2729
2959
  this.refreshAllViews();
2960
+ controller.onUnbind(this);
2730
2961
  }
2731
2962
  /**
2732
- * Unbinds this behavior from the source.
2733
- * @param source - The source to unbind from.
2963
+ * Unbinds this behavior.
2734
2964
  */
2735
2965
  unbind() {
2736
- this.source = null;
2737
- this.items = null;
2738
2966
  if (this.itemsObserver !== null) {
2739
2967
  this.itemsObserver.unsubscribe(this);
2740
2968
  }
2741
2969
  this.unbindAllViews();
2742
- this.itemsBindingObserver.dispose();
2743
- this.templateBindingObserver.dispose();
2744
2970
  }
2745
2971
  /**
2746
2972
  * Handles changes in the array, its items, and the repeat template.
@@ -2748,15 +2974,18 @@ class RepeatBehavior {
2748
2974
  * @param args - The details about what was changed.
2749
2975
  */
2750
2976
  handleChange(source, args) {
2751
- if (source === this.itemsBinding) {
2752
- this.items = this.itemsBindingObserver.observe(this.source, this.context);
2977
+ if (args === this.itemsBindingObserver) {
2978
+ this.items = this.itemsBindingObserver.bind(this.controller);
2753
2979
  this.observeItems();
2754
2980
  this.refreshAllViews();
2755
2981
  }
2756
- else if (source === this.templateBinding) {
2757
- this.template = this.templateBindingObserver.observe(this.source, this.context);
2982
+ else if (args === this.templateBindingObserver) {
2983
+ this.template = this.templateBindingObserver.bind(this.controller);
2758
2984
  this.refreshAllViews(true);
2759
2985
  }
2986
+ else if (!args[0]) {
2987
+ return;
2988
+ }
2760
2989
  else if (args[0].reset) {
2761
2990
  this.refreshAllViews();
2762
2991
  }
@@ -2781,39 +3010,57 @@ class RepeatBehavior {
2781
3010
  }
2782
3011
  updateViews(splices) {
2783
3012
  const views = this.views;
2784
- const childContext = this.childContext;
2785
- const totalRemoved = [];
2786
3013
  const bindView = this.bindView;
2787
- let removeDelta = 0;
2788
- for (let i = 0, ii = splices.length; i < ii; ++i) {
2789
- const splice = splices[i];
2790
- const removed = splice.removed;
2791
- totalRemoved.push(...views.splice(splice.index + removeDelta, removed.length));
2792
- removeDelta -= splice.addedCount;
2793
- }
2794
3014
  const items = this.items;
2795
3015
  const template = this.template;
3016
+ const controller = this.controller;
3017
+ const recycle = this.directive.options.recycle;
3018
+ const leftoverViews = [];
3019
+ let leftoverIndex = 0;
3020
+ let availableViews = 0;
2796
3021
  for (let i = 0, ii = splices.length; i < ii; ++i) {
2797
3022
  const splice = splices[i];
3023
+ const removed = splice.removed;
3024
+ let removeIndex = 0;
2798
3025
  let addIndex = splice.index;
2799
3026
  const end = addIndex + splice.addedCount;
3027
+ const removedViews = views.splice(splice.index, removed.length);
3028
+ const totalAvailableViews = (availableViews =
3029
+ leftoverViews.length + removedViews.length);
2800
3030
  for (; addIndex < end; ++addIndex) {
2801
3031
  const neighbor = views[addIndex];
2802
3032
  const location = neighbor ? neighbor.firstChild : this.location;
2803
- const view = this.options.recycle && totalRemoved.length > 0
2804
- ? totalRemoved.shift()
2805
- : template.create();
3033
+ let view;
3034
+ if (recycle && availableViews > 0) {
3035
+ if (removeIndex <= totalAvailableViews && removedViews.length > 0) {
3036
+ view = removedViews[removeIndex];
3037
+ removeIndex++;
3038
+ }
3039
+ else {
3040
+ view = leftoverViews[leftoverIndex];
3041
+ leftoverIndex++;
3042
+ }
3043
+ availableViews--;
3044
+ }
3045
+ else {
3046
+ view = template.create();
3047
+ }
2806
3048
  views.splice(addIndex, 0, view);
2807
- bindView(view, items, addIndex, childContext);
3049
+ bindView(view, items, addIndex, controller);
2808
3050
  view.insertBefore(location);
2809
3051
  }
3052
+ if (removedViews[removeIndex]) {
3053
+ leftoverViews.push(...removedViews.slice(removeIndex));
3054
+ }
2810
3055
  }
2811
- for (let i = 0, ii = totalRemoved.length; i < ii; ++i) {
2812
- totalRemoved[i].dispose();
3056
+ for (let i = leftoverIndex, ii = leftoverViews.length; i < ii; ++i) {
3057
+ leftoverViews[i].dispose();
2813
3058
  }
2814
- if (this.options.positioning) {
3059
+ if (this.directive.options.positioning) {
2815
3060
  for (let i = 0, ii = views.length; i < ii; ++i) {
2816
- views[i].context.updatePosition(i, ii);
3061
+ const context = views[i].context;
3062
+ context.length = i;
3063
+ context.index = ii;
2817
3064
  }
2818
3065
  }
2819
3066
  }
@@ -2822,11 +3069,11 @@ class RepeatBehavior {
2822
3069
  const template = this.template;
2823
3070
  const location = this.location;
2824
3071
  const bindView = this.bindView;
2825
- const childContext = this.childContext;
3072
+ const controller = this.controller;
2826
3073
  let itemsLength = items.length;
2827
3074
  let views = this.views;
2828
3075
  let viewsLength = views.length;
2829
- if (itemsLength === 0 || templateChanged) {
3076
+ if (itemsLength === 0 || templateChanged || !this.directive.options.recycle) {
2830
3077
  // all views need to be removed
2831
3078
  HTMLView.disposeContiguousBatch(views);
2832
3079
  viewsLength = 0;
@@ -2836,7 +3083,7 @@ class RepeatBehavior {
2836
3083
  this.views = views = new Array(itemsLength);
2837
3084
  for (let i = 0; i < itemsLength; ++i) {
2838
3085
  const view = template.create();
2839
- bindView(view, items, i, childContext);
3086
+ bindView(view, items, i, controller);
2840
3087
  views[i] = view;
2841
3088
  view.insertBefore(location);
2842
3089
  }
@@ -2847,11 +3094,11 @@ class RepeatBehavior {
2847
3094
  for (; i < itemsLength; ++i) {
2848
3095
  if (i < viewsLength) {
2849
3096
  const view = views[i];
2850
- bindView(view, items, i, childContext);
3097
+ bindView(view, items, i, controller);
2851
3098
  }
2852
3099
  else {
2853
3100
  const view = template.create();
2854
- bindView(view, items, i, childContext);
3101
+ bindView(view, items, i, controller);
2855
3102
  views.push(view);
2856
3103
  view.insertBefore(location);
2857
3104
  }
@@ -2876,17 +3123,19 @@ class RepeatBehavior {
2876
3123
  class RepeatDirective {
2877
3124
  /**
2878
3125
  * Creates an instance of RepeatDirective.
2879
- * @param itemsBinding - The binding that provides the array to render.
3126
+ * @param dataBinding - The binding that provides the array to render.
2880
3127
  * @param templateBinding - The template binding used to obtain a template to render for each item in the array.
2881
3128
  * @param options - Options used to turn on special repeat features.
2882
3129
  */
2883
- constructor(itemsBinding, templateBinding, options) {
2884
- this.itemsBinding = itemsBinding;
3130
+ constructor(dataBinding, templateBinding, options) {
3131
+ this.dataBinding = dataBinding;
2885
3132
  this.templateBinding = templateBinding;
2886
3133
  this.options = options;
3134
+ /**
3135
+ * The unique id of the factory.
3136
+ */
3137
+ this.id = nextId();
2887
3138
  ArrayObserver.enable();
2888
- this.isItemsBindingVolatile = Observable.isVolatileBinding(itemsBinding);
2889
- this.isTemplateBindingVolatile = Observable.isVolatileBinding(templateBinding);
2890
3139
  }
2891
3140
  /**
2892
3141
  * Creates a placeholder string based on the directive's index within the template.
@@ -2899,16 +3148,23 @@ class RepeatDirective {
2899
3148
  * Creates a behavior for the provided target node.
2900
3149
  * @param target - The node instance to create the behavior for.
2901
3150
  */
2902
- createBehavior(targets) {
2903
- return new RepeatBehavior(targets[this.nodeId], this.itemsBinding, this.isItemsBindingVolatile, this.templateBinding, this.isTemplateBindingVolatile, this.options);
3151
+ createBehavior() {
3152
+ return new RepeatBehavior(this);
2904
3153
  }
2905
3154
  }
2906
3155
  HTMLDirective.define(RepeatDirective);
2907
- function repeat(itemsBinding, templateOrTemplateBinding, options = defaultRepeatOptions) {
2908
- const templateBinding = isFunction(templateOrTemplateBinding)
2909
- ? templateOrTemplateBinding
2910
- : () => templateOrTemplateBinding;
2911
- return new RepeatDirective(itemsBinding, templateBinding, options);
3156
+ /**
3157
+ * A directive that enables list rendering.
3158
+ * @param items - The array to render.
3159
+ * @param template - The template or a template binding used obtain a template
3160
+ * to render for each item in the array.
3161
+ * @param options - Options used to turn on special repeat features.
3162
+ * @public
3163
+ */
3164
+ function repeat(items, template, options = defaultRepeatOptions) {
3165
+ const dataBinding = normalizeBinding(items);
3166
+ const templateBinding = normalizeBinding(template);
3167
+ return new RepeatDirective(dataBinding, templateBinding, Object.assign(Object.assign({}, defaultRepeatOptions), options));
2912
3168
  }
2913
3169
 
2914
3170
  const selectElements = (value) => value.nodeType === 1;
@@ -2937,11 +3193,12 @@ class NodeObservationDirective extends StatelessAttachedAttributeDirective {
2937
3193
  * @param context - The execution context that the binding is operating within.
2938
3194
  * @param targets - The targets that behaviors in a view can attach to.
2939
3195
  */
2940
- bind(source, context, targets) {
2941
- const target = targets[this.nodeId];
2942
- target[this.sourceProperty] = source;
2943
- this.updateTarget(source, this.computeNodes(target));
3196
+ bind(controller) {
3197
+ const target = controller.targets[this.nodeId];
3198
+ target[this.sourceProperty] = controller.source;
3199
+ this.updateTarget(controller.source, this.computeNodes(target));
2944
3200
  this.observe(target);
3201
+ controller.onUnbind(this);
2945
3202
  }
2946
3203
  /**
2947
3204
  * Unbinds this behavior from the source.
@@ -2949,9 +3206,9 @@ class NodeObservationDirective extends StatelessAttachedAttributeDirective {
2949
3206
  * @param context - The execution context that the binding is operating within.
2950
3207
  * @param targets - The targets that behaviors in a view can attach to.
2951
3208
  */
2952
- unbind(source, context, targets) {
2953
- const target = targets[this.nodeId];
2954
- this.updateTarget(source, emptyArray);
3209
+ unbind(controller) {
3210
+ const target = controller.targets[this.nodeId];
3211
+ this.updateTarget(controller.source, emptyArray);
2955
3212
  this.disconnect(target);
2956
3213
  target[this.sourceProperty] = null;
2957
3214
  }
@@ -3100,6 +3357,16 @@ function children(propertyOrOptions) {
3100
3357
 
3101
3358
  const booleanMode = "boolean";
3102
3359
  const reflectMode = "reflect";
3360
+ /**
3361
+ * Metadata used to configure a custom attribute's behavior.
3362
+ * @public
3363
+ */
3364
+ const AttributeConfiguration = Object.freeze({
3365
+ /**
3366
+ * Locates all attribute configurations associated with a type.
3367
+ */
3368
+ locate: createMetadataLocator(),
3369
+ });
3103
3370
  /**
3104
3371
  * A {@link ValueConverter} that converts to and from `boolean` values.
3105
3372
  * @remarks
@@ -3237,7 +3504,7 @@ class AttributeDefinition {
3237
3504
  */
3238
3505
  static collect(Owner, ...attributeLists) {
3239
3506
  const attributes = [];
3240
- attributeLists.push(Owner.attributes);
3507
+ attributeLists.push(AttributeConfiguration.locate(Owner));
3241
3508
  for (let i = 0, ii = attributeLists.length; i < ii; ++i) {
3242
3509
  const list = attributeLists[i];
3243
3510
  if (list === void 0) {
@@ -3267,9 +3534,7 @@ function attr(configOrTarget, prop) {
3267
3534
  // - @attr({...opts})
3268
3535
  config.property = $prop;
3269
3536
  }
3270
- const attributes = $target.constructor.attributes ||
3271
- ($target.constructor.attributes = []);
3272
- attributes.push(config);
3537
+ AttributeConfiguration.locate($target.constructor).push(config);
3273
3538
  }
3274
3539
  if (arguments.length > 1) {
3275
3540
  // Non invocation:
@@ -3287,25 +3552,24 @@ function attr(configOrTarget, prop) {
3287
3552
 
3288
3553
  const defaultShadowOptions = { mode: "open" };
3289
3554
  const defaultElementOptions = {};
3555
+ const fastElementBaseTypes = new Set();
3290
3556
  const fastElementRegistry = FAST.getById(4 /* KernelServiceId.elementRegistry */, () => createTypeRegistry());
3291
3557
  /**
3292
3558
  * Defines metadata for a FASTElement.
3293
3559
  * @public
3294
3560
  */
3295
3561
  class FASTElementDefinition {
3296
- /**
3297
- * Creates an instance of FASTElementDefinition.
3298
- * @param type - The type this definition is being created for.
3299
- * @param nameOrConfig - The name of the element to define or a config object
3300
- * that describes the element to define.
3301
- */
3302
3562
  constructor(type, nameOrConfig = type.definition) {
3563
+ var _a;
3564
+ this.platformDefined = false;
3303
3565
  if (isString(nameOrConfig)) {
3304
3566
  nameOrConfig = { name: nameOrConfig };
3305
3567
  }
3306
3568
  this.type = type;
3307
3569
  this.name = nameOrConfig.name;
3308
3570
  this.template = nameOrConfig.template;
3571
+ this.registry = (_a = nameOrConfig.registry) !== null && _a !== void 0 ? _a : customElements;
3572
+ const proto = type.prototype;
3309
3573
  const attributes = AttributeDefinition.collect(type, nameOrConfig.attributes);
3310
3574
  const observedAttributes = new Array(attributes.length);
3311
3575
  const propertyLookup = {};
@@ -3315,9 +3579,13 @@ class FASTElementDefinition {
3315
3579
  observedAttributes[i] = current.attribute;
3316
3580
  propertyLookup[current.name] = current;
3317
3581
  attributeLookup[current.attribute] = current;
3582
+ Observable.defineProperty(proto, current);
3318
3583
  }
3584
+ Reflect.defineProperty(type, "observedAttributes", {
3585
+ value: observedAttributes,
3586
+ enumerable: true,
3587
+ });
3319
3588
  this.attributes = attributes;
3320
- this.observedAttributes = observedAttributes;
3321
3589
  this.propertyLookup = propertyLookup;
3322
3590
  this.attributeLookup = attributeLookup;
3323
3591
  this.shadowOptions =
@@ -3330,43 +3598,50 @@ class FASTElementDefinition {
3330
3598
  nameOrConfig.elementOptions === void 0
3331
3599
  ? defaultElementOptions
3332
3600
  : Object.assign(Object.assign({}, defaultElementOptions), nameOrConfig.elementOptions);
3333
- this.styles =
3334
- nameOrConfig.styles === void 0
3335
- ? void 0
3336
- : Array.isArray(nameOrConfig.styles)
3337
- ? new ElementStyles(nameOrConfig.styles)
3338
- : nameOrConfig.styles instanceof ElementStyles
3339
- ? nameOrConfig.styles
3340
- : new ElementStyles([nameOrConfig.styles]);
3601
+ this.styles = ElementStyles.normalize(nameOrConfig.styles);
3602
+ fastElementRegistry.register(this);
3341
3603
  }
3342
3604
  /**
3343
3605
  * Indicates if this element has been defined in at least one registry.
3344
3606
  */
3345
3607
  get isDefined() {
3346
- return !!fastElementRegistry.getByType(this.type);
3608
+ return this.platformDefined;
3347
3609
  }
3348
3610
  /**
3349
3611
  * Defines a custom element based on this definition.
3350
3612
  * @param registry - The element registry to define the element in.
3613
+ * @remarks
3614
+ * This operation is idempotent per registry.
3351
3615
  */
3352
- define(registry = customElements) {
3616
+ define(registry = this.registry) {
3353
3617
  const type = this.type;
3354
- if (fastElementRegistry.register(this)) {
3355
- const attributes = this.attributes;
3356
- const proto = type.prototype;
3357
- for (let i = 0, ii = attributes.length; i < ii; ++i) {
3358
- Observable.defineProperty(proto, attributes[i]);
3359
- }
3360
- Reflect.defineProperty(type, "observedAttributes", {
3361
- value: this.observedAttributes,
3362
- enumerable: true,
3363
- });
3364
- }
3365
3618
  if (!registry.get(this.name)) {
3619
+ this.platformDefined = true;
3366
3620
  registry.define(this.name, type, this.elementOptions);
3367
3621
  }
3368
3622
  return this;
3369
3623
  }
3624
+ /**
3625
+ * Creates an instance of FASTElementDefinition.
3626
+ * @param type - The type this definition is being created for.
3627
+ * @param nameOrDef - The name of the element to define or a config object
3628
+ * that describes the element to define.
3629
+ */
3630
+ static compose(type, nameOrDef) {
3631
+ if (fastElementBaseTypes.has(type) || fastElementRegistry.getByType(type)) {
3632
+ return new FASTElementDefinition(class extends type {
3633
+ }, nameOrDef);
3634
+ }
3635
+ return new FASTElementDefinition(type, nameOrDef);
3636
+ }
3637
+ /**
3638
+ * Registers a FASTElement base type.
3639
+ * @param type - The type to register as a base type.
3640
+ * @internal
3641
+ */
3642
+ static registerBaseType(type) {
3643
+ fastElementBaseTypes.add(type);
3644
+ }
3370
3645
  }
3371
3646
  /**
3372
3647
  * Gets the element definition associated with the specified type.
@@ -3379,22 +3654,22 @@ FASTElementDefinition.getByType = fastElementRegistry.getByType;
3379
3654
  */
3380
3655
  FASTElementDefinition.getForInstance = fastElementRegistry.getForInstance;
3381
3656
 
3382
- const shadowRoots = new WeakMap();
3383
3657
  const defaultEventOptions = {
3384
3658
  bubbles: true,
3385
3659
  composed: true,
3386
3660
  cancelable: true,
3387
3661
  };
3662
+ const isConnectedPropertyName = "isConnected";
3663
+ const shadowRoots = new WeakMap();
3388
3664
  function getShadowRoot(element) {
3389
3665
  var _a, _b;
3390
3666
  return (_b = (_a = element.shadowRoot) !== null && _a !== void 0 ? _a : shadowRoots.get(element)) !== null && _b !== void 0 ? _b : null;
3391
3667
  }
3392
- const isConnectedPropertyName = "isConnected";
3393
3668
  /**
3394
3669
  * Controls the lifecycle and rendering of a `FASTElement`.
3395
3670
  * @public
3396
3671
  */
3397
- class Controller extends PropertyChangeNotifier {
3672
+ class ElementController extends PropertyChangeNotifier {
3398
3673
  /**
3399
3674
  * Creates a Controller to control the specified element.
3400
3675
  * @param element - The element to be controlled by this controller.
@@ -3405,12 +3680,12 @@ class Controller extends PropertyChangeNotifier {
3405
3680
  constructor(element, definition) {
3406
3681
  super(element);
3407
3682
  this.boundObservables = null;
3408
- this.behaviors = null;
3409
3683
  this.needsInitialization = true;
3410
3684
  this.hasExistingShadowRoot = false;
3411
3685
  this._template = null;
3412
- this._styles = null;
3413
3686
  this._isConnected = false;
3687
+ this.behaviors = null;
3688
+ this._mainStyles = null;
3414
3689
  /**
3415
3690
  * This allows Observable.getNotifier(...) to return the Controller
3416
3691
  * when the notifier for the Controller itself is being requested. The
@@ -3426,7 +3701,7 @@ class Controller extends PropertyChangeNotifier {
3426
3701
  * If `null` then the element is managing its own rendering.
3427
3702
  */
3428
3703
  this.view = null;
3429
- this.element = element;
3704
+ this.source = element;
3430
3705
  this.definition = definition;
3431
3706
  const shadowOptions = definition.shadowOptions;
3432
3707
  if (shadowOptions !== void 0) {
@@ -3480,9 +3755,9 @@ class Controller extends PropertyChangeNotifier {
3480
3755
  // 1. Template overrides take top precedence.
3481
3756
  if (this._template === null) {
3482
3757
  const definition = this.definition;
3483
- if (this.element.resolveTemplate) {
3758
+ if (this.source.resolveTemplate) {
3484
3759
  // 2. Allow for element instance overrides next.
3485
- this._template = this.element.resolveTemplate();
3760
+ this._template = this.source.resolveTemplate();
3486
3761
  }
3487
3762
  else if (definition.template) {
3488
3763
  // 3. Default to the static definition.
@@ -3501,48 +3776,92 @@ class Controller extends PropertyChangeNotifier {
3501
3776
  }
3502
3777
  }
3503
3778
  /**
3504
- * Gets/sets the primary styles used for the component.
3505
- * @remarks
3506
- * This value can only be accurately read after connect but can be set at any time.
3779
+ * The main set of styles used for the component, independent
3780
+ * of any dynamically added styles.
3507
3781
  */
3508
- get styles() {
3782
+ get mainStyles() {
3509
3783
  var _a;
3510
3784
  // 1. Styles overrides take top precedence.
3511
- if (this._styles === null) {
3785
+ if (this._mainStyles === null) {
3512
3786
  const definition = this.definition;
3513
- if (this.element.resolveStyles) {
3787
+ if (this.source.resolveStyles) {
3514
3788
  // 2. Allow for element instance overrides next.
3515
- this._styles = this.element.resolveStyles();
3789
+ this._mainStyles = this.source.resolveStyles();
3516
3790
  }
3517
3791
  else if (definition.styles) {
3518
3792
  // 3. Default to the static definition.
3519
- this._styles = (_a = definition.styles) !== null && _a !== void 0 ? _a : null;
3793
+ this._mainStyles = (_a = definition.styles) !== null && _a !== void 0 ? _a : null;
3520
3794
  }
3521
3795
  }
3522
- return this._styles;
3796
+ return this._mainStyles;
3523
3797
  }
3524
- set styles(value) {
3525
- if (this._styles === value) {
3798
+ set mainStyles(value) {
3799
+ if (this._mainStyles === value) {
3526
3800
  return;
3527
3801
  }
3528
- if (this._styles !== null) {
3529
- this.removeStyles(this._styles);
3802
+ if (this._mainStyles !== null) {
3803
+ this.removeStyles(this._mainStyles);
3530
3804
  }
3531
- this._styles = value;
3805
+ this._mainStyles = value;
3532
3806
  if (!this.needsInitialization) {
3533
3807
  this.addStyles(value);
3534
3808
  }
3535
3809
  }
3810
+ /**
3811
+ * Adds the behavior to the component.
3812
+ * @param behavior - The behavior to add.
3813
+ */
3814
+ addBehavior(behavior) {
3815
+ var _a, _b;
3816
+ const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
3817
+ const count = (_b = targetBehaviors.get(behavior)) !== null && _b !== void 0 ? _b : 0;
3818
+ if (count === 0) {
3819
+ targetBehaviors.set(behavior, 1);
3820
+ behavior.addedCallback && behavior.addedCallback(this);
3821
+ if (behavior.connectedCallback && this.isConnected) {
3822
+ behavior.connectedCallback(this);
3823
+ }
3824
+ }
3825
+ else {
3826
+ targetBehaviors.set(behavior, count + 1);
3827
+ }
3828
+ }
3829
+ /**
3830
+ * Removes the behavior from the component.
3831
+ * @param behavior - The behavior to remove.
3832
+ * @param force - Forces removal even if this behavior was added more than once.
3833
+ */
3834
+ removeBehavior(behavior, force = false) {
3835
+ const targetBehaviors = this.behaviors;
3836
+ if (targetBehaviors === null) {
3837
+ return;
3838
+ }
3839
+ const count = targetBehaviors.get(behavior);
3840
+ if (count === void 0) {
3841
+ return;
3842
+ }
3843
+ if (count === 1 || force) {
3844
+ targetBehaviors.delete(behavior);
3845
+ if (behavior.disconnectedCallback && this.isConnected) {
3846
+ behavior.disconnectedCallback(this);
3847
+ }
3848
+ behavior.removedCallback && behavior.removedCallback(this);
3849
+ }
3850
+ else {
3851
+ targetBehaviors.set(behavior, count - 1);
3852
+ }
3853
+ }
3536
3854
  /**
3537
3855
  * Adds styles to this element. Providing an HTMLStyleElement will attach the element instance to the shadowRoot.
3538
3856
  * @param styles - The styles to add.
3539
3857
  */
3540
3858
  addStyles(styles) {
3859
+ var _a;
3541
3860
  if (!styles) {
3542
3861
  return;
3543
3862
  }
3544
- const target = getShadowRoot(this.element) ||
3545
- this.element.getRootNode();
3863
+ const source = this.source;
3864
+ const target = (_a = getShadowRoot(source)) !== null && _a !== void 0 ? _a : source.getRootNode();
3546
3865
  if (styles instanceof HTMLElement) {
3547
3866
  target.append(styles);
3548
3867
  }
@@ -3550,7 +3869,9 @@ class Controller extends PropertyChangeNotifier {
3550
3869
  const sourceBehaviors = styles.behaviors;
3551
3870
  styles.addStylesTo(target);
3552
3871
  if (sourceBehaviors !== null) {
3553
- this.addBehaviors(sourceBehaviors);
3872
+ for (let i = 0, ii = sourceBehaviors.length; i < ii; ++i) {
3873
+ this.addBehavior(sourceBehaviors[i]);
3874
+ }
3554
3875
  }
3555
3876
  }
3556
3877
  }
@@ -3559,11 +3880,12 @@ class Controller extends PropertyChangeNotifier {
3559
3880
  * @param styles - the styles to remove.
3560
3881
  */
3561
3882
  removeStyles(styles) {
3883
+ var _a;
3562
3884
  if (!styles) {
3563
3885
  return;
3564
3886
  }
3565
- const target = getShadowRoot(this.element) ||
3566
- this.element.getRootNode();
3887
+ const source = this.source;
3888
+ const target = (_a = getShadowRoot(source)) !== null && _a !== void 0 ? _a : source.getRootNode();
3567
3889
  if (styles instanceof HTMLElement) {
3568
3890
  target.removeChild(styles);
3569
3891
  }
@@ -3571,85 +3893,29 @@ class Controller extends PropertyChangeNotifier {
3571
3893
  const sourceBehaviors = styles.behaviors;
3572
3894
  styles.removeStylesFrom(target);
3573
3895
  if (sourceBehaviors !== null) {
3574
- this.removeBehaviors(sourceBehaviors);
3575
- }
3576
- }
3577
- }
3578
- /**
3579
- * Adds behaviors to this element.
3580
- * @param behaviors - The behaviors to add.
3581
- */
3582
- addBehaviors(behaviors) {
3583
- var _a;
3584
- const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
3585
- const length = behaviors.length;
3586
- const behaviorsToBind = [];
3587
- for (let i = 0; i < length; ++i) {
3588
- const behavior = behaviors[i];
3589
- if (targetBehaviors.has(behavior)) {
3590
- targetBehaviors.set(behavior, targetBehaviors.get(behavior) + 1);
3591
- }
3592
- else {
3593
- targetBehaviors.set(behavior, 1);
3594
- behaviorsToBind.push(behavior);
3595
- }
3596
- }
3597
- if (this._isConnected) {
3598
- const element = this.element;
3599
- const context = ExecutionContext.default;
3600
- for (let i = 0; i < behaviorsToBind.length; ++i) {
3601
- behaviorsToBind[i].bind(element, context);
3602
- }
3603
- }
3604
- }
3605
- /**
3606
- * Removes behaviors from this element.
3607
- * @param behaviors - The behaviors to remove.
3608
- * @param force - Forces unbinding of behaviors.
3609
- */
3610
- removeBehaviors(behaviors, force = false) {
3611
- const targetBehaviors = this.behaviors;
3612
- if (targetBehaviors === null) {
3613
- return;
3614
- }
3615
- const length = behaviors.length;
3616
- const behaviorsToUnbind = [];
3617
- for (let i = 0; i < length; ++i) {
3618
- const behavior = behaviors[i];
3619
- if (targetBehaviors.has(behavior)) {
3620
- const count = targetBehaviors.get(behavior) - 1;
3621
- count === 0 || force
3622
- ? targetBehaviors.delete(behavior) && behaviorsToUnbind.push(behavior)
3623
- : targetBehaviors.set(behavior, count);
3624
- }
3625
- }
3626
- if (this._isConnected) {
3627
- const element = this.element;
3628
- const context = ExecutionContext.default;
3629
- for (let i = 0; i < behaviorsToUnbind.length; ++i) {
3630
- behaviorsToUnbind[i].unbind(element, context);
3896
+ for (let i = 0, ii = sourceBehaviors.length; i < ii; ++i) {
3897
+ this.addBehavior(sourceBehaviors[i]);
3898
+ }
3631
3899
  }
3632
3900
  }
3633
3901
  }
3634
3902
  /**
3635
3903
  * Runs connected lifecycle behavior on the associated element.
3636
3904
  */
3637
- onConnectedCallback() {
3905
+ connect() {
3638
3906
  if (this._isConnected) {
3639
3907
  return;
3640
3908
  }
3641
- const element = this.element;
3642
- const context = ExecutionContext.default;
3643
3909
  if (this.needsInitialization) {
3644
3910
  this.finishInitialization();
3645
3911
  }
3646
3912
  else if (this.view !== null) {
3647
- this.view.bind(element, context);
3913
+ this.view.bind(this.source);
3648
3914
  }
3649
3915
  const behaviors = this.behaviors;
3650
3916
  if (behaviors !== null) {
3651
- for (const behavior of behaviors.keys()) {
3652
- behavior.bind(element, context);
3917
+ for (const key of behaviors.keys()) {
3918
+ key.connectedCallback && key.connectedCallback(this);
3653
3919
  }
3654
3920
  }
3655
3921
  this.setIsConnected(true);
@@ -3657,21 +3923,18 @@ class Controller extends PropertyChangeNotifier {
3657
3923
  /**
3658
3924
  * Runs disconnected lifecycle behavior on the associated element.
3659
3925
  */
3660
- onDisconnectedCallback() {
3926
+ disconnect() {
3661
3927
  if (!this._isConnected) {
3662
3928
  return;
3663
3929
  }
3664
3930
  this.setIsConnected(false);
3665
- const view = this.view;
3666
- if (view !== null) {
3667
- view.unbind();
3931
+ if (this.view !== null) {
3932
+ this.view.unbind();
3668
3933
  }
3669
3934
  const behaviors = this.behaviors;
3670
3935
  if (behaviors !== null) {
3671
- const element = this.element;
3672
- const context = ExecutionContext.default;
3673
- for (const behavior of behaviors.keys()) {
3674
- behavior.unbind(element, context);
3936
+ for (const key of behaviors.keys()) {
3937
+ key.disconnectedCallback && key.disconnectedCallback(this);
3675
3938
  }
3676
3939
  }
3677
3940
  }
@@ -3684,7 +3947,7 @@ class Controller extends PropertyChangeNotifier {
3684
3947
  onAttributeChangedCallback(name, oldValue, newValue) {
3685
3948
  const attrDef = this.definition.attributeLookup[name];
3686
3949
  if (attrDef !== void 0) {
3687
- attrDef.onAttributeChangedCallback(this.element, newValue);
3950
+ attrDef.onAttributeChangedCallback(this.source, newValue);
3688
3951
  }
3689
3952
  }
3690
3953
  /**
@@ -3697,12 +3960,12 @@ class Controller extends PropertyChangeNotifier {
3697
3960
  */
3698
3961
  emit(type, detail, options) {
3699
3962
  if (this._isConnected) {
3700
- return this.element.dispatchEvent(new CustomEvent(type, Object.assign(Object.assign({ detail }, defaultEventOptions), options)));
3963
+ return this.source.dispatchEvent(new CustomEvent(type, Object.assign(Object.assign({ detail }, defaultEventOptions), options)));
3701
3964
  }
3702
3965
  return false;
3703
3966
  }
3704
3967
  finishInitialization() {
3705
- const element = this.element;
3968
+ const element = this.source;
3706
3969
  const boundObservables = this.boundObservables;
3707
3970
  // If we have any observables that were bound, re-apply their values.
3708
3971
  if (boundObservables !== null) {
@@ -3714,15 +3977,15 @@ class Controller extends PropertyChangeNotifier {
3714
3977
  this.boundObservables = null;
3715
3978
  }
3716
3979
  this.renderTemplate(this.template);
3717
- this.addStyles(this.styles);
3980
+ this.addStyles(this.mainStyles);
3718
3981
  this.needsInitialization = false;
3719
3982
  }
3720
3983
  renderTemplate(template) {
3721
3984
  var _a;
3722
- const element = this.element;
3723
3985
  // When getting the host to render to, we start by looking
3724
3986
  // up the shadow root. If there isn't one, then that means
3725
3987
  // we're doing a Light DOM render to the element's direct children.
3988
+ const element = this.source;
3726
3989
  const host = (_a = getShadowRoot(element)) !== null && _a !== void 0 ? _a : element;
3727
3990
  if (this.view !== null) {
3728
3991
  // If there's already a view, we need to unbind and remove through dispose.
@@ -3739,6 +4002,8 @@ class Controller extends PropertyChangeNotifier {
3739
4002
  if (template) {
3740
4003
  // If a new template was provided, render it.
3741
4004
  this.view = template.render(element, host, element);
4005
+ this.view.sourceLifetime =
4006
+ SourceLifetime.coupled;
3742
4007
  }
3743
4008
  }
3744
4009
  /**
@@ -3758,31 +4023,48 @@ class Controller extends PropertyChangeNotifier {
3758
4023
  if (definition === void 0) {
3759
4024
  throw FAST.error(1401 /* Message.missingElementDefinition */);
3760
4025
  }
3761
- return (element.$fastController = new Controller(element, definition));
4026
+ return (element.$fastController = new ElementController(element, definition));
3762
4027
  }
3763
4028
  }
3764
4029
 
3765
4030
  /* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
3766
4031
  function createFASTElement(BaseType) {
3767
- return class extends BaseType {
4032
+ const type = class extends BaseType {
3768
4033
  constructor() {
3769
4034
  /* eslint-disable-next-line */
3770
4035
  super();
3771
- Controller.forCustomElement(this);
4036
+ ElementController.forCustomElement(this);
3772
4037
  }
3773
4038
  $emit(type, detail, options) {
3774
4039
  return this.$fastController.emit(type, detail, options);
3775
4040
  }
3776
4041
  connectedCallback() {
3777
- this.$fastController.onConnectedCallback();
4042
+ this.$fastController.connect();
3778
4043
  }
3779
4044
  disconnectedCallback() {
3780
- this.$fastController.onDisconnectedCallback();
4045
+ this.$fastController.disconnect();
3781
4046
  }
3782
4047
  attributeChangedCallback(name, oldValue, newValue) {
3783
4048
  this.$fastController.onAttributeChangedCallback(name, oldValue, newValue);
3784
4049
  }
3785
4050
  };
4051
+ FASTElementDefinition.registerBaseType(type);
4052
+ return type;
4053
+ }
4054
+ function compose(type, nameOrDef) {
4055
+ if (isFunction(type)) {
4056
+ return FASTElementDefinition.compose(type, nameOrDef);
4057
+ }
4058
+ return FASTElementDefinition.compose(this, type);
4059
+ }
4060
+ function define(type, nameOrDef) {
4061
+ if (isFunction(type)) {
4062
+ return FASTElementDefinition.compose(type, nameOrDef).define().type;
4063
+ }
4064
+ return FASTElementDefinition.compose(this, type).define().type;
4065
+ }
4066
+ function from(BaseType) {
4067
+ return createFASTElement(BaseType);
3786
4068
  }
3787
4069
  /**
3788
4070
  * A minimal base class for FASTElements that also provides
@@ -3795,18 +4077,19 @@ const FASTElement = Object.assign(createFASTElement(HTMLElement), {
3795
4077
  * provided base type.
3796
4078
  * @param BaseType - The base element type to inherit from.
3797
4079
  */
3798
- from(BaseType) {
3799
- return createFASTElement(BaseType);
3800
- },
4080
+ from,
3801
4081
  /**
3802
4082
  * Defines a platform custom element based on the provided type and definition.
3803
4083
  * @param type - The custom element type to define.
3804
4084
  * @param nameOrDef - The name of the element to define or a definition object
3805
4085
  * that describes the element to define.
3806
4086
  */
3807
- define(type, nameOrDef) {
3808
- return new FASTElementDefinition(type, nameOrDef).define().type;
3809
- },
4087
+ define,
4088
+ /**
4089
+ * Defines metadata for a FASTElement which can be used to later define the element.
4090
+ * @public
4091
+ */
4092
+ compose,
3810
4093
  });
3811
4094
  /**
3812
4095
  * Decorator: Defines a platform custom element based on `FASTElement`.
@@ -3817,8 +4100,8 @@ const FASTElement = Object.assign(createFASTElement(HTMLElement), {
3817
4100
  function customElement(nameOrDef) {
3818
4101
  /* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
3819
4102
  return function (type) {
3820
- new FASTElementDefinition(type, nameOrDef).define();
4103
+ define(type, nameOrDef);
3821
4104
  };
3822
4105
  }
3823
4106
 
3824
- export { AdoptedStyleSheetsStrategy, ArrayObserver, Aspect, AttributeDefinition, BindingConfig, BindingMode, CSSDirective, ChangeBinding, ChildrenDirective, Compiler, Controller, DOM, ElementStyles, EventBinding, ExecutionContext, FAST, FASTElement, FASTElementDefinition, HTMLBindingDirective, HTMLDirective, HTMLView, Markup, NodeObservationDirective, Observable, OneTimeBinding, Parser, PropertyChangeNotifier, RefDirective, RepeatBehavior, RepeatDirective, SignalBinding, SlottedDirective, Splice, SpliceStrategy, SpliceStrategySupport, StatelessAttachedAttributeDirective, SubscriberSet, TwoWayBinding, UpdateBinding, Updates, ViewTemplate, attr, bind, booleanConverter, child, children, createTypeRegistry, css, cssDirective, cssPartial, customElement, elements, emptyArray, html, htmlDirective, item, length, nullableNumberConverter, observable, onChange, oneTime, ref, repeat, signal, slotted, twoWay, volatile, when };
4107
+ export { AdoptedStyleSheetsStrategy, ArrayObserver, Aspect, AttributeConfiguration, AttributeDefinition, Binding, CSSDirective, ChildrenDirective, Compiler, DOM, ElementController, ElementStyles, ExecutionContext, FAST, FASTElement, FASTElementDefinition, HTMLBindingDirective, HTMLDirective, HTMLView, Markup, NodeObservationDirective, Observable, Parser, PropertyChangeNotifier, RefDirective, RepeatBehavior, RepeatDirective, SlottedDirective, SourceLifetime, Splice, SpliceStrategy, SpliceStrategySupport, StatelessAttachedAttributeDirective, SubscriberSet, Updates, ViewBehaviorOrchestrator, ViewTemplate, attr, bind, booleanConverter, children, createMetadataLocator, createTypeRegistry, css, cssDirective, cssPartial, customElement, elements, emptyArray, html, htmlDirective, lengthOf, listener, normalizeBinding, nullableNumberConverter, observable, oneTime, ref, repeat, slotted, volatile, when };