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

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 (58) hide show
  1. package/CHANGELOG.json +147 -0
  2. package/CHANGELOG.md +42 -1
  3. package/dist/dts/components/fast-definitions.d.ts +11 -8
  4. package/dist/dts/components/fast-element.d.ts +13 -3
  5. package/dist/dts/context.d.ts +157 -0
  6. package/dist/dts/di/di.d.ts +854 -0
  7. package/dist/dts/hooks.d.ts +2 -2
  8. package/dist/dts/interfaces.d.ts +39 -7
  9. package/dist/dts/metadata.d.ts +25 -0
  10. package/dist/dts/observation/arrays.d.ts +1 -1
  11. package/dist/dts/observation/behavior.d.ts +4 -4
  12. package/dist/dts/observation/observable.d.ts +59 -72
  13. package/dist/dts/styles/element-styles.d.ts +6 -0
  14. package/dist/dts/templating/binding-signal.d.ts +21 -0
  15. package/dist/dts/templating/binding-two-way.d.ts +31 -0
  16. package/dist/dts/templating/binding.d.ts +74 -201
  17. package/dist/dts/templating/compiler.d.ts +1 -2
  18. package/dist/dts/templating/html-directive.d.ts +31 -3
  19. package/dist/dts/templating/render.d.ts +277 -0
  20. package/dist/dts/templating/repeat.d.ts +13 -63
  21. package/dist/dts/templating/template.d.ts +11 -60
  22. package/dist/dts/templating/view.d.ts +9 -9
  23. package/dist/dts/templating/when.d.ts +3 -3
  24. package/dist/dts/testing/exports.d.ts +2 -0
  25. package/dist/dts/testing/fixture.d.ts +90 -0
  26. package/dist/dts/testing/timeout.d.ts +7 -0
  27. package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +0 -0
  28. package/dist/esm/components/fast-definitions.js +27 -27
  29. package/dist/esm/components/fast-element.js +20 -4
  30. package/dist/esm/context.js +163 -0
  31. package/dist/esm/debug.js +35 -4
  32. package/dist/esm/di/di.js +1349 -0
  33. package/dist/esm/metadata.js +60 -0
  34. package/dist/esm/observation/arrays.js +1 -1
  35. package/dist/esm/observation/observable.js +73 -21
  36. package/dist/esm/platform.js +1 -1
  37. package/dist/esm/styles/element-styles.js +14 -0
  38. package/dist/esm/templating/binding-signal.js +79 -0
  39. package/dist/esm/templating/binding-two-way.js +98 -0
  40. package/dist/esm/templating/binding.js +137 -313
  41. package/dist/esm/templating/compiler.js +30 -7
  42. package/dist/esm/templating/html-directive.js +16 -2
  43. package/dist/esm/templating/render.js +392 -0
  44. package/dist/esm/templating/repeat.js +60 -38
  45. package/dist/esm/templating/template.js +9 -26
  46. package/dist/esm/templating/when.js +5 -4
  47. package/dist/esm/testing/exports.js +2 -0
  48. package/dist/esm/testing/fixture.js +88 -0
  49. package/dist/esm/testing/timeout.js +24 -0
  50. package/dist/fast-element.api.json +8509 -10358
  51. package/dist/fast-element.d.ts +315 -522
  52. package/dist/fast-element.debug.js +417 -438
  53. package/dist/fast-element.debug.min.js +1 -1
  54. package/dist/fast-element.js +382 -434
  55. package/dist/fast-element.min.js +1 -1
  56. package/dist/fast-element.untrimmed.d.ts +324 -529
  57. package/docs/api-report.md +124 -232
  58. package/package.json +32 -4
@@ -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
+ });
@@ -255,7 +255,7 @@ export const ArrayObserver = Object.freeze({
255
255
  * @returns The length of the array.
256
256
  * @public
257
257
  */
258
- export function length(array) {
258
+ export function lengthOf(array) {
259
259
  if (!array) {
260
260
  return 0;
261
261
  }
@@ -63,7 +63,7 @@ export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () =>
63
63
  }
64
64
  }
65
65
  }
66
- class BindingObserverImplementation extends SubscriberSet {
66
+ class ExpressionNotifierImplementation extends SubscriberSet {
67
67
  constructor(binding, initialSubscriber, isVolatileBinding = false) {
68
68
  super(binding, initialSubscriber);
69
69
  this.binding = binding;
@@ -218,14 +218,14 @@ export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () =>
218
218
  */
219
219
  getAccessors,
220
220
  /**
221
- * Creates a {@link BindingObserver} that can watch the
222
- * provided {@link Binding} for changes.
221
+ * Creates a {@link ExpressionNotifier} that can watch the
222
+ * provided {@link Expression} for changes.
223
223
  * @param binding - The binding to observe.
224
224
  * @param initialSubscriber - An initial subscriber to changes in the binding value.
225
225
  * @param isVolatileBinding - Indicates whether the binding's dependency list must be re-evaluated on every value evaluation.
226
226
  */
227
227
  binding(binding, initialSubscriber, isVolatileBinding = this.isVolatileBinding(binding)) {
228
- return new BindingObserverImplementation(binding, initialSubscriber, isVolatileBinding);
228
+ return new ExpressionNotifierImplementation(binding, initialSubscriber, isVolatileBinding);
229
229
  },
230
230
  /**
231
231
  * Determines whether a binding expression is volatile and needs to have its dependency list re-evaluated
@@ -272,72 +272,124 @@ const contextEvent = FAST.getById(3 /* KernelServiceId.contextEvent */, () => {
272
272
  },
273
273
  };
274
274
  });
275
- class DefaultExecutionContext {
275
+ /**
276
+ * Provides additional contextual information available to behaviors and expressions.
277
+ * @public
278
+ */
279
+ export class ExecutionContext {
276
280
  constructor(parentSource = null, parentContext = null) {
281
+ /**
282
+ * The index of the current item within a repeat context.
283
+ */
277
284
  this.index = 0;
285
+ /**
286
+ * The length of the current collection within a repeat context.
287
+ */
278
288
  this.length = 0;
279
289
  this.parent = parentSource;
280
290
  this.parentContext = parentContext;
281
291
  }
292
+ /**
293
+ * The current event within an event handler.
294
+ */
282
295
  get event() {
283
296
  return contextEvent.get();
284
297
  }
298
+ /**
299
+ * Indicates whether the current item within a repeat context
300
+ * has an even index.
301
+ */
285
302
  get isEven() {
286
303
  return this.index % 2 === 0;
287
304
  }
305
+ /**
306
+ * Indicates whether the current item within a repeat context
307
+ * has an odd index.
308
+ */
288
309
  get isOdd() {
289
310
  return this.index % 2 !== 0;
290
311
  }
312
+ /**
313
+ * Indicates whether the current item within a repeat context
314
+ * is the first item in the collection.
315
+ */
291
316
  get isFirst() {
292
317
  return this.index === 0;
293
318
  }
319
+ /**
320
+ * Indicates whether the current item within a repeat context
321
+ * is somewhere in the middle of the collection.
322
+ */
294
323
  get isInMiddle() {
295
324
  return !this.isFirst && !this.isLast;
296
325
  }
326
+ /**
327
+ * Indicates whether the current item within a repeat context
328
+ * is the last item in the collection.
329
+ */
297
330
  get isLast() {
298
331
  return this.index === this.length - 1;
299
332
  }
333
+ /**
334
+ * Returns the typed event detail of a custom event.
335
+ */
300
336
  eventDetail() {
301
337
  return this.event.detail;
302
338
  }
339
+ /**
340
+ * Returns the typed event target of the event.
341
+ */
303
342
  eventTarget() {
304
343
  return this.event.target;
305
344
  }
345
+ /**
346
+ * Updates the position/size on a context associated with a list item.
347
+ * @param index - The new index of the item.
348
+ * @param length - The new length of the list.
349
+ */
306
350
  updatePosition(index, length) {
307
351
  this.index = index;
308
352
  this.length = length;
309
353
  }
354
+ /**
355
+ * Creates a new execution context descendent from the current context.
356
+ * @param source - The source for the context if different than the parent.
357
+ * @returns A child execution context.
358
+ */
310
359
  createChildContext(parentSource) {
311
- return new DefaultExecutionContext(parentSource, this);
360
+ return new ExecutionContext(parentSource, this);
312
361
  }
362
+ /**
363
+ * Creates a new execution context descent suitable for use in list rendering.
364
+ * @param item - The list item to serve as the source.
365
+ * @param index - The index of the item in the list.
366
+ * @param length - The length of the list.
367
+ */
313
368
  createItemContext(index, length) {
314
369
  const childContext = Object.create(this);
315
370
  childContext.index = index;
316
371
  childContext.length = length;
317
372
  return childContext;
318
373
  }
319
- }
320
- Observable.defineProperty(DefaultExecutionContext.prototype, "index");
321
- Observable.defineProperty(DefaultExecutionContext.prototype, "length");
322
- /**
323
- * The common execution context APIs.
324
- * @public
325
- */
326
- export const ExecutionContext = Object.freeze({
327
- default: new DefaultExecutionContext(),
328
374
  /**
329
375
  * Sets the event for the current execution context.
330
376
  * @param event - The event to set.
331
377
  * @internal
332
378
  */
333
- setEvent(event) {
379
+ static setEvent(event) {
334
380
  contextEvent.set(event);
335
- },
381
+ }
336
382
  /**
337
383
  * Creates a new root execution context.
338
384
  * @returns A new execution context.
339
385
  */
340
- create() {
341
- return new DefaultExecutionContext();
342
- },
343
- });
386
+ static create() {
387
+ return new ExecutionContext();
388
+ }
389
+ }
390
+ /**
391
+ * The default execution context.
392
+ */
393
+ ExecutionContext.default = new ExecutionContext();
394
+ Observable.defineProperty(ExecutionContext.prototype, "index");
395
+ Observable.defineProperty(ExecutionContext.prototype, "length");
@@ -26,7 +26,7 @@ if (FAST.error === void 0) {
26
26
  Object.assign(FAST, {
27
27
  warn() { },
28
28
  error(code) {
29
- return new Error(`Code ${code}`);
29
+ return new Error(`Error ${code}`);
30
30
  },
31
31
  addMessages() { },
32
32
  });
@@ -71,6 +71,20 @@ export class ElementStyles {
71
71
  static setDefaultStrategy(Strategy) {
72
72
  DefaultStyleStrategy = Strategy;
73
73
  }
74
+ /**
75
+ * Normalizes a set of composable style options.
76
+ * @param styles - The style options to normalize.
77
+ * @returns A singular ElementStyles instance or undefined.
78
+ */
79
+ static normalize(styles) {
80
+ return styles === void 0
81
+ ? void 0
82
+ : Array.isArray(styles)
83
+ ? new ElementStyles(styles)
84
+ : styles instanceof ElementStyles
85
+ ? styles
86
+ : new ElementStyles([styles]);
87
+ }
74
88
  }
75
89
  /**
76
90
  * Indicates whether the DOM supports the adoptedStyleSheets feature.
@@ -0,0 +1,79 @@
1
+ import { isString } from "../interfaces.js";
2
+ import { Binding } from "./html-directive.js";
3
+ const subscribers = Object.create(null);
4
+ export const Signal = Object.freeze({
5
+ subscribe(signal, subscriber) {
6
+ const found = subscribers[signal];
7
+ if (found) {
8
+ found instanceof Set
9
+ ? found.add(subscriber)
10
+ : (subscribers[signal] = new Set([found, subscriber]));
11
+ }
12
+ else {
13
+ subscribers[signal] = subscriber;
14
+ }
15
+ },
16
+ unsubscribe(signal, subscriber) {
17
+ const found = subscribers[signal];
18
+ if (found && found instanceof Set) {
19
+ found.delete(subscriber);
20
+ }
21
+ else {
22
+ subscribers[signal] = void 0;
23
+ }
24
+ },
25
+ /**
26
+ * Sends the specified signal to signaled bindings.
27
+ * @param signal - The signal to send.
28
+ * @public
29
+ */
30
+ send(signal) {
31
+ const found = subscribers[signal];
32
+ if (found) {
33
+ found instanceof Set
34
+ ? found.forEach(x => x.handleChange(this, signal))
35
+ : found.handleChange(this, signal);
36
+ }
37
+ },
38
+ });
39
+ class SignalObserver {
40
+ constructor(dataBinding, subscriber) {
41
+ this.dataBinding = dataBinding;
42
+ this.subscriber = subscriber;
43
+ }
44
+ observe(source, context) {
45
+ const signal = (this.signal = this.getSignal(source, context));
46
+ Signal.subscribe(signal, this);
47
+ return this.dataBinding.evaluate(source, context);
48
+ }
49
+ dispose() {
50
+ Signal.unsubscribe(this.signal, this);
51
+ }
52
+ handleChange() {
53
+ this.subscriber.handleChange(this.dataBinding.evaluate, this);
54
+ }
55
+ getSignal(source, context) {
56
+ const options = this.dataBinding.options;
57
+ return isString(options) ? options : options(source, context);
58
+ }
59
+ }
60
+ class SignalBinding extends Binding {
61
+ constructor(evaluate, options) {
62
+ super();
63
+ this.evaluate = evaluate;
64
+ this.options = options;
65
+ }
66
+ createObserver(directive, subscriber) {
67
+ return new SignalObserver(this, subscriber);
68
+ }
69
+ }
70
+ /**
71
+ * Creates a signal binding configuration with the supplied options.
72
+ * @param binding - The binding to refresh when signaled.
73
+ * @param options - The signal name or a binding to use to retrieve the signal name.
74
+ * @returns A binding configuration.
75
+ * @public
76
+ */
77
+ export function signal(binding, options) {
78
+ return new SignalBinding(binding, options);
79
+ }
@@ -0,0 +1,98 @@
1
+ import { isString } from "../interfaces.js";
2
+ import { Observable, } from "../observation/observable.js";
3
+ import { FAST } from "../platform.js";
4
+ import { Binding } from "./html-directive.js";
5
+ const defaultOptions = {
6
+ fromView: v => v,
7
+ };
8
+ let twoWaySettings = {
9
+ determineChangeEvent() {
10
+ return "change";
11
+ },
12
+ };
13
+ class TwoWayObserver {
14
+ constructor(directive, subscriber, dataBinding) {
15
+ this.directive = directive;
16
+ this.subscriber = subscriber;
17
+ this.dataBinding = dataBinding;
18
+ this.notifier = Observable.binding(dataBinding.evaluate, this, dataBinding.isVolatile);
19
+ }
20
+ observe(source, context) {
21
+ var _a;
22
+ if (!this.changeEvent) {
23
+ this.changeEvent =
24
+ (_a = this.dataBinding.options.changeEvent) !== null && _a !== void 0 ? _a : twoWaySettings.determineChangeEvent(this.directive, this.target);
25
+ }
26
+ this.target.addEventListener(this.changeEvent, this);
27
+ return this.notifier.observe(source, context);
28
+ }
29
+ dispose() {
30
+ this.notifier.dispose();
31
+ this.target.removeEventListener(this.changeEvent, this);
32
+ }
33
+ /** @internal */
34
+ handleChange(subject, args) {
35
+ this.subscriber.handleChange(this.dataBinding.evaluate, this);
36
+ }
37
+ /** @internal */
38
+ handleEvent(event) {
39
+ const directive = this.directive;
40
+ const target = event.currentTarget;
41
+ const notifier = this.notifier;
42
+ const last = notifier.last; // using internal API!!!
43
+ if (!last) {
44
+ FAST.warn(1203 /* Message.twoWayBindingRequiresObservables */);
45
+ return;
46
+ }
47
+ let value;
48
+ switch (directive.aspectType) {
49
+ case 1:
50
+ value = target.getAttribute(directive.targetAspect);
51
+ break;
52
+ case 2:
53
+ value = target.hasAttribute(directive.targetAspect);
54
+ break;
55
+ case 4:
56
+ value = target.innerText;
57
+ break;
58
+ default:
59
+ value = target[directive.targetAspect];
60
+ break;
61
+ }
62
+ last.propertySource[last.propertyName] = this.dataBinding.options.fromView(value);
63
+ }
64
+ }
65
+ class TwoWayBinding extends Binding {
66
+ constructor(evaluate, isVolatile, options = defaultOptions) {
67
+ super();
68
+ this.evaluate = evaluate;
69
+ this.isVolatile = isVolatile;
70
+ this.options = options;
71
+ if (!options.fromView) {
72
+ options.fromView = defaultOptions.fromView;
73
+ }
74
+ }
75
+ createObserver(directive, subscriber) {
76
+ return new TwoWayObserver(directive, subscriber, this);
77
+ }
78
+ /**
79
+ * Configures two-way binding.
80
+ * @param settings - The settings to use for the two-way binding system.
81
+ */
82
+ static configure(settings) {
83
+ twoWaySettings = settings;
84
+ }
85
+ }
86
+ /**
87
+ * Creates a default binding.
88
+ * @param binding - The binding to refresh when changed.
89
+ * @param isBindingVolatile - Indicates whether the binding is volatile or not.
90
+ * @returns A binding configuration.
91
+ * @public
92
+ */
93
+ export function twoWay(binding, optionsOrChangeEvent, isBindingVolatile = Observable.isVolatileBinding(binding)) {
94
+ if (isString(optionsOrChangeEvent)) {
95
+ optionsOrChangeEvent = { changeEvent: optionsOrChangeEvent };
96
+ }
97
+ return new TwoWayBinding(binding, isBindingVolatile, optionsOrChangeEvent);
98
+ }