@ng-native/fabric 0.9.0 → 0.11.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 +55 -1
- package/dist/css.js +250 -17
- package/dist/css.js.map +1 -1
- package/dist/engine.d.ts +66 -0
- package/dist/engine.js +326 -32
- package/dist/engine.js.map +1 -1
- package/package.json +1 -1
package/dist/css.d.ts
CHANGED
|
@@ -51,6 +51,11 @@ export interface Compound {
|
|
|
51
51
|
readonly nth?: readonly NthTest[];
|
|
52
52
|
/** `:empty`: no children at all, text included. */
|
|
53
53
|
readonly empty?: true;
|
|
54
|
+
/**
|
|
55
|
+
* What a `::ng-deep` is written after: an element of the component the sheet is of, or its
|
|
56
|
+
* host. A rule with one is for what is under it, in other components' views too.
|
|
57
|
+
*/
|
|
58
|
+
readonly own?: true;
|
|
54
59
|
/** `:has()`: every one of these must find a match beneath the node. */
|
|
55
60
|
readonly has?: readonly HasTest[];
|
|
56
61
|
}
|
|
@@ -65,6 +70,8 @@ export interface NthTest {
|
|
|
65
70
|
readonly a: number;
|
|
66
71
|
readonly b: number;
|
|
67
72
|
readonly fromEnd?: true;
|
|
73
|
+
/** Counted among the siblings with the node's own element name: `:nth-of-type()`. */
|
|
74
|
+
readonly ofType?: true;
|
|
68
75
|
}
|
|
69
76
|
export type Combinator = 'descendant' | 'child' | 'next-sibling' | 'later-sibling';
|
|
70
77
|
export interface StyleRule {
|
|
@@ -72,6 +79,8 @@ export interface StyleRule {
|
|
|
72
79
|
/** Between compounds; length is `compounds.length - 1`. */
|
|
73
80
|
readonly combinators: readonly Combinator[];
|
|
74
81
|
readonly specificity: number;
|
|
82
|
+
/** Written with `::ng-deep`: for what is under its component, in other components' views too. */
|
|
83
|
+
readonly deep?: true;
|
|
75
84
|
/**
|
|
76
85
|
* The cascade layer the rule is in, as its place in its sheet's `layers`, or nothing for a rule
|
|
77
86
|
* in no layer, which beats every layered one whatever their specificity.
|
|
@@ -162,6 +171,16 @@ export interface TokenValue {
|
|
|
162
171
|
readonly lineHeight?: {
|
|
163
172
|
readonly __defer: DeferredDeclaration['compute'];
|
|
164
173
|
};
|
|
174
|
+
/**
|
|
175
|
+
* Two to four lengths, which a shorthand of sides or corners takes a value each from:
|
|
176
|
+
* `padding: var(--list-padding)` of `--list-padding: 0.25rem 0.5rem`.
|
|
177
|
+
*/
|
|
178
|
+
readonly lengths?: readonly (number | string)[];
|
|
179
|
+
/**
|
|
180
|
+
* The same where a part is a `var()`, each such part as the alias a token that is one is:
|
|
181
|
+
* `0 var(--modal-padding) var(--modal-padding)`. Worked out into `lengths` where it is defined.
|
|
182
|
+
*/
|
|
183
|
+
readonly deferredLengths?: readonly (number | string | TokenValue)[];
|
|
165
184
|
/** A whole shadow list, in the processed shape `boxShadow` takes. */
|
|
166
185
|
readonly shadow?: readonly unknown[];
|
|
167
186
|
/** One filter function, as the one-entry list `filter` takes: a slot of Tailwind's filters. */
|
|
@@ -674,6 +693,15 @@ export interface SiblingReach {
|
|
|
674
693
|
* Where no sheet reaches either way, only the elements at the two ends can match differently.
|
|
675
694
|
*/
|
|
676
695
|
export declare function siblingReach(sheet: StyleSheet): SiblingReach;
|
|
696
|
+
/**
|
|
697
|
+
* A compound whose element's place is read from another element, with the classes the rule asks
|
|
698
|
+
* of what that element is in: its parent's where `child`, and otherwise of anything above it.
|
|
699
|
+
*/
|
|
700
|
+
export interface PlaceReader {
|
|
701
|
+
readonly compound: Compound;
|
|
702
|
+
readonly above?: readonly string[];
|
|
703
|
+
readonly child?: boolean;
|
|
704
|
+
}
|
|
677
705
|
/**
|
|
678
706
|
* Each compound in a sheet whose element's place among its siblings is read from another
|
|
679
707
|
* element: one with something under it in the rule, `.row:nth-child(odd) .label` and
|
|
@@ -687,7 +715,7 @@ export declare function siblingReach(sheet: StyleSheet): SiblingReach;
|
|
|
687
715
|
* A place read by the element a rule styles, or by the elements before it that the rule steps
|
|
688
716
|
* from (`.a:first-child + .b`), is that element's own: the rules it matches say.
|
|
689
717
|
*/
|
|
690
|
-
export declare function placeReadElsewhere(sheet: StyleSheet): readonly
|
|
718
|
+
export declare function placeReadElsewhere(sheet: StyleSheet): readonly PlaceReader[];
|
|
691
719
|
/** One rule in a cascade: the sheet it came from, which `:host` needs, and its weight here. */
|
|
692
720
|
interface RuleEntry {
|
|
693
721
|
readonly rule: StyleRule;
|
|
@@ -757,6 +785,17 @@ export interface Subjects {
|
|
|
757
785
|
*/
|
|
758
786
|
own?: boolean;
|
|
759
787
|
}
|
|
788
|
+
/**
|
|
789
|
+
* A box a rule asks `:has()` of that is not the node it styles, `.card:has(.x) .title`, by the
|
|
790
|
+
* classes the rule asks of that box, with what the rule is for: the nodes under such a box to
|
|
791
|
+
* match again when what is in it changes.
|
|
792
|
+
*/
|
|
793
|
+
export interface HasAbove {
|
|
794
|
+
readonly classes: readonly string[];
|
|
795
|
+
readonly subjects: Subjects;
|
|
796
|
+
}
|
|
797
|
+
/** Each box a sheet's rules ask `:has()` of above the node they style. */
|
|
798
|
+
export declare function hasAbove(sheet: StyleSheet): readonly HasAbove[];
|
|
760
799
|
/** Whether an inline style sets a property children inherit. Allocates nothing: it runs per set. */
|
|
761
800
|
export declare function setsInherited(style: unknown): boolean;
|
|
762
801
|
/**
|
|
@@ -878,6 +917,12 @@ export declare class StyleResolver {
|
|
|
878
917
|
/** The tests of the `class` attribute itself in those sheets, which any class may answer. */
|
|
879
918
|
private readonly classTests;
|
|
880
919
|
private readonly noted;
|
|
920
|
+
/**
|
|
921
|
+
* The sheets with a rule written with `::ng-deep`, which is for what is under the component
|
|
922
|
+
* in the views of the components it holds. None in most apps, and nothing is asked then.
|
|
923
|
+
*/
|
|
924
|
+
private readonly deepSheets;
|
|
925
|
+
private readonly deepIndexes;
|
|
881
926
|
/** Read the classes a sheet names, once, as soon as any node is given it. */
|
|
882
927
|
noteSheet(sheet: StyleSheet | null | undefined): void;
|
|
883
928
|
/** The props a selector of some sheet asks about: an id, and each attribute by its name. */
|
|
@@ -1009,6 +1054,13 @@ export declare class StyleResolver {
|
|
|
1009
1054
|
* it, so it loses to their extra attribute and wins a tie with them.
|
|
1010
1055
|
*/
|
|
1011
1056
|
private rulesFor;
|
|
1057
|
+
/**
|
|
1058
|
+
* Add the `::ng-deep` rules of each component a node is in whose sheet is not the node's own:
|
|
1059
|
+
* a node is tried against its own component's rules already, those among them.
|
|
1060
|
+
*/
|
|
1061
|
+
private reachedFromAbove;
|
|
1062
|
+
/** A sheet's `::ng-deep` rules alone, filed as a component's own are. */
|
|
1063
|
+
private deepIndex;
|
|
1012
1064
|
/** Weakest first: by layer where any sheet has one, then by weight, then as they were filed. */
|
|
1013
1065
|
private readonly cascadeOrder;
|
|
1014
1066
|
/** A component's sheet as the rules of a host or of a creator, which differ only in their place. */
|
|
@@ -1049,6 +1101,8 @@ export declare class StyleResolver {
|
|
|
1049
1101
|
* edge the inline style sets takes the other form of it out, as a later rule would.
|
|
1050
1102
|
*/
|
|
1051
1103
|
overOtherForms(inline: Readonly<Record<string, unknown>>, style: Record<string, unknown>): void;
|
|
1104
|
+
/** Whether a settled style is of an element read right to left: by its own, or the app's. */
|
|
1105
|
+
readsRightToLeft(style: Readonly<Record<string, unknown>>): boolean;
|
|
1052
1106
|
/**
|
|
1053
1107
|
* The direction an element is laid out in: the last `direction` its own rules give it, the one
|
|
1054
1108
|
* it inherits, or the app's. A logical corner is a different physical one in each.
|
package/dist/css.js
CHANGED
|
@@ -259,6 +259,16 @@ function matchesValue(value, operator, expected) {
|
|
|
259
259
|
return value === expected || value.startsWith(`${expected}-`);
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
|
+
/**
|
|
263
|
+
* Whether a node is one a compound written before `::ng-deep` may be: an element of the view of
|
|
264
|
+
* the component the sheet is of. Its host is one only where the compound says `:host`, which is
|
|
265
|
+
* asked of it already: a class a parent gives the host is no anchor.
|
|
266
|
+
*/
|
|
267
|
+
function ownedBy(node, compound, sheet) {
|
|
268
|
+
if (compound.host !== undefined || compound.hostContext !== undefined)
|
|
269
|
+
return true;
|
|
270
|
+
return node.sheet === sheet;
|
|
271
|
+
}
|
|
262
272
|
/*
|
|
263
273
|
* Exempt from the complexity limit deliberately. This is a flat conjunction of independent
|
|
264
274
|
* guards, not nested logic: cyclomatic complexity scores the two the same, and they are not the
|
|
@@ -280,6 +290,8 @@ function matchesCompound(node, compound, sheet) {
|
|
|
280
290
|
}
|
|
281
291
|
if (compound.type !== undefined && compound.type !== node.name)
|
|
282
292
|
return false;
|
|
293
|
+
if (compound.own !== undefined && !ownedBy(node, compound, sheet))
|
|
294
|
+
return false;
|
|
283
295
|
if (compound.id !== undefined && node.props['nativeID'] !== compound.id)
|
|
284
296
|
return false;
|
|
285
297
|
for (const className of compound.classes) {
|
|
@@ -433,6 +445,82 @@ function matchAny(first, next, rule, index, compound, sheet) {
|
|
|
433
445
|
}
|
|
434
446
|
return false;
|
|
435
447
|
}
|
|
448
|
+
const BIT_OF = new Map();
|
|
449
|
+
/** Past this many names the bits are worked out again: ids made per row would be kept for ever. */
|
|
450
|
+
const BITS_KEPT = 4096;
|
|
451
|
+
/** The bit a class, a name or an id has among the sixty-four. */
|
|
452
|
+
function bitOf(kind, name) {
|
|
453
|
+
const key = kind + name;
|
|
454
|
+
let bit = BIT_OF.get(key);
|
|
455
|
+
if (bit === undefined) {
|
|
456
|
+
let hash = 0;
|
|
457
|
+
for (let at = 0; at < key.length; at++)
|
|
458
|
+
hash = (Math.imul(hash, 31) + key.charCodeAt(at)) | 0;
|
|
459
|
+
bit = (hash ^ (hash >>> 16)) & 63;
|
|
460
|
+
// A bit is its name's hash, so one forgotten is the same when it is asked for again.
|
|
461
|
+
if (BIT_OF.size >= BITS_KEPT)
|
|
462
|
+
BIT_OF.clear();
|
|
463
|
+
BIT_OF.set(key, bit);
|
|
464
|
+
}
|
|
465
|
+
return bit;
|
|
466
|
+
}
|
|
467
|
+
const NAMED_ABOVE = new WeakMap();
|
|
468
|
+
/**
|
|
469
|
+
* The classes, names and ids a rule names of the node's ancestors: of each part joined to what
|
|
470
|
+
* is on its right by a descendant or a child combinator. One joined by a sibling combinator is
|
|
471
|
+
* no ancestor of the node, though the parts to its left that are ancestors of it are ancestors
|
|
472
|
+
* of the node as well. Null where it names none, a rule of one part among them.
|
|
473
|
+
*/
|
|
474
|
+
function namedAbove(rule) {
|
|
475
|
+
let named = NAMED_ABOVE.get(rule);
|
|
476
|
+
if (named !== undefined)
|
|
477
|
+
return named;
|
|
478
|
+
let [low, high] = [0, 0];
|
|
479
|
+
const add = (bit) => {
|
|
480
|
+
if (bit < 32)
|
|
481
|
+
low |= 1 << bit;
|
|
482
|
+
else
|
|
483
|
+
high |= 1 << (bit - 32);
|
|
484
|
+
};
|
|
485
|
+
for (let at = 0; at < rule.compounds.length - 1; at++) {
|
|
486
|
+
const joined = rule.combinators[at];
|
|
487
|
+
if (joined === 'next-sibling' || joined === 'later-sibling')
|
|
488
|
+
continue;
|
|
489
|
+
const compound = rule.compounds[at];
|
|
490
|
+
for (const className of compound.classes)
|
|
491
|
+
add(bitOf('.', className));
|
|
492
|
+
if (compound.type !== undefined)
|
|
493
|
+
add(bitOf('<', compound.type));
|
|
494
|
+
if (compound.id !== undefined)
|
|
495
|
+
add(bitOf('#', compound.id));
|
|
496
|
+
}
|
|
497
|
+
named = low === 0 && high === 0 ? null : [low, high];
|
|
498
|
+
NAMED_ABOVE.set(rule, named);
|
|
499
|
+
return named;
|
|
500
|
+
}
|
|
501
|
+
/** The classes, names and ids of a node's ancestors, as bits. */
|
|
502
|
+
function bitsAbove(node) {
|
|
503
|
+
let [low, high] = [0, 0];
|
|
504
|
+
const add = (bit) => {
|
|
505
|
+
if (bit < 32)
|
|
506
|
+
low |= 1 << bit;
|
|
507
|
+
else
|
|
508
|
+
high |= 1 << (bit - 32);
|
|
509
|
+
};
|
|
510
|
+
for (let up = node.parent; up; up = up.parent) {
|
|
511
|
+
if (up.classes)
|
|
512
|
+
for (const className of up.classes)
|
|
513
|
+
add(bitOf('.', className));
|
|
514
|
+
if (up.name !== undefined)
|
|
515
|
+
add(bitOf('<', up.name));
|
|
516
|
+
const id = up.props?.['nativeID'];
|
|
517
|
+
if (typeof id === 'string')
|
|
518
|
+
add(bitOf('#', id));
|
|
519
|
+
}
|
|
520
|
+
return [low, high];
|
|
521
|
+
}
|
|
522
|
+
/** Whether what is above a node lacks something a rule names there. */
|
|
523
|
+
const lacks = (above, named) => (named[0] & ~above[0]) !== 0 || (named[1] & ~above[1]) !== 0;
|
|
436
524
|
const TAKES_PARENTS = new WeakMap();
|
|
437
525
|
/** Whether a rule has an `inherit` in it, which is settled from the parent's own style. */
|
|
438
526
|
function takesParents(rule) {
|
|
@@ -496,8 +584,9 @@ function stepsAlong(combinators) {
|
|
|
496
584
|
* matched again by other means, and which way it reaches is not worked out.
|
|
497
585
|
*/
|
|
498
586
|
function countSiblings(compound, reach, withinHas) {
|
|
499
|
-
// Which is first and which is last is the ends, and no count.
|
|
500
|
-
|
|
587
|
+
// Which is first and which is last is the ends, and no count. Not of one name: the first of
|
|
588
|
+
// its name is wherever the others of it are not.
|
|
589
|
+
const counts = (compound.nth ?? []).filter((test) => test.a !== 0 || test.b !== 1 || test.ofType);
|
|
501
590
|
if (counts.some((test) => withinHas || !test.fromEnd))
|
|
502
591
|
reach.after = Infinity;
|
|
503
592
|
if (counts.some((test) => withinHas || test.fromEnd))
|
|
@@ -537,10 +626,13 @@ export function placeReadElsewhere(sheet) {
|
|
|
537
626
|
if (joined === 'next-sibling' || joined === 'later-sibling')
|
|
538
627
|
return;
|
|
539
628
|
const run = rule.compounds.slice(start, at + 1);
|
|
629
|
+
// What the run is in: the compound before it, which every element of it is under.
|
|
630
|
+
const list = rule.compounds[start - 1];
|
|
631
|
+
const child = rule.combinators[start - 1] === 'child';
|
|
540
632
|
start = at + 1;
|
|
541
633
|
const above = at < rule.compounds.length - 1;
|
|
542
634
|
if (above && (run.length > 1 || run.some(readsPlace)))
|
|
543
|
-
elsewhere.push(compound);
|
|
635
|
+
elsewhere.push({ compound, above: list?.classes, child });
|
|
544
636
|
});
|
|
545
637
|
}
|
|
546
638
|
known = elsewhere;
|
|
@@ -567,7 +659,7 @@ function placeReadAbove(compound, elsewhere) {
|
|
|
567
659
|
];
|
|
568
660
|
for (const inner of above)
|
|
569
661
|
if (readsPlace(inner))
|
|
570
|
-
elsewhere.push(inner);
|
|
662
|
+
elsewhere.push({ compound: inner });
|
|
571
663
|
for (const inner of nestedCompounds(compound))
|
|
572
664
|
placeReadAbove(inner, elsewhere);
|
|
573
665
|
}
|
|
@@ -601,10 +693,10 @@ function matchesNth(node, test) {
|
|
|
601
693
|
const siblings = node.parent?.children;
|
|
602
694
|
if (!siblings)
|
|
603
695
|
return false;
|
|
604
|
-
if (test.a === 0 && test.b === 1) {
|
|
696
|
+
if (test.a === 0 && test.b === 1 && !test.ofType) {
|
|
605
697
|
return (test.fromEnd ? lastElement(siblings) : firstElement(siblings)) === node;
|
|
606
698
|
}
|
|
607
|
-
const from = countPosition(node, siblings, test.fromEnd === true);
|
|
699
|
+
const from = countPosition(node, siblings, test.fromEnd === true, test.ofType === true);
|
|
608
700
|
if (from === 0)
|
|
609
701
|
return false;
|
|
610
702
|
// `an + b` for some whole number of steps, which is what CSS counts from.
|
|
@@ -822,11 +914,11 @@ function byImportance(matched, places) {
|
|
|
822
914
|
}));
|
|
823
915
|
return [...plain, ...important];
|
|
824
916
|
}
|
|
825
|
-
function countPosition(node, siblings, fromEnd) {
|
|
917
|
+
function countPosition(node, siblings, fromEnd, ofType) {
|
|
826
918
|
let position = 0;
|
|
827
919
|
let seen = 0;
|
|
828
920
|
for (const sibling of siblings) {
|
|
829
|
-
if (!isElement(sibling))
|
|
921
|
+
if (!isElement(sibling) || (ofType && sibling.name !== node.name))
|
|
830
922
|
continue;
|
|
831
923
|
seen++;
|
|
832
924
|
if (sibling === node)
|
|
@@ -1128,6 +1220,42 @@ function subjectsOf(sheet) {
|
|
|
1128
1220
|
subjects.set(sheet, (found = all));
|
|
1129
1221
|
return found;
|
|
1130
1222
|
}
|
|
1223
|
+
const HAS_ABOVE = new WeakMap();
|
|
1224
|
+
/** Whether a compound, or one it asks of the same node, uses `:has()`. */
|
|
1225
|
+
const asksBeneath = (compound) => compound.has !== undefined ||
|
|
1226
|
+
[...(compound.not ?? []), ...(compound.is ?? []).flat()].some(asksBeneath);
|
|
1227
|
+
/**
|
|
1228
|
+
* The boxes above the styled node that a compound asks `:has()` of: the compound's own node,
|
|
1229
|
+
* where that is not the styled one, and each box it is asked to be inside,
|
|
1230
|
+
* `.body:is(.card:has(.x) *) .title`.
|
|
1231
|
+
*/
|
|
1232
|
+
function* boxesAsked(compound, styled) {
|
|
1233
|
+
if (!styled && asksBeneath(compound))
|
|
1234
|
+
yield compound;
|
|
1235
|
+
for (const key of ['ancestors', 'parents', 'hostContext']) {
|
|
1236
|
+
for (const outer of compound[key] ?? [])
|
|
1237
|
+
yield* boxesAsked(outer, false);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
/** Each box a sheet's rules ask `:has()` of above the node they style. */
|
|
1241
|
+
export function hasAbove(sheet) {
|
|
1242
|
+
let known = HAS_ABOVE.get(sheet);
|
|
1243
|
+
if (known === undefined) {
|
|
1244
|
+
const found = [];
|
|
1245
|
+
for (const rule of sheet.rules) {
|
|
1246
|
+
const last = rule.compounds.length - 1;
|
|
1247
|
+
for (const [at, compound] of rule.compounds.entries()) {
|
|
1248
|
+
for (const box of boxesAsked(compound, at === last)) {
|
|
1249
|
+
const subjects = noSubjects();
|
|
1250
|
+
noteSubject(subjects, rule);
|
|
1251
|
+
found.push({ classes: box.classes, subjects });
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
HAS_ABOVE.set(sheet, (known = found));
|
|
1256
|
+
}
|
|
1257
|
+
return known;
|
|
1258
|
+
}
|
|
1131
1259
|
/** Note in `into` what a rule is for. */
|
|
1132
1260
|
function noteSubject(into, rule) {
|
|
1133
1261
|
const subject = rule.compounds.at(-1);
|
|
@@ -1245,10 +1373,10 @@ function classPlaces(rule) {
|
|
|
1245
1373
|
}
|
|
1246
1374
|
const joined = rule.combinators[index];
|
|
1247
1375
|
under &&= joined === 'child' || joined === 'descendant';
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1376
|
+
// A box the element is under, by its classes and by those it is asked to have or not to,
|
|
1377
|
+
// `.box:not(.busy) .row`: each is asked of that box, as its own are.
|
|
1378
|
+
const over = under ? inside : elsewhere;
|
|
1379
|
+
placeClasses(compound, over, over, elsewhere);
|
|
1252
1380
|
}
|
|
1253
1381
|
for (const name of elsewhere) {
|
|
1254
1382
|
own.delete(name);
|
|
@@ -1627,11 +1755,19 @@ export class StyleResolver {
|
|
|
1627
1755
|
/** The tests of the `class` attribute itself in those sheets, which any class may answer. */
|
|
1628
1756
|
classTests = [];
|
|
1629
1757
|
noted = new WeakSet();
|
|
1758
|
+
/**
|
|
1759
|
+
* The sheets with a rule written with `::ng-deep`, which is for what is under the component
|
|
1760
|
+
* in the views of the components it holds. None in most apps, and nothing is asked then.
|
|
1761
|
+
*/
|
|
1762
|
+
deepSheets = new Set();
|
|
1763
|
+
deepIndexes = new WeakMap();
|
|
1630
1764
|
/** Read the classes a sheet names, once, as soon as any node is given it. */
|
|
1631
1765
|
noteSheet(sheet) {
|
|
1632
1766
|
if (!sheet || this.noted.has(sheet))
|
|
1633
1767
|
return;
|
|
1634
1768
|
this.noted.add(sheet);
|
|
1769
|
+
if (sheet.rules.some((rule) => rule.deep))
|
|
1770
|
+
this.deepSheets.add(sheet);
|
|
1635
1771
|
const { classes, reads, named } = classReach(sheet);
|
|
1636
1772
|
for (const [name, how] of classes)
|
|
1637
1773
|
this.noteReach(name, how);
|
|
@@ -1935,6 +2071,7 @@ export class StyleResolver {
|
|
|
1935
2071
|
hasNoRules(node) {
|
|
1936
2072
|
return (node.sheet === null &&
|
|
1937
2073
|
node.hostSheet === null &&
|
|
2074
|
+
this.deepSheets.size === 0 &&
|
|
1938
2075
|
this.globalSheet === null &&
|
|
1939
2076
|
this.addedSheets.length === 0 &&
|
|
1940
2077
|
!node.customProperties &&
|
|
@@ -2015,9 +2152,33 @@ export class StyleResolver {
|
|
|
2015
2152
|
indexes.push(this.ownIndex(node.hostSheet, HOSTS));
|
|
2016
2153
|
if (node.sheet)
|
|
2017
2154
|
indexes.push(this.ownIndex(node.sheet, CREATED));
|
|
2155
|
+
if (this.deepSheets.size)
|
|
2156
|
+
this.reachedFromAbove(node, indexes);
|
|
2018
2157
|
indexes.push(this.sharedIndex());
|
|
2019
2158
|
return candidateRules(node, indexes, this.cascadeOrder);
|
|
2020
2159
|
}
|
|
2160
|
+
/**
|
|
2161
|
+
* Add the `::ng-deep` rules of each component a node is in whose sheet is not the node's own:
|
|
2162
|
+
* a node is tried against its own component's rules already, those among them.
|
|
2163
|
+
*/
|
|
2164
|
+
reachedFromAbove(node, indexes) {
|
|
2165
|
+
for (let up = node.parent; up; up = up.parent) {
|
|
2166
|
+
const sheet = up.hostSheet;
|
|
2167
|
+
if (!sheet || sheet === node.sheet || sheet === node.hostSheet)
|
|
2168
|
+
continue;
|
|
2169
|
+
if (this.deepSheets.has(sheet))
|
|
2170
|
+
indexes.push(this.deepIndex(sheet));
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
/** A sheet's `::ng-deep` rules alone, filed as a component's own are. */
|
|
2174
|
+
deepIndex(sheet) {
|
|
2175
|
+
let index = this.deepIndexes.get(sheet);
|
|
2176
|
+
if (!index) {
|
|
2177
|
+
const deep = this.entries(sheet, COMPONENT_SPECIFICITY_BUMP).filter(({ rule }) => rule.deep);
|
|
2178
|
+
this.deepIndexes.set(sheet, (index = indexRules(deep, undefined, HOSTS * SHEET_ROOM)));
|
|
2179
|
+
}
|
|
2180
|
+
return index;
|
|
2181
|
+
}
|
|
2021
2182
|
/** Weakest first: by layer where any sheet has one, then by weight, then as they were filed. */
|
|
2022
2183
|
cascadeOrder = (a, b) => {
|
|
2023
2184
|
const layers = this.layered
|
|
@@ -2157,8 +2318,15 @@ export class StyleResolver {
|
|
|
2157
2318
|
/** The rules that apply to a node, weakest first. */
|
|
2158
2319
|
matched(node, entries) {
|
|
2159
2320
|
const out = [];
|
|
2321
|
+
// What the node's ancestors are, gathered for the first rule that names one.
|
|
2322
|
+
let above;
|
|
2160
2323
|
for (const { rule, sheet } of entries) {
|
|
2161
|
-
if (this.conditionHolds(rule)
|
|
2324
|
+
if (!this.conditionHolds(rule))
|
|
2325
|
+
continue;
|
|
2326
|
+
const named = namedAbove(rule);
|
|
2327
|
+
if (named && lacks((above ??= bitsAbove(node)), named))
|
|
2328
|
+
continue;
|
|
2329
|
+
if (matches(node, rule, sheet))
|
|
2162
2330
|
out.push(rule);
|
|
2163
2331
|
}
|
|
2164
2332
|
return out;
|
|
@@ -2208,13 +2376,17 @@ export class StyleResolver {
|
|
|
2208
2376
|
for (const [at, key] of written.entries()) {
|
|
2209
2377
|
if (!(key in TWIN.ltr))
|
|
2210
2378
|
continue;
|
|
2211
|
-
twin ??= TWIN[(style
|
|
2379
|
+
twin ??= TWIN[this.readsRightToLeft(style) ? 'rtl' : 'ltr'];
|
|
2212
2380
|
const other = twin[key];
|
|
2213
2381
|
// Where the inline style sets both, the one it set later stands.
|
|
2214
2382
|
if (written.indexOf(other) < at)
|
|
2215
2383
|
delete style[other];
|
|
2216
2384
|
}
|
|
2217
2385
|
}
|
|
2386
|
+
/** Whether a settled style is of an element read right to left: by its own, or the app's. */
|
|
2387
|
+
readsRightToLeft(style) {
|
|
2388
|
+
return (style['direction'] ?? this.conditions.direction) === 'rtl';
|
|
2389
|
+
}
|
|
2218
2390
|
/**
|
|
2219
2391
|
* The direction an element is laid out in: the last `direction` its own rules give it, the one
|
|
2220
2392
|
* it inherits, or the app's. A logical corner is a different physical one in each.
|
|
@@ -2682,6 +2854,9 @@ function substitutable(token, tokens) {
|
|
|
2682
2854
|
return hslSubstitutable(token.hsl, tokens);
|
|
2683
2855
|
if (token.deferredColour)
|
|
2684
2856
|
return colourSubstitutable(token.deferredColour, tokens);
|
|
2857
|
+
if (token.deferredLengths) {
|
|
2858
|
+
return token.deferredLengths.every((part) => typeof part !== 'object' || substitutedIn(part, tokens) !== undefined);
|
|
2859
|
+
}
|
|
2685
2860
|
// Each marker is one reading of the same text, and a fallback one cannot read is dropped from it.
|
|
2686
2861
|
return token.deferredCalc.some((marker) => calcSubstitutable(marker.expression, tokens));
|
|
2687
2862
|
}
|
|
@@ -2760,7 +2935,7 @@ function inCycles(names, waitingOn) {
|
|
|
2760
2935
|
}
|
|
2761
2936
|
/** Whether a token is made of others, and so worked out where it is defined. */
|
|
2762
2937
|
function isDerived(token) {
|
|
2763
|
-
return Boolean(token?.hsl || token?.deferredColour || token?.deferredCalc);
|
|
2938
|
+
return Boolean(token?.hsl || token?.deferredColour || token?.deferredCalc || token?.deferredLengths);
|
|
2764
2939
|
}
|
|
2765
2940
|
/** A token made of others, worked out from the tokens in scope. */
|
|
2766
2941
|
function derived(token, tokens) {
|
|
@@ -2768,8 +2943,23 @@ function derived(token, tokens) {
|
|
|
2768
2943
|
return colourToken(resolveHsl(token.hsl, tokens));
|
|
2769
2944
|
if (token.deferredColour)
|
|
2770
2945
|
return colourToken(resolveColour(token.deferredColour, tokens));
|
|
2946
|
+
if (token.deferredLengths)
|
|
2947
|
+
return lengthsToken(token, tokens);
|
|
2771
2948
|
return calcToken(token.deferredCalc, tokens);
|
|
2772
2949
|
}
|
|
2950
|
+
/**
|
|
2951
|
+
* A token of several lengths with each part that is a `var()` followed. Where a part comes to
|
|
2952
|
+
* no length the token is what else it reads as, a shadow whose colour is a token being several
|
|
2953
|
+
* lengths and a `var()` too, or nothing where it reads as nothing else.
|
|
2954
|
+
*/
|
|
2955
|
+
function lengthsToken(token, tokens) {
|
|
2956
|
+
const { deferredLengths, ...rest } = token;
|
|
2957
|
+
const lengths = deferredLengths.map((part) => typeof part === 'object' ? substitutedIn(part, tokens)?.length : part);
|
|
2958
|
+
if (lengths.every((length) => length !== undefined)) {
|
|
2959
|
+
return { ...rest, lengths: lengths };
|
|
2960
|
+
}
|
|
2961
|
+
return Object.keys(rest).length ? rest : undefined;
|
|
2962
|
+
}
|
|
2773
2963
|
/**
|
|
2774
2964
|
* Each alias settled to what it names. `follow` writes back every one that resolves; one in a
|
|
2775
2965
|
* cycle is removed only once all are followed, as removed any sooner, the next one round the
|
|
@@ -2943,7 +3133,7 @@ function referenced(declaration, tokens) {
|
|
|
2943
3133
|
// property unset rather than trying the next, or the fallback.
|
|
2944
3134
|
const names = [declaration.reference, ...(declaration.alternatives ?? [])];
|
|
2945
3135
|
const token = firstSet(names, tokens);
|
|
2946
|
-
let value = token ?
|
|
3136
|
+
let value = token ? formFor(token, declaration) : fallbackOf(declaration, tokens);
|
|
2947
3137
|
// `calc(var(--n) * 1px)`: the arithmetic gives a unitless token its unit, which is the usual
|
|
2948
3138
|
// way to turn a count into a length. So it reads the bare number, and a length is no such thing.
|
|
2949
3139
|
if (token && declaration.adjust?.number && declaration.kind === 'length') {
|
|
@@ -2991,9 +3181,52 @@ function tokenForm(token, kind) {
|
|
|
2991
3181
|
const value = formOf(token, kind);
|
|
2992
3182
|
return value === undefined && kind === 'color' && isCurrentColour(token) ? CURRENT_COLOUR : value;
|
|
2993
3183
|
}
|
|
3184
|
+
/** A corner's place among four as CSS writes them, before a side's: `borderTopLeftRadius`. */
|
|
3185
|
+
const PLACES = [
|
|
3186
|
+
[/TopLeft|TopStart|StartStart/, 0],
|
|
3187
|
+
[/TopRight|TopEnd|StartEnd/, 1],
|
|
3188
|
+
[/BottomRight|BottomEnd|EndEnd/, 2],
|
|
3189
|
+
[/BottomLeft|BottomStart|EndStart/, 3],
|
|
3190
|
+
[/Top/, 0],
|
|
3191
|
+
[/Right|End/, 1],
|
|
3192
|
+
[/Bottom/, 2],
|
|
3193
|
+
[/Left|Start/, 3],
|
|
3194
|
+
];
|
|
3195
|
+
/** Where a side or a corner comes in a shorthand of four, whatever order its props are kept in. */
|
|
3196
|
+
const placeOf = (prop) => PLACES.find(([named]) => named.test(prop))?.[1] ?? 0;
|
|
3197
|
+
/** The lengths of a token that holds several, for the props of a shorthand to take one each. */
|
|
3198
|
+
class EachSide {
|
|
3199
|
+
lengths;
|
|
3200
|
+
constructor(lengths) {
|
|
3201
|
+
this.lengths = lengths;
|
|
3202
|
+
}
|
|
3203
|
+
/**
|
|
3204
|
+
* The length for one of a shorthand's four props, as CSS gives them: two are a pair repeated,
|
|
3205
|
+
* and of three the left takes the right's. Nothing for a property that is not such a
|
|
3206
|
+
* shorthand: a token of several lengths is no value for it, and it is unset.
|
|
3207
|
+
*/
|
|
3208
|
+
at(props, prop) {
|
|
3209
|
+
if (props.length !== 4)
|
|
3210
|
+
return undefined;
|
|
3211
|
+
const index = placeOf(prop);
|
|
3212
|
+
return this.lengths[index] ?? this.lengths[index - 2] ?? this.lengths[0];
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
/**
|
|
3216
|
+
* A set token's value in the form a declaration wants, or its several lengths where it wants a
|
|
3217
|
+
* length and the token has no one: for a shorthand that takes one a side, see `writeSettled`.
|
|
3218
|
+
* Not with arithmetic on it, which is of one length.
|
|
3219
|
+
*/
|
|
3220
|
+
function formFor(token, declaration) {
|
|
3221
|
+
const value = tokenForm(token, declaration.kind);
|
|
3222
|
+
if (value !== undefined || !token.lengths || declaration.kind !== 'length')
|
|
3223
|
+
return value;
|
|
3224
|
+
return declaration.adjust ? undefined : new EachSide(token.lengths);
|
|
3225
|
+
}
|
|
2994
3226
|
/** What a deferred declaration settled to, written to one of its props. */
|
|
2995
3227
|
function writeSettled(own, prop, declaration, settled, layers) {
|
|
2996
|
-
const
|
|
3228
|
+
const one = settled instanceof EachSide ? settled.at(declaration.props, prop) : settled;
|
|
3229
|
+
const value = one ?? declaration.unset;
|
|
2997
3230
|
if (declaration.layers)
|
|
2998
3231
|
writeLayer(own, prop, value, layers);
|
|
2999
3232
|
else
|