@microsoft/fast-element 2.0.0-beta.2 → 2.0.0-beta.20
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.
- package/CHANGELOG.json +488 -0
- package/CHANGELOG.md +180 -1
- package/dist/dts/components/attributes.d.ts +15 -0
- package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +74 -28
- package/dist/dts/components/fast-definitions.d.ts +41 -9
- package/dist/dts/components/fast-element.d.ts +14 -26
- package/dist/dts/components/hydration.d.ts +14 -0
- package/dist/{esm/observation/behavior.js → dts/components/install-hydration.d.ts} +0 -0
- package/dist/dts/context.d.ts +1 -1
- package/dist/dts/di/di.d.ts +894 -0
- package/dist/dts/dom-policy.d.ts +68 -0
- package/dist/dts/dom.d.ts +100 -0
- package/dist/dts/index.d.ts +5 -4
- package/dist/dts/index.rollup.d.ts +0 -1
- package/dist/dts/index.rollup.debug.d.ts +0 -1
- package/dist/dts/interfaces.d.ts +60 -79
- package/dist/dts/observation/observable.d.ts +99 -54
- package/dist/dts/pending-task.d.ts +20 -0
- package/dist/dts/platform.d.ts +7 -0
- package/dist/dts/polyfills.d.ts +0 -8
- package/dist/dts/state/exports.d.ts +3 -0
- package/dist/dts/state/reactive.d.ts +8 -0
- package/dist/dts/state/state.d.ts +141 -0
- package/dist/dts/state/visitor.d.ts +6 -0
- package/dist/dts/state/watch.d.ts +10 -0
- package/dist/dts/styles/css-directive.d.ts +2 -2
- package/dist/dts/styles/css.d.ts +0 -5
- package/dist/dts/styles/element-styles.d.ts +10 -17
- package/dist/dts/styles/host.d.ts +68 -0
- package/dist/dts/styles/style-strategy.d.ts +42 -0
- package/dist/dts/templating/binding-signal.d.ts +12 -27
- package/dist/dts/templating/binding-two-way.d.ts +22 -37
- package/dist/dts/templating/binding.d.ts +76 -208
- package/dist/dts/templating/children.d.ts +1 -1
- package/dist/dts/templating/compiler.d.ts +11 -13
- package/dist/dts/templating/html-directive.d.ts +91 -97
- package/dist/dts/templating/node-observation.d.ts +15 -6
- package/dist/dts/templating/ref.d.ts +7 -11
- package/dist/dts/templating/render.d.ts +296 -0
- package/dist/dts/templating/repeat.d.ts +23 -34
- package/dist/dts/templating/slotted.d.ts +1 -1
- package/dist/dts/templating/template.d.ts +92 -14
- package/dist/dts/templating/view.d.ts +81 -11
- package/dist/dts/templating/when.d.ts +3 -3
- package/dist/dts/testing/exports.d.ts +3 -0
- package/dist/dts/testing/fakes.d.ts +14 -0
- package/dist/dts/testing/fixture.d.ts +84 -0
- package/dist/dts/testing/timeout.d.ts +7 -0
- package/dist/dts/utilities.d.ts +53 -18
- package/dist/esm/components/attributes.js +28 -5
- package/dist/esm/components/{controller.js → element-controller.js} +239 -137
- package/dist/esm/components/fast-definitions.js +38 -30
- package/dist/esm/components/fast-element.js +27 -16
- package/dist/esm/components/hydration.js +35 -0
- package/dist/esm/components/install-hydration.js +2 -0
- package/dist/esm/context.js +5 -1
- package/dist/esm/debug.js +40 -5
- package/dist/esm/di/di.js +1430 -0
- package/dist/esm/dom-policy.js +337 -0
- package/dist/esm/dom.js +101 -0
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.rollup.debug.js +3 -1
- package/dist/esm/index.rollup.js +3 -1
- package/dist/esm/interfaces.js +52 -0
- package/dist/esm/observation/arrays.js +303 -2
- package/dist/esm/observation/observable.js +88 -142
- package/dist/esm/observation/update-queue.js +2 -2
- package/dist/esm/pending-task.js +16 -0
- package/dist/esm/platform.js +27 -2
- package/dist/esm/polyfills.js +3 -61
- package/dist/esm/state/exports.js +3 -0
- package/dist/esm/state/reactive.js +34 -0
- package/dist/esm/state/state.js +148 -0
- package/dist/esm/state/visitor.js +28 -0
- package/dist/esm/state/watch.js +36 -0
- package/dist/esm/styles/css.js +4 -9
- package/dist/esm/styles/element-styles.js +14 -33
- package/dist/esm/styles/host.js +1 -0
- package/dist/esm/styles/style-strategy.js +1 -0
- package/dist/esm/templating/binding-signal.js +67 -62
- package/dist/esm/templating/binding-two-way.js +72 -39
- package/dist/esm/templating/binding.js +142 -286
- package/dist/esm/templating/children.js +8 -4
- package/dist/esm/templating/compiler.js +59 -43
- package/dist/esm/templating/html-directive.js +56 -75
- package/dist/esm/templating/node-observation.js +20 -13
- package/dist/esm/templating/ref.js +4 -12
- package/dist/esm/templating/render.js +402 -0
- package/dist/esm/templating/repeat.js +88 -75
- package/dist/esm/templating/template.js +132 -60
- package/dist/esm/templating/view.js +113 -29
- package/dist/esm/templating/when.js +5 -4
- package/dist/esm/testing/exports.js +3 -0
- package/dist/esm/testing/fakes.js +107 -0
- package/dist/esm/testing/fixture.js +86 -0
- package/dist/esm/testing/timeout.js +24 -0
- package/dist/esm/utilities.js +95 -95
- package/dist/fast-element.api.json +9487 -8326
- package/dist/fast-element.d.ts +847 -644
- package/dist/fast-element.debug.js +1993 -1166
- package/dist/fast-element.debug.min.js +1 -1
- package/dist/fast-element.js +1903 -1111
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +911 -701
- package/docs/api-report.md +329 -252
- package/package.json +38 -16
- package/dist/dts/hooks.d.ts +0 -20
- package/dist/dts/observation/behavior.d.ts +0 -19
- package/dist/dts/observation/splice-strategies.d.ts +0 -13
- package/dist/dts/templating/dom.d.ts +0 -41
- package/dist/esm/hooks.js +0 -32
- package/dist/esm/observation/splice-strategies.js +0 -400
- package/dist/esm/templating/dom.js +0 -49
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { noop } from "../interfaces.js";
|
|
2
|
+
import { ExecutionContext, Observable, SourceLifetime, } from "../observation/observable.js";
|
|
1
3
|
function removeNodeSequence(firstNode, lastNode) {
|
|
2
4
|
const parent = firstNode.parentNode;
|
|
3
5
|
let current = firstNode;
|
|
@@ -24,17 +26,92 @@ export class HTMLView {
|
|
|
24
26
|
this.factories = factories;
|
|
25
27
|
this.targets = targets;
|
|
26
28
|
this.behaviors = null;
|
|
29
|
+
this.unbindables = [];
|
|
27
30
|
/**
|
|
28
31
|
* The data that the view is bound to.
|
|
29
32
|
*/
|
|
30
33
|
this.source = null;
|
|
34
|
+
/**
|
|
35
|
+
* Indicates whether the controller is bound.
|
|
36
|
+
*/
|
|
37
|
+
this.isBound = false;
|
|
38
|
+
/**
|
|
39
|
+
* Indicates how the source's lifetime relates to the controller's lifetime.
|
|
40
|
+
*/
|
|
41
|
+
this.sourceLifetime = SourceLifetime.unknown;
|
|
31
42
|
/**
|
|
32
43
|
* The execution context the view is running within.
|
|
33
44
|
*/
|
|
34
|
-
this.context =
|
|
45
|
+
this.context = this;
|
|
46
|
+
/**
|
|
47
|
+
* The index of the current item within a repeat context.
|
|
48
|
+
*/
|
|
49
|
+
this.index = 0;
|
|
50
|
+
/**
|
|
51
|
+
* The length of the current collection within a repeat context.
|
|
52
|
+
*/
|
|
53
|
+
this.length = 0;
|
|
54
|
+
/**
|
|
55
|
+
* Opts out of JSON stringification.
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
this.toJSON = noop;
|
|
35
59
|
this.firstChild = fragment.firstChild;
|
|
36
60
|
this.lastChild = fragment.lastChild;
|
|
37
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* The current event within an event handler.
|
|
64
|
+
*/
|
|
65
|
+
get event() {
|
|
66
|
+
return ExecutionContext.getEvent();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Indicates whether the current item within a repeat context
|
|
70
|
+
* has an even index.
|
|
71
|
+
*/
|
|
72
|
+
get isEven() {
|
|
73
|
+
return this.index % 2 === 0;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Indicates whether the current item within a repeat context
|
|
77
|
+
* has an odd index.
|
|
78
|
+
*/
|
|
79
|
+
get isOdd() {
|
|
80
|
+
return this.index % 2 !== 0;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Indicates whether the current item within a repeat context
|
|
84
|
+
* is the first item in the collection.
|
|
85
|
+
*/
|
|
86
|
+
get isFirst() {
|
|
87
|
+
return this.index === 0;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Indicates whether the current item within a repeat context
|
|
91
|
+
* is somewhere in the middle of the collection.
|
|
92
|
+
*/
|
|
93
|
+
get isInMiddle() {
|
|
94
|
+
return !this.isFirst && !this.isLast;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Indicates whether the current item within a repeat context
|
|
98
|
+
* is the last item in the collection.
|
|
99
|
+
*/
|
|
100
|
+
get isLast() {
|
|
101
|
+
return this.index === this.length - 1;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Returns the typed event detail of a custom event.
|
|
105
|
+
*/
|
|
106
|
+
eventDetail() {
|
|
107
|
+
return this.event.detail;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Returns the typed event target of the event.
|
|
111
|
+
*/
|
|
112
|
+
eventTarget() {
|
|
113
|
+
return this.event.target;
|
|
114
|
+
}
|
|
38
115
|
/**
|
|
39
116
|
* Appends the view's DOM nodes to the referenced node.
|
|
40
117
|
* @param node - The parent node to append the view's DOM nodes to.
|
|
@@ -51,8 +128,10 @@ export class HTMLView {
|
|
|
51
128
|
node.parentNode.insertBefore(this.fragment, node);
|
|
52
129
|
}
|
|
53
130
|
else {
|
|
54
|
-
const parentNode = node.parentNode;
|
|
55
131
|
const end = this.lastChild;
|
|
132
|
+
if (node.previousSibling === end)
|
|
133
|
+
return;
|
|
134
|
+
const parentNode = node.parentNode;
|
|
56
135
|
let current = this.firstChild;
|
|
57
136
|
let next;
|
|
58
137
|
while (current !== end) {
|
|
@@ -87,58 +166,61 @@ export class HTMLView {
|
|
|
87
166
|
removeNodeSequence(this.firstChild, this.lastChild);
|
|
88
167
|
this.unbind();
|
|
89
168
|
}
|
|
169
|
+
onUnbind(behavior) {
|
|
170
|
+
this.unbindables.push(behavior);
|
|
171
|
+
}
|
|
90
172
|
/**
|
|
91
173
|
* Binds a view's behaviors to its binding source.
|
|
92
174
|
* @param source - The binding source for the view's binding behaviors.
|
|
93
175
|
* @param context - The execution context to run the behaviors within.
|
|
94
176
|
*/
|
|
95
|
-
bind(source, context) {
|
|
96
|
-
|
|
97
|
-
const oldSource = this.source;
|
|
98
|
-
if (oldSource === source) {
|
|
177
|
+
bind(source, context = this) {
|
|
178
|
+
if (this.source === source) {
|
|
99
179
|
return;
|
|
100
180
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
106
|
-
const current = behaviors[i];
|
|
107
|
-
current.unbind(oldSource, context, targets);
|
|
108
|
-
current.bind(source, context, targets);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
else if (behaviors === null) {
|
|
181
|
+
let behaviors = this.behaviors;
|
|
182
|
+
if (behaviors === null) {
|
|
183
|
+
this.source = source;
|
|
184
|
+
this.context = context;
|
|
112
185
|
this.behaviors = behaviors = new Array(this.factories.length);
|
|
113
186
|
const factories = this.factories;
|
|
114
187
|
for (let i = 0, ii = factories.length; i < ii; ++i) {
|
|
115
|
-
const behavior = factories[i].createBehavior(
|
|
116
|
-
behavior.bind(
|
|
188
|
+
const behavior = factories[i].createBehavior();
|
|
189
|
+
behavior.bind(this);
|
|
117
190
|
behaviors[i] = behavior;
|
|
118
191
|
}
|
|
119
192
|
}
|
|
120
193
|
else {
|
|
194
|
+
if (this.source !== null) {
|
|
195
|
+
this.evaluateUnbindables();
|
|
196
|
+
}
|
|
197
|
+
this.isBound = false;
|
|
198
|
+
this.source = source;
|
|
199
|
+
this.context = context;
|
|
121
200
|
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
122
|
-
behaviors[i].bind(
|
|
201
|
+
behaviors[i].bind(this);
|
|
123
202
|
}
|
|
124
203
|
}
|
|
204
|
+
this.isBound = true;
|
|
125
205
|
}
|
|
126
206
|
/**
|
|
127
207
|
* Unbinds a view's behaviors from its binding source.
|
|
128
208
|
*/
|
|
129
209
|
unbind() {
|
|
130
|
-
|
|
131
|
-
if (oldSource === null) {
|
|
210
|
+
if (!this.isBound || this.source === null) {
|
|
132
211
|
return;
|
|
133
212
|
}
|
|
134
|
-
|
|
135
|
-
const context = this.context;
|
|
136
|
-
const behaviors = this.behaviors;
|
|
137
|
-
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
138
|
-
behaviors[i].unbind(oldSource, context, targets);
|
|
139
|
-
}
|
|
213
|
+
this.evaluateUnbindables();
|
|
140
214
|
this.source = null;
|
|
141
|
-
this.context =
|
|
215
|
+
this.context = this;
|
|
216
|
+
this.isBound = false;
|
|
217
|
+
}
|
|
218
|
+
evaluateUnbindables() {
|
|
219
|
+
const unbindables = this.unbindables;
|
|
220
|
+
for (let i = 0, ii = unbindables.length; i < ii; ++i) {
|
|
221
|
+
unbindables[i].unbind(this);
|
|
222
|
+
}
|
|
223
|
+
unbindables.length = 0;
|
|
142
224
|
}
|
|
143
225
|
/**
|
|
144
226
|
* Efficiently disposes of a contiguous range of synthetic view instances.
|
|
@@ -154,3 +236,5 @@ export class HTMLView {
|
|
|
154
236
|
}
|
|
155
237
|
}
|
|
156
238
|
}
|
|
239
|
+
Observable.defineProperty(HTMLView.prototype, "index");
|
|
240
|
+
Observable.defineProperty(HTMLView.prototype, "length");
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { isFunction } from "../interfaces.js";
|
|
2
2
|
/**
|
|
3
3
|
* A directive that enables basic conditional rendering in a template.
|
|
4
|
-
* @param
|
|
4
|
+
* @param condition - The condition to test for rendering.
|
|
5
5
|
* @param templateOrTemplateBinding - The template or a binding that gets
|
|
6
6
|
* the template to render when the condition is true.
|
|
7
7
|
* @public
|
|
8
8
|
*/
|
|
9
|
-
export function when(
|
|
10
|
-
const
|
|
9
|
+
export function when(condition, templateOrTemplateBinding) {
|
|
10
|
+
const dataBinding = isFunction(condition) ? condition : () => condition;
|
|
11
|
+
const templateBinding = isFunction(templateOrTemplateBinding)
|
|
11
12
|
? templateOrTemplateBinding
|
|
12
13
|
: () => templateOrTemplateBinding;
|
|
13
|
-
return (source, context) =>
|
|
14
|
+
return (source, context) => dataBinding(source, context) ? templateBinding(source, context) : null;
|
|
14
15
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { ExecutionContext, } from "../index.js";
|
|
2
|
+
import { noop } from "../interfaces.js";
|
|
3
|
+
export const Fake = Object.freeze({
|
|
4
|
+
executionContext(parent, parentContext) {
|
|
5
|
+
return {
|
|
6
|
+
/**
|
|
7
|
+
* The index of the current item within a repeat context.
|
|
8
|
+
*/
|
|
9
|
+
index: 0,
|
|
10
|
+
/**
|
|
11
|
+
* The length of the current collection within a repeat context.
|
|
12
|
+
*/
|
|
13
|
+
length: 0,
|
|
14
|
+
/**
|
|
15
|
+
* The parent data source within a nested context.
|
|
16
|
+
*/
|
|
17
|
+
parent: parent,
|
|
18
|
+
/**
|
|
19
|
+
* The parent execution context when in nested context scenarios.
|
|
20
|
+
*/
|
|
21
|
+
parentContext: parentContext,
|
|
22
|
+
/**
|
|
23
|
+
* The current event within an event handler.
|
|
24
|
+
*/
|
|
25
|
+
get event() {
|
|
26
|
+
return ExecutionContext.getEvent();
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* Indicates whether the current item within a repeat context
|
|
30
|
+
* has an even index.
|
|
31
|
+
*/
|
|
32
|
+
get isEven() {
|
|
33
|
+
return this.index % 2 === 0;
|
|
34
|
+
},
|
|
35
|
+
/**
|
|
36
|
+
* Indicates whether the current item within a repeat context
|
|
37
|
+
* has an odd index.
|
|
38
|
+
*/
|
|
39
|
+
get isOdd() {
|
|
40
|
+
return this.index % 2 !== 0;
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* Indicates whether the current item within a repeat context
|
|
44
|
+
* is the first item in the collection.
|
|
45
|
+
*/
|
|
46
|
+
get isFirst() {
|
|
47
|
+
return this.index === 0;
|
|
48
|
+
},
|
|
49
|
+
/**
|
|
50
|
+
* Indicates whether the current item within a repeat context
|
|
51
|
+
* is somewhere in the middle of the collection.
|
|
52
|
+
*/
|
|
53
|
+
get isInMiddle() {
|
|
54
|
+
return !this.isFirst && !this.isLast;
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* Indicates whether the current item within a repeat context
|
|
58
|
+
* is the last item in the collection.
|
|
59
|
+
*/
|
|
60
|
+
get isLast() {
|
|
61
|
+
return this.index === this.length - 1;
|
|
62
|
+
},
|
|
63
|
+
/**
|
|
64
|
+
* Returns the typed event detail of a custom event.
|
|
65
|
+
*/
|
|
66
|
+
eventDetail() {
|
|
67
|
+
return this.event.detail;
|
|
68
|
+
},
|
|
69
|
+
/**
|
|
70
|
+
* Returns the typed event target of the event.
|
|
71
|
+
*/
|
|
72
|
+
eventTarget() {
|
|
73
|
+
return this.event.target;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
viewController(targets = {}, ...behaviors) {
|
|
78
|
+
const unbindables = new Set();
|
|
79
|
+
return {
|
|
80
|
+
isBound: false,
|
|
81
|
+
context: null,
|
|
82
|
+
onUnbind(object) {
|
|
83
|
+
unbindables.add(object);
|
|
84
|
+
},
|
|
85
|
+
source: null,
|
|
86
|
+
targets,
|
|
87
|
+
toJSON: noop,
|
|
88
|
+
bind(source, context = Fake.executionContext()) {
|
|
89
|
+
if (this.isBound) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
this.source = source;
|
|
93
|
+
this.context = context;
|
|
94
|
+
behaviors.forEach(x => x.bind(this));
|
|
95
|
+
this.isBound = true;
|
|
96
|
+
},
|
|
97
|
+
unbind() {
|
|
98
|
+
if (this.isBound) {
|
|
99
|
+
unbindables.forEach(x => x.unbind(this));
|
|
100
|
+
this.source = null;
|
|
101
|
+
this.context = null;
|
|
102
|
+
this.isBound = false;
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
},
|
|
107
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { FASTElementDefinition } from "../components/fast-definitions.js";
|
|
11
|
+
import { ViewTemplate } from "../templating/template.js";
|
|
12
|
+
function findElement(view) {
|
|
13
|
+
let current = view.firstChild;
|
|
14
|
+
while (current !== null && current.nodeType !== 1) {
|
|
15
|
+
current = current.nextSibling;
|
|
16
|
+
}
|
|
17
|
+
return current;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates a random, unique name suitable for use as a Custom Element name.
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export function uniqueElementName(prefix = "fast-unique") {
|
|
24
|
+
return `${prefix}-${Math.random().toString(36).substring(7)}`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Creates a test fixture suitable for testing custom elements, templates, and bindings.
|
|
28
|
+
* @param templateNameOrType An HTML template or single element name to create the fixture for.
|
|
29
|
+
* @param options Enables customizing fixture creation behavior.
|
|
30
|
+
* @remarks
|
|
31
|
+
* Yields control to the caller one Microtask later, in order to
|
|
32
|
+
* ensure that the DOM has settled.
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export function fixture(templateNameOrType, options = {}) {
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
const document = options.document || globalThis.document;
|
|
38
|
+
const parent = options.parent || document.createElement("div");
|
|
39
|
+
const source = options.source || {};
|
|
40
|
+
if (typeof templateNameOrType === "function") {
|
|
41
|
+
const def = FASTElementDefinition.getByType(templateNameOrType);
|
|
42
|
+
if (!def) {
|
|
43
|
+
throw new Error("Missing FASTElement definition.");
|
|
44
|
+
}
|
|
45
|
+
templateNameOrType = def.name;
|
|
46
|
+
}
|
|
47
|
+
if (typeof templateNameOrType === "string") {
|
|
48
|
+
const html = `<${templateNameOrType}></${templateNameOrType}>`;
|
|
49
|
+
templateNameOrType = new ViewTemplate(html);
|
|
50
|
+
}
|
|
51
|
+
const view = templateNameOrType.create();
|
|
52
|
+
const element = findElement(view);
|
|
53
|
+
let isConnected = false;
|
|
54
|
+
view.bind(source);
|
|
55
|
+
view.appendTo(parent);
|
|
56
|
+
customElements.upgrade(parent);
|
|
57
|
+
// Hook into the Microtask Queue to ensure the DOM is settled
|
|
58
|
+
// before yielding control to the caller.
|
|
59
|
+
yield Promise.resolve();
|
|
60
|
+
const connect = () => __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
if (isConnected) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
isConnected = true;
|
|
65
|
+
document.body.appendChild(parent);
|
|
66
|
+
yield Promise.resolve();
|
|
67
|
+
});
|
|
68
|
+
const disconnect = () => __awaiter(this, void 0, void 0, function* () {
|
|
69
|
+
if (!isConnected) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
isConnected = false;
|
|
73
|
+
document.body.removeChild(parent);
|
|
74
|
+
yield Promise.resolve();
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
document,
|
|
78
|
+
template: templateNameOrType,
|
|
79
|
+
view,
|
|
80
|
+
parent,
|
|
81
|
+
element,
|
|
82
|
+
connect,
|
|
83
|
+
disconnect,
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* A timeout helper for use in tests.
|
|
12
|
+
* @param timeout The length of the timeout.
|
|
13
|
+
* @returns A promise that resolves once the configured time has elapsed.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export function timeout(timeout = 0) {
|
|
17
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
window.setTimeout(() => {
|
|
20
|
+
resolve(void 0);
|
|
21
|
+
}, timeout);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
package/dist/esm/utilities.js
CHANGED
|
@@ -1,98 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
function shouldTraverse(value, traversed) {
|
|
5
|
-
return (value !== null &&
|
|
6
|
-
value !== void 0 &&
|
|
7
|
-
typeof value === "object" &&
|
|
8
|
-
!traversed.has(value));
|
|
9
|
-
}
|
|
10
|
-
function traverseObject(object, deep, visitor, data, traversed) {
|
|
11
|
-
if (!shouldTraverse(object, traversed)) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
traversed.add(object);
|
|
15
|
-
if (Array.isArray(object)) {
|
|
16
|
-
visitor.visitArray(object, data);
|
|
17
|
-
for (const item of object) {
|
|
18
|
-
traverseObject(item, deep, visitor, data, traversed);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
visitor.visitObject(object, data);
|
|
23
|
-
for (const key in object) {
|
|
24
|
-
const value = object[key];
|
|
25
|
-
visitor.visitProperty(object, key, value, data);
|
|
26
|
-
if (deep) {
|
|
27
|
-
traverseObject(value, deep, visitor, data, traversed);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
const noop = () => void 0;
|
|
33
|
-
const observed = new WeakSet();
|
|
34
|
-
const makeObserverVisitor = {
|
|
35
|
-
visitObject: noop,
|
|
36
|
-
visitArray: noop,
|
|
37
|
-
visitProperty(object, propertyName, value) {
|
|
38
|
-
Reflect.defineProperty(object, propertyName, {
|
|
39
|
-
enumerable: true,
|
|
40
|
-
get() {
|
|
41
|
-
Observable.track(object, propertyName);
|
|
42
|
-
return value;
|
|
43
|
-
},
|
|
44
|
-
set(newValue) {
|
|
45
|
-
if (value !== newValue) {
|
|
46
|
-
value = newValue;
|
|
47
|
-
Observable.notify(object, propertyName);
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
function watchObject(object, data) {
|
|
54
|
-
const notifier = Observable.getNotifier(object);
|
|
55
|
-
notifier.subscribe(data.subscriber);
|
|
56
|
-
data.notifiers.push(notifier);
|
|
57
|
-
}
|
|
58
|
-
const watchVisitor = {
|
|
59
|
-
visitProperty: noop,
|
|
60
|
-
visitObject: watchObject,
|
|
61
|
-
visitArray: watchObject,
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Converts a plain object to an observable object.
|
|
65
|
-
* @param object - The object to make observable.
|
|
66
|
-
* @param deep - Indicates whether or not to deeply convert the oject.
|
|
67
|
-
* @returns The converted object.
|
|
68
|
-
* @beta
|
|
69
|
-
*/
|
|
70
|
-
export function makeObservable(object, deep = false) {
|
|
71
|
-
traverseObject(object, deep, makeObserverVisitor, void 0, observed);
|
|
72
|
-
return object;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Deeply subscribes to changes in existing observable objects.
|
|
76
|
-
* @param object - The observable object to watch.
|
|
77
|
-
* @param subscriber - The handler to call when changes are made to the object.
|
|
78
|
-
* @returns A disposable that can be used to unsubscribe from change updates.
|
|
79
|
-
* @beta
|
|
80
|
-
*/
|
|
81
|
-
export function watch(object, subscriber) {
|
|
82
|
-
const data = {
|
|
83
|
-
notifiers: [],
|
|
84
|
-
subscriber: isFunction(subscriber) ? { handleChange: subscriber } : subscriber,
|
|
85
|
-
};
|
|
86
|
-
ArrayObserver.enable();
|
|
87
|
-
traverseObject(object, true, watchVisitor, data, new Set());
|
|
88
|
-
return {
|
|
89
|
-
dispose() {
|
|
90
|
-
for (const n of data.notifiers) {
|
|
91
|
-
n.unsubscribe(data.subscriber);
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
}
|
|
1
|
+
import { DOM } from "./dom.js";
|
|
2
|
+
import { ExecutionContext } from "./observation/observable.js";
|
|
3
|
+
import { nextId } from "./templating/markup.js";
|
|
96
4
|
/**
|
|
97
5
|
* Retrieves the "composed parent" element of a node, ignoring DOM tree boundaries.
|
|
98
6
|
* When the parent of a node is a shadow-root, it will return the host
|
|
@@ -137,3 +45,95 @@ export function composedContains(reference, test) {
|
|
|
137
45
|
}
|
|
138
46
|
return false;
|
|
139
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
export class UnobservableMutationObserver extends MutationObserver {
|
|
52
|
+
/**
|
|
53
|
+
* An extension of MutationObserver that supports unobserving nodes.
|
|
54
|
+
* @param callback - The callback to invoke when observed nodes are changed.
|
|
55
|
+
*/
|
|
56
|
+
constructor(callback) {
|
|
57
|
+
function handler(mutations) {
|
|
58
|
+
this.callback.call(null, mutations.filter(record => this.observedNodes.has(record.target)));
|
|
59
|
+
}
|
|
60
|
+
super(handler);
|
|
61
|
+
this.callback = callback;
|
|
62
|
+
this.observedNodes = new Set();
|
|
63
|
+
}
|
|
64
|
+
observe(target, options) {
|
|
65
|
+
this.observedNodes.add(target);
|
|
66
|
+
super.observe(target, options);
|
|
67
|
+
}
|
|
68
|
+
unobserve(target) {
|
|
69
|
+
this.observedNodes.delete(target);
|
|
70
|
+
if (this.observedNodes.size < 1) {
|
|
71
|
+
this.disconnect();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Bridges between ViewBehaviors and HostBehaviors, enabling a host to
|
|
77
|
+
* control ViewBehaviors.
|
|
78
|
+
* @public
|
|
79
|
+
*/
|
|
80
|
+
export const ViewBehaviorOrchestrator = Object.freeze({
|
|
81
|
+
/**
|
|
82
|
+
* Creates a ViewBehaviorOrchestrator.
|
|
83
|
+
* @param source - The source to to associate behaviors with.
|
|
84
|
+
* @returns A ViewBehaviorOrchestrator.
|
|
85
|
+
*/
|
|
86
|
+
create(source) {
|
|
87
|
+
const behaviors = [];
|
|
88
|
+
const targets = {};
|
|
89
|
+
let unbindables = null;
|
|
90
|
+
let isConnected = false;
|
|
91
|
+
return {
|
|
92
|
+
source,
|
|
93
|
+
context: ExecutionContext.default,
|
|
94
|
+
targets,
|
|
95
|
+
get isBound() {
|
|
96
|
+
return isConnected;
|
|
97
|
+
},
|
|
98
|
+
addBehaviorFactory(factory, target) {
|
|
99
|
+
var _a, _b, _c, _d;
|
|
100
|
+
const compiled = factory;
|
|
101
|
+
compiled.id = (_a = compiled.id) !== null && _a !== void 0 ? _a : nextId();
|
|
102
|
+
compiled.targetNodeId = (_b = compiled.targetNodeId) !== null && _b !== void 0 ? _b : nextId();
|
|
103
|
+
compiled.targetTagName = (_c = target.tagName) !== null && _c !== void 0 ? _c : null;
|
|
104
|
+
compiled.policy = (_d = compiled.policy) !== null && _d !== void 0 ? _d : DOM.policy;
|
|
105
|
+
this.addTarget(compiled.targetNodeId, target);
|
|
106
|
+
this.addBehavior(compiled.createBehavior());
|
|
107
|
+
},
|
|
108
|
+
addTarget(nodeId, target) {
|
|
109
|
+
targets[nodeId] = target;
|
|
110
|
+
},
|
|
111
|
+
addBehavior(behavior) {
|
|
112
|
+
behaviors.push(behavior);
|
|
113
|
+
if (isConnected) {
|
|
114
|
+
behavior.bind(this);
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
onUnbind(unbindable) {
|
|
118
|
+
if (unbindables === null) {
|
|
119
|
+
unbindables = [];
|
|
120
|
+
}
|
|
121
|
+
unbindables.push(unbindable);
|
|
122
|
+
},
|
|
123
|
+
connectedCallback(controller) {
|
|
124
|
+
if (!isConnected) {
|
|
125
|
+
isConnected = true;
|
|
126
|
+
behaviors.forEach(x => x.bind(this));
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
disconnectedCallback(controller) {
|
|
130
|
+
if (isConnected) {
|
|
131
|
+
isConnected = false;
|
|
132
|
+
if (unbindables !== null) {
|
|
133
|
+
unbindables.forEach(x => x.unbind(this));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
});
|