@microsoft/fast-element 2.0.0-beta.2 → 2.0.0-beta.21
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 +509 -0
- package/CHANGELOG.md +189 -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 +7 -7
- package/dist/dts/di/di.d.ts +894 -0
- package/dist/dts/dom-policy.d.ts +83 -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 +62 -80
- package/dist/dts/metadata.d.ts +5 -5
- package/dist/dts/observation/observable.d.ts +99 -54
- package/dist/dts/pending-task.d.ts +32 -0
- package/dist/dts/platform.d.ts +8 -1
- 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 +55 -19
- package/dist/esm/components/attributes.js +28 -5
- package/dist/esm/components/{controller.js → element-controller.js} +238 -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 +7 -3
- package/dist/esm/debug.js +41 -5
- package/dist/esm/di/di.js +1430 -0
- package/dist/esm/dom-policy.js +345 -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/metadata.js +9 -8
- 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 +28 -0
- package/dist/esm/platform.js +28 -3
- 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 +97 -96
- package/dist/fast-element.api.json +9741 -8201
- package/dist/fast-element.d.ts +889 -646
- package/dist/fast-element.debug.js +2001 -1167
- package/dist/fast-element.debug.min.js +1 -1
- package/dist/fast-element.js +1907 -1109
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +913 -703
- package/docs/api-report.md +331 -258
- 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,24 +1,26 @@
|
|
|
1
|
-
import "../interfaces.js";
|
|
1
|
+
import { noop } from "../interfaces.js";
|
|
2
2
|
import { PropertyChangeNotifier } from "../observation/notifier.js";
|
|
3
|
-
import {
|
|
3
|
+
import { Observable, SourceLifetime } from "../observation/observable.js";
|
|
4
4
|
import { FAST } from "../platform.js";
|
|
5
|
+
import { ElementStyles } from "../styles/element-styles.js";
|
|
5
6
|
import { FASTElementDefinition } from "./fast-definitions.js";
|
|
6
|
-
const shadowRoots = new WeakMap();
|
|
7
7
|
const defaultEventOptions = {
|
|
8
8
|
bubbles: true,
|
|
9
9
|
composed: true,
|
|
10
10
|
cancelable: true,
|
|
11
11
|
};
|
|
12
|
+
const isConnectedPropertyName = "isConnected";
|
|
13
|
+
const shadowRoots = new WeakMap();
|
|
12
14
|
function getShadowRoot(element) {
|
|
13
15
|
var _a, _b;
|
|
14
16
|
return (_b = (_a = element.shadowRoot) !== null && _a !== void 0 ? _a : shadowRoots.get(element)) !== null && _b !== void 0 ? _b : null;
|
|
15
17
|
}
|
|
16
|
-
|
|
18
|
+
let elementControllerStrategy;
|
|
17
19
|
/**
|
|
18
20
|
* Controls the lifecycle and rendering of a `FASTElement`.
|
|
19
21
|
* @public
|
|
20
22
|
*/
|
|
21
|
-
export class
|
|
23
|
+
export class ElementController extends PropertyChangeNotifier {
|
|
22
24
|
/**
|
|
23
25
|
* Creates a Controller to control the specified element.
|
|
24
26
|
* @param element - The element to be controlled by this controller.
|
|
@@ -29,12 +31,18 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
29
31
|
constructor(element, definition) {
|
|
30
32
|
super(element);
|
|
31
33
|
this.boundObservables = null;
|
|
32
|
-
this.behaviors = null;
|
|
33
34
|
this.needsInitialization = true;
|
|
34
35
|
this.hasExistingShadowRoot = false;
|
|
35
36
|
this._template = null;
|
|
36
|
-
this.
|
|
37
|
-
|
|
37
|
+
this.stage = 3 /* Stages.disconnected */;
|
|
38
|
+
/**
|
|
39
|
+
* A guard against connecting behaviors multiple times
|
|
40
|
+
* during connect in scenarios where a behavior adds
|
|
41
|
+
* another behavior during it's connectedCallback
|
|
42
|
+
*/
|
|
43
|
+
this.guardBehaviorConnection = false;
|
|
44
|
+
this.behaviors = null;
|
|
45
|
+
this._mainStyles = null;
|
|
38
46
|
/**
|
|
39
47
|
* This allows Observable.getNotifier(...) to return the Controller
|
|
40
48
|
* when the notifier for the Controller itself is being requested. The
|
|
@@ -50,7 +58,12 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
50
58
|
* If `null` then the element is managing its own rendering.
|
|
51
59
|
*/
|
|
52
60
|
this.view = null;
|
|
53
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Opts out of JSON stringification.
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
this.toJSON = noop;
|
|
66
|
+
this.source = element;
|
|
54
67
|
this.definition = definition;
|
|
55
68
|
const shadowOptions = definition.shadowOptions;
|
|
56
69
|
if (shadowOptions !== void 0) {
|
|
@@ -88,11 +101,7 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
88
101
|
*/
|
|
89
102
|
get isConnected() {
|
|
90
103
|
Observable.track(this, isConnectedPropertyName);
|
|
91
|
-
return this.
|
|
92
|
-
}
|
|
93
|
-
setIsConnected(value) {
|
|
94
|
-
this._isConnected = value;
|
|
95
|
-
Observable.notify(this, isConnectedPropertyName);
|
|
104
|
+
return this.stage === 1 /* Stages.connected */;
|
|
96
105
|
}
|
|
97
106
|
/**
|
|
98
107
|
* Gets/sets the template used to render the component.
|
|
@@ -104,9 +113,9 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
104
113
|
// 1. Template overrides take top precedence.
|
|
105
114
|
if (this._template === null) {
|
|
106
115
|
const definition = this.definition;
|
|
107
|
-
if (this.
|
|
116
|
+
if (this.source.resolveTemplate) {
|
|
108
117
|
// 2. Allow for element instance overrides next.
|
|
109
|
-
this._template = this.
|
|
118
|
+
this._template = this.source.resolveTemplate();
|
|
110
119
|
}
|
|
111
120
|
else if (definition.template) {
|
|
112
121
|
// 3. Default to the static definition.
|
|
@@ -125,56 +134,104 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
125
134
|
}
|
|
126
135
|
}
|
|
127
136
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* This value can only be accurately read after connect but can be set at any time.
|
|
137
|
+
* The main set of styles used for the component, independent
|
|
138
|
+
* of any dynamically added styles.
|
|
131
139
|
*/
|
|
132
|
-
get
|
|
140
|
+
get mainStyles() {
|
|
133
141
|
var _a;
|
|
134
142
|
// 1. Styles overrides take top precedence.
|
|
135
|
-
if (this.
|
|
143
|
+
if (this._mainStyles === null) {
|
|
136
144
|
const definition = this.definition;
|
|
137
|
-
if (this.
|
|
145
|
+
if (this.source.resolveStyles) {
|
|
138
146
|
// 2. Allow for element instance overrides next.
|
|
139
|
-
this.
|
|
147
|
+
this._mainStyles = this.source.resolveStyles();
|
|
140
148
|
}
|
|
141
149
|
else if (definition.styles) {
|
|
142
150
|
// 3. Default to the static definition.
|
|
143
|
-
this.
|
|
151
|
+
this._mainStyles = (_a = definition.styles) !== null && _a !== void 0 ? _a : null;
|
|
144
152
|
}
|
|
145
153
|
}
|
|
146
|
-
return this.
|
|
154
|
+
return this._mainStyles;
|
|
147
155
|
}
|
|
148
|
-
set
|
|
149
|
-
if (this.
|
|
156
|
+
set mainStyles(value) {
|
|
157
|
+
if (this._mainStyles === value) {
|
|
150
158
|
return;
|
|
151
159
|
}
|
|
152
|
-
if (this.
|
|
153
|
-
this.removeStyles(this.
|
|
160
|
+
if (this._mainStyles !== null) {
|
|
161
|
+
this.removeStyles(this._mainStyles);
|
|
154
162
|
}
|
|
155
|
-
this.
|
|
163
|
+
this._mainStyles = value;
|
|
156
164
|
if (!this.needsInitialization) {
|
|
157
165
|
this.addStyles(value);
|
|
158
166
|
}
|
|
159
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Adds the behavior to the component.
|
|
170
|
+
* @param behavior - The behavior to add.
|
|
171
|
+
*/
|
|
172
|
+
addBehavior(behavior) {
|
|
173
|
+
var _a, _b;
|
|
174
|
+
const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
|
|
175
|
+
const count = (_b = targetBehaviors.get(behavior)) !== null && _b !== void 0 ? _b : 0;
|
|
176
|
+
if (count === 0) {
|
|
177
|
+
targetBehaviors.set(behavior, 1);
|
|
178
|
+
behavior.addedCallback && behavior.addedCallback(this);
|
|
179
|
+
if (behavior.connectedCallback &&
|
|
180
|
+
!this.guardBehaviorConnection &&
|
|
181
|
+
(this.stage === 1 /* Stages.connected */ || this.stage === 0 /* Stages.connecting */)) {
|
|
182
|
+
behavior.connectedCallback(this);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
targetBehaviors.set(behavior, count + 1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Removes the behavior from the component.
|
|
191
|
+
* @param behavior - The behavior to remove.
|
|
192
|
+
* @param force - Forces removal even if this behavior was added more than once.
|
|
193
|
+
*/
|
|
194
|
+
removeBehavior(behavior, force = false) {
|
|
195
|
+
const targetBehaviors = this.behaviors;
|
|
196
|
+
if (targetBehaviors === null) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const count = targetBehaviors.get(behavior);
|
|
200
|
+
if (count === void 0) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (count === 1 || force) {
|
|
204
|
+
targetBehaviors.delete(behavior);
|
|
205
|
+
if (behavior.disconnectedCallback && this.stage !== 3 /* Stages.disconnected */) {
|
|
206
|
+
behavior.disconnectedCallback(this);
|
|
207
|
+
}
|
|
208
|
+
behavior.removedCallback && behavior.removedCallback(this);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
targetBehaviors.set(behavior, count - 1);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
160
214
|
/**
|
|
161
215
|
* Adds styles to this element. Providing an HTMLStyleElement will attach the element instance to the shadowRoot.
|
|
162
216
|
* @param styles - The styles to add.
|
|
163
217
|
*/
|
|
164
218
|
addStyles(styles) {
|
|
219
|
+
var _a;
|
|
165
220
|
if (!styles) {
|
|
166
221
|
return;
|
|
167
222
|
}
|
|
168
|
-
const
|
|
169
|
-
this.element.getRootNode();
|
|
223
|
+
const source = this.source;
|
|
170
224
|
if (styles instanceof HTMLElement) {
|
|
225
|
+
const target = (_a = getShadowRoot(source)) !== null && _a !== void 0 ? _a : this.source;
|
|
171
226
|
target.append(styles);
|
|
172
227
|
}
|
|
173
|
-
else if (!styles.isAttachedTo(
|
|
228
|
+
else if (!styles.isAttachedTo(source)) {
|
|
174
229
|
const sourceBehaviors = styles.behaviors;
|
|
175
|
-
styles.addStylesTo(
|
|
230
|
+
styles.addStylesTo(source);
|
|
176
231
|
if (sourceBehaviors !== null) {
|
|
177
|
-
|
|
232
|
+
for (let i = 0, ii = sourceBehaviors.length; i < ii; ++i) {
|
|
233
|
+
this.addBehavior(sourceBehaviors[i]);
|
|
234
|
+
}
|
|
178
235
|
}
|
|
179
236
|
}
|
|
180
237
|
}
|
|
@@ -183,121 +240,82 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
183
240
|
* @param styles - the styles to remove.
|
|
184
241
|
*/
|
|
185
242
|
removeStyles(styles) {
|
|
243
|
+
var _a;
|
|
186
244
|
if (!styles) {
|
|
187
245
|
return;
|
|
188
246
|
}
|
|
189
|
-
const
|
|
190
|
-
this.element.getRootNode();
|
|
247
|
+
const source = this.source;
|
|
191
248
|
if (styles instanceof HTMLElement) {
|
|
249
|
+
const target = (_a = getShadowRoot(source)) !== null && _a !== void 0 ? _a : source;
|
|
192
250
|
target.removeChild(styles);
|
|
193
251
|
}
|
|
194
|
-
else if (styles.isAttachedTo(
|
|
252
|
+
else if (styles.isAttachedTo(source)) {
|
|
195
253
|
const sourceBehaviors = styles.behaviors;
|
|
196
|
-
styles.removeStylesFrom(
|
|
254
|
+
styles.removeStylesFrom(source);
|
|
197
255
|
if (sourceBehaviors !== null) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Adds behaviors to this element.
|
|
204
|
-
* @param behaviors - The behaviors to add.
|
|
205
|
-
*/
|
|
206
|
-
addBehaviors(behaviors) {
|
|
207
|
-
var _a;
|
|
208
|
-
const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
|
|
209
|
-
const length = behaviors.length;
|
|
210
|
-
const behaviorsToBind = [];
|
|
211
|
-
for (let i = 0; i < length; ++i) {
|
|
212
|
-
const behavior = behaviors[i];
|
|
213
|
-
if (targetBehaviors.has(behavior)) {
|
|
214
|
-
targetBehaviors.set(behavior, targetBehaviors.get(behavior) + 1);
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
targetBehaviors.set(behavior, 1);
|
|
218
|
-
behaviorsToBind.push(behavior);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
if (this._isConnected) {
|
|
222
|
-
const element = this.element;
|
|
223
|
-
const context = ExecutionContext.default;
|
|
224
|
-
for (let i = 0; i < behaviorsToBind.length; ++i) {
|
|
225
|
-
behaviorsToBind[i].bind(element, context);
|
|
256
|
+
for (let i = 0, ii = sourceBehaviors.length; i < ii; ++i) {
|
|
257
|
+
this.addBehavior(sourceBehaviors[i]);
|
|
258
|
+
}
|
|
226
259
|
}
|
|
227
260
|
}
|
|
228
261
|
}
|
|
229
262
|
/**
|
|
230
|
-
*
|
|
231
|
-
* @param behaviors - The behaviors to remove.
|
|
232
|
-
* @param force - Forces unbinding of behaviors.
|
|
263
|
+
* Runs connected lifecycle behavior on the associated element.
|
|
233
264
|
*/
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (targetBehaviors === null) {
|
|
265
|
+
connect() {
|
|
266
|
+
if (this.stage !== 3 /* Stages.disconnected */) {
|
|
237
267
|
return;
|
|
238
268
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
269
|
+
this.stage = 0 /* Stages.connecting */;
|
|
270
|
+
// If we have any observables that were bound, re-apply their values.
|
|
271
|
+
if (this.boundObservables !== null) {
|
|
272
|
+
const element = this.source;
|
|
273
|
+
const boundObservables = this.boundObservables;
|
|
274
|
+
const propertyNames = Object.keys(boundObservables);
|
|
275
|
+
for (let i = 0, ii = propertyNames.length; i < ii; ++i) {
|
|
276
|
+
const propertyName = propertyNames[i];
|
|
277
|
+
element[propertyName] = boundObservables[propertyName];
|
|
248
278
|
}
|
|
279
|
+
this.boundObservables = null;
|
|
249
280
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
for (
|
|
254
|
-
|
|
281
|
+
const behaviors = this.behaviors;
|
|
282
|
+
if (behaviors !== null) {
|
|
283
|
+
this.guardBehaviorConnection = true;
|
|
284
|
+
for (const key of behaviors.keys()) {
|
|
285
|
+
key.connectedCallback && key.connectedCallback(this);
|
|
255
286
|
}
|
|
287
|
+
this.guardBehaviorConnection = false;
|
|
256
288
|
}
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Runs connected lifecycle behavior on the associated element.
|
|
260
|
-
*/
|
|
261
|
-
onConnectedCallback() {
|
|
262
|
-
if (this._isConnected) {
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
const element = this.element;
|
|
266
|
-
const context = ExecutionContext.default;
|
|
267
289
|
if (this.needsInitialization) {
|
|
268
|
-
this.
|
|
290
|
+
this.renderTemplate(this.template);
|
|
291
|
+
this.addStyles(this.mainStyles);
|
|
292
|
+
this.needsInitialization = false;
|
|
269
293
|
}
|
|
270
294
|
else if (this.view !== null) {
|
|
271
|
-
this.view.bind(
|
|
295
|
+
this.view.bind(this.source);
|
|
272
296
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
for (const behavior of behaviors.keys()) {
|
|
276
|
-
behavior.bind(element, context);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
this.setIsConnected(true);
|
|
297
|
+
this.stage = 1 /* Stages.connected */;
|
|
298
|
+
Observable.notify(this, isConnectedPropertyName);
|
|
280
299
|
}
|
|
281
300
|
/**
|
|
282
301
|
* Runs disconnected lifecycle behavior on the associated element.
|
|
283
302
|
*/
|
|
284
|
-
|
|
285
|
-
if (
|
|
303
|
+
disconnect() {
|
|
304
|
+
if (this.stage !== 1 /* Stages.connected */) {
|
|
286
305
|
return;
|
|
287
306
|
}
|
|
288
|
-
this.
|
|
289
|
-
|
|
290
|
-
if (view !== null) {
|
|
291
|
-
view.unbind();
|
|
307
|
+
this.stage = 2 /* Stages.disconnecting */;
|
|
308
|
+
Observable.notify(this, isConnectedPropertyName);
|
|
309
|
+
if (this.view !== null) {
|
|
310
|
+
this.view.unbind();
|
|
292
311
|
}
|
|
293
312
|
const behaviors = this.behaviors;
|
|
294
313
|
if (behaviors !== null) {
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
for (const behavior of behaviors.keys()) {
|
|
298
|
-
behavior.unbind(element, context);
|
|
314
|
+
for (const key of behaviors.keys()) {
|
|
315
|
+
key.disconnectedCallback && key.disconnectedCallback(this);
|
|
299
316
|
}
|
|
300
317
|
}
|
|
318
|
+
this.stage = 3 /* Stages.disconnected */;
|
|
301
319
|
}
|
|
302
320
|
/**
|
|
303
321
|
* Runs the attribute changed callback for the associated element.
|
|
@@ -308,7 +326,7 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
308
326
|
onAttributeChangedCallback(name, oldValue, newValue) {
|
|
309
327
|
const attrDef = this.definition.attributeLookup[name];
|
|
310
328
|
if (attrDef !== void 0) {
|
|
311
|
-
attrDef.onAttributeChangedCallback(this.
|
|
329
|
+
attrDef.onAttributeChangedCallback(this.source, newValue);
|
|
312
330
|
}
|
|
313
331
|
}
|
|
314
332
|
/**
|
|
@@ -320,33 +338,17 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
320
338
|
* Only emits events if connected.
|
|
321
339
|
*/
|
|
322
340
|
emit(type, detail, options) {
|
|
323
|
-
if (this.
|
|
324
|
-
return this.
|
|
341
|
+
if (this.stage === 1 /* Stages.connected */) {
|
|
342
|
+
return this.source.dispatchEvent(new CustomEvent(type, Object.assign(Object.assign({ detail }, defaultEventOptions), options)));
|
|
325
343
|
}
|
|
326
344
|
return false;
|
|
327
345
|
}
|
|
328
|
-
finishInitialization() {
|
|
329
|
-
const element = this.element;
|
|
330
|
-
const boundObservables = this.boundObservables;
|
|
331
|
-
// If we have any observables that were bound, re-apply their values.
|
|
332
|
-
if (boundObservables !== null) {
|
|
333
|
-
const propertyNames = Object.keys(boundObservables);
|
|
334
|
-
for (let i = 0, ii = propertyNames.length; i < ii; ++i) {
|
|
335
|
-
const propertyName = propertyNames[i];
|
|
336
|
-
element[propertyName] = boundObservables[propertyName];
|
|
337
|
-
}
|
|
338
|
-
this.boundObservables = null;
|
|
339
|
-
}
|
|
340
|
-
this.renderTemplate(this.template);
|
|
341
|
-
this.addStyles(this.styles);
|
|
342
|
-
this.needsInitialization = false;
|
|
343
|
-
}
|
|
344
346
|
renderTemplate(template) {
|
|
345
347
|
var _a;
|
|
346
|
-
const element = this.element;
|
|
347
348
|
// When getting the host to render to, we start by looking
|
|
348
349
|
// up the shadow root. If there isn't one, then that means
|
|
349
350
|
// we're doing a Light DOM render to the element's direct children.
|
|
351
|
+
const element = this.source;
|
|
350
352
|
const host = (_a = getShadowRoot(element)) !== null && _a !== void 0 ? _a : element;
|
|
351
353
|
if (this.view !== null) {
|
|
352
354
|
// If there's already a view, we need to unbind and remove through dispose.
|
|
@@ -363,6 +365,8 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
363
365
|
if (template) {
|
|
364
366
|
// If a new template was provided, render it.
|
|
365
367
|
this.view = template.render(element, host, element);
|
|
368
|
+
this.view.sourceLifetime =
|
|
369
|
+
SourceLifetime.coupled;
|
|
366
370
|
}
|
|
367
371
|
}
|
|
368
372
|
/**
|
|
@@ -382,6 +386,103 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
382
386
|
if (definition === void 0) {
|
|
383
387
|
throw FAST.error(1401 /* Message.missingElementDefinition */);
|
|
384
388
|
}
|
|
385
|
-
return (element.$fastController = new
|
|
389
|
+
return (element.$fastController = new elementControllerStrategy(element, definition));
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Sets the strategy that ElementController.forCustomElement uses to construct
|
|
393
|
+
* ElementController instances for an element.
|
|
394
|
+
* @param strategy - The strategy to use.
|
|
395
|
+
*/
|
|
396
|
+
static setStrategy(strategy) {
|
|
397
|
+
elementControllerStrategy = strategy;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
// Set default strategy for ElementController
|
|
401
|
+
ElementController.setStrategy(ElementController);
|
|
402
|
+
/**
|
|
403
|
+
* Converts a styleTarget into the operative target. When the provided target is an Element
|
|
404
|
+
* that is a FASTElement, the function will return the ShadowRoot for that element. Otherwise,
|
|
405
|
+
* it will return the root node for the element.
|
|
406
|
+
* @param target
|
|
407
|
+
* @returns
|
|
408
|
+
*/
|
|
409
|
+
function normalizeStyleTarget(target) {
|
|
410
|
+
var _a;
|
|
411
|
+
if ("adoptedStyleSheets" in target) {
|
|
412
|
+
return target;
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
return ((_a = getShadowRoot(target)) !== null && _a !== void 0 ? _a : target.getRootNode());
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// Default StyleStrategy implementations are defined in this module because they
|
|
419
|
+
// require access to element shadowRoots, and we don't want to leak shadowRoot
|
|
420
|
+
// objects out of this module.
|
|
421
|
+
/**
|
|
422
|
+
* https://wicg.github.io/construct-stylesheets/
|
|
423
|
+
* https://developers.google.com/web/updates/2019/02/constructable-stylesheets
|
|
424
|
+
*
|
|
425
|
+
* @internal
|
|
426
|
+
*/
|
|
427
|
+
export class AdoptedStyleSheetsStrategy {
|
|
428
|
+
constructor(styles) {
|
|
429
|
+
const styleSheetCache = AdoptedStyleSheetsStrategy.styleSheetCache;
|
|
430
|
+
this.sheets = styles.map((x) => {
|
|
431
|
+
if (x instanceof CSSStyleSheet) {
|
|
432
|
+
return x;
|
|
433
|
+
}
|
|
434
|
+
let sheet = styleSheetCache.get(x);
|
|
435
|
+
if (sheet === void 0) {
|
|
436
|
+
sheet = new CSSStyleSheet();
|
|
437
|
+
sheet.replaceSync(x);
|
|
438
|
+
styleSheetCache.set(x, sheet);
|
|
439
|
+
}
|
|
440
|
+
return sheet;
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
addStylesTo(target) {
|
|
444
|
+
const t = normalizeStyleTarget(target);
|
|
445
|
+
t.adoptedStyleSheets = [...t.adoptedStyleSheets, ...this.sheets];
|
|
446
|
+
}
|
|
447
|
+
removeStylesFrom(target) {
|
|
448
|
+
const t = normalizeStyleTarget(target);
|
|
449
|
+
const sheets = this.sheets;
|
|
450
|
+
t.adoptedStyleSheets = t.adoptedStyleSheets.filter((x) => sheets.indexOf(x) === -1);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
AdoptedStyleSheetsStrategy.styleSheetCache = new Map();
|
|
454
|
+
let id = 0;
|
|
455
|
+
const nextStyleId = () => `fast-${++id}`;
|
|
456
|
+
function usableStyleTarget(target) {
|
|
457
|
+
return target === document ? document.body : target;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* @internal
|
|
461
|
+
*/
|
|
462
|
+
export class StyleElementStrategy {
|
|
463
|
+
constructor(styles) {
|
|
464
|
+
this.styles = styles;
|
|
465
|
+
this.styleClass = nextStyleId();
|
|
466
|
+
}
|
|
467
|
+
addStylesTo(target) {
|
|
468
|
+
target = usableStyleTarget(normalizeStyleTarget(target));
|
|
469
|
+
const styles = this.styles;
|
|
470
|
+
const styleClass = this.styleClass;
|
|
471
|
+
for (let i = 0; i < styles.length; i++) {
|
|
472
|
+
const element = document.createElement("style");
|
|
473
|
+
element.innerHTML = styles[i];
|
|
474
|
+
element.className = styleClass;
|
|
475
|
+
target.append(element);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
removeStylesFrom(target) {
|
|
479
|
+
target = usableStyleTarget(normalizeStyleTarget(target));
|
|
480
|
+
const styles = target.querySelectorAll(`.${this.styleClass}`);
|
|
481
|
+
for (let i = 0, ii = styles.length; i < ii; ++i) {
|
|
482
|
+
target.removeChild(styles[i]);
|
|
483
|
+
}
|
|
386
484
|
}
|
|
387
485
|
}
|
|
486
|
+
ElementStyles.setDefaultStrategy(ElementStyles.supportsAdoptedStyleSheets
|
|
487
|
+
? AdoptedStyleSheetsStrategy
|
|
488
|
+
: StyleElementStrategy);
|
|
@@ -1,29 +1,28 @@
|
|
|
1
|
-
import { isString } from "../interfaces.js";
|
|
1
|
+
import { isString, KernelServiceId } from "../interfaces.js";
|
|
2
2
|
import { Observable } from "../observation/observable.js";
|
|
3
3
|
import { createTypeRegistry, FAST } from "../platform.js";
|
|
4
4
|
import { ElementStyles } from "../styles/element-styles.js";
|
|
5
5
|
import { AttributeDefinition } from "./attributes.js";
|
|
6
6
|
const defaultShadowOptions = { mode: "open" };
|
|
7
7
|
const defaultElementOptions = {};
|
|
8
|
-
const
|
|
8
|
+
const fastElementBaseTypes = new Set();
|
|
9
|
+
const fastElementRegistry = FAST.getById(KernelServiceId.elementRegistry, () => createTypeRegistry());
|
|
9
10
|
/**
|
|
10
11
|
* Defines metadata for a FASTElement.
|
|
11
12
|
* @public
|
|
12
13
|
*/
|
|
13
14
|
export class FASTElementDefinition {
|
|
14
|
-
/**
|
|
15
|
-
* Creates an instance of FASTElementDefinition.
|
|
16
|
-
* @param type - The type this definition is being created for.
|
|
17
|
-
* @param nameOrConfig - The name of the element to define or a config object
|
|
18
|
-
* that describes the element to define.
|
|
19
|
-
*/
|
|
20
15
|
constructor(type, nameOrConfig = type.definition) {
|
|
16
|
+
var _a;
|
|
17
|
+
this.platformDefined = false;
|
|
21
18
|
if (isString(nameOrConfig)) {
|
|
22
19
|
nameOrConfig = { name: nameOrConfig };
|
|
23
20
|
}
|
|
24
21
|
this.type = type;
|
|
25
22
|
this.name = nameOrConfig.name;
|
|
26
23
|
this.template = nameOrConfig.template;
|
|
24
|
+
this.registry = (_a = nameOrConfig.registry) !== null && _a !== void 0 ? _a : customElements;
|
|
25
|
+
const proto = type.prototype;
|
|
27
26
|
const attributes = AttributeDefinition.collect(type, nameOrConfig.attributes);
|
|
28
27
|
const observedAttributes = new Array(attributes.length);
|
|
29
28
|
const propertyLookup = {};
|
|
@@ -33,9 +32,13 @@ export class FASTElementDefinition {
|
|
|
33
32
|
observedAttributes[i] = current.attribute;
|
|
34
33
|
propertyLookup[current.name] = current;
|
|
35
34
|
attributeLookup[current.attribute] = current;
|
|
35
|
+
Observable.defineProperty(proto, current);
|
|
36
36
|
}
|
|
37
|
+
Reflect.defineProperty(type, "observedAttributes", {
|
|
38
|
+
value: observedAttributes,
|
|
39
|
+
enumerable: true,
|
|
40
|
+
});
|
|
37
41
|
this.attributes = attributes;
|
|
38
|
-
this.observedAttributes = observedAttributes;
|
|
39
42
|
this.propertyLookup = propertyLookup;
|
|
40
43
|
this.attributeLookup = attributeLookup;
|
|
41
44
|
this.shadowOptions =
|
|
@@ -48,20 +51,14 @@ export class FASTElementDefinition {
|
|
|
48
51
|
nameOrConfig.elementOptions === void 0
|
|
49
52
|
? defaultElementOptions
|
|
50
53
|
: Object.assign(Object.assign({}, defaultElementOptions), nameOrConfig.elementOptions);
|
|
51
|
-
this.styles =
|
|
52
|
-
|
|
53
|
-
? void 0
|
|
54
|
-
: Array.isArray(nameOrConfig.styles)
|
|
55
|
-
? new ElementStyles(nameOrConfig.styles)
|
|
56
|
-
: nameOrConfig.styles instanceof ElementStyles
|
|
57
|
-
? nameOrConfig.styles
|
|
58
|
-
: new ElementStyles([nameOrConfig.styles]);
|
|
54
|
+
this.styles = ElementStyles.normalize(nameOrConfig.styles);
|
|
55
|
+
fastElementRegistry.register(this);
|
|
59
56
|
}
|
|
60
57
|
/**
|
|
61
58
|
* Indicates if this element has been defined in at least one registry.
|
|
62
59
|
*/
|
|
63
60
|
get isDefined() {
|
|
64
|
-
return
|
|
61
|
+
return this.platformDefined;
|
|
65
62
|
}
|
|
66
63
|
/**
|
|
67
64
|
* Defines a custom element based on this definition.
|
|
@@ -69,24 +66,35 @@ export class FASTElementDefinition {
|
|
|
69
66
|
* @remarks
|
|
70
67
|
* This operation is idempotent per registry.
|
|
71
68
|
*/
|
|
72
|
-
define(registry =
|
|
69
|
+
define(registry = this.registry) {
|
|
73
70
|
const type = this.type;
|
|
74
|
-
if (fastElementRegistry.register(this)) {
|
|
75
|
-
const attributes = this.attributes;
|
|
76
|
-
const proto = type.prototype;
|
|
77
|
-
for (let i = 0, ii = attributes.length; i < ii; ++i) {
|
|
78
|
-
Observable.defineProperty(proto, attributes[i]);
|
|
79
|
-
}
|
|
80
|
-
Reflect.defineProperty(type, "observedAttributes", {
|
|
81
|
-
value: this.observedAttributes,
|
|
82
|
-
enumerable: true,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
71
|
if (!registry.get(this.name)) {
|
|
72
|
+
this.platformDefined = true;
|
|
86
73
|
registry.define(this.name, type, this.elementOptions);
|
|
87
74
|
}
|
|
88
75
|
return this;
|
|
89
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Creates an instance of FASTElementDefinition.
|
|
79
|
+
* @param type - The type this definition is being created for.
|
|
80
|
+
* @param nameOrDef - The name of the element to define or a config object
|
|
81
|
+
* that describes the element to define.
|
|
82
|
+
*/
|
|
83
|
+
static compose(type, nameOrDef) {
|
|
84
|
+
if (fastElementBaseTypes.has(type) || fastElementRegistry.getByType(type)) {
|
|
85
|
+
return new FASTElementDefinition(class extends type {
|
|
86
|
+
}, nameOrDef);
|
|
87
|
+
}
|
|
88
|
+
return new FASTElementDefinition(type, nameOrDef);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Registers a FASTElement base type.
|
|
92
|
+
* @param type - The type to register as a base type.
|
|
93
|
+
* @internal
|
|
94
|
+
*/
|
|
95
|
+
static registerBaseType(type) {
|
|
96
|
+
fastElementBaseTypes.add(type);
|
|
97
|
+
}
|
|
90
98
|
}
|
|
91
99
|
/**
|
|
92
100
|
* Gets the element definition associated with the specified type.
|