@microsoft/fast-element 1.10.2 → 2.0.0-beta.3

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 (104) hide show
  1. package/.eslintrc.json +1 -12
  2. package/CHANGELOG.json +387 -1
  3. package/CHANGELOG.md +74 -2
  4. package/README.md +2 -2
  5. package/dist/dts/components/attributes.d.ts +4 -1
  6. package/dist/dts/components/controller.d.ts +12 -11
  7. package/dist/dts/components/fast-definitions.d.ts +10 -2
  8. package/dist/dts/components/fast-element.d.ts +12 -5
  9. package/dist/dts/context.d.ts +157 -0
  10. package/dist/dts/debug.d.ts +1 -0
  11. package/dist/dts/hooks.d.ts +20 -0
  12. package/dist/dts/index.d.ts +16 -15
  13. package/dist/dts/index.debug.d.ts +2 -0
  14. package/dist/dts/index.rollup.d.ts +2 -0
  15. package/dist/dts/index.rollup.debug.d.ts +3 -0
  16. package/dist/dts/interfaces.d.ts +145 -0
  17. package/dist/dts/metadata.d.ts +25 -0
  18. package/dist/dts/observation/arrays.d.ts +207 -0
  19. package/dist/dts/observation/behavior.d.ts +4 -4
  20. package/dist/dts/observation/notifier.d.ts +18 -18
  21. package/dist/dts/observation/observable.d.ts +56 -18
  22. package/dist/dts/observation/splice-strategies.d.ts +13 -0
  23. package/dist/dts/observation/update-queue.d.ts +40 -0
  24. package/dist/dts/platform.d.ts +18 -67
  25. package/dist/dts/polyfills.d.ts +8 -0
  26. package/dist/dts/styles/css-directive.d.ts +43 -5
  27. package/dist/dts/styles/css.d.ts +19 -3
  28. package/dist/dts/styles/element-styles.d.ts +42 -62
  29. package/dist/dts/templating/binding-signal.d.ts +38 -0
  30. package/dist/dts/templating/binding-two-way.d.ts +56 -0
  31. package/dist/dts/templating/binding.d.ts +233 -65
  32. package/dist/dts/templating/children.d.ts +18 -15
  33. package/dist/dts/templating/compiler.d.ts +46 -28
  34. package/dist/dts/templating/dom.d.ts +41 -0
  35. package/dist/dts/templating/html-directive.d.ts +181 -43
  36. package/dist/dts/templating/markup.d.ts +48 -0
  37. package/dist/dts/templating/node-observation.d.ts +45 -29
  38. package/dist/dts/templating/ref.d.ts +6 -12
  39. package/dist/dts/templating/repeat.d.ts +26 -14
  40. package/dist/dts/templating/slotted.d.ts +13 -14
  41. package/dist/dts/templating/template.d.ts +27 -21
  42. package/dist/dts/templating/view.d.ts +15 -22
  43. package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +1 -1
  44. package/dist/dts/utilities.d.ts +40 -0
  45. package/dist/esm/components/attributes.js +25 -24
  46. package/dist/esm/components/controller.js +77 -57
  47. package/dist/esm/components/fast-definitions.js +16 -22
  48. package/dist/esm/components/fast-element.js +10 -2
  49. package/dist/esm/context.js +159 -0
  50. package/dist/esm/debug.js +30 -0
  51. package/dist/esm/hooks.js +32 -0
  52. package/dist/esm/index.debug.js +2 -0
  53. package/dist/esm/index.js +19 -14
  54. package/dist/esm/index.rollup.debug.js +3 -0
  55. package/dist/esm/index.rollup.js +2 -0
  56. package/dist/esm/interfaces.js +8 -1
  57. package/dist/esm/metadata.js +60 -0
  58. package/dist/esm/observation/arrays.js +269 -0
  59. package/dist/esm/observation/notifier.js +27 -35
  60. package/dist/esm/observation/observable.js +93 -68
  61. package/dist/esm/observation/{array-change-records.js → splice-strategies.js} +136 -62
  62. package/dist/esm/observation/update-queue.js +67 -0
  63. package/dist/esm/platform.js +36 -42
  64. package/dist/esm/polyfills.js +85 -0
  65. package/dist/esm/styles/css-directive.js +29 -13
  66. package/dist/esm/styles/css.js +27 -40
  67. package/dist/esm/styles/element-styles.js +65 -104
  68. package/dist/esm/templating/binding-signal.js +84 -0
  69. package/dist/esm/templating/binding-two-way.js +82 -0
  70. package/dist/esm/templating/binding.js +306 -153
  71. package/dist/esm/templating/children.js +33 -23
  72. package/dist/esm/templating/compiler.js +236 -152
  73. package/dist/esm/templating/dom.js +49 -0
  74. package/dist/esm/templating/html-directive.js +128 -40
  75. package/dist/esm/templating/markup.js +75 -0
  76. package/dist/esm/templating/node-observation.js +50 -45
  77. package/dist/esm/templating/ref.js +7 -16
  78. package/dist/esm/templating/repeat.js +39 -36
  79. package/dist/esm/templating/slotted.js +23 -20
  80. package/dist/esm/templating/template.js +51 -95
  81. package/dist/esm/templating/view.js +44 -43
  82. package/dist/esm/templating/when.js +2 -1
  83. package/dist/esm/utilities.js +139 -0
  84. package/dist/fast-element.api.json +11789 -5377
  85. package/dist/fast-element.d.ts +1178 -530
  86. package/dist/fast-element.debug.js +3722 -0
  87. package/dist/fast-element.debug.min.js +1 -0
  88. package/dist/fast-element.js +3484 -4033
  89. package/dist/fast-element.min.js +1 -1
  90. package/dist/fast-element.untrimmed.d.ts +2699 -0
  91. package/docs/api-report.md +472 -219
  92. package/docs/fast-element-2-changes.md +15 -0
  93. package/docs/guide/declaring-templates.md +4 -4
  94. package/docs/guide/defining-elements.md +2 -2
  95. package/docs/guide/next-steps.md +2 -2
  96. package/docs/guide/observables-and-state.md +1 -1
  97. package/docs/guide/using-directives.md +1 -1
  98. package/karma.conf.cjs +6 -17
  99. package/package.json +63 -15
  100. package/dist/dts/dom.d.ts +0 -112
  101. package/dist/dts/observation/array-change-records.d.ts +0 -48
  102. package/dist/dts/observation/array-observer.d.ts +0 -9
  103. package/dist/esm/dom.js +0 -207
  104. package/dist/esm/observation/array-observer.js +0 -177
@@ -0,0 +1,60 @@
1
+ import { emptyArray } from "./platform.js";
2
+ // Tiny polyfill for TypeScript's Reflect metadata API.
3
+ const metadataByTarget = new Map();
4
+ if (!("metadata" in Reflect)) {
5
+ Reflect.metadata = function (key, value) {
6
+ return function (target) {
7
+ Reflect.defineMetadata(key, value, target);
8
+ };
9
+ };
10
+ Reflect.defineMetadata = function (key, value, target) {
11
+ let metadata = metadataByTarget.get(target);
12
+ if (metadata === void 0) {
13
+ metadataByTarget.set(target, (metadata = new Map()));
14
+ }
15
+ metadata.set(key, value);
16
+ };
17
+ Reflect.getOwnMetadata = function (key, target) {
18
+ const metadata = metadataByTarget.get(target);
19
+ if (metadata !== void 0) {
20
+ return metadata.get(key);
21
+ }
22
+ return void 0;
23
+ };
24
+ }
25
+ /**
26
+ * Provides basic metadata capabilities used by Context and Dependency Injection.
27
+ */
28
+ export const Metadata = Object.freeze({
29
+ /**
30
+ * Gets the "design:paramtypes" metadata for the specified type.
31
+ * @param Type - The type to get the metadata for.
32
+ * @returns The metadata array or a frozen empty array if no metadata is found.
33
+ */
34
+ getDesignParamTypes: Type => {
35
+ var _a;
36
+ return (_a = Reflect.getOwnMetadata("design:paramtypes", Type)) !== null && _a !== void 0 ? _a : emptyArray;
37
+ },
38
+ /**
39
+ * Gets the "annotation:paramtypes" metadata for the specified type.
40
+ * @param Type - The type to get the metadata for.
41
+ * @returns The metadata array or a frozen empty array if no metadata is found.
42
+ */
43
+ getAnnotationParamTypes: Type => {
44
+ var _a;
45
+ return (_a = Reflect.getOwnMetadata("annotation:paramtypes", Type)) !== null && _a !== void 0 ? _a : emptyArray;
46
+ },
47
+ /**
48
+ *
49
+ * @param Type - Gets the "annotation:paramtypes" metadata for the specified type. If none is found,
50
+ * an empty, mutable metadata array is created and added.
51
+ * @returns The metadata array.
52
+ */
53
+ getOrCreateAnnotationParamTypes(Type) {
54
+ let types = this.getAnnotationParamTypes(Type);
55
+ if (types === emptyArray) {
56
+ Reflect.defineMetadata("annotation:paramtypes", (types = []), Type);
57
+ }
58
+ return types;
59
+ },
60
+ });
@@ -0,0 +1,269 @@
1
+ import { emptyArray } from "../platform.js";
2
+ import { SubscriberSet } from "./notifier.js";
3
+ import { Observable } from "./observable.js";
4
+ import { Updates } from "./update-queue.js";
5
+ /**
6
+ * A splice map is a representation of how a previous array of items
7
+ * was transformed into a new array of items. Conceptually it is a list of
8
+ * tuples of
9
+ *
10
+ * (index, removed, addedCount)
11
+ *
12
+ * which are kept in ascending index order of. The tuple represents that at
13
+ * the |index|, |removed| sequence of items were removed, and counting forward
14
+ * from |index|, |addedCount| items were added.
15
+ * @public
16
+ */
17
+ export class Splice {
18
+ /**
19
+ * Creates a splice.
20
+ * @param index - The index that the splice occurs at.
21
+ * @param removed - The items that were removed.
22
+ * @param addedCount - The number of items that were added.
23
+ */
24
+ constructor(index, removed, addedCount) {
25
+ this.index = index;
26
+ this.removed = removed;
27
+ this.addedCount = addedCount;
28
+ }
29
+ /**
30
+ * Adjusts the splice index based on the provided array.
31
+ * @param array - The array to adjust to.
32
+ * @returns The same splice, mutated based on the reference array.
33
+ */
34
+ adjustTo(array) {
35
+ let index = this.index;
36
+ const arrayLength = array.length;
37
+ if (index > arrayLength) {
38
+ index = arrayLength - this.addedCount;
39
+ }
40
+ else if (index < 0) {
41
+ index = arrayLength + this.removed.length + index - this.addedCount;
42
+ }
43
+ this.index = index < 0 ? 0 : index;
44
+ return this;
45
+ }
46
+ }
47
+ /**
48
+ * Indicates what level of feature support the splice
49
+ * strategy provides.
50
+ * @public
51
+ */
52
+ export const SpliceStrategySupport = Object.freeze({
53
+ /**
54
+ * Only supports resets.
55
+ */
56
+ reset: 1,
57
+ /**
58
+ * Supports tracking splices and resets.
59
+ */
60
+ splice: 2,
61
+ /**
62
+ * Supports tracking splices and resets, while applying some form
63
+ * of optimization, such as merging, to the splices.
64
+ */
65
+ optimized: 3,
66
+ });
67
+ const reset = new Splice(0, emptyArray, 0);
68
+ reset.reset = true;
69
+ const resetSplices = [reset];
70
+ let defaultSpliceStrategy = Object.freeze({
71
+ support: SpliceStrategySupport.splice,
72
+ normalize(previous, current, changes) {
73
+ return previous === void 0 ? changes !== null && changes !== void 0 ? changes : emptyArray : resetSplices;
74
+ },
75
+ pop(array, observer, pop, args) {
76
+ const notEmpty = array.length > 0;
77
+ const result = pop.apply(array, args);
78
+ if (notEmpty) {
79
+ observer.addSplice(new Splice(array.length, [result], 0));
80
+ }
81
+ return result;
82
+ },
83
+ push(array, observer, push, args) {
84
+ const result = push.apply(array, args);
85
+ observer.addSplice(new Splice(array.length - args.length, [], args.length).adjustTo(array));
86
+ return result;
87
+ },
88
+ reverse(array, observer, reverse, args) {
89
+ const result = reverse.apply(array, args);
90
+ observer.reset(array);
91
+ return result;
92
+ },
93
+ shift(array, observer, shift, args) {
94
+ const notEmpty = array.length > 0;
95
+ const result = shift.apply(array, args);
96
+ if (notEmpty) {
97
+ observer.addSplice(new Splice(0, [result], 0));
98
+ }
99
+ return result;
100
+ },
101
+ sort(array, observer, sort, args) {
102
+ const result = sort.apply(array, args);
103
+ observer.reset(array);
104
+ return result;
105
+ },
106
+ splice(array, observer, splice, args) {
107
+ const result = splice.apply(array, args);
108
+ observer.addSplice(new Splice(+args[0], result, args.length > 2 ? args.length - 2 : 0).adjustTo(array));
109
+ return result;
110
+ },
111
+ unshift(array, observer, unshift, args) {
112
+ const result = unshift.apply(array, args);
113
+ observer.addSplice(new Splice(0, [], args.length).adjustTo(array));
114
+ return result;
115
+ },
116
+ });
117
+ /**
118
+ * Functionality related to tracking changes in arrays.
119
+ * @public
120
+ */
121
+ export const SpliceStrategy = Object.freeze({
122
+ /**
123
+ * A set of changes that represent a full array reset.
124
+ */
125
+ reset: resetSplices,
126
+ /**
127
+ * Sets the default strategy to use for array observers.
128
+ * @param strategy - The splice strategy to use.
129
+ */
130
+ setDefaultStrategy(strategy) {
131
+ defaultSpliceStrategy = strategy;
132
+ },
133
+ });
134
+ function setNonEnumerable(target, property, value) {
135
+ Reflect.defineProperty(target, property, {
136
+ value,
137
+ enumerable: false,
138
+ });
139
+ }
140
+ class DefaultArrayObserver extends SubscriberSet {
141
+ constructor(subject) {
142
+ super(subject);
143
+ this.oldCollection = void 0;
144
+ this.splices = void 0;
145
+ this.needsQueue = true;
146
+ this._strategy = null;
147
+ this._lengthObserver = void 0;
148
+ this.call = this.flush;
149
+ setNonEnumerable(subject, "$fastController", this);
150
+ }
151
+ get strategy() {
152
+ return this._strategy;
153
+ }
154
+ set strategy(value) {
155
+ this._strategy = value;
156
+ }
157
+ get lengthObserver() {
158
+ let observer = this._lengthObserver;
159
+ if (observer === void 0) {
160
+ const array = this.subject;
161
+ this._lengthObserver = observer = {
162
+ length: array.length,
163
+ handleChange() {
164
+ if (this.length !== array.length) {
165
+ this.length = array.length;
166
+ Observable.notify(observer, "length");
167
+ }
168
+ },
169
+ };
170
+ this.subscribe(observer);
171
+ }
172
+ return observer;
173
+ }
174
+ subscribe(subscriber) {
175
+ this.flush();
176
+ super.subscribe(subscriber);
177
+ }
178
+ addSplice(splice) {
179
+ if (this.splices === void 0) {
180
+ this.splices = [splice];
181
+ }
182
+ else {
183
+ this.splices.push(splice);
184
+ }
185
+ this.enqueue();
186
+ }
187
+ reset(oldCollection) {
188
+ this.oldCollection = oldCollection;
189
+ this.enqueue();
190
+ }
191
+ flush() {
192
+ var _a;
193
+ const splices = this.splices;
194
+ const oldCollection = this.oldCollection;
195
+ if (splices === void 0 && oldCollection === void 0) {
196
+ return;
197
+ }
198
+ this.needsQueue = true;
199
+ this.splices = void 0;
200
+ this.oldCollection = void 0;
201
+ this.notify(((_a = this._strategy) !== null && _a !== void 0 ? _a : defaultSpliceStrategy).normalize(oldCollection, this.subject, splices));
202
+ }
203
+ enqueue() {
204
+ if (this.needsQueue) {
205
+ this.needsQueue = false;
206
+ Updates.enqueue(this);
207
+ }
208
+ }
209
+ }
210
+ let enabled = false;
211
+ /**
212
+ * An observer for arrays.
213
+ * @public
214
+ */
215
+ export const ArrayObserver = Object.freeze({
216
+ /**
217
+ * Enables the array observation mechanism.
218
+ * @remarks
219
+ * Array observation is enabled automatically when using the
220
+ * {@link RepeatDirective}, so calling this API manually is
221
+ * not typically necessary.
222
+ */
223
+ enable() {
224
+ if (enabled) {
225
+ return;
226
+ }
227
+ enabled = true;
228
+ Observable.setArrayObserverFactory((collection) => new DefaultArrayObserver(collection));
229
+ const proto = Array.prototype;
230
+ if (!proto.$fastPatch) {
231
+ setNonEnumerable(proto, "$fastPatch", 1);
232
+ [
233
+ proto.pop,
234
+ proto.push,
235
+ proto.reverse,
236
+ proto.shift,
237
+ proto.sort,
238
+ proto.splice,
239
+ proto.unshift,
240
+ ].forEach(method => {
241
+ proto[method.name] = function (...args) {
242
+ var _a;
243
+ const o = this.$fastController;
244
+ return o === void 0
245
+ ? method.apply(this, args)
246
+ : ((_a = o.strategy) !== null && _a !== void 0 ? _a : defaultSpliceStrategy)[method.name](this, o, method, args);
247
+ };
248
+ });
249
+ }
250
+ },
251
+ });
252
+ /**
253
+ * Enables observing the length of an array.
254
+ * @param array - The array to observe the length of.
255
+ * @returns The length of the array.
256
+ * @public
257
+ */
258
+ export function lengthOf(array) {
259
+ if (!array) {
260
+ return 0;
261
+ }
262
+ let arrayObserver = array.$fastController;
263
+ if (arrayObserver === void 0) {
264
+ ArrayObserver.enable();
265
+ arrayObserver = Observable.getNotifier(array);
266
+ }
267
+ Observable.track(arrayObserver.lengthObserver, "length");
268
+ return array.length;
269
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * An implementation of {@link Notifier} that efficiently keeps track of
3
3
  * subscribers interested in a specific change notification on an
4
- * observable source.
4
+ * observable subject.
5
5
  *
6
6
  * @remarks
7
7
  * This set is optimized for the most common scenario of 1 or 2 subscribers.
@@ -11,15 +11,15 @@
11
11
  */
12
12
  export class SubscriberSet {
13
13
  /**
14
- * Creates an instance of SubscriberSet for the specified source.
15
- * @param source - The object source that subscribers will receive notifications from.
14
+ * Creates an instance of SubscriberSet for the specified subject.
15
+ * @param subject - The subject that subscribers will receive notifications from.
16
16
  * @param initialSubscriber - An initial subscriber to changes.
17
17
  */
18
- constructor(source, initialSubscriber) {
18
+ constructor(subject, initialSubscriber) {
19
19
  this.sub1 = void 0;
20
20
  this.sub2 = void 0;
21
21
  this.spillover = void 0;
22
- this.source = source;
22
+ this.subject = subject;
23
23
  this.sub1 = initialSubscriber;
24
24
  }
25
25
  /**
@@ -87,20 +87,20 @@ export class SubscriberSet {
87
87
  */
88
88
  notify(args) {
89
89
  const spillover = this.spillover;
90
- const source = this.source;
90
+ const subject = this.subject;
91
91
  if (spillover === void 0) {
92
92
  const sub1 = this.sub1;
93
93
  const sub2 = this.sub2;
94
94
  if (sub1 !== void 0) {
95
- sub1.handleChange(source, args);
95
+ sub1.handleChange(subject, args);
96
96
  }
97
97
  if (sub2 !== void 0) {
98
- sub2.handleChange(source, args);
98
+ sub2.handleChange(subject, args);
99
99
  }
100
100
  }
101
101
  else {
102
102
  for (let i = 0, ii = spillover.length; i < ii; ++i) {
103
- spillover[i].handleChange(source, args);
103
+ spillover[i].handleChange(subject, args);
104
104
  }
105
105
  }
106
106
  }
@@ -112,25 +112,22 @@ export class SubscriberSet {
112
112
  */
113
113
  export class PropertyChangeNotifier {
114
114
  /**
115
- * Creates an instance of PropertyChangeNotifier for the specified source.
116
- * @param source - The object source that subscribers will receive notifications from.
115
+ * Creates an instance of PropertyChangeNotifier for the specified subject.
116
+ * @param subject - The object that subscribers will receive notifications for.
117
117
  */
118
- constructor(source) {
118
+ constructor(subject) {
119
119
  this.subscribers = {};
120
- this.sourceSubscribers = null;
121
- this.source = source;
120
+ this.subjectSubscribers = null;
121
+ this.subject = subject;
122
122
  }
123
123
  /**
124
124
  * Notifies all subscribers, based on the specified property.
125
125
  * @param propertyName - The property name, passed along to subscribers during notification.
126
126
  */
127
127
  notify(propertyName) {
128
- var _a;
129
- const subscribers = this.subscribers[propertyName];
130
- if (subscribers !== void 0) {
131
- subscribers.notify(propertyName);
132
- }
133
- (_a = this.sourceSubscribers) === null || _a === void 0 ? void 0 : _a.notify(propertyName);
128
+ var _a, _b;
129
+ (_a = this.subscribers[propertyName]) === null || _a === void 0 ? void 0 : _a.notify(propertyName);
130
+ (_b = this.subjectSubscribers) === null || _b === void 0 ? void 0 : _b.notify(propertyName);
134
131
  }
135
132
  /**
136
133
  * Subscribes to notification of changes in an object's state.
@@ -138,19 +135,17 @@ export class PropertyChangeNotifier {
138
135
  * @param propertyToWatch - The name of the property that the subscriber is interested in watching for changes.
139
136
  */
140
137
  subscribe(subscriber, propertyToWatch) {
141
- var _a;
138
+ var _a, _b;
139
+ let subscribers;
142
140
  if (propertyToWatch) {
143
- let subscribers = this.subscribers[propertyToWatch];
144
- if (subscribers === void 0) {
145
- this.subscribers[propertyToWatch] = subscribers = new SubscriberSet(this.source);
146
- }
147
- subscribers.subscribe(subscriber);
141
+ subscribers =
142
+ (_a = this.subscribers[propertyToWatch]) !== null && _a !== void 0 ? _a : (this.subscribers[propertyToWatch] = new SubscriberSet(this.subject));
148
143
  }
149
144
  else {
150
- this.sourceSubscribers =
151
- (_a = this.sourceSubscribers) !== null && _a !== void 0 ? _a : new SubscriberSet(this.source);
152
- this.sourceSubscribers.subscribe(subscriber);
145
+ subscribers =
146
+ (_b = this.subjectSubscribers) !== null && _b !== void 0 ? _b : (this.subjectSubscribers = new SubscriberSet(this.subject));
153
147
  }
148
+ subscribers.subscribe(subscriber);
154
149
  }
155
150
  /**
156
151
  * Unsubscribes from notification of changes in an object's state.
@@ -158,15 +153,12 @@ export class PropertyChangeNotifier {
158
153
  * @param propertyToUnwatch - The name of the property that the subscriber is no longer interested in watching.
159
154
  */
160
155
  unsubscribe(subscriber, propertyToUnwatch) {
161
- var _a;
156
+ var _a, _b;
162
157
  if (propertyToUnwatch) {
163
- const subscribers = this.subscribers[propertyToUnwatch];
164
- if (subscribers !== void 0) {
165
- subscribers.unsubscribe(subscriber);
166
- }
158
+ (_a = this.subscribers[propertyToUnwatch]) === null || _a === void 0 ? void 0 : _a.unsubscribe(subscriber);
167
159
  }
168
160
  else {
169
- (_a = this.sourceSubscribers) === null || _a === void 0 ? void 0 : _a.unsubscribe(subscriber);
161
+ (_b = this.subjectSubscribers) === null || _b === void 0 ? void 0 : _b.unsubscribe(subscriber);
170
162
  }
171
163
  }
172
164
  }