@ng-native/fabric 0.13.0 → 0.15.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 +63 -6
- package/dist/css.js +268 -59
- package/dist/css.js.map +1 -1
- package/dist/defer-triggers.js +2 -8
- package/dist/defer-triggers.js.map +1 -1
- package/dist/engine.d.ts +201 -21
- package/dist/engine.js +915 -125
- package/dist/engine.js.map +1 -1
- package/dist/fabric.d.ts +1 -1
- package/dist/fabric.js +25 -0
- package/dist/fabric.js.map +1 -1
- package/dist/font-faces.d.ts +19 -0
- package/dist/font-faces.js +42 -0
- package/dist/font-faces.js.map +1 -1
- package/dist/forms-inputs.d.ts +1 -1
- package/dist/forms-inputs.js +2 -2
- package/dist/forms-inputs.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/inline-derived-token.js +56 -7
- package/dist/inline-derived-token.js.map +1 -1
- package/dist/inline-token.d.ts +4 -3
- package/dist/inline-token.js +41 -8
- package/dist/inline-token.js.map +1 -1
- package/dist/native-drive.d.ts +42 -1
- package/dist/native-drive.js +135 -9
- package/dist/native-drive.js.map +1 -1
- package/dist/node-global.d.ts +9 -0
- package/dist/node-global.js +41 -0
- package/dist/node-global.js.map +1 -0
- package/dist/relative-colour.d.ts +2 -2
- package/dist/relative-colour.js +4 -0
- package/dist/relative-colour.js.map +1 -1
- package/dist/scroll-animation.d.ts +12 -0
- package/dist/scroll-animation.js +10 -0
- package/dist/scroll-animation.js.map +1 -1
- package/dist/transition.d.ts +3 -2
- package/dist/transition.js +17 -8
- package/dist/transition.js.map +1 -1
- package/package.json +1 -1
package/dist/css.js
CHANGED
|
@@ -208,12 +208,15 @@ export const styleStats = {
|
|
|
208
208
|
nodesResolved: 0,
|
|
209
209
|
/** Rules filed by key selector: each sheet's once, however many sheets come after it. */
|
|
210
210
|
rulesFiled: 0,
|
|
211
|
+
/** Nodes asked whether a rule `:has()` was asked for could be for them: see `isFor`. */
|
|
212
|
+
subjectTests: 0,
|
|
211
213
|
};
|
|
212
214
|
export function resetStyleStats() {
|
|
213
215
|
styleStats.compoundTests = 0;
|
|
214
216
|
styleStats.ruleTests = 0;
|
|
215
217
|
styleStats.nodesResolved = 0;
|
|
216
218
|
styleStats.rulesFiled = 0;
|
|
219
|
+
styleStats.subjectTests = 0;
|
|
217
220
|
}
|
|
218
221
|
/** A prop's value as an attribute test compares it: in lower case, under the i flag. */
|
|
219
222
|
const attributeText = (actual, test) => test.insensitive ? String(actual).toLowerCase() : String(actual);
|
|
@@ -252,8 +255,8 @@ function matchesValue(value, operator, expected) {
|
|
|
252
255
|
case 'substring':
|
|
253
256
|
return value.includes(expected);
|
|
254
257
|
case 'includes':
|
|
255
|
-
// `~=` matches one whole word of a
|
|
256
|
-
return value.split(
|
|
258
|
+
// `~=` matches one whole word of a list split at CSS's spaces, which a no-break space is not.
|
|
259
|
+
return value.split(CSS_SPACE).includes(expected);
|
|
257
260
|
case 'dash-match':
|
|
258
261
|
// `|=` matches the value itself or the value followed by a hyphen, as `lang` uses.
|
|
259
262
|
return value === expected || value.startsWith(`${expected}-`);
|
|
@@ -288,7 +291,7 @@ function matchesCompound(node, compound, sheet) {
|
|
|
288
291
|
return false;
|
|
289
292
|
}
|
|
290
293
|
}
|
|
291
|
-
if (compound.type !== undefined && compound.type !== node.
|
|
294
|
+
if (compound.type !== undefined && compound.type !== node.tag)
|
|
292
295
|
return false;
|
|
293
296
|
if (compound.own !== undefined && !ownedBy(node, compound, sheet))
|
|
294
297
|
return false;
|
|
@@ -511,8 +514,8 @@ function bitsAbove(node) {
|
|
|
511
514
|
if (up.classes)
|
|
512
515
|
for (const className of up.classes)
|
|
513
516
|
add(bitOf('.', className));
|
|
514
|
-
if (up.
|
|
515
|
-
add(bitOf('<', up.
|
|
517
|
+
if (up.tag !== undefined)
|
|
518
|
+
add(bitOf('<', up.tag));
|
|
516
519
|
const id = up.props?.['nativeID'];
|
|
517
520
|
if (typeof id === 'string')
|
|
518
521
|
add(bitOf('#', id));
|
|
@@ -640,6 +643,36 @@ export function placeReadElsewhere(sheet) {
|
|
|
640
643
|
}
|
|
641
644
|
return known;
|
|
642
645
|
}
|
|
646
|
+
const NAMED_BESIDE = new WeakMap();
|
|
647
|
+
/**
|
|
648
|
+
* The props a sheet's rules ask of an element before another in a child list, `[data-on] ~ .x`:
|
|
649
|
+
* those whose change can restyle the elements after it. An id is asked as `nativeID`.
|
|
650
|
+
*/
|
|
651
|
+
export function namedBeside(sheet) {
|
|
652
|
+
let named = NAMED_BESIDE.get(sheet);
|
|
653
|
+
if (named === undefined) {
|
|
654
|
+
named = new Set();
|
|
655
|
+
for (const rule of sheet.rules) {
|
|
656
|
+
rule.combinators.forEach((joined, at) => {
|
|
657
|
+
if (joined === 'next-sibling' || joined === 'later-sibling') {
|
|
658
|
+
propsNamed(rule.compounds[at], named);
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
NAMED_BESIDE.set(sheet, named);
|
|
663
|
+
}
|
|
664
|
+
return named;
|
|
665
|
+
}
|
|
666
|
+
/** Add each prop a compound, or one nested in it at any depth, asks about: an attribute or an id. */
|
|
667
|
+
function propsNamed(compound, into) {
|
|
668
|
+
if (compound.id !== undefined)
|
|
669
|
+
into.add('nativeID');
|
|
670
|
+
for (const test of compound.attributes ?? [])
|
|
671
|
+
into.add(test.name);
|
|
672
|
+
const within = (compound.has ?? []).flatMap((test) => test.any);
|
|
673
|
+
for (const inner of [...nestedCompounds(compound), ...within])
|
|
674
|
+
propsNamed(inner, into);
|
|
675
|
+
}
|
|
643
676
|
/** Whether a compound, or one nested in it at any depth, asks about a place in a child list. */
|
|
644
677
|
function readsPlace(compound) {
|
|
645
678
|
if (compound.nth?.length)
|
|
@@ -918,7 +951,7 @@ function countPosition(node, siblings, fromEnd, ofType) {
|
|
|
918
951
|
let position = 0;
|
|
919
952
|
let seen = 0;
|
|
920
953
|
for (const sibling of siblings) {
|
|
921
|
-
if (!isElement(sibling) || (ofType && sibling.
|
|
954
|
+
if (!isElement(sibling) || (ofType && sibling.tag !== node.tag))
|
|
922
955
|
continue;
|
|
923
956
|
seen++;
|
|
924
957
|
if (sibling === node)
|
|
@@ -1115,7 +1148,7 @@ function reach(node, index, found) {
|
|
|
1115
1148
|
};
|
|
1116
1149
|
if (index.universal.length)
|
|
1117
1150
|
found.push(...index.universal);
|
|
1118
|
-
take(`type:${node.
|
|
1151
|
+
take(`type:${node.tag}`);
|
|
1119
1152
|
const id = node.props['nativeID'];
|
|
1120
1153
|
if (typeof id === 'string')
|
|
1121
1154
|
take(`id:${id}`);
|
|
@@ -1187,6 +1220,13 @@ function importantNames(result, twin) {
|
|
|
1187
1220
|
}
|
|
1188
1221
|
/** What `em` falls back to when nothing in scope has set a font size. The web's default. */
|
|
1189
1222
|
const DEFAULT_FONT_SIZE = 16;
|
|
1223
|
+
/**
|
|
1224
|
+
* The rules a node matched, to style it from again: for a change above it, and not for one of
|
|
1225
|
+
* its own or beneath it, which can change what it matches.
|
|
1226
|
+
*/
|
|
1227
|
+
function rulesKept(cached, node) {
|
|
1228
|
+
return node.ownDirty || node.hasDirty ? undefined : cached.rules;
|
|
1229
|
+
}
|
|
1190
1230
|
/** Shared empty result. Never handed out anywhere that mutates it. */
|
|
1191
1231
|
const EMPTY = {};
|
|
1192
1232
|
/** Stands in for the parent of a root node, so the comparison needs no null case. */
|
|
@@ -1287,14 +1327,19 @@ function classReach(sheet) {
|
|
|
1287
1327
|
for (const rule of sheet.rules) {
|
|
1288
1328
|
const every = new Set();
|
|
1289
1329
|
collectClasses(rule, every, reads, named);
|
|
1290
|
-
const { own, inside } = classPlaces(rule);
|
|
1330
|
+
const { own, inside, beneath, parentHas } = classPlaces(rule);
|
|
1291
1331
|
for (const name of every) {
|
|
1292
|
-
|
|
1332
|
+
const placed = own.has(name) || inside.has(name) || beneath.has(name) || parentHas.has(name);
|
|
1333
|
+
if (!placed)
|
|
1293
1334
|
classes.set(name, true);
|
|
1294
1335
|
if (own.has(name))
|
|
1295
1336
|
noteOwn(classes, name);
|
|
1296
1337
|
if (inside.has(name))
|
|
1297
1338
|
noteInside(classes, name, rule);
|
|
1339
|
+
if (beneath.has(name))
|
|
1340
|
+
noteBeneath(classes, name, 'beneath');
|
|
1341
|
+
if (parentHas.has(name))
|
|
1342
|
+
noteBeneath(classes, name, 'parentHas');
|
|
1298
1343
|
}
|
|
1299
1344
|
}
|
|
1300
1345
|
reaches.set(sheet, (found = { classes, reads, named }));
|
|
@@ -1310,6 +1355,16 @@ function noteOwn(found, name) {
|
|
|
1310
1355
|
else
|
|
1311
1356
|
found.set(name, { ...noSubjects(), own: true });
|
|
1312
1357
|
}
|
|
1358
|
+
/** Note a rule as one that names a class in `:has()`, or in `:has(> )` alone. */
|
|
1359
|
+
function noteBeneath(found, name, how) {
|
|
1360
|
+
const subjects = found.get(name);
|
|
1361
|
+
if (subjects === true)
|
|
1362
|
+
return;
|
|
1363
|
+
if (subjects)
|
|
1364
|
+
subjects[how] = true;
|
|
1365
|
+
else
|
|
1366
|
+
found.set(name, { ...noSubjects(), [how]: true });
|
|
1367
|
+
}
|
|
1313
1368
|
/** Note a rule as one that names a class as what its element is inside. */
|
|
1314
1369
|
function noteInside(found, name, rule) {
|
|
1315
1370
|
let subjects = found.get(name);
|
|
@@ -1333,8 +1388,6 @@ const noSubjects = () => ({
|
|
|
1333
1388
|
inside: new Set(),
|
|
1334
1389
|
any: false,
|
|
1335
1390
|
});
|
|
1336
|
-
/** The reach of classes that rules are for the element of, and for nothing under it. */
|
|
1337
|
-
const OWN_ALONE = { ...noSubjects(), own: true };
|
|
1338
1391
|
/** Add to `into` what `from` is for. */
|
|
1339
1392
|
function addSubjects(into, from) {
|
|
1340
1393
|
for (const name of from.classes)
|
|
@@ -1346,6 +1399,17 @@ function addSubjects(into, from) {
|
|
|
1346
1399
|
into.any ||= from.any;
|
|
1347
1400
|
if (from.own)
|
|
1348
1401
|
into.own = true;
|
|
1402
|
+
if (from.beneath)
|
|
1403
|
+
into.beneath = true;
|
|
1404
|
+
if (from.parentHas)
|
|
1405
|
+
into.parentHas = true;
|
|
1406
|
+
}
|
|
1407
|
+
/** What all of `each` are for, as one. */
|
|
1408
|
+
export function joinSubjects(each) {
|
|
1409
|
+
const all = noSubjects();
|
|
1410
|
+
for (const one of each)
|
|
1411
|
+
addSubjects(all, one);
|
|
1412
|
+
return all;
|
|
1349
1413
|
}
|
|
1350
1414
|
/**
|
|
1351
1415
|
* Where a rule names each class it names, for the classes it names in no other place than these:
|
|
@@ -1354,21 +1418,29 @@ function addSubjects(into, from) {
|
|
|
1354
1418
|
* it, which are asked of that element;
|
|
1355
1419
|
* - `inside`, as what that element is inside: the classes of a compound before the last, with
|
|
1356
1420
|
* nothing but `>` and a space between there and the element, and those of what `:is(.box *)`
|
|
1357
|
-
* and `:is(.box > *)` put over it
|
|
1421
|
+
* and `:is(.box > *)` put over it;
|
|
1422
|
+
* - `beneath`, inside `:has()`, wherever in the rule that is: what it asks of is under the box
|
|
1423
|
+
* that answers it;
|
|
1424
|
+
* - `parentHas`, of what `:has(> )` asks of the box's children themselves, and nowhere else in
|
|
1425
|
+
* `:has()`: the element is right under that box.
|
|
1358
1426
|
*
|
|
1359
|
-
* A class named anywhere else in the rule is in
|
|
1360
|
-
*
|
|
1427
|
+
* A class named anywhere else in the rule is in none, whatever else names it: beside the element,
|
|
1428
|
+
* inside `:host-context()`, or in `:not()` of a box the element is in. A test of the class
|
|
1429
|
+
* attribute is placed as a class is, by `classTestKey`.
|
|
1361
1430
|
*/
|
|
1362
1431
|
function classPlaces(rule) {
|
|
1363
1432
|
const own = new Set();
|
|
1364
1433
|
const inside = new Set();
|
|
1434
|
+
const beneath = new Set();
|
|
1435
|
+
const parentHas = new Set();
|
|
1365
1436
|
const elsewhere = new Set();
|
|
1437
|
+
const below = { beneath, parentHas, elsewhere };
|
|
1366
1438
|
const last = rule.compounds.length - 1;
|
|
1367
1439
|
let under = true;
|
|
1368
1440
|
for (let index = last; index >= 0; index--) {
|
|
1369
1441
|
const compound = rule.compounds[index];
|
|
1370
1442
|
if (index === last) {
|
|
1371
|
-
placeClasses(compound, own, inside,
|
|
1443
|
+
placeClasses(compound, own, inside, below);
|
|
1372
1444
|
continue;
|
|
1373
1445
|
}
|
|
1374
1446
|
const joined = rule.combinators[index];
|
|
@@ -1376,36 +1448,75 @@ function classPlaces(rule) {
|
|
|
1376
1448
|
// A box the element is under, by its classes and by those it is asked to have or not to,
|
|
1377
1449
|
// `.box:not(.busy) .row`: each is asked of that box, as its own are.
|
|
1378
1450
|
const over = under ? inside : elsewhere;
|
|
1379
|
-
placeClasses(compound, over, over,
|
|
1451
|
+
placeClasses(compound, over, over, below);
|
|
1380
1452
|
}
|
|
1381
1453
|
for (const name of elsewhere) {
|
|
1382
1454
|
own.delete(name);
|
|
1383
1455
|
inside.delete(name);
|
|
1456
|
+
beneath.delete(name);
|
|
1457
|
+
parentHas.delete(name);
|
|
1384
1458
|
}
|
|
1385
|
-
return { own, inside };
|
|
1459
|
+
return { own, inside, beneath, parentHas };
|
|
1386
1460
|
}
|
|
1387
1461
|
/**
|
|
1388
1462
|
* The classes of a compound asked of the element a rule is for, into `at`, and of the compounds
|
|
1389
1463
|
* it puts over that element, into `inside`. What any other part of it names goes `elsewhere`:
|
|
1390
1464
|
* a part read here by name is one this knows the reach of, and one added later is not.
|
|
1391
1465
|
*/
|
|
1392
|
-
function placeClasses(compound, at, inside,
|
|
1393
|
-
const { classes, is, not, ancestors, parents, type: _t, id: _i, root: _r, pseudo: _p, ...rest } = compound;
|
|
1394
|
-
for (const name of classes)
|
|
1466
|
+
function placeClasses(compound, at, inside, below) {
|
|
1467
|
+
const { classes, is, not, ancestors, parents, attributes, has, type: _t, id: _i, root: _r, pseudo: _p, ...rest } = compound;
|
|
1468
|
+
for (const name of namesOf(classes, attributes))
|
|
1395
1469
|
at.add(name);
|
|
1396
1470
|
for (const alternatives of is ?? []) {
|
|
1397
1471
|
for (const option of alternatives)
|
|
1398
|
-
placeClasses(option, at, inside,
|
|
1472
|
+
placeClasses(option, at, inside, below);
|
|
1399
1473
|
}
|
|
1400
1474
|
for (const excluded of not ?? [])
|
|
1401
|
-
placeClasses(excluded, at, inside,
|
|
1475
|
+
placeClasses(excluded, at, inside, below);
|
|
1402
1476
|
// What is over the element is over it whichever of these said so, and what is over that is too.
|
|
1403
1477
|
for (const above of [...(ancestors ?? []), ...(parents ?? [])]) {
|
|
1404
|
-
placeClasses(above, inside, inside,
|
|
1478
|
+
placeClasses(above, inside, inside, below);
|
|
1405
1479
|
}
|
|
1406
|
-
|
|
1407
|
-
collectClasses(rest, elsewhere, []);
|
|
1480
|
+
placeHas(has, below);
|
|
1481
|
+
collectClasses(rest, below.elsewhere, []);
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* The classes `:has()` asks of what is under the box that answers it, into `beneath`, wherever
|
|
1485
|
+
* in the rule it is written, or into `parentHas` for what `:has(> )` asks of the box's children.
|
|
1486
|
+
* One it can ask of what is above the box goes `elsewhere`: `:is()` in `:has()` is not relative,
|
|
1487
|
+
* so the `.night` of `:has(:is(.night .cell))` can be any element over the cell.
|
|
1488
|
+
*/
|
|
1489
|
+
function placeHas(tests, below) {
|
|
1490
|
+
for (const test of tests ?? []) {
|
|
1491
|
+
const into = test.child ? below.parentHas : below.beneath;
|
|
1492
|
+
for (const compound of test.any)
|
|
1493
|
+
placeBeneath(compound, into, below);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
/** `placeHas` for one compound of a `:has()` argument, whose own classes go `into`. */
|
|
1497
|
+
function placeBeneath(compound, into, below) {
|
|
1498
|
+
const { classes, attributes, is, not, has, type: _t, id: _i, root: _r, pseudo: _p, ...rest } = compound;
|
|
1499
|
+
for (const name of namesOf(classes, attributes))
|
|
1500
|
+
into.add(name);
|
|
1501
|
+
for (const alternatives of is ?? []) {
|
|
1502
|
+
for (const option of alternatives)
|
|
1503
|
+
placeBeneath(option, into, below);
|
|
1504
|
+
}
|
|
1505
|
+
for (const excluded of not ?? [])
|
|
1506
|
+
placeBeneath(excluded, into, below);
|
|
1507
|
+
placeHas(has, below);
|
|
1508
|
+
collectClasses(rest, below.elsewhere, []);
|
|
1509
|
+
}
|
|
1510
|
+
/** A compound's classes, and its tests of the class attribute, which are asked as its classes are. */
|
|
1511
|
+
function namesOf(classes, attributes) {
|
|
1512
|
+
const tests = attributes?.filter((test) => test.name === 'class');
|
|
1513
|
+
return tests?.length ? [...classes, ...tests.map(classTestKey)] : classes;
|
|
1408
1514
|
}
|
|
1515
|
+
/**
|
|
1516
|
+
* A test of the class attribute, `[class^="p-"]`, by a name no class can have: it has a reach
|
|
1517
|
+
* as a class does, for what any class it answers can restyle.
|
|
1518
|
+
*/
|
|
1519
|
+
const classTestKey = (test) => `\0${test.operator ?? ''}${test.insensitive ? 'i' : ''}\0${test.value ?? ''}`;
|
|
1409
1520
|
/** What a rule declares, which names no element. */
|
|
1410
1521
|
const DECLARED = new Set(['declarations', 'important', 'tokens']);
|
|
1411
1522
|
/**
|
|
@@ -1425,8 +1536,10 @@ function collectClasses(value, into, reads, named) {
|
|
|
1425
1536
|
if (Array.isArray(part.attributes)) {
|
|
1426
1537
|
for (const test of part.attributes) {
|
|
1427
1538
|
named?.add(test.name);
|
|
1428
|
-
if (test.name
|
|
1429
|
-
|
|
1539
|
+
if (test.name !== 'class')
|
|
1540
|
+
continue;
|
|
1541
|
+
reads.push(test);
|
|
1542
|
+
into.add(classTestKey(test));
|
|
1430
1543
|
}
|
|
1431
1544
|
}
|
|
1432
1545
|
for (const [key, inner] of Object.entries(value)) {
|
|
@@ -1460,7 +1573,7 @@ function boxAround(rule) {
|
|
|
1460
1573
|
}
|
|
1461
1574
|
/** Whether a rule among these could be for a node: never no where one is. */
|
|
1462
1575
|
function writtenFor(of, node) {
|
|
1463
|
-
if (of.any || of.types.has(node.
|
|
1576
|
+
if (of.any || of.types.has(node.tag))
|
|
1464
1577
|
return true;
|
|
1465
1578
|
for (const name of node.classes ?? [])
|
|
1466
1579
|
if (of.classes.has(name))
|
|
@@ -1725,8 +1838,11 @@ export class StyleResolver {
|
|
|
1725
1838
|
const at = replacing ? this.addedSheets.indexOf(replacing) : -1;
|
|
1726
1839
|
if (at === -1)
|
|
1727
1840
|
this.addedSheets.push(sheet);
|
|
1728
|
-
else
|
|
1841
|
+
else {
|
|
1729
1842
|
this.addedSheets[at] = sheet;
|
|
1843
|
+
this.forgetBeside(replacing);
|
|
1844
|
+
}
|
|
1845
|
+
this.noteBeside(sheet);
|
|
1730
1846
|
// One added at the end is filed after what is there. One in another's place files them all again.
|
|
1731
1847
|
if (at !== -1)
|
|
1732
1848
|
this.filed = null;
|
|
@@ -1753,7 +1869,7 @@ export class StyleResolver {
|
|
|
1753
1869
|
/** How far each class named by the sheets met so far reaches: see `classReach`. */
|
|
1754
1870
|
reach = new Map();
|
|
1755
1871
|
/** The tests of the `class` attribute itself in those sheets, which any class may answer. */
|
|
1756
|
-
classTests =
|
|
1872
|
+
classTests = new Map();
|
|
1757
1873
|
noted = new WeakSet();
|
|
1758
1874
|
/**
|
|
1759
1875
|
* The sheets with a rule written with `::ng-deep`, which is for what is under the component
|
|
@@ -1761,9 +1877,17 @@ export class StyleResolver {
|
|
|
1761
1877
|
*/
|
|
1762
1878
|
deepSheets = new Set();
|
|
1763
1879
|
deepIndexes = new WeakMap();
|
|
1764
|
-
/**
|
|
1765
|
-
|
|
1766
|
-
|
|
1880
|
+
/**
|
|
1881
|
+
* Read the classes a sheet names, once, as soon as any node is given it. One `scoped` to a
|
|
1882
|
+
* component or a host asks of its elements for good, global or not.
|
|
1883
|
+
*/
|
|
1884
|
+
noteSheet(sheet, scoped = false) {
|
|
1885
|
+
if (!sheet)
|
|
1886
|
+
return;
|
|
1887
|
+
if (scoped)
|
|
1888
|
+
this.scoped.add(sheet);
|
|
1889
|
+
this.noteBeside(sheet);
|
|
1890
|
+
if (this.noted.has(sheet))
|
|
1767
1891
|
return;
|
|
1768
1892
|
this.noted.add(sheet);
|
|
1769
1893
|
if (sheet.rules.some((rule) => rule.deep))
|
|
@@ -1771,7 +1895,8 @@ export class StyleResolver {
|
|
|
1771
1895
|
const { classes, reads, named } = classReach(sheet);
|
|
1772
1896
|
for (const [name, how] of classes)
|
|
1773
1897
|
this.noteReach(name, how);
|
|
1774
|
-
|
|
1898
|
+
for (const test of reads)
|
|
1899
|
+
this.classTests.set(classTestKey(test), test);
|
|
1775
1900
|
for (const name of named)
|
|
1776
1901
|
this.named.add(name);
|
|
1777
1902
|
}
|
|
@@ -1784,6 +1909,37 @@ export class StyleResolver {
|
|
|
1784
1909
|
reads(prop) {
|
|
1785
1910
|
return this.named.has(prop);
|
|
1786
1911
|
}
|
|
1912
|
+
/**
|
|
1913
|
+
* By prop, how many sheets in play ask it of an element before another: see `namedBeside`. A
|
|
1914
|
+
* global sheet taken away, or replaced, asks no more.
|
|
1915
|
+
*/
|
|
1916
|
+
besideNamed = new Map();
|
|
1917
|
+
besideNoted = new WeakSet();
|
|
1918
|
+
/** The sheets a component or a host was given: see `noteSheet`. */
|
|
1919
|
+
scoped = new WeakSet();
|
|
1920
|
+
noteBeside(sheet) {
|
|
1921
|
+
if (this.besideNoted.has(sheet))
|
|
1922
|
+
return;
|
|
1923
|
+
this.besideNoted.add(sheet);
|
|
1924
|
+
for (const name of namedBeside(sheet)) {
|
|
1925
|
+
this.besideNamed.set(name, (this.besideNamed.get(name) ?? 0) + 1);
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
forgetBeside(sheet) {
|
|
1929
|
+
if (this.scoped.has(sheet) || !this.besideNoted.delete(sheet))
|
|
1930
|
+
return;
|
|
1931
|
+
for (const name of namedBeside(sheet)) {
|
|
1932
|
+
const left = this.besideNamed.get(name) - 1;
|
|
1933
|
+
if (left)
|
|
1934
|
+
this.besideNamed.set(name, left);
|
|
1935
|
+
else
|
|
1936
|
+
this.besideNamed.delete(name);
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
/** Whether a prop changing can change what the elements after its element match. */
|
|
1940
|
+
readsBeside(prop) {
|
|
1941
|
+
return this.besideNamed.has(prop);
|
|
1942
|
+
}
|
|
1787
1943
|
noteReach(name, how) {
|
|
1788
1944
|
const had = this.reach.get(name);
|
|
1789
1945
|
if (had === true)
|
|
@@ -1807,28 +1963,29 @@ export class StyleResolver {
|
|
|
1807
1963
|
* of them and nothing is styled again.
|
|
1808
1964
|
*/
|
|
1809
1965
|
reachOf(classes) {
|
|
1810
|
-
let
|
|
1811
|
-
let own = false;
|
|
1966
|
+
let found = null;
|
|
1812
1967
|
for (const name of classes) {
|
|
1813
|
-
const how
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1968
|
+
for (const how of this.reachesOf(name)) {
|
|
1969
|
+
if (how === true)
|
|
1970
|
+
return true;
|
|
1971
|
+
addSubjects((found ??= noSubjects()), how);
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
return found;
|
|
1975
|
+
}
|
|
1976
|
+
/** How far a class reaches by its name, and by each test of the class attribute it answers. */
|
|
1977
|
+
*reachesOf(name) {
|
|
1978
|
+
const how = this.reach.get(name);
|
|
1979
|
+
if (how)
|
|
1980
|
+
yield how;
|
|
1981
|
+
for (const [key, test] of this.classTests) {
|
|
1982
|
+
if (answers(test, name))
|
|
1983
|
+
yield this.reach.get(key) ?? true;
|
|
1823
1984
|
}
|
|
1824
|
-
if (!under)
|
|
1825
|
-
return own ? OWN_ALONE : null;
|
|
1826
|
-
if (own)
|
|
1827
|
-
under.own = true;
|
|
1828
|
-
return under;
|
|
1829
1985
|
}
|
|
1830
1986
|
/** Whether one of the rules `subjects` stands for could be for a node. */
|
|
1831
1987
|
isFor(subjects, node) {
|
|
1988
|
+
styleStats.subjectTests++;
|
|
1832
1989
|
return writtenFor(subjects, node);
|
|
1833
1990
|
}
|
|
1834
1991
|
/**
|
|
@@ -1860,6 +2017,7 @@ export class StyleResolver {
|
|
|
1860
2017
|
if (at === -1)
|
|
1861
2018
|
return false;
|
|
1862
2019
|
this.addedSheets.splice(at, 1);
|
|
2020
|
+
this.forgetBeside(sheet);
|
|
1863
2021
|
this.filed = null;
|
|
1864
2022
|
this.additions.length = 0;
|
|
1865
2023
|
this.generation = ++generations;
|
|
@@ -1919,8 +2077,7 @@ export class StyleResolver {
|
|
|
1919
2077
|
return this.unstyled(node, epoch, parent, parentInherited, scope, parentScope);
|
|
1920
2078
|
}
|
|
1921
2079
|
styleStats.nodesResolved++;
|
|
1922
|
-
|
|
1923
|
-
const rules = stands && !node.ownDirty ? cached.rules : undefined;
|
|
2080
|
+
const rules = stands ? rulesKept(cached, node) : undefined;
|
|
1924
2081
|
const matched = found ?? rules ?? this.matchedBy(node);
|
|
1925
2082
|
const parentTokens = parent ? parent.tokens : this.tokensOnRoot;
|
|
1926
2083
|
this.heir(node, parent, matched);
|
|
@@ -1938,11 +2095,13 @@ export class StyleResolver {
|
|
|
1938
2095
|
* change it was marked on the element, its parent's `scope` is the one it was styled under,
|
|
1939
2096
|
* and no sheet that could match it has come since. It is being styled again all the same, for
|
|
1940
2097
|
* a change of its own that alters nothing under it, or for what it inherits.
|
|
2098
|
+
*
|
|
2099
|
+
* A change beneath it is not one: what it answers `:has()` is asked again, and the elements a
|
|
2100
|
+
* rule asking that of it is for are marked on their own (`markUnderHas`), not all under it.
|
|
1941
2101
|
*/
|
|
1942
2102
|
matchesStand(cached, node, parentScope) {
|
|
1943
2103
|
return (cached !== null &&
|
|
1944
2104
|
!node.styleDirty &&
|
|
1945
|
-
!node.hasDirty &&
|
|
1946
2105
|
!node.stateDirty &&
|
|
1947
2106
|
cached.scope !== SHARED_SCOPE &&
|
|
1948
2107
|
parentScope !== SHARED_SCOPE &&
|
|
@@ -3298,14 +3457,17 @@ function boundKind(prop) {
|
|
|
3298
3457
|
* the compiler writes for the same value in a rule. `token` is the value as a token, which is an
|
|
3299
3458
|
* alias when it is a `var()`; null for any other.
|
|
3300
3459
|
*
|
|
3301
|
-
*
|
|
3302
|
-
*
|
|
3303
|
-
*
|
|
3460
|
+
* A colour made of tokens, `color-mix(in srgb, var(--brand), white 20%)`, is worked out from the
|
|
3461
|
+
* tokens where it is used, as a fallback of the same shape is.
|
|
3462
|
+
*
|
|
3463
|
+
* ponytail: any other value has to be the whole `var()`. One inside a longer value, `calc()`
|
|
3464
|
+
* included, is what the compiler parses at build time and nothing here does; write the sum in a
|
|
3465
|
+
* custom property, `[style.--gap]`, and read that in the stylesheet.
|
|
3304
3466
|
*/
|
|
3305
3467
|
export function boundDeclaration(prop, token, on) {
|
|
3306
|
-
if (!token?.alias)
|
|
3307
|
-
return null;
|
|
3308
3468
|
const kind = boundKind(prop);
|
|
3469
|
+
if (!token?.alias)
|
|
3470
|
+
return derivedColour(prop, token, kind, on);
|
|
3309
3471
|
const [reference, ...alternatives] = aliasesOf(token);
|
|
3310
3472
|
for (; token?.alias; token = token.fallback)
|
|
3311
3473
|
;
|
|
@@ -3321,6 +3483,53 @@ export function boundDeclaration(prop, token, on) {
|
|
|
3321
3483
|
...(token && isDerived(token) ? { fallbackToken: token } : {}),
|
|
3322
3484
|
};
|
|
3323
3485
|
}
|
|
3486
|
+
/** A CSS number: `1.5`, `+1.5`, `.5`, `1e0`, `-2`. */
|
|
3487
|
+
const CSS_NUMBER = String.raw `[+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?`;
|
|
3488
|
+
/** A length in `em` or a viewport unit, the whole value: `2em`, `-0.5em`, `50vw`. */
|
|
3489
|
+
const RELATIVE_LENGTH = new RegExp(String.raw `^\s*(${CSS_NUMBER})(em|vw|vh|vmin|vmax)\s*$`, 'i');
|
|
3490
|
+
/** A number with no unit, as a `line-height` is written: a multiple of the font size. */
|
|
3491
|
+
const UNITLESS = new RegExp(String.raw `^\s*(${CSS_NUMBER})\s*$`, 'i');
|
|
3492
|
+
/** A negative `line-height`, of a number or a length, which CSS has no value for. */
|
|
3493
|
+
const NEGATIVE = new RegExp(String.raw `^\s*-(?:\d|\.\d)`);
|
|
3494
|
+
/** Whether `text` is a `line-height` below zero, which a browser drops: `-1.5`, `-1em`, `-2px`. */
|
|
3495
|
+
export const isNegativeLineHeight = (prop, text) => prop === 'lineHeight' && NEGATIVE.test(text);
|
|
3496
|
+
/**
|
|
3497
|
+
* A bound declaration of a length in `em` or a viewport unit, `[style.width]="'2em'"`, as the
|
|
3498
|
+
* deferred declaration the compiler writes for the same value in a rule: measured where it is
|
|
3499
|
+
* used, against the font size in scope. A viewport unit is measured against the viewport, and
|
|
3500
|
+
* again when it changes. A `line-height` with no unit is the number a rule hands down. Null for
|
|
3501
|
+
* any other value, and for a property that takes no length.
|
|
3502
|
+
*/
|
|
3503
|
+
export function boundRelativeLength(prop, text, on) {
|
|
3504
|
+
const kind = boundKind(prop);
|
|
3505
|
+
if (kind !== 'length' && kind !== 'lineHeight')
|
|
3506
|
+
return null;
|
|
3507
|
+
const relative = RELATIVE_LENGTH.exec(text);
|
|
3508
|
+
if (relative) {
|
|
3509
|
+
const unit = relative[2].toLowerCase();
|
|
3510
|
+
return {
|
|
3511
|
+
props: [prop],
|
|
3512
|
+
...(on === undefined ? {} : { on }),
|
|
3513
|
+
compute: { unit, factor: Number(relative[1]) },
|
|
3514
|
+
};
|
|
3515
|
+
}
|
|
3516
|
+
// A line height with no unit is a number each text under it multiplies its own font size by,
|
|
3517
|
+
// not the points it comes to here: the compiler writes the same for it in a rule.
|
|
3518
|
+
const unitless = kind === 'lineHeight' ? UNITLESS.exec(text) : null;
|
|
3519
|
+
if (!unitless)
|
|
3520
|
+
return null;
|
|
3521
|
+
return {
|
|
3522
|
+
props: [prop],
|
|
3523
|
+
...(on === undefined ? {} : { on }),
|
|
3524
|
+
compute: { unit: 'em', factor: Number(unitless[1]), multiple: true },
|
|
3525
|
+
};
|
|
3526
|
+
}
|
|
3527
|
+
/** A bound colour made of tokens, worked out where it is used; null for any other value. */
|
|
3528
|
+
function derivedColour(prop, token, kind, on) {
|
|
3529
|
+
if (!token || kind !== 'color' || !isDerived(token))
|
|
3530
|
+
return null;
|
|
3531
|
+
return { props: [prop], ...(on === undefined ? {} : { on }), kind, fallbackToken: token };
|
|
3532
|
+
}
|
|
3324
3533
|
/** The names a `var()` tries in turn: its own, then each `var()` nested as its fallback. */
|
|
3325
3534
|
function aliasesOf(token) {
|
|
3326
3535
|
const names = [];
|