@ng-native/fabric 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/css.d.ts +51 -3
- package/dist/css.js +194 -40
- package/dist/css.js.map +1 -1
- package/dist/engine.d.ts +61 -9
- package/dist/engine.js +238 -50
- package/dist/engine.js.map +1 -1
- package/dist/transition.d.ts +11 -0
- package/dist/transition.js.map +1 -1
- package/package.json +1 -1
package/dist/css.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export interface Compound {
|
|
|
30
30
|
readonly not?: readonly Compound[];
|
|
31
31
|
/** `:host`: the node must be the host of the component whose sheet is being evaluated. */
|
|
32
32
|
readonly host?: true;
|
|
33
|
-
/** `:host-context()
|
|
33
|
+
/** `:host-context()`, once for each written: the host, or one of its ancestors, must match it. */
|
|
34
34
|
readonly hostContext?: readonly Compound[];
|
|
35
35
|
/**
|
|
36
36
|
* `:is(<compound> *)`: every one of these must match some ancestor, the node itself excluded.
|
|
@@ -485,6 +485,18 @@ export interface StyleCache {
|
|
|
485
485
|
context: object;
|
|
486
486
|
/** The parent's `context` this was computed from. */
|
|
487
487
|
parentContext: object;
|
|
488
|
+
/**
|
|
489
|
+
* Identity token standing for what an element under this node could match differently: minted
|
|
490
|
+
* when the node is styled for a change that can alter that, and kept when it is styled again
|
|
491
|
+
* for one that cannot, a custom property of its own or an inherited value from above. An
|
|
492
|
+
* element whose parent's is the one it was last styled under matches the rules it did, so it
|
|
493
|
+
* is styled from those it kept and they are not found again.
|
|
494
|
+
*/
|
|
495
|
+
scope: object;
|
|
496
|
+
/** The parent's `scope` this was computed from. */
|
|
497
|
+
parentScope: object;
|
|
498
|
+
/** The rules the node matched, for a styling that finds its parent's `scope` as it was. */
|
|
499
|
+
rules?: readonly StyleRule[];
|
|
488
500
|
/** The conditions version this was resolved under. */
|
|
489
501
|
generation: number;
|
|
490
502
|
style: Record<string, unknown>;
|
|
@@ -570,6 +582,12 @@ export interface StyleTarget {
|
|
|
570
582
|
styleCache: StyleCache | null;
|
|
571
583
|
/** Set when something that could change what this node matches has changed. */
|
|
572
584
|
styleDirty: boolean;
|
|
585
|
+
/**
|
|
586
|
+
* Set when what this node matches, or a custom property it holds, may have changed, and nothing
|
|
587
|
+
* that an element under it is matched by: the node is matched and styled again, and those under
|
|
588
|
+
* it are styled from the rules they matched. Absent on a hand-built target.
|
|
589
|
+
*/
|
|
590
|
+
ownDirty?: boolean;
|
|
573
591
|
/**
|
|
574
592
|
* Set when something beneath this node changed and a sheet uses `:has()`: the node is matched
|
|
575
593
|
* again, and restyled only if the rules it matches came out different. Absent on a hand-built
|
|
@@ -733,6 +751,11 @@ export interface Subjects {
|
|
|
733
751
|
readonly inside: Set<string>;
|
|
734
752
|
/** A rule for anything anywhere: no class, no name, and no such box to be in. */
|
|
735
753
|
any: boolean;
|
|
754
|
+
/**
|
|
755
|
+
* In what a class reaches: a rule is for the element that has the class, `.on`, which is then
|
|
756
|
+
* matched again itself. Unset where the rules are only for elements under it.
|
|
757
|
+
*/
|
|
758
|
+
own?: boolean;
|
|
736
759
|
}
|
|
737
760
|
/** Whether an inline style sets a property children inherit. Allocates nothing: it runs per set. */
|
|
738
761
|
export declare function setsInherited(style: unknown): boolean;
|
|
@@ -865,10 +888,13 @@ export declare class StyleResolver {
|
|
|
865
888
|
*/
|
|
866
889
|
reads(prop: string): boolean;
|
|
867
890
|
private noteReach;
|
|
891
|
+
/** Whether a class's reach names any element under the one that has it. */
|
|
892
|
+
reachesUnder(subjects: Subjects): boolean;
|
|
868
893
|
/**
|
|
869
894
|
* What classes coming to an element or going from it can restyle: `true` for it and all
|
|
870
|
-
* under it and after it, as any change to it does; the
|
|
871
|
-
* rules are for; or null, where no rule names any
|
|
895
|
+
* under it and after it, as any change to it does; the element itself, where `own`, and the
|
|
896
|
+
* elements under it to match again, by what rules are for; or null, where no rule names any
|
|
897
|
+
* of them and nothing is styled again.
|
|
872
898
|
*/
|
|
873
899
|
reachOf(classes: Iterable<string>): true | Subjects | null;
|
|
874
900
|
/** Whether one of the rules `subjects` stands for could be for a node. */
|
|
@@ -889,6 +915,15 @@ export declare class StyleResolver {
|
|
|
889
915
|
* resolves at most once however many descendants ask for its inherited values.
|
|
890
916
|
*/
|
|
891
917
|
resolve(node: StyleTarget, epoch: number): StyleCache;
|
|
918
|
+
/** A node styled now, from the rules found for it or from those it kept: see `matchesStand`. */
|
|
919
|
+
private styledAgain;
|
|
920
|
+
/**
|
|
921
|
+
* Whether what an element could match is as it was when it was last styled: nothing that can
|
|
922
|
+
* change it was marked on the element, its parent's `scope` is the one it was styled under,
|
|
923
|
+
* and no sheet that could match it has come since. It is being styled again all the same, for
|
|
924
|
+
* a change of its own that alters nothing under it, or for what it inherits.
|
|
925
|
+
*/
|
|
926
|
+
private matchesStand;
|
|
892
927
|
/**
|
|
893
928
|
* A cache of a node just styled, with a context of its own. It keeps the rules the node
|
|
894
929
|
* matched, for the node to be compared with, once a sheet has a use for them: see `tracksHas`.
|
|
@@ -925,6 +960,12 @@ export declare class StyleResolver {
|
|
|
925
960
|
* without resolving it. What lets a commit step over a clean child in one comparison.
|
|
926
961
|
*/
|
|
927
962
|
holds(node: StyleTarget, parentContext: object): boolean;
|
|
963
|
+
/**
|
|
964
|
+
* Whether a node was last styled under a box holding the one cache shared by every box with
|
|
965
|
+
* nothing to style. Such boxes hand the same `context` down, so the node cannot tell one from
|
|
966
|
+
* another by it: moved under another box, it has to be told.
|
|
967
|
+
*/
|
|
968
|
+
styledUnderShared(node: StyleTarget): boolean;
|
|
928
969
|
/**
|
|
929
970
|
* Whether a previous result still stands: nothing about the node changed, nothing above it
|
|
930
971
|
* moved, and the conditions have not.
|
|
@@ -945,6 +986,8 @@ export declare class StyleResolver {
|
|
|
945
986
|
* token the device had seeded.
|
|
946
987
|
*/
|
|
947
988
|
private unstyled;
|
|
989
|
+
/** The one cache of every node with nothing to style and nothing to hand down, given to one more. */
|
|
990
|
+
private sharedEmpty;
|
|
948
991
|
/**
|
|
949
992
|
* The rules worth trying against a node, in cascade order.
|
|
950
993
|
*
|
|
@@ -1030,6 +1073,11 @@ export declare class StyleResolver {
|
|
|
1030
1073
|
* A declaration with no token and no usable fallback is dropped rather than written as
|
|
1031
1074
|
* undefined, which is what a browser does with a value it cannot resolve.
|
|
1032
1075
|
*/
|
|
1076
|
+
/**
|
|
1077
|
+
* What declarations that wait for a node's tokens come to on it, where no rule of the node's
|
|
1078
|
+
* carries them: a keyframe's, which is settled against the element that plays it.
|
|
1079
|
+
*/
|
|
1080
|
+
settleFor(node: StyleTarget, deferred: readonly DeferredDeclaration[], epoch: number): Record<string, unknown>;
|
|
1033
1081
|
private applyDeferred;
|
|
1034
1082
|
/** Note what the node being resolved takes an `inherit` from, and that its parent has an heir. */
|
|
1035
1083
|
private heir;
|
package/dist/css.js
CHANGED
|
@@ -222,10 +222,11 @@ const attributeText = (actual, test) => test.insensitive ? String(actual).toLowe
|
|
|
222
222
|
*
|
|
223
223
|
* A prop set to `false` or `null` counts as absent, matching the web, where an attribute is either
|
|
224
224
|
* present or not and a `disabled` binding that evaluates false removes it. Everything else is
|
|
225
|
-
* compared as a string, so `[tabIndex="0"]` works against a numeric prop.
|
|
225
|
+
* compared as a string, so `[tabIndex="0"]` works against a numeric prop. `class` is no prop: it
|
|
226
|
+
* is the element's class list, as the attribute would spell it.
|
|
226
227
|
*/
|
|
227
228
|
function matchesAttribute(node, test) {
|
|
228
|
-
const actual = node.props[test.name];
|
|
229
|
+
const actual = test.name === 'class' ? classAttribute(node) : node.props[test.name];
|
|
229
230
|
if (actual === undefined || actual === null || actual === false)
|
|
230
231
|
return false;
|
|
231
232
|
if (test.operator === undefined)
|
|
@@ -235,6 +236,8 @@ function matchesAttribute(node, test) {
|
|
|
235
236
|
return false;
|
|
236
237
|
return matchesValue(attributeText(actual, test), test.operator, test.value);
|
|
237
238
|
}
|
|
239
|
+
/** The classes of a node in the order they were set, one space between each; none is absent. */
|
|
240
|
+
const classAttribute = (node) => node.classes?.size ? [...node.classes].join(' ') : undefined;
|
|
238
241
|
/** The operators an empty value can still match by: `=` and `|=`. */
|
|
239
242
|
const EMPTY_MATCHES = new Set(['equal', 'dash-match']);
|
|
240
243
|
/** Whether an attribute's value, as `attributeText` gives it, passes an operator's test. */
|
|
@@ -336,13 +339,15 @@ function matchesCompound(node, compound, sheet) {
|
|
|
336
339
|
}
|
|
337
340
|
}
|
|
338
341
|
if (compound.hostContext) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
342
|
+
for (const context of compound.hostContext) {
|
|
343
|
+
// The host itself counts, as it does on the web.
|
|
344
|
+
let found = false;
|
|
345
|
+
for (let n = node; n && !found; n = n.parent) {
|
|
346
|
+
found = matchesCompound(n, context, sheet);
|
|
347
|
+
}
|
|
348
|
+
if (!found)
|
|
349
|
+
return false;
|
|
343
350
|
}
|
|
344
|
-
if (!found)
|
|
345
|
-
return false;
|
|
346
351
|
}
|
|
347
352
|
return true;
|
|
348
353
|
}
|
|
@@ -1094,6 +1099,13 @@ const DEFAULT_FONT_SIZE = 16;
|
|
|
1094
1099
|
const EMPTY = {};
|
|
1095
1100
|
/** Stands in for the parent of a root node, so the comparison needs no null case. */
|
|
1096
1101
|
const ROOT_CONTEXT = {};
|
|
1102
|
+
/** The `scope` over a node with no parent. */
|
|
1103
|
+
const ROOT_SCOPE = {};
|
|
1104
|
+
/**
|
|
1105
|
+
* The `scope` of the one cache every node with nothing to style shares. It is no one node's, so
|
|
1106
|
+
* nothing styled under it, or holding it, is taken to match what it did.
|
|
1107
|
+
*/
|
|
1108
|
+
const SHARED_SCOPE = {};
|
|
1097
1109
|
/** Shared empty token map, for the overwhelmingly common case of a subtree defining none. */
|
|
1098
1110
|
const NO_TOKENS = {};
|
|
1099
1111
|
/**
|
|
@@ -1147,17 +1159,29 @@ function classReach(sheet) {
|
|
|
1147
1159
|
for (const rule of sheet.rules) {
|
|
1148
1160
|
const every = new Set();
|
|
1149
1161
|
collectClasses(rule, every, reads, named);
|
|
1150
|
-
const inside =
|
|
1162
|
+
const { own, inside } = classPlaces(rule);
|
|
1151
1163
|
for (const name of every) {
|
|
1152
|
-
if (!inside.has(name))
|
|
1164
|
+
if (!own.has(name) && !inside.has(name))
|
|
1153
1165
|
classes.set(name, true);
|
|
1154
|
-
|
|
1166
|
+
if (own.has(name))
|
|
1167
|
+
noteOwn(classes, name);
|
|
1168
|
+
if (inside.has(name))
|
|
1155
1169
|
noteInside(classes, name, rule);
|
|
1156
1170
|
}
|
|
1157
1171
|
}
|
|
1158
1172
|
reaches.set(sheet, (found = { classes, reads, named }));
|
|
1159
1173
|
return found;
|
|
1160
1174
|
}
|
|
1175
|
+
/** Note a rule as one for the element that has a class. */
|
|
1176
|
+
function noteOwn(found, name) {
|
|
1177
|
+
const subjects = found.get(name);
|
|
1178
|
+
if (subjects === true)
|
|
1179
|
+
return;
|
|
1180
|
+
if (subjects)
|
|
1181
|
+
subjects.own = true;
|
|
1182
|
+
else
|
|
1183
|
+
found.set(name, { ...noSubjects(), own: true });
|
|
1184
|
+
}
|
|
1161
1185
|
/** Note a rule as one that names a class as what its element is inside. */
|
|
1162
1186
|
function noteInside(found, name, rule) {
|
|
1163
1187
|
let subjects = found.get(name);
|
|
@@ -1181,6 +1205,8 @@ const noSubjects = () => ({
|
|
|
1181
1205
|
inside: new Set(),
|
|
1182
1206
|
any: false,
|
|
1183
1207
|
});
|
|
1208
|
+
/** The reach of classes that rules are for the element of, and for nothing under it. */
|
|
1209
|
+
const OWN_ALONE = { ...noSubjects(), own: true };
|
|
1184
1210
|
/** Add to `into` what `from` is for. */
|
|
1185
1211
|
function addSubjects(into, from) {
|
|
1186
1212
|
for (const name of from.classes)
|
|
@@ -1190,30 +1216,67 @@ function addSubjects(into, from) {
|
|
|
1190
1216
|
for (const name of from.inside)
|
|
1191
1217
|
into.inside.add(name);
|
|
1192
1218
|
into.any ||= from.any;
|
|
1219
|
+
if (from.own)
|
|
1220
|
+
into.own = true;
|
|
1193
1221
|
}
|
|
1194
1222
|
/**
|
|
1195
|
-
*
|
|
1196
|
-
*
|
|
1223
|
+
* Where a rule names each class it names, for the classes it names in no other place than these:
|
|
1224
|
+
*
|
|
1225
|
+
* - `own`, on the element the rule is for: its own classes, and those in `:is()` and `:not()` of
|
|
1226
|
+
* it, which are asked of that element;
|
|
1227
|
+
* - `inside`, as what that element is inside: the classes of a compound before the last, with
|
|
1228
|
+
* nothing but `>` and a space between there and the element, and those of what `:is(.box *)`
|
|
1229
|
+
* and `:is(.box > *)` put over it.
|
|
1230
|
+
*
|
|
1231
|
+
* A class named anywhere else in the rule is in neither, whatever else names it: beside the
|
|
1232
|
+
* element, inside `:has()` or `:host-context()`, or in `:not()` of a box the element is in.
|
|
1197
1233
|
*/
|
|
1198
|
-
function
|
|
1234
|
+
function classPlaces(rule) {
|
|
1235
|
+
const own = new Set();
|
|
1199
1236
|
const inside = new Set();
|
|
1200
1237
|
const elsewhere = new Set();
|
|
1201
1238
|
const last = rule.compounds.length - 1;
|
|
1202
1239
|
let under = true;
|
|
1203
1240
|
for (let index = last; index >= 0; index--) {
|
|
1204
1241
|
const compound = rule.compounds[index];
|
|
1205
|
-
if (index
|
|
1206
|
-
|
|
1207
|
-
|
|
1242
|
+
if (index === last) {
|
|
1243
|
+
placeClasses(compound, own, inside, elsewhere);
|
|
1244
|
+
continue;
|
|
1208
1245
|
}
|
|
1246
|
+
const joined = rule.combinators[index];
|
|
1247
|
+
under &&= joined === 'child' || joined === 'descendant';
|
|
1209
1248
|
const { classes, ...rest } = compound;
|
|
1210
1249
|
collectClasses(rest, elsewhere, []);
|
|
1211
1250
|
for (const name of classes)
|
|
1212
|
-
(
|
|
1251
|
+
(under ? inside : elsewhere).add(name);
|
|
1213
1252
|
}
|
|
1214
|
-
for (const name of elsewhere)
|
|
1253
|
+
for (const name of elsewhere) {
|
|
1254
|
+
own.delete(name);
|
|
1215
1255
|
inside.delete(name);
|
|
1216
|
-
|
|
1256
|
+
}
|
|
1257
|
+
return { own, inside };
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1260
|
+
* The classes of a compound asked of the element a rule is for, into `at`, and of the compounds
|
|
1261
|
+
* it puts over that element, into `inside`. What any other part of it names goes `elsewhere`:
|
|
1262
|
+
* a part read here by name is one this knows the reach of, and one added later is not.
|
|
1263
|
+
*/
|
|
1264
|
+
function placeClasses(compound, at, inside, elsewhere) {
|
|
1265
|
+
const { classes, is, not, ancestors, parents, type: _t, id: _i, root: _r, pseudo: _p, ...rest } = compound;
|
|
1266
|
+
for (const name of classes)
|
|
1267
|
+
at.add(name);
|
|
1268
|
+
for (const alternatives of is ?? []) {
|
|
1269
|
+
for (const option of alternatives)
|
|
1270
|
+
placeClasses(option, at, inside, elsewhere);
|
|
1271
|
+
}
|
|
1272
|
+
for (const excluded of not ?? [])
|
|
1273
|
+
placeClasses(excluded, at, inside, elsewhere);
|
|
1274
|
+
// What is over the element is over it whichever of these said so, and what is over that is too.
|
|
1275
|
+
for (const above of [...(ancestors ?? []), ...(parents ?? [])]) {
|
|
1276
|
+
placeClasses(above, inside, inside, elsewhere);
|
|
1277
|
+
}
|
|
1278
|
+
// `attributes` among them: a test of the `class` attribute is answered through `classTests`.
|
|
1279
|
+
collectClasses(rest, elsewhere, []);
|
|
1217
1280
|
}
|
|
1218
1281
|
/** What a rule declares, which names no element. */
|
|
1219
1282
|
const DECLARED = new Set(['declarations', 'important', 'tokens']);
|
|
@@ -1283,12 +1346,22 @@ function writtenFor(of, node) {
|
|
|
1283
1346
|
}
|
|
1284
1347
|
return false;
|
|
1285
1348
|
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Whether a node has its answer for this commit already. Not one marked since it was given the
|
|
1351
|
+
* one cache every box with nothing to style shares, see `unstyled`: another of them resolved in
|
|
1352
|
+
* this commit has set that cache's epoch, and it is not this node's answer.
|
|
1353
|
+
*/
|
|
1354
|
+
function resolvedIn(epoch, cache, node) {
|
|
1355
|
+
return (cache !== null && cache.epoch === epoch && (!node.styleDirty || cache.context !== ROOT_CONTEXT));
|
|
1356
|
+
}
|
|
1286
1357
|
function emptyCacheFor(epoch, generation) {
|
|
1287
1358
|
return {
|
|
1288
1359
|
epoch,
|
|
1289
1360
|
generation,
|
|
1290
1361
|
context: ROOT_CONTEXT,
|
|
1291
1362
|
parentContext: ROOT_CONTEXT,
|
|
1363
|
+
scope: SHARED_SCOPE,
|
|
1364
|
+
parentScope: SHARED_SCOPE,
|
|
1292
1365
|
style: EMPTY,
|
|
1293
1366
|
inherited: EMPTY,
|
|
1294
1367
|
tokens: NO_TOKENS,
|
|
@@ -1584,20 +1657,38 @@ export class StyleResolver {
|
|
|
1584
1657
|
else
|
|
1585
1658
|
addSubjects(had ?? this.reach.set(name, noSubjects()).get(name), how);
|
|
1586
1659
|
}
|
|
1660
|
+
/** Whether a class's reach names any element under the one that has it. */
|
|
1661
|
+
reachesUnder(subjects) {
|
|
1662
|
+
return (subjects.any ||
|
|
1663
|
+
subjects.classes.size > 0 ||
|
|
1664
|
+
subjects.types.size > 0 ||
|
|
1665
|
+
subjects.inside.size > 0);
|
|
1666
|
+
}
|
|
1587
1667
|
/**
|
|
1588
1668
|
* What classes coming to an element or going from it can restyle: `true` for it and all
|
|
1589
|
-
* under it and after it, as any change to it does; the
|
|
1590
|
-
* rules are for; or null, where no rule names any
|
|
1669
|
+
* under it and after it, as any change to it does; the element itself, where `own`, and the
|
|
1670
|
+
* elements under it to match again, by what rules are for; or null, where no rule names any
|
|
1671
|
+
* of them and nothing is styled again.
|
|
1591
1672
|
*/
|
|
1592
1673
|
reachOf(classes) {
|
|
1593
1674
|
let under = null;
|
|
1675
|
+
let own = false;
|
|
1594
1676
|
for (const name of classes) {
|
|
1595
1677
|
const how = this.reach.get(name);
|
|
1596
1678
|
if (how === true || this.classTests.some((test) => answers(test, name)))
|
|
1597
1679
|
return true;
|
|
1598
|
-
if (how)
|
|
1680
|
+
if (!how)
|
|
1681
|
+
continue;
|
|
1682
|
+
own ||= how.own === true;
|
|
1683
|
+
// Made only for a class that reaches under: most are a rule's own, and this is asked for
|
|
1684
|
+
// every element as it is given its classes.
|
|
1685
|
+
if (this.reachesUnder(how))
|
|
1599
1686
|
addSubjects((under ??= noSubjects()), how);
|
|
1600
1687
|
}
|
|
1688
|
+
if (!under)
|
|
1689
|
+
return own ? OWN_ALONE : null;
|
|
1690
|
+
if (own)
|
|
1691
|
+
under.own = true;
|
|
1601
1692
|
return under;
|
|
1602
1693
|
}
|
|
1603
1694
|
/** Whether one of the rules `subjects` stands for could be for a node. */
|
|
@@ -1658,7 +1749,7 @@ export class StyleResolver {
|
|
|
1658
1749
|
const cached = node.styleCache;
|
|
1659
1750
|
// Within one commit a node is asked for its inherited map once per descendant, so this is the
|
|
1660
1751
|
// hot path and it must not walk anywhere.
|
|
1661
|
-
if (
|
|
1752
|
+
if (resolvedIn(epoch, cached, node))
|
|
1662
1753
|
return cached;
|
|
1663
1754
|
const parent = node.parent ? this.resolve(node.parent, epoch) : null;
|
|
1664
1755
|
const parentContext = parent ? parent.context : ROOT_CONTEXT;
|
|
@@ -1676,33 +1767,66 @@ export class StyleResolver {
|
|
|
1676
1767
|
this.justMatched = null;
|
|
1677
1768
|
if (kept)
|
|
1678
1769
|
return kept;
|
|
1770
|
+
return this.styledAgain(node, epoch, parent, found);
|
|
1771
|
+
}
|
|
1772
|
+
/** A node styled now, from the rules found for it or from those it kept: see `matchesStand`. */
|
|
1773
|
+
styledAgain(node, epoch, parent, found) {
|
|
1774
|
+
const cached = node.styleCache;
|
|
1775
|
+
const parentContext = parent ? parent.context : ROOT_CONTEXT;
|
|
1679
1776
|
const parentInherited = parent ? parent.inherited : EMPTY;
|
|
1777
|
+
const parentScope = parent ? parent.scope : ROOT_SCOPE;
|
|
1778
|
+
const stands = this.matchesStand(cached, node, parentScope);
|
|
1779
|
+
// The scope it keeps, or none: it then has a new one, which its new `context` serves as.
|
|
1780
|
+
const scope = stands ? cached.scope : null;
|
|
1680
1781
|
// A box the engine made around loose text is in no template, so no rule matches it.
|
|
1681
1782
|
if (node.anonymous || this.hasNoRules(node)) {
|
|
1682
|
-
return this.unstyled(node, epoch, parent,
|
|
1783
|
+
return this.unstyled(node, epoch, parent, parentInherited, scope, parentScope);
|
|
1683
1784
|
}
|
|
1684
1785
|
styleStats.nodesResolved++;
|
|
1685
|
-
|
|
1786
|
+
// Its own rules are found again for a change of its own, and not for one above it.
|
|
1787
|
+
const rules = stands && !node.ownDirty ? cached.rules : undefined;
|
|
1788
|
+
const matched = found ?? rules ?? this.matchedBy(node);
|
|
1686
1789
|
const parentTokens = parent ? parent.tokens : this.tokensOnRoot;
|
|
1687
1790
|
this.heir(node, parent, matched);
|
|
1688
1791
|
const styled = this.styled(node, matched, parentTokens, parentInherited);
|
|
1689
|
-
const cache = this.cached(epoch, parentContext, styled, matched);
|
|
1792
|
+
const cache = this.cached(epoch, parentContext, styled, matched, scope, parentScope);
|
|
1690
1793
|
node.styleCache = cache;
|
|
1691
1794
|
node.styleDirty = false;
|
|
1795
|
+
node.ownDirty = false;
|
|
1692
1796
|
node.hasDirty = false;
|
|
1693
1797
|
node.stateDirty = false;
|
|
1694
1798
|
return cache;
|
|
1695
1799
|
}
|
|
1800
|
+
/**
|
|
1801
|
+
* Whether what an element could match is as it was when it was last styled: nothing that can
|
|
1802
|
+
* change it was marked on the element, its parent's `scope` is the one it was styled under,
|
|
1803
|
+
* and no sheet that could match it has come since. It is being styled again all the same, for
|
|
1804
|
+
* a change of its own that alters nothing under it, or for what it inherits.
|
|
1805
|
+
*/
|
|
1806
|
+
matchesStand(cached, node, parentScope) {
|
|
1807
|
+
return (cached !== null &&
|
|
1808
|
+
!node.styleDirty &&
|
|
1809
|
+
!node.hasDirty &&
|
|
1810
|
+
!node.stateDirty &&
|
|
1811
|
+
cached.scope !== SHARED_SCOPE &&
|
|
1812
|
+
parentScope !== SHARED_SCOPE &&
|
|
1813
|
+
cached.parentScope === parentScope &&
|
|
1814
|
+
this.current(cached, node));
|
|
1815
|
+
}
|
|
1696
1816
|
/**
|
|
1697
1817
|
* A cache of a node just styled, with a context of its own. It keeps the rules the node
|
|
1698
1818
|
* matched, for the node to be compared with, once a sheet has a use for them: see `tracksHas`.
|
|
1699
1819
|
*/
|
|
1700
|
-
cached(epoch, parentContext, styled, matched) {
|
|
1820
|
+
cached(epoch, parentContext, styled, matched, scope, parentScope) {
|
|
1821
|
+
const context = {};
|
|
1701
1822
|
const cache = {
|
|
1702
1823
|
epoch,
|
|
1703
1824
|
generation: this.generation,
|
|
1704
|
-
context
|
|
1825
|
+
context,
|
|
1705
1826
|
parentContext,
|
|
1827
|
+
scope: scope ?? context,
|
|
1828
|
+
parentScope,
|
|
1829
|
+
rules: matched,
|
|
1706
1830
|
...styled,
|
|
1707
1831
|
};
|
|
1708
1832
|
if (this.tracksHas)
|
|
@@ -1725,6 +1849,7 @@ export class StyleResolver {
|
|
|
1725
1849
|
const stands = (node.hasDirty === true || node.stateDirty === true) &&
|
|
1726
1850
|
cached?.matched !== undefined &&
|
|
1727
1851
|
!node.styleDirty &&
|
|
1852
|
+
!node.ownDirty &&
|
|
1728
1853
|
cached.parentContext === parentContext &&
|
|
1729
1854
|
this.current(cached, node);
|
|
1730
1855
|
if (!stands)
|
|
@@ -1764,6 +1889,7 @@ export class StyleResolver {
|
|
|
1764
1889
|
const stands = node.stateDirty === true &&
|
|
1765
1890
|
cached !== null &&
|
|
1766
1891
|
!node.styleDirty &&
|
|
1892
|
+
!node.ownDirty &&
|
|
1767
1893
|
!node.hasDirty &&
|
|
1768
1894
|
cached.parentContext === parentContext &&
|
|
1769
1895
|
this.current(cached, node) &&
|
|
@@ -1781,6 +1907,14 @@ export class StyleResolver {
|
|
|
1781
1907
|
holds(node, parentContext) {
|
|
1782
1908
|
return this.reusable(node.styleCache, node, parentContext);
|
|
1783
1909
|
}
|
|
1910
|
+
/**
|
|
1911
|
+
* Whether a node was last styled under a box holding the one cache shared by every box with
|
|
1912
|
+
* nothing to style. Such boxes hand the same `context` down, so the node cannot tell one from
|
|
1913
|
+
* another by it: moved under another box, it has to be told.
|
|
1914
|
+
*/
|
|
1915
|
+
styledUnderShared(node) {
|
|
1916
|
+
return node.styleCache !== null && node.styleCache.parentContext === ROOT_CONTEXT;
|
|
1917
|
+
}
|
|
1784
1918
|
/**
|
|
1785
1919
|
* Whether a previous result still stands: nothing about the node changed, nothing above it
|
|
1786
1920
|
* moved, and the conditions have not.
|
|
@@ -1788,6 +1922,7 @@ export class StyleResolver {
|
|
|
1788
1922
|
reusable(cached, node, parentContext) {
|
|
1789
1923
|
return (cached !== null &&
|
|
1790
1924
|
!node.styleDirty &&
|
|
1925
|
+
!node.ownDirty &&
|
|
1791
1926
|
!node.hasDirty &&
|
|
1792
1927
|
!node.stateDirty &&
|
|
1793
1928
|
cached.parentContext === parentContext &&
|
|
@@ -1815,35 +1950,43 @@ export class StyleResolver {
|
|
|
1815
1950
|
* carry: the shared object holds none, and the surface root answering with it dropped every
|
|
1816
1951
|
* token the device had seeded.
|
|
1817
1952
|
*/
|
|
1818
|
-
unstyled(node, epoch, parent,
|
|
1953
|
+
unstyled(node, epoch, parent, parentInherited, scope, parentScope) {
|
|
1819
1954
|
const tokens = parent ? parent.tokens : this.tokensOnRoot;
|
|
1955
|
+
const parentContext = parent ? parent.context : ROOT_CONTEXT;
|
|
1820
1956
|
// What inline style sets is inherited too, with no rule to read it against.
|
|
1821
1957
|
const inline = node.inlineInherits ? inlineInherited(node.props['style']) : null;
|
|
1822
|
-
|
|
1958
|
+
const nothing = !inline &&
|
|
1823
1959
|
parentInherited === EMPTY &&
|
|
1824
1960
|
parentContext === ROOT_CONTEXT &&
|
|
1825
|
-
tokens === NO_TOKENS
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
}
|
|
1830
|
-
node.styleCache = this.emptyCache;
|
|
1831
|
-
return this.emptyCache;
|
|
1832
|
-
}
|
|
1961
|
+
tokens === NO_TOKENS;
|
|
1962
|
+
if (nothing && !node.styleDirty && !node.ownDirty)
|
|
1963
|
+
return this.sharedEmpty(node, epoch);
|
|
1964
|
+
const context = {};
|
|
1833
1965
|
const passthrough = {
|
|
1834
1966
|
epoch,
|
|
1835
1967
|
generation: this.generation,
|
|
1836
|
-
context
|
|
1968
|
+
context,
|
|
1837
1969
|
parentContext,
|
|
1970
|
+
scope: scope ?? context,
|
|
1971
|
+
parentScope,
|
|
1838
1972
|
style: unstyledStyle(parentInherited, inline),
|
|
1839
1973
|
inherited: inline ? inheritFrom(parentInherited, inline) : parentInherited,
|
|
1840
1974
|
tokens,
|
|
1841
1975
|
};
|
|
1842
1976
|
node.styleCache = passthrough;
|
|
1843
1977
|
node.styleDirty = false;
|
|
1978
|
+
node.ownDirty = false;
|
|
1844
1979
|
node.stateDirty = false;
|
|
1845
1980
|
return passthrough;
|
|
1846
1981
|
}
|
|
1982
|
+
/** The one cache of every node with nothing to style and nothing to hand down, given to one more. */
|
|
1983
|
+
sharedEmpty(node, epoch) {
|
|
1984
|
+
if (this.emptyCache.epoch !== epoch || this.emptyCache.generation !== this.generation) {
|
|
1985
|
+
this.emptyCache = emptyCacheFor(epoch, this.generation);
|
|
1986
|
+
}
|
|
1987
|
+
node.styleCache = this.emptyCache;
|
|
1988
|
+
return this.emptyCache;
|
|
1989
|
+
}
|
|
1847
1990
|
/**
|
|
1848
1991
|
* The rules worth trying against a node, in cascade order.
|
|
1849
1992
|
*
|
|
@@ -2150,6 +2293,17 @@ export class StyleResolver {
|
|
|
2150
2293
|
* A declaration with no token and no usable fallback is dropped rather than written as
|
|
2151
2294
|
* undefined, which is what a browser does with a value it cannot resolve.
|
|
2152
2295
|
*/
|
|
2296
|
+
/**
|
|
2297
|
+
* What declarations that wait for a node's tokens come to on it, where no rule of the node's
|
|
2298
|
+
* carries them: a keyframe's, which is settled against the element that plays it.
|
|
2299
|
+
*/
|
|
2300
|
+
settleFor(node, deferred, epoch) {
|
|
2301
|
+
const { tokens } = this.resolve(node, epoch);
|
|
2302
|
+
const above = node.parent ? this.resolve(node.parent, epoch).inherited : EMPTY;
|
|
2303
|
+
const own = {};
|
|
2304
|
+
this.applyDeferred(deferred, own, tokens, above, null);
|
|
2305
|
+
return own;
|
|
2306
|
+
}
|
|
2153
2307
|
applyDeferred(deferred, own, tokens, parentInherited, important) {
|
|
2154
2308
|
for (const declaration of settlingOrder(deferred)) {
|
|
2155
2309
|
if (declaration.inherit) {
|