@microsoft/fast-element 1.7.1 → 1.9.0

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 (56) hide show
  1. package/.eslintrc.json +30 -0
  2. package/CHANGELOG.json +73 -1
  3. package/CHANGELOG.md +26 -2
  4. package/dist/dts/components/attributes.d.ts +1 -1
  5. package/dist/dts/components/controller.d.ts +6 -6
  6. package/dist/dts/components/fast-definitions.d.ts +5 -5
  7. package/dist/dts/components/fast-element.d.ts +2 -2
  8. package/dist/dts/dom.d.ts +4 -4
  9. package/dist/dts/index.d.ts +26 -26
  10. package/dist/dts/observation/behavior.d.ts +1 -1
  11. package/dist/dts/observation/observable.d.ts +51 -50
  12. package/dist/dts/platform.d.ts +37 -0
  13. package/dist/dts/styles/css-directive.d.ts +2 -2
  14. package/dist/dts/styles/css.d.ts +2 -2
  15. package/dist/dts/styles/element-styles.d.ts +1 -1
  16. package/dist/dts/templating/binding.d.ts +3 -3
  17. package/dist/dts/templating/children.d.ts +2 -2
  18. package/dist/dts/templating/compiler.d.ts +1 -1
  19. package/dist/dts/templating/html-directive.d.ts +1 -1
  20. package/dist/dts/templating/node-observation.d.ts +1 -1
  21. package/dist/dts/templating/ref.d.ts +2 -2
  22. package/dist/dts/templating/repeat.d.ts +6 -6
  23. package/dist/dts/templating/slotted.d.ts +2 -2
  24. package/dist/dts/templating/template.d.ts +3 -3
  25. package/dist/dts/templating/view.d.ts +2 -2
  26. package/dist/dts/templating/when.d.ts +2 -2
  27. package/dist/esm/components/attributes.js +2 -2
  28. package/dist/esm/components/controller.js +4 -4
  29. package/dist/esm/components/fast-definitions.js +31 -14
  30. package/dist/esm/components/fast-element.js +2 -2
  31. package/dist/esm/dom.js +55 -50
  32. package/dist/esm/index.js +23 -23
  33. package/dist/esm/observation/array-change-records.js +1 -1
  34. package/dist/esm/observation/array-observer.js +12 -6
  35. package/dist/esm/observation/observable.js +244 -236
  36. package/dist/esm/platform.js +23 -0
  37. package/dist/esm/styles/css.js +2 -2
  38. package/dist/esm/styles/element-styles.js +1 -1
  39. package/dist/esm/templating/binding.js +5 -5
  40. package/dist/esm/templating/children.js +2 -2
  41. package/dist/esm/templating/compiler.js +2 -2
  42. package/dist/esm/templating/html-directive.js +1 -1
  43. package/dist/esm/templating/node-observation.js +2 -2
  44. package/dist/esm/templating/ref.js +1 -1
  45. package/dist/esm/templating/repeat.js +6 -6
  46. package/dist/esm/templating/slotted.js +2 -2
  47. package/dist/esm/templating/template.js +6 -6
  48. package/dist/fast-element.api.json +43 -48
  49. package/dist/fast-element.d.ts +53 -13
  50. package/dist/fast-element.js +428 -344
  51. package/dist/fast-element.min.js +1 -1
  52. package/docs/api-report.md +39 -12
  53. package/docs/guide/observables-and-state.md +10 -8
  54. package/docs/guide/using-directives.md +1 -1
  55. package/karma.conf.cjs +152 -0
  56. package/package.json +11 -10
@@ -41,6 +41,41 @@ if ($global.trustedTypes === void 0) {
41
41
  createPolicy: (n, r) => r
42
42
  };
43
43
  }
44
+
45
+ const propConfig = {
46
+ configurable: false,
47
+ enumerable: false,
48
+ writable: false
49
+ };
50
+
51
+ if ($global.FAST === void 0) {
52
+ Reflect.defineProperty($global, "FAST", Object.assign({
53
+ value: Object.create(null)
54
+ }, propConfig));
55
+ }
56
+ /**
57
+ * The FAST global.
58
+ * @internal
59
+ */
60
+
61
+
62
+ const FAST = $global.FAST;
63
+
64
+ if (FAST.getById === void 0) {
65
+ const storage = Object.create(null);
66
+ Reflect.defineProperty(FAST, "getById", Object.assign({
67
+ value(id, initialize) {
68
+ let found = storage[id];
69
+
70
+ if (found === void 0) {
71
+ found = initialize ? storage[id] = initialize() : null;
72
+ }
73
+
74
+ return found;
75
+ }
76
+
77
+ }, propConfig));
78
+ }
44
79
  /**
45
80
  * A readonly, empty array.
46
81
  * @remarks
@@ -52,33 +87,75 @@ if ($global.trustedTypes === void 0) {
52
87
 
53
88
  const emptyArray = Object.freeze([]);
54
89
 
55
- const updateQueue = [];
56
- /* eslint-disable */
90
+ const updateQueue = $global.FAST.getById(1
91
+ /* updateQueue */
92
+ , () => {
93
+ const tasks = [];
94
+ const pendingErrors = [];
57
95
 
58
- const fastHTMLPolicy = $global.trustedTypes.createPolicy("fast-html", {
59
- createHTML: html => html
60
- });
61
- /* eslint-enable */
96
+ function throwFirstError() {
97
+ if (pendingErrors.length) {
98
+ throw pendingErrors.shift();
99
+ }
100
+ }
62
101
 
63
- let htmlPolicy = fastHTMLPolicy; // We use a queue so we can ensure errors are thrown in order.
102
+ function tryRunTask(task) {
103
+ try {
104
+ task.call();
105
+ } catch (error) {
106
+ pendingErrors.push(error);
107
+ setTimeout(throwFirstError, 0);
108
+ }
109
+ }
64
110
 
65
- const pendingErrors = [];
111
+ function process() {
112
+ const capacity = 1024;
113
+ let index = 0;
66
114
 
67
- function throwFirstError() {
68
- if (pendingErrors.length) {
69
- throw pendingErrors.shift();
115
+ while (index < tasks.length) {
116
+ tryRunTask(tasks[index]);
117
+ index++; // Prevent leaking memory for long chains of recursive calls to `DOM.queueUpdate`.
118
+ // If we call `DOM.queueUpdate` within a task scheduled by `DOM.queueUpdate`, the queue will
119
+ // grow, but to avoid an O(n) walk for every task we execute, we don't
120
+ // shift tasks off the queue after they have been executed.
121
+ // Instead, we periodically shift 1024 tasks off the queue.
122
+
123
+ if (index > capacity) {
124
+ // Manually shift all values starting at the index back to the
125
+ // beginning of the queue.
126
+ for (let scan = 0, newLength = tasks.length - index; scan < newLength; scan++) {
127
+ tasks[scan] = tasks[scan + index];
128
+ }
129
+
130
+ tasks.length -= index;
131
+ index = 0;
132
+ }
133
+ }
134
+
135
+ tasks.length = 0;
70
136
  }
71
- }
72
137
 
73
- function tryRunTask(task) {
74
- try {
75
- task.call();
76
- } catch (error) {
77
- pendingErrors.push(error);
78
- setTimeout(throwFirstError, 0);
138
+ function enqueue(callable) {
139
+ if (tasks.length < 1) {
140
+ $global.requestAnimationFrame(process);
141
+ }
142
+
143
+ tasks.push(callable);
79
144
  }
80
- }
81
145
 
146
+ return Object.freeze({
147
+ enqueue,
148
+ process
149
+ });
150
+ });
151
+ /* eslint-disable */
152
+
153
+ const fastHTMLPolicy = $global.trustedTypes.createPolicy("fast-html", {
154
+ createHTML: html => html
155
+ });
156
+ /* eslint-enable */
157
+
158
+ let htmlPolicy = fastHTMLPolicy;
82
159
  const marker = `fast-${Math.random().toString(36).substring(2, 8)}`;
83
160
  /** @internal */
84
161
 
@@ -176,13 +253,7 @@ const DOM = Object.freeze({
176
253
  * Schedules DOM update work in the next async batch.
177
254
  * @param callable - The callable function or object to queue.
178
255
  */
179
- queueUpdate(callable) {
180
- if (updateQueue.length < 1) {
181
- window.requestAnimationFrame(DOM.processUpdates);
182
- }
183
-
184
- updateQueue.push(callable);
185
- },
256
+ queueUpdate: updateQueue.enqueue,
186
257
 
187
258
  /**
188
259
  * Immediately processes all work previously scheduled
@@ -191,40 +262,13 @@ const DOM = Object.freeze({
191
262
  * This also forces nextUpdate promises
192
263
  * to resolve.
193
264
  */
194
- processUpdates() {
195
- const capacity = 1024;
196
- let index = 0;
197
-
198
- while (index < updateQueue.length) {
199
- tryRunTask(updateQueue[index]);
200
- index++; // Prevent leaking memory for long chains of recursive calls to `DOM.queueUpdate`.
201
- // If we call `DOM.queueUpdate` within a task scheduled by `DOM.queueUpdate`, the queue will
202
- // grow, but to avoid an O(n) walk for every task we execute, we don't
203
- // shift tasks off the queue after they have been executed.
204
- // Instead, we periodically shift 1024 tasks off the queue.
205
-
206
- if (index > capacity) {
207
- // Manually shift all values starting at the index back to the
208
- // beginning of the queue.
209
- for (let scan = 0, newLength = updateQueue.length - index; scan < newLength; scan++) {
210
- updateQueue[scan] = updateQueue[scan + index];
211
- }
212
-
213
- updateQueue.length -= index;
214
- index = 0;
215
- }
216
- }
217
-
218
- updateQueue.length = 0;
219
- },
265
+ processUpdates: updateQueue.process,
220
266
 
221
267
  /**
222
268
  * Resolves with the next DOM update.
223
269
  */
224
270
  nextUpdate() {
225
- return new Promise(resolve => {
226
- DOM.queueUpdate(resolve);
227
- });
271
+ return new Promise(updateQueue.enqueue);
228
272
  },
229
273
 
230
274
  /**
@@ -484,69 +528,25 @@ class PropertyChangeNotifier {
484
528
 
485
529
  }
486
530
 
487
- const volatileRegex = /(:|&&|\|\||if)/;
488
- const notifierLookup = new WeakMap();
489
- const accessorLookup = new WeakMap();
490
- let watcher = void 0;
491
-
492
- let createArrayObserver = array => {
493
- throw new Error("Must call enableArrayObservation before observing arrays.");
494
- };
495
-
496
- class DefaultObservableAccessor {
497
- constructor(name) {
498
- this.name = name;
499
- this.field = `_${name}`;
500
- this.callback = `${name}Changed`;
501
- }
502
-
503
- getValue(source) {
504
- if (watcher !== void 0) {
505
- watcher.watch(source, this.name);
506
- }
507
-
508
- return source[this.field];
509
- }
510
-
511
- setValue(source, newValue) {
512
- const field = this.field;
513
- const oldValue = source[field];
514
-
515
- if (oldValue !== newValue) {
516
- source[field] = newValue;
517
- const callback = source[this.callback];
518
-
519
- if (typeof callback === "function") {
520
- callback.call(source, oldValue, newValue);
521
- }
522
- /* eslint-disable-next-line @typescript-eslint/no-use-before-define */
523
-
524
-
525
- getNotifier(source).notify(this.name);
526
- }
527
- }
528
-
529
- }
530
531
  /**
531
532
  * Common Observable APIs.
532
533
  * @public
533
534
  */
534
535
 
536
+ const Observable = FAST.getById(2
537
+ /* observable */
538
+ , () => {
539
+ const volatileRegex = /(:|&&|\|\||if)/;
540
+ const notifierLookup = new WeakMap();
541
+ const accessorLookup = new WeakMap();
542
+ const queueUpdate = DOM.queueUpdate;
543
+ let watcher = void 0;
544
+
545
+ let createArrayObserver = array => {
546
+ throw new Error("Must call enableArrayObservation before observing arrays.");
547
+ };
535
548
 
536
- const Observable = Object.freeze({
537
- /**
538
- * @internal
539
- * @param factory - The factory used to create array observers.
540
- */
541
- setArrayObserverFactory(factory) {
542
- createArrayObserver = factory;
543
- },
544
-
545
- /**
546
- * Gets a notifier for an object or Array.
547
- * @param source - The object or Array to get the notifier for.
548
- */
549
- getNotifier(source) {
549
+ function getNotifier(source) {
550
550
  let found = source.$fastController || notifierLookup.get(source);
551
551
 
552
552
  if (found === void 0) {
@@ -558,68 +558,9 @@ const Observable = Object.freeze({
558
558
  }
559
559
 
560
560
  return found;
561
- },
562
-
563
- /**
564
- * Records a property change for a source object.
565
- * @param source - The object to record the change against.
566
- * @param propertyName - The property to track as changed.
567
- */
568
- track(source, propertyName) {
569
- if (watcher !== void 0) {
570
- watcher.watch(source, propertyName);
571
- }
572
- },
573
-
574
- /**
575
- * Notifies watchers that the currently executing property getter or function is volatile
576
- * with respect to its observable dependencies.
577
- */
578
- trackVolatile() {
579
- if (watcher !== void 0) {
580
- watcher.needsRefresh = true;
581
- }
582
- },
583
-
584
- /**
585
- * Notifies subscribers of a source object of changes.
586
- * @param source - the object to notify of changes.
587
- * @param args - The change args to pass to subscribers.
588
- */
589
- notify(source, args) {
590
- /* eslint-disable-next-line @typescript-eslint/no-use-before-define */
591
- getNotifier(source).notify(args);
592
- },
593
-
594
- /**
595
- * Defines an observable property on an object or prototype.
596
- * @param target - The target object to define the observable on.
597
- * @param nameOrAccessor - The name of the property to define as observable;
598
- * or a custom accessor that specifies the property name and accessor implementation.
599
- */
600
- defineProperty(target, nameOrAccessor) {
601
- if (typeof nameOrAccessor === "string") {
602
- nameOrAccessor = new DefaultObservableAccessor(nameOrAccessor);
603
- }
604
-
605
- this.getAccessors(target).push(nameOrAccessor);
606
- Reflect.defineProperty(target, nameOrAccessor.name, {
607
- enumerable: true,
608
- get: function () {
609
- return nameOrAccessor.getValue(this);
610
- },
611
- set: function (newValue) {
612
- nameOrAccessor.setValue(this, newValue);
613
- }
614
- });
615
- },
561
+ }
616
562
 
617
- /**
618
- * Finds all the observable accessors defined on the target,
619
- * including its prototype chain.
620
- * @param target - The target object to search for accessor on.
621
- */
622
- getAccessors(target) {
563
+ function getAccessors(target) {
623
564
  let accessors = accessorLookup.get(target);
624
565
 
625
566
  if (accessors === void 0) {
@@ -640,33 +581,253 @@ const Observable = Object.freeze({
640
581
  }
641
582
 
642
583
  return accessors;
643
- },
584
+ }
644
585
 
645
- /**
646
- * Creates a {@link BindingObserver} that can watch the
647
- * provided {@link Binding} for changes.
648
- * @param binding - The binding to observe.
649
- * @param initialSubscriber - An initial subscriber to changes in the binding value.
650
- * @param isVolatileBinding - Indicates whether the binding's dependency list must be re-evaluated on every value evaluation.
651
- */
652
- binding(binding, initialSubscriber, isVolatileBinding = this.isVolatileBinding(binding)) {
653
- /* eslint-disable-next-line @typescript-eslint/no-use-before-define */
654
- return new BindingObserverImplementation(binding, initialSubscriber, isVolatileBinding);
655
- },
586
+ class DefaultObservableAccessor {
587
+ constructor(name) {
588
+ this.name = name;
589
+ this.field = `_${name}`;
590
+ this.callback = `${name}Changed`;
591
+ }
592
+
593
+ getValue(source) {
594
+ if (watcher !== void 0) {
595
+ watcher.watch(source, this.name);
596
+ }
597
+
598
+ return source[this.field];
599
+ }
600
+
601
+ setValue(source, newValue) {
602
+ const field = this.field;
603
+ const oldValue = source[field];
604
+
605
+ if (oldValue !== newValue) {
606
+ source[field] = newValue;
607
+ const callback = source[this.callback];
608
+
609
+ if (typeof callback === "function") {
610
+ callback.call(source, oldValue, newValue);
611
+ }
612
+
613
+ getNotifier(source).notify(this.name);
614
+ }
615
+ }
656
616
 
657
- /**
658
- * Determines whether a binding expression is volatile and needs to have its dependency list re-evaluated
659
- * on every evaluation of the value.
660
- * @param binding - The binding to inspect.
661
- */
662
- isVolatileBinding(binding) {
663
- return volatileRegex.test(binding.toString());
664
617
  }
665
618
 
619
+ class BindingObserverImplementation extends SubscriberSet {
620
+ constructor(binding, initialSubscriber, isVolatileBinding = false) {
621
+ super(binding, initialSubscriber);
622
+ this.binding = binding;
623
+ this.isVolatileBinding = isVolatileBinding;
624
+ this.needsRefresh = true;
625
+ this.needsQueue = true;
626
+ this.first = this;
627
+ this.last = null;
628
+ this.propertySource = void 0;
629
+ this.propertyName = void 0;
630
+ this.notifier = void 0;
631
+ this.next = void 0;
632
+ }
633
+
634
+ observe(source, context) {
635
+ if (this.needsRefresh && this.last !== null) {
636
+ this.disconnect();
637
+ }
638
+
639
+ const previousWatcher = watcher;
640
+ watcher = this.needsRefresh ? this : void 0;
641
+ this.needsRefresh = this.isVolatileBinding;
642
+ const result = this.binding(source, context);
643
+ watcher = previousWatcher;
644
+ return result;
645
+ }
646
+
647
+ disconnect() {
648
+ if (this.last !== null) {
649
+ let current = this.first;
650
+
651
+ while (current !== void 0) {
652
+ current.notifier.unsubscribe(this, current.propertyName);
653
+ current = current.next;
654
+ }
655
+
656
+ this.last = null;
657
+ this.needsRefresh = this.needsQueue = true;
658
+ }
659
+ }
660
+
661
+ watch(propertySource, propertyName) {
662
+ const prev = this.last;
663
+ const notifier = getNotifier(propertySource);
664
+ const current = prev === null ? this.first : {};
665
+ current.propertySource = propertySource;
666
+ current.propertyName = propertyName;
667
+ current.notifier = notifier;
668
+ notifier.subscribe(this, propertyName);
669
+
670
+ if (prev !== null) {
671
+ if (!this.needsRefresh) {
672
+ // Declaring the variable prior to assignment below circumvents
673
+ // a bug in Angular's optimization process causing infinite recursion
674
+ // of this watch() method. Details https://github.com/microsoft/fast/issues/4969
675
+ let prevValue;
676
+ watcher = void 0;
677
+ /* eslint-disable-next-line */
678
+
679
+ prevValue = prev.propertySource[prev.propertyName];
680
+ watcher = this;
681
+
682
+ if (propertySource === prevValue) {
683
+ this.needsRefresh = true;
684
+ }
685
+ }
686
+
687
+ prev.next = current;
688
+ }
689
+
690
+ this.last = current;
691
+ }
692
+
693
+ handleChange() {
694
+ if (this.needsQueue) {
695
+ this.needsQueue = false;
696
+ queueUpdate(this);
697
+ }
698
+ }
699
+
700
+ call() {
701
+ if (this.last !== null) {
702
+ this.needsQueue = true;
703
+ this.notify(this);
704
+ }
705
+ }
706
+
707
+ records() {
708
+ let next = this.first;
709
+ return {
710
+ next: () => {
711
+ const current = next;
712
+
713
+ if (current === undefined) {
714
+ return {
715
+ value: void 0,
716
+ done: true
717
+ };
718
+ } else {
719
+ next = next.next;
720
+ return {
721
+ value: current,
722
+ done: false
723
+ };
724
+ }
725
+ },
726
+ [Symbol.iterator]: function () {
727
+ return this;
728
+ }
729
+ };
730
+ }
731
+
732
+ }
733
+
734
+ return Object.freeze({
735
+ /**
736
+ * @internal
737
+ * @param factory - The factory used to create array observers.
738
+ */
739
+ setArrayObserverFactory(factory) {
740
+ createArrayObserver = factory;
741
+ },
742
+
743
+ /**
744
+ * Gets a notifier for an object or Array.
745
+ * @param source - The object or Array to get the notifier for.
746
+ */
747
+ getNotifier,
748
+
749
+ /**
750
+ * Records a property change for a source object.
751
+ * @param source - The object to record the change against.
752
+ * @param propertyName - The property to track as changed.
753
+ */
754
+ track(source, propertyName) {
755
+ if (watcher !== void 0) {
756
+ watcher.watch(source, propertyName);
757
+ }
758
+ },
759
+
760
+ /**
761
+ * Notifies watchers that the currently executing property getter or function is volatile
762
+ * with respect to its observable dependencies.
763
+ */
764
+ trackVolatile() {
765
+ if (watcher !== void 0) {
766
+ watcher.needsRefresh = true;
767
+ }
768
+ },
769
+
770
+ /**
771
+ * Notifies subscribers of a source object of changes.
772
+ * @param source - the object to notify of changes.
773
+ * @param args - The change args to pass to subscribers.
774
+ */
775
+ notify(source, args) {
776
+ getNotifier(source).notify(args);
777
+ },
778
+
779
+ /**
780
+ * Defines an observable property on an object or prototype.
781
+ * @param target - The target object to define the observable on.
782
+ * @param nameOrAccessor - The name of the property to define as observable;
783
+ * or a custom accessor that specifies the property name and accessor implementation.
784
+ */
785
+ defineProperty(target, nameOrAccessor) {
786
+ if (typeof nameOrAccessor === "string") {
787
+ nameOrAccessor = new DefaultObservableAccessor(nameOrAccessor);
788
+ }
789
+
790
+ getAccessors(target).push(nameOrAccessor);
791
+ Reflect.defineProperty(target, nameOrAccessor.name, {
792
+ enumerable: true,
793
+ get: function () {
794
+ return nameOrAccessor.getValue(this);
795
+ },
796
+ set: function (newValue) {
797
+ nameOrAccessor.setValue(this, newValue);
798
+ }
799
+ });
800
+ },
801
+
802
+ /**
803
+ * Finds all the observable accessors defined on the target,
804
+ * including its prototype chain.
805
+ * @param target - The target object to search for accessor on.
806
+ */
807
+ getAccessors,
808
+
809
+ /**
810
+ * Creates a {@link BindingObserver} that can watch the
811
+ * provided {@link Binding} for changes.
812
+ * @param binding - The binding to observe.
813
+ * @param initialSubscriber - An initial subscriber to changes in the binding value.
814
+ * @param isVolatileBinding - Indicates whether the binding's dependency list must be re-evaluated on every value evaluation.
815
+ */
816
+ binding(binding, initialSubscriber, isVolatileBinding = this.isVolatileBinding(binding)) {
817
+ return new BindingObserverImplementation(binding, initialSubscriber, isVolatileBinding);
818
+ },
819
+
820
+ /**
821
+ * Determines whether a binding expression is volatile and needs to have its dependency list re-evaluated
822
+ * on every evaluation of the value.
823
+ * @param binding - The binding to inspect.
824
+ */
825
+ isVolatileBinding(binding) {
826
+ return volatileRegex.test(binding.toString());
827
+ }
828
+
829
+ });
666
830
  });
667
- const getNotifier = Observable.getNotifier;
668
- const trackVolatile = Observable.trackVolatile;
669
- const queueUpdate = DOM.queueUpdate;
670
831
  /**
671
832
  * Decorator: Defines an observable property on the target.
672
833
  * @param target - The target to define the observable on.
@@ -688,20 +849,26 @@ function observable(target, nameOrAccessor) {
688
849
  function volatile(target, name, descriptor) {
689
850
  return Object.assign({}, descriptor, {
690
851
  get: function () {
691
- trackVolatile();
852
+ Observable.trackVolatile();
692
853
  return descriptor.get.apply(this);
693
854
  }
694
855
  });
695
856
  }
696
- let currentEvent = null;
697
- /**
698
- * @param event - The event to set as current for the context.
699
- * @internal
700
- */
857
+ const contextEvent = FAST.getById(3
858
+ /* contextEvent */
859
+ , () => {
860
+ let current = null;
861
+ return {
862
+ get() {
863
+ return current;
864
+ },
701
865
 
702
- function setCurrentEvent(event) {
703
- currentEvent = event;
704
- }
866
+ set(event) {
867
+ current = event;
868
+ }
869
+
870
+ };
871
+ });
705
872
  /**
706
873
  * Provides additional contextual information available to behaviors and expressions.
707
874
  * @public
@@ -735,7 +902,7 @@ class ExecutionContext {
735
902
 
736
903
 
737
904
  get event() {
738
- return currentEvent;
905
+ return contextEvent.get();
739
906
  }
740
907
  /**
741
908
  * Indicates whether the current item within a repeat context
@@ -782,6 +949,16 @@ class ExecutionContext {
782
949
  get isLast() {
783
950
  return this.index === this.length - 1;
784
951
  }
952
+ /**
953
+ * Sets the event for the current execution context.
954
+ * @param event - The event to set.
955
+ * @internal
956
+ */
957
+
958
+
959
+ static setEvent(event) {
960
+ contextEvent.set(event);
961
+ }
785
962
 
786
963
  }
787
964
  Observable.defineProperty(ExecutionContext.prototype, "index");
@@ -793,127 +970,6 @@ Observable.defineProperty(ExecutionContext.prototype, "length");
793
970
 
794
971
  const defaultExecutionContext = Object.seal(new ExecutionContext());
795
972
 
796
- class BindingObserverImplementation extends SubscriberSet {
797
- constructor(binding, initialSubscriber, isVolatileBinding = false) {
798
- super(binding, initialSubscriber);
799
- this.binding = binding;
800
- this.isVolatileBinding = isVolatileBinding;
801
- this.needsRefresh = true;
802
- this.needsQueue = true;
803
- this.first = this;
804
- this.last = null;
805
- this.propertySource = void 0;
806
- this.propertyName = void 0;
807
- this.notifier = void 0;
808
- this.next = void 0;
809
- }
810
-
811
- observe(source, context) {
812
- if (this.needsRefresh && this.last !== null) {
813
- this.disconnect();
814
- }
815
-
816
- const previousWatcher = watcher;
817
- watcher = this.needsRefresh ? this : void 0;
818
- this.needsRefresh = this.isVolatileBinding;
819
- const result = this.binding(source, context);
820
- watcher = previousWatcher;
821
- return result;
822
- }
823
-
824
- disconnect() {
825
- if (this.last !== null) {
826
- let current = this.first;
827
-
828
- while (current !== void 0) {
829
- current.notifier.unsubscribe(this, current.propertyName);
830
- current = current.next;
831
- }
832
-
833
- this.last = null;
834
- this.needsRefresh = this.needsQueue = true;
835
- }
836
- }
837
- /** @internal */
838
-
839
-
840
- watch(propertySource, propertyName) {
841
- const prev = this.last;
842
- const notifier = getNotifier(propertySource);
843
- const current = prev === null ? this.first : {};
844
- current.propertySource = propertySource;
845
- current.propertyName = propertyName;
846
- current.notifier = notifier;
847
- notifier.subscribe(this, propertyName);
848
-
849
- if (prev !== null) {
850
- if (!this.needsRefresh) {
851
- // Declaring the variable prior to assignment below circumvents
852
- // a bug in Angular's optimization process causing infinite recursion
853
- // of this watch() method. Details https://github.com/microsoft/fast/issues/4969
854
- let prevValue;
855
- watcher = void 0;
856
- /* eslint-disable-next-line */
857
-
858
- prevValue = prev.propertySource[prev.propertyName];
859
- watcher = this;
860
-
861
- if (propertySource === prevValue) {
862
- this.needsRefresh = true;
863
- }
864
- }
865
-
866
- prev.next = current;
867
- }
868
-
869
- this.last = current;
870
- }
871
- /** @internal */
872
-
873
-
874
- handleChange() {
875
- if (this.needsQueue) {
876
- this.needsQueue = false;
877
- queueUpdate(this);
878
- }
879
- }
880
- /** @internal */
881
-
882
-
883
- call() {
884
- if (this.last !== null) {
885
- this.needsQueue = true;
886
- this.notify(this);
887
- }
888
- }
889
-
890
- records() {
891
- let next = this.first;
892
- return {
893
- next: () => {
894
- const current = next;
895
-
896
- if (current === undefined) {
897
- return {
898
- value: void 0,
899
- done: true
900
- };
901
- } else {
902
- next = next.next;
903
- return {
904
- value: current,
905
- done: false
906
- };
907
- }
908
- },
909
- [Symbol.iterator]: function () {
910
- return this;
911
- }
912
- };
913
- }
914
-
915
- }
916
-
917
973
  /**
918
974
  * Instructs the template engine to apply behavior to a node.
919
975
  * @public
@@ -1276,9 +1332,9 @@ class BindingBehavior {
1276
1332
 
1277
1333
 
1278
1334
  handleEvent(event) {
1279
- setCurrentEvent(event);
1335
+ ExecutionContext.setEvent(event);
1280
1336
  const result = this.binding(this.source, this.context);
1281
- setCurrentEvent(null);
1337
+ ExecutionContext.setEvent(null);
1282
1338
 
1283
1339
  if (result !== true) {
1284
1340
  event.preventDefault();
@@ -2274,7 +2330,26 @@ const defaultShadowOptions = {
2274
2330
  mode: "open"
2275
2331
  };
2276
2332
  const defaultElementOptions = {};
2277
- const fastDefinitions = new Map();
2333
+ const fastRegistry = FAST.getById(4
2334
+ /* elementRegistry */
2335
+ , () => {
2336
+ const typeToDefinition = new Map();
2337
+ return Object.freeze({
2338
+ register(definition) {
2339
+ if (typeToDefinition.has(definition.type)) {
2340
+ return false;
2341
+ }
2342
+
2343
+ typeToDefinition.set(definition.type, definition);
2344
+ return true;
2345
+ },
2346
+
2347
+ getByType(key) {
2348
+ return typeToDefinition.get(key);
2349
+ }
2350
+
2351
+ });
2352
+ });
2278
2353
  /**
2279
2354
  * Defines metadata for a FASTElement.
2280
2355
  * @public
@@ -2317,6 +2392,14 @@ class FASTElementDefinition {
2317
2392
  this.elementOptions = nameOrConfig.elementOptions === void 0 ? defaultElementOptions : Object.assign(Object.assign({}, defaultElementOptions), nameOrConfig.elementOptions);
2318
2393
  this.styles = nameOrConfig.styles === void 0 ? void 0 : Array.isArray(nameOrConfig.styles) ? ElementStyles.create(nameOrConfig.styles) : nameOrConfig.styles instanceof ElementStyles ? nameOrConfig.styles : ElementStyles.create([nameOrConfig.styles]);
2319
2394
  }
2395
+ /**
2396
+ * Indicates if this element has been defined in at least one registry.
2397
+ */
2398
+
2399
+
2400
+ get isDefined() {
2401
+ return !!fastRegistry.getByType(this.type);
2402
+ }
2320
2403
  /**
2321
2404
  * Defines a custom element based on this definition.
2322
2405
  * @param registry - The element registry to define the element in.
@@ -2326,7 +2409,7 @@ class FASTElementDefinition {
2326
2409
  define(registry = customElements) {
2327
2410
  const type = this.type;
2328
2411
 
2329
- if (!this.isDefined) {
2412
+ if (fastRegistry.register(this)) {
2330
2413
  const attributes = this.attributes;
2331
2414
  const proto = type.prototype;
2332
2415
 
@@ -2338,8 +2421,6 @@ class FASTElementDefinition {
2338
2421
  value: this.observedAttributes,
2339
2422
  enumerable: true
2340
2423
  });
2341
- fastDefinitions.set(type, this);
2342
- this.isDefined = true;
2343
2424
  }
2344
2425
 
2345
2426
  if (!registry.get(this.name)) {
@@ -2348,17 +2429,14 @@ class FASTElementDefinition {
2348
2429
 
2349
2430
  return this;
2350
2431
  }
2351
- /**
2352
- * Gets the element definition associated with the specified type.
2353
- * @param type - The custom element type to retrieve the definition for.
2354
- */
2355
-
2356
-
2357
- static forType(type) {
2358
- return fastDefinitions.get(type);
2359
- }
2360
2432
 
2361
2433
  }
2434
+ /**
2435
+ * Gets the element definition associated with the specified type.
2436
+ * @param type - The custom element type to retrieve the definition for.
2437
+ */
2438
+
2439
+ FASTElementDefinition.forType = fastRegistry.getByType;
2362
2440
 
2363
2441
  const shadowRoots = new WeakMap();
2364
2442
  const defaultEventOptions = {
@@ -3434,7 +3512,10 @@ class ArrayObserver extends SubscriberSet {
3434
3512
  this.splices = void 0;
3435
3513
  this.needsQueue = true;
3436
3514
  this.call = this.flush;
3437
- source.$fastController = this;
3515
+ Reflect.defineProperty(source, "$fastController", {
3516
+ value: this,
3517
+ enumerable: false
3518
+ });
3438
3519
  }
3439
3520
 
3440
3521
  addSplice(splice) {
@@ -3505,7 +3586,10 @@ function enableArrayObservation() {
3505
3586
  return;
3506
3587
  }
3507
3588
 
3508
- proto.$fastPatch = true;
3589
+ Reflect.defineProperty(proto, "$fastPatch", {
3590
+ value: 1,
3591
+ enumerable: false
3592
+ });
3509
3593
  const pop = proto.pop;
3510
3594
  const push = proto.push;
3511
3595
  const reverse = proto.reverse;
@@ -4157,4 +4241,4 @@ function children(propertyOrOptions) {
4157
4241
  return new AttachedBehaviorHTMLDirective("fast-children", ChildrenBehavior, propertyOrOptions);
4158
4242
  }
4159
4243
 
4160
- export { $global, AttachedBehaviorHTMLDirective, AttributeDefinition, BindingBehavior, CSSDirective, ChildrenBehavior, Controller, DOM, ElementStyles, ExecutionContext, FASTElement, FASTElementDefinition, HTMLBindingDirective, HTMLDirective, HTMLView, Observable, PropertyChangeNotifier, RefBehavior, RepeatBehavior, RepeatDirective, SlottedBehavior, SubscriberSet, TargetedHTMLDirective, ViewTemplate, attr, booleanConverter, children, compileTemplate, css, cssPartial, customElement, defaultExecutionContext, elements, emptyArray, enableArrayObservation, html, nullableNumberConverter, observable, ref, repeat, setCurrentEvent, slotted, volatile, when };
4244
+ export { $global, AttachedBehaviorHTMLDirective, AttributeDefinition, BindingBehavior, CSSDirective, ChildrenBehavior, Controller, DOM, ElementStyles, ExecutionContext, FAST, FASTElement, FASTElementDefinition, HTMLBindingDirective, HTMLDirective, HTMLView, Observable, PropertyChangeNotifier, RefBehavior, RepeatBehavior, RepeatDirective, SlottedBehavior, SubscriberSet, TargetedHTMLDirective, ViewTemplate, attr, booleanConverter, children, compileTemplate, css, cssPartial, customElement, defaultExecutionContext, elements, emptyArray, enableArrayObservation, html, nullableNumberConverter, observable, ref, repeat, slotted, volatile, when };