@ng-prism/core 22.4.1 → 22.6.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/README.md +2 -0
- package/dist/app/canvas/prism-canvas-toolbar.component.d.ts +33 -2
- package/dist/app/canvas/prism-canvas-toolbar.component.d.ts.map +1 -1
- package/dist/app/canvas/prism-canvas-toolbar.component.js +135 -28
- package/dist/app/canvas/state-chips.d.ts +50 -0
- package/dist/app/canvas/state-chips.d.ts.map +1 -0
- package/dist/app/canvas/state-chips.js +40 -0
- package/dist/app/component-head/prism-component-head.component.d.ts +1 -0
- package/dist/app/component-head/prism-component-head.component.d.ts.map +1 -1
- package/dist/app/component-head/prism-component-head.component.js +11 -6
- package/dist/app/component-head/prism-head-info.component.d.ts +2 -1
- package/dist/app/component-head/prism-head-info.component.d.ts.map +1 -1
- package/dist/app/component-head/prism-head-info.component.js +30 -7
- package/dist/app/directives/resize-value.d.ts +1 -1
- package/dist/app/directives/resize-value.js +1 -1
- package/dist/app/discovery-manifest.d.ts +2 -2
- package/dist/app/discovery-manifest.d.ts.map +1 -1
- package/dist/app/discovery-manifest.js +22 -4
- package/dist/app/overview/open-in-playground.d.ts +11 -0
- package/dist/app/overview/open-in-playground.d.ts.map +1 -0
- package/dist/app/overview/open-in-playground.js +12 -0
- package/dist/app/overview/overview-matrix.d.ts +79 -0
- package/dist/app/overview/overview-matrix.d.ts.map +1 -0
- package/dist/app/overview/overview-matrix.js +98 -0
- package/dist/app/overview/overview-visibility.d.ts +10 -2
- package/dist/app/overview/overview-visibility.d.ts.map +1 -1
- package/dist/app/overview/overview-visibility.js +14 -3
- package/dist/app/overview/prism-overview-cell.component.d.ts +29 -2
- package/dist/app/overview/prism-overview-cell.component.d.ts.map +1 -1
- package/dist/app/overview/prism-overview-cell.component.js +145 -27
- package/dist/app/overview/prism-overview-matrix.component.d.ts +29 -0
- package/dist/app/overview/prism-overview-matrix.component.d.ts.map +1 -0
- package/dist/app/overview/prism-overview-matrix.component.js +164 -0
- package/dist/app/overview/prism-overview.component.d.ts +4 -0
- package/dist/app/overview/prism-overview.component.d.ts.map +1 -1
- package/dist/app/overview/prism-overview.component.js +37 -14
- package/dist/app/panels/a11y/a11y-core.plugin.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-core.plugin.js +0 -1
- package/dist/app/panels/controls/controls-plugin.d.ts.map +1 -1
- package/dist/app/panels/controls/controls-plugin.js +1 -2
- package/dist/app/panels/events/events-plugin.d.ts.map +1 -1
- package/dist/app/panels/events/events-plugin.js +1 -2
- package/dist/app/pseudo/pseudo-selector.d.ts +24 -0
- package/dist/app/pseudo/pseudo-selector.d.ts.map +1 -0
- package/dist/app/pseudo/pseudo-selector.js +136 -0
- package/dist/app/pseudo/pseudo-state-marker.d.ts +66 -0
- package/dist/app/pseudo/pseudo-state-marker.d.ts.map +1 -0
- package/dist/app/pseudo/pseudo-state-marker.js +165 -0
- package/dist/app/pseudo/pseudo-stylesheets.d.ts +49 -0
- package/dist/app/pseudo/pseudo-stylesheets.d.ts.map +1 -0
- package/dist/app/pseudo/pseudo-stylesheets.js +137 -0
- package/dist/app/pseudo/pseudo-targets.d.ts +11 -0
- package/dist/app/pseudo/pseudo-targets.d.ts.map +1 -0
- package/dist/app/pseudo/pseudo-targets.js +46 -0
- package/dist/app/pseudo/state-fit.d.ts +28 -0
- package/dist/app/pseudo/state-fit.d.ts.map +1 -0
- package/dist/app/pseudo/state-fit.js +97 -0
- package/dist/app/renderer/input-bindings.d.ts +16 -0
- package/dist/app/renderer/input-bindings.d.ts.map +1 -0
- package/dist/app/renderer/input-bindings.js +21 -0
- package/dist/app/renderer/known-inputs.d.ts +8 -1
- package/dist/app/renderer/known-inputs.d.ts.map +1 -1
- package/dist/app/renderer/known-inputs.js +13 -5
- package/dist/app/renderer/prism-renderer.component.d.ts +18 -1
- package/dist/app/renderer/prism-renderer.component.d.ts.map +1 -1
- package/dist/app/renderer/prism-renderer.component.js +68 -22
- package/dist/app/renderer/projectable-content.d.ts +8 -1
- package/dist/app/renderer/projectable-content.d.ts.map +1 -1
- package/dist/app/renderer/projectable-content.js +40 -29
- package/dist/app/renderer/rendered-key.d.ts +38 -0
- package/dist/app/renderer/rendered-key.d.ts.map +1 -0
- package/dist/app/renderer/rendered-key.js +34 -0
- package/dist/app/renderer/snippet-generator.js +7 -5
- package/dist/app/services/prism-capture.service.d.ts +2 -0
- package/dist/app/services/prism-capture.service.d.ts.map +1 -1
- package/dist/app/services/prism-capture.service.js +25 -0
- package/dist/app/services/prism-pseudo-state.service.d.ts +93 -0
- package/dist/app/services/prism-pseudo-state.service.d.ts.map +1 -0
- package/dist/app/services/prism-pseudo-state.service.js +155 -0
- package/dist/app/services/prism-renderer.service.d.ts +17 -0
- package/dist/app/services/prism-renderer.service.d.ts.map +1 -1
- package/dist/app/services/prism-renderer.service.js +37 -2
- package/dist/app/services/prism-url-state.service.d.ts.map +1 -1
- package/dist/app/services/prism-url-state.service.js +39 -8
- package/dist/app/theme/prism-default-theme.d.ts.map +1 -1
- package/dist/app/theme/prism-default-theme.js +6 -5
- package/dist/builder/config-loader/deprecated-options.d.ts +7 -0
- package/dist/builder/config-loader/deprecated-options.d.ts.map +1 -0
- package/dist/builder/config-loader/deprecated-options.js +23 -0
- package/dist/builder/manifest/runtime-manifest.generator.d.ts.map +1 -1
- package/dist/builder/manifest/runtime-manifest.generator.js +3 -2
- package/dist/builder/scanner/component.scanner.d.ts.map +1 -1
- package/dist/builder/scanner/component.scanner.js +27 -0
- package/dist/builder/scanner/entry-point-discovery.d.ts +5 -0
- package/dist/builder/scanner/entry-point-discovery.d.ts.map +1 -1
- package/dist/builder/scanner/entry-point-discovery.js +14 -0
- package/dist/builder/scanner/entry-point.scanner.d.ts +3 -1
- package/dist/builder/scanner/entry-point.scanner.d.ts.map +1 -1
- package/dist/builder/scanner/entry-point.scanner.js +7 -6
- package/dist/builder/scanner/input.extractor.d.ts.map +1 -1
- package/dist/builder/scanner/input.extractor.js +22 -3
- package/dist/builder/scanner/pseudo-states.d.ts +12 -0
- package/dist/builder/scanner/pseudo-states.d.ts.map +1 -0
- package/dist/builder/scanner/pseudo-states.js +58 -0
- package/dist/builder/scanner/scanner.d.ts +2 -2
- package/dist/builder/scanner/scanner.d.ts.map +1 -1
- package/dist/builder/scanner/scanner.js +16 -6
- package/dist/builder/scanner/showcase-diagnostics.js +9 -9
- package/dist/builder/scanner/showcase-states.d.ts +17 -0
- package/dist/builder/scanner/showcase-states.d.ts.map +1 -0
- package/dist/builder/scanner/showcase-states.js +58 -0
- package/dist/builder/scanner/source-file-cache.d.ts +26 -0
- package/dist/builder/scanner/source-file-cache.d.ts.map +1 -0
- package/dist/builder/scanner/source-file-cache.js +60 -0
- package/dist/builder/shared/prism-pipeline.d.ts.map +1 -1
- package/dist/builder/shared/prism-pipeline.js +28 -13
- package/dist/decorator/index.d.ts +1 -1
- package/dist/decorator/index.d.ts.map +1 -1
- package/dist/decorator/showcase.types.d.ts +33 -0
- package/dist/decorator/showcase.types.d.ts.map +1 -1
- package/dist/plugin/index.d.ts +3 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1 -0
- package/dist/plugin/plugin.types.d.ts +53 -7
- package/dist/plugin/plugin.types.d.ts.map +1 -1
- package/dist/shared/pseudo-state.type.d.ts +22 -0
- package/dist/shared/pseudo-state.type.d.ts.map +1 -0
- package/dist/shared/pseudo-state.type.js +2 -0
- package/package.json +1 -1
- package/src/builder/build/schema.json +6 -6
- package/src/builder/serve/schema.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"a11y-core.plugin.d.ts","sourceRoot":"","sources":["../../../../src/app/panels/a11y/a11y-core.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"a11y-core.plugin.d.ts","sourceRoot":"","sources":["../../../../src/app/panels/a11y/a11y-core.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE,eAAO,MAAM,eAAe,EAAE,eAO7B,CAAC"}
|
|
@@ -2,7 +2,6 @@ export const A11Y_CORE_PANEL = {
|
|
|
2
2
|
id: 'a11y',
|
|
3
3
|
label: 'A11y',
|
|
4
4
|
icon: 'accessibility',
|
|
5
|
-
position: 'bottom',
|
|
6
5
|
placement: 'addon',
|
|
7
6
|
loadComponent: () => import('./a11y-panel.component.js').then((m) => m.A11yPanelComponent),
|
|
8
7
|
loadOverlayComponent: () => import('./a11y-overlay-host.component.js').then((m) => m.A11yOverlayHostComponent)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controls-plugin.d.ts","sourceRoot":"","sources":["../../../../src/app/panels/controls/controls-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGrE,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"controls-plugin.d.ts","sourceRoot":"","sources":["../../../../src/app/panels/controls/controls-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGrE,eAAO,MAAM,eAAe,EAAE,aAU7B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events-plugin.d.ts","sourceRoot":"","sources":["../../../../src/app/panels/events/events-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGrE,eAAO,MAAM,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"events-plugin.d.ts","sourceRoot":"","sources":["../../../../src/app/panels/events/events-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGrE,eAAO,MAAM,aAAa,EAAE,aAU3B,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type PseudoState } from '../../shared/pseudo-state.type.js';
|
|
2
|
+
/** Prefix of the classes that stand in for a forced pseudo-class. */
|
|
3
|
+
export declare const PSEUDO_CLASS_PREFIX = "prism-pseudo--";
|
|
4
|
+
/** The class that stands in for `state`, e.g. `prism-pseudo--focus-visible`. */
|
|
5
|
+
export declare function pseudoStateClass(state: PseudoState): string;
|
|
6
|
+
/**
|
|
7
|
+
* The selector with every forced pseudo-class `:x` widened to
|
|
8
|
+
* `:is(:x, .prism-pseudo--x)` ({@link pseudoStateClass}), or `null` when it
|
|
9
|
+
* uses none or has been widened before.
|
|
10
|
+
*
|
|
11
|
+
* Without the class on any element the widened selector matches exactly what
|
|
12
|
+
* the original matched, with the same specificity: `:is()` takes the highest
|
|
13
|
+
* of its arguments, and a class weighs what a pseudo-class weighs. With the
|
|
14
|
+
* class, an element counts as being in the state whether it is forced or real,
|
|
15
|
+
* which keeps `:not(:hover)` exact in both directions and lets a forced state
|
|
16
|
+
* combine with a real one in the same selector.
|
|
17
|
+
*
|
|
18
|
+
* Tokenised rather than string-replaced. An escaped colon (`.md\:hover`) and an
|
|
19
|
+
* attribute value (`[title=":hover"]`) are left alone, and a state that follows
|
|
20
|
+
* a pseudo-element (`::part(x):hover`) is kept as it is, because `:is()` is not
|
|
21
|
+
* allowed there.
|
|
22
|
+
*/
|
|
23
|
+
export declare function rewritePseudoSelector(selectorText: string): string | null;
|
|
24
|
+
//# sourceMappingURL=pseudo-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pseudo-selector.d.ts","sourceRoot":"","sources":["../../../src/app/pseudo/pseudo-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAEpF,qEAAqE;AACrE,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAE3D;AAWD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgDzE"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { PSEUDO_STATES } from '../../shared/pseudo-state.type.js';
|
|
2
|
+
/** Prefix of the classes that stand in for a forced pseudo-class. */
|
|
3
|
+
export const PSEUDO_CLASS_PREFIX = 'prism-pseudo--';
|
|
4
|
+
/** The class that stands in for `state`, e.g. `prism-pseudo--focus-visible`. */
|
|
5
|
+
export function pseudoStateClass(state) {
|
|
6
|
+
return `${PSEUDO_CLASS_PREFIX}${state}`;
|
|
7
|
+
}
|
|
8
|
+
const FORCEABLE = new Set(PSEUDO_STATES);
|
|
9
|
+
/** CSS 2 pseudo-elements, which still parse with a single colon. */
|
|
10
|
+
const LEGACY_PSEUDO_ELEMENTS = new Set(['before', 'after', 'first-line', 'first-letter']);
|
|
11
|
+
const HEX_DIGIT = /[0-9a-f]/i;
|
|
12
|
+
const WHITESPACE = /[ \t\n\r\f]/;
|
|
13
|
+
const IDENT_CHAR = /[a-z0-9_-]/i;
|
|
14
|
+
/**
|
|
15
|
+
* The selector with every forced pseudo-class `:x` widened to
|
|
16
|
+
* `:is(:x, .prism-pseudo--x)` ({@link pseudoStateClass}), or `null` when it
|
|
17
|
+
* uses none or has been widened before.
|
|
18
|
+
*
|
|
19
|
+
* Without the class on any element the widened selector matches exactly what
|
|
20
|
+
* the original matched, with the same specificity: `:is()` takes the highest
|
|
21
|
+
* of its arguments, and a class weighs what a pseudo-class weighs. With the
|
|
22
|
+
* class, an element counts as being in the state whether it is forced or real,
|
|
23
|
+
* which keeps `:not(:hover)` exact in both directions and lets a forced state
|
|
24
|
+
* combine with a real one in the same selector.
|
|
25
|
+
*
|
|
26
|
+
* Tokenised rather than string-replaced. An escaped colon (`.md\:hover`) and an
|
|
27
|
+
* attribute value (`[title=":hover"]`) are left alone, and a state that follows
|
|
28
|
+
* a pseudo-element (`::part(x):hover`) is kept as it is, because `:is()` is not
|
|
29
|
+
* allowed there.
|
|
30
|
+
*/
|
|
31
|
+
export function rewritePseudoSelector(selectorText) {
|
|
32
|
+
const s = selectorText;
|
|
33
|
+
if (s.includes(PSEUDO_CLASS_PREFIX))
|
|
34
|
+
return null;
|
|
35
|
+
let out = '';
|
|
36
|
+
let changed = false;
|
|
37
|
+
// One entry per nesting level: whether the compound being read follows a pseudo-element.
|
|
38
|
+
const afterPseudoElement = [false];
|
|
39
|
+
let i = 0;
|
|
40
|
+
while (i < s.length) {
|
|
41
|
+
const ch = s[i];
|
|
42
|
+
const level = afterPseudoElement.length - 1;
|
|
43
|
+
let end = i + 1;
|
|
44
|
+
if (ch === '\\') {
|
|
45
|
+
end = escapeEnd(s, i);
|
|
46
|
+
}
|
|
47
|
+
else if (ch === '"' || ch === "'") {
|
|
48
|
+
end = stringEnd(s, i);
|
|
49
|
+
}
|
|
50
|
+
else if (ch === '[') {
|
|
51
|
+
end = attributeEnd(s, i);
|
|
52
|
+
}
|
|
53
|
+
else if (ch === '(') {
|
|
54
|
+
afterPseudoElement.push(false);
|
|
55
|
+
}
|
|
56
|
+
else if (ch === ')') {
|
|
57
|
+
if (level > 0)
|
|
58
|
+
afterPseudoElement.pop();
|
|
59
|
+
}
|
|
60
|
+
else if (ch === ',' || ch === '>' || ch === '+' || ch === '~' || WHITESPACE.test(ch)) {
|
|
61
|
+
afterPseudoElement[level] = false;
|
|
62
|
+
}
|
|
63
|
+
else if (ch === ':') {
|
|
64
|
+
const isElement = s[i + 1] === ':';
|
|
65
|
+
const nameStart = i + (isElement ? 2 : 1);
|
|
66
|
+
end = identEnd(s, nameStart);
|
|
67
|
+
const name = s.slice(nameStart, end).toLowerCase();
|
|
68
|
+
if (!isElement && FORCEABLE.has(name) && s[end] !== '(' && !afterPseudoElement[level]) {
|
|
69
|
+
out += `:is(${s.slice(i, end)}, .${PSEUDO_CLASS_PREFIX}${name})`;
|
|
70
|
+
changed = true;
|
|
71
|
+
i = end;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (isElement || LEGACY_PSEUDO_ELEMENTS.has(name))
|
|
75
|
+
afterPseudoElement[level] = true;
|
|
76
|
+
}
|
|
77
|
+
out += s.slice(i, end);
|
|
78
|
+
i = end;
|
|
79
|
+
}
|
|
80
|
+
return changed ? out : null;
|
|
81
|
+
}
|
|
82
|
+
/** End of the escape starting at `start`: a hex escape takes up to six digits and one whitespace character. */
|
|
83
|
+
function escapeEnd(s, start) {
|
|
84
|
+
let i = start + 1;
|
|
85
|
+
if (i >= s.length)
|
|
86
|
+
return i;
|
|
87
|
+
if (!HEX_DIGIT.test(s[i]))
|
|
88
|
+
return i + 1;
|
|
89
|
+
while (i < s.length && i < start + 7 && HEX_DIGIT.test(s[i]))
|
|
90
|
+
i++;
|
|
91
|
+
if (s[i] === '\r' && s[i + 1] === '\n')
|
|
92
|
+
return i + 2;
|
|
93
|
+
return i < s.length && WHITESPACE.test(s[i]) ? i + 1 : i;
|
|
94
|
+
}
|
|
95
|
+
function identEnd(s, start) {
|
|
96
|
+
let i = start;
|
|
97
|
+
while (i < s.length) {
|
|
98
|
+
if (s[i] === '\\') {
|
|
99
|
+
i = escapeEnd(s, i);
|
|
100
|
+
}
|
|
101
|
+
else if (IDENT_CHAR.test(s[i]) || s.charCodeAt(i) >= 0x80) {
|
|
102
|
+
i++;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return i;
|
|
109
|
+
}
|
|
110
|
+
function stringEnd(s, start) {
|
|
111
|
+
const quote = s[start];
|
|
112
|
+
let i = start + 1;
|
|
113
|
+
while (i < s.length) {
|
|
114
|
+
if (s[i] === '\\')
|
|
115
|
+
i += 2;
|
|
116
|
+
else if (s[i] === quote)
|
|
117
|
+
return i + 1;
|
|
118
|
+
else
|
|
119
|
+
i++;
|
|
120
|
+
}
|
|
121
|
+
return i;
|
|
122
|
+
}
|
|
123
|
+
function attributeEnd(s, start) {
|
|
124
|
+
let i = start + 1;
|
|
125
|
+
while (i < s.length) {
|
|
126
|
+
if (s[i] === '\\')
|
|
127
|
+
i = escapeEnd(s, i);
|
|
128
|
+
else if (s[i] === '"' || s[i] === "'")
|
|
129
|
+
i = stringEnd(s, i);
|
|
130
|
+
else if (s[i] === ']')
|
|
131
|
+
return i + 1;
|
|
132
|
+
else
|
|
133
|
+
i++;
|
|
134
|
+
}
|
|
135
|
+
return i;
|
|
136
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type ForcedPseudoStates, type PseudoState } from '../../shared/pseudo-state.type.js';
|
|
2
|
+
import type { PseudoStyleSheets } from './pseudo-stylesheets.js';
|
|
3
|
+
import { type StateFit } from './state-fit.js';
|
|
4
|
+
/** The element a marker forces states in, and the states it forces there. */
|
|
5
|
+
export interface AppliedPseudoStates {
|
|
6
|
+
root: Element;
|
|
7
|
+
/** The variant's own states with the toggles on top, unfiltered as in 22.5.0. */
|
|
8
|
+
states: ForcedPseudoStates | null;
|
|
9
|
+
/** The active state's pseudo, `null` when no state is active. */
|
|
10
|
+
state: ForcedPseudoStates | null;
|
|
11
|
+
/** `null` when `state` is `null`. Re-evaluated on every mark. */
|
|
12
|
+
fit: StateFit | null;
|
|
13
|
+
}
|
|
14
|
+
/** The pseudo-classes actually forced right now: `states`, plus `state` while it fits. */
|
|
15
|
+
export declare function appliedStateNames(applied: AppliedPseudoStates | null): PseudoState[];
|
|
16
|
+
/**
|
|
17
|
+
* Forces a variant's pseudo states on one rendered component.
|
|
18
|
+
*
|
|
19
|
+
* Puts the stand-in class of each state ({@link pseudoStateClass}) on the
|
|
20
|
+
* targeted elements, and holds the document's {@link PseudoStyleSheets} so that
|
|
21
|
+
* every selector using the pseudo-class also matches that class. The
|
|
22
|
+
* component's own CSS then applies, with no special case for sibling
|
|
23
|
+
* combinators, pseudo-elements, `:has()` or `:not()`.
|
|
24
|
+
*
|
|
25
|
+
* A second layer carries the component state that is active: its pseudo is
|
|
26
|
+
* forced only while it fits, and only on the targets a user could reach
|
|
27
|
+
* ({@link evaluateStateFit}). The variant's own states are forced as they are.
|
|
28
|
+
* Fit and reach are measured with the variant's classes and the state's on all
|
|
29
|
+
* of its targets at once, on every pass. The first pass, the one
|
|
30
|
+
* `data-prism-rendered` waits for, therefore marks what any later pass would,
|
|
31
|
+
* and a rule that takes away the pointer under its own `:hover` reads as not
|
|
32
|
+
* fitting, as the browser could not keep such an element hovered either.
|
|
33
|
+
*
|
|
34
|
+
* The root is watched while states are forced: an element rendered later
|
|
35
|
+
* (`@if`), or one whose classes or attributes change so that it starts or
|
|
36
|
+
* stops matching a selector (`button:not([disabled])`), is marked again, and
|
|
37
|
+
* the state is checked again.
|
|
38
|
+
*
|
|
39
|
+
* One marker per rendered component: the Playground canvas has one, each
|
|
40
|
+
* Overview cell has its own, so a state never leaks into a neighbouring cell.
|
|
41
|
+
*/
|
|
42
|
+
export declare class PseudoStateMarker {
|
|
43
|
+
private readonly stylesheets;
|
|
44
|
+
private readonly _applied;
|
|
45
|
+
private observer;
|
|
46
|
+
/**
|
|
47
|
+
* What the marks are in place for, `null` while nothing is forced and no
|
|
48
|
+
* state is active. A signal, so the renderer can hold back
|
|
49
|
+
* `data-prism-rendered` until the states it reports are the ones on screen.
|
|
50
|
+
* A state that does not fit keeps it set, with the reason in `fit`.
|
|
51
|
+
*/
|
|
52
|
+
readonly applied: import("@angular/core").Signal<AppliedPseudoStates | null>;
|
|
53
|
+
constructor(stylesheets: PseudoStyleSheets);
|
|
54
|
+
/**
|
|
55
|
+
* Forces `states`, and `state` where it fits, under `root`, replacing
|
|
56
|
+
* whatever this marker forced before.
|
|
57
|
+
*/
|
|
58
|
+
apply(root: Element | null, states: ForcedPseudoStates | null | undefined, state?: ForcedPseudoStates | null): void;
|
|
59
|
+
/** Removes every mark, stops watching, and releases the stylesheets. */
|
|
60
|
+
clear(): void;
|
|
61
|
+
private observe;
|
|
62
|
+
private mark;
|
|
63
|
+
/** Puts the class of `name` on exactly `targets` under `root`. */
|
|
64
|
+
private write;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=pseudo-state-marker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pseudo-state-marker.d.ts","sourceRoot":"","sources":["../../../src/app/pseudo/pseudo-state-marker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,kBAAkB,EAAiB,KAAK,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAE7G,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,EAAsC,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAEnF,6EAA6E;AAC7E,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,iFAAiF;IACjF,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAClC,iEAAiE;IACjE,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACjC,iEAAiE;IACjE,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACxB;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,GAAG,WAAW,EAAE,CAMpF;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,iBAAiB;IAYd,OAAO,CAAC,QAAQ,CAAC,WAAW;IAXxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;IACrE,OAAO,CAAC,QAAQ,CAAiC;IAEjD;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,6DAA8B;gBAEjB,WAAW,EAAE,iBAAiB;IAE3D;;;OAGG;IACH,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,kBAAkB,GAAG,IAAI,GAAG,IAAI;IAqBnH,wEAAwE;IACxE,KAAK,IAAI,IAAI;IAab,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,IAAI;IA2CZ,kEAAkE;IAClE,OAAO,CAAC,KAAK;CAYhB"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { signal } from '@angular/core';
|
|
2
|
+
import { PSEUDO_STATES } from '../../shared/pseudo-state.type.js';
|
|
3
|
+
import { PSEUDO_CLASS_PREFIX, pseudoStateClass } from './pseudo-selector.js';
|
|
4
|
+
import { forcesAnyState, hasTarget, resolveTargets } from './pseudo-targets.js';
|
|
5
|
+
import { evaluateStateFit, reachableTargets } from './state-fit.js';
|
|
6
|
+
/** The pseudo-classes actually forced right now: `states`, plus `state` while it fits. */
|
|
7
|
+
export function appliedStateNames(applied) {
|
|
8
|
+
if (!applied)
|
|
9
|
+
return [];
|
|
10
|
+
const { states, state, fit } = applied;
|
|
11
|
+
const stateForced = !!state && !!fit?.fits;
|
|
12
|
+
return PSEUDO_STATES.filter((name) => hasTarget(states?.[name]) || (stateForced && hasTarget(state[name])));
|
|
13
|
+
}
|
|
14
|
+
function sameFit(a, b) {
|
|
15
|
+
if (a === null || b === null)
|
|
16
|
+
return a === b;
|
|
17
|
+
return a.fits ? b.fits : !b.fits && a.reason === b.reason;
|
|
18
|
+
}
|
|
19
|
+
/** Every element under `root`, `root` included, that carries a forced-state class. */
|
|
20
|
+
function markedElements(root) {
|
|
21
|
+
const marked = Array.from(root.querySelectorAll(`[class*="${PSEUDO_CLASS_PREFIX}"]`));
|
|
22
|
+
return Array.from(root.classList).some((cls) => cls.startsWith(PSEUDO_CLASS_PREFIX)) ? [root, ...marked] : marked;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Forces a variant's pseudo states on one rendered component.
|
|
26
|
+
*
|
|
27
|
+
* Puts the stand-in class of each state ({@link pseudoStateClass}) on the
|
|
28
|
+
* targeted elements, and holds the document's {@link PseudoStyleSheets} so that
|
|
29
|
+
* every selector using the pseudo-class also matches that class. The
|
|
30
|
+
* component's own CSS then applies, with no special case for sibling
|
|
31
|
+
* combinators, pseudo-elements, `:has()` or `:not()`.
|
|
32
|
+
*
|
|
33
|
+
* A second layer carries the component state that is active: its pseudo is
|
|
34
|
+
* forced only while it fits, and only on the targets a user could reach
|
|
35
|
+
* ({@link evaluateStateFit}). The variant's own states are forced as they are.
|
|
36
|
+
* Fit and reach are measured with the variant's classes and the state's on all
|
|
37
|
+
* of its targets at once, on every pass. The first pass, the one
|
|
38
|
+
* `data-prism-rendered` waits for, therefore marks what any later pass would,
|
|
39
|
+
* and a rule that takes away the pointer under its own `:hover` reads as not
|
|
40
|
+
* fitting, as the browser could not keep such an element hovered either.
|
|
41
|
+
*
|
|
42
|
+
* The root is watched while states are forced: an element rendered later
|
|
43
|
+
* (`@if`), or one whose classes or attributes change so that it starts or
|
|
44
|
+
* stops matching a selector (`button:not([disabled])`), is marked again, and
|
|
45
|
+
* the state is checked again.
|
|
46
|
+
*
|
|
47
|
+
* One marker per rendered component: the Playground canvas has one, each
|
|
48
|
+
* Overview cell has its own, so a state never leaks into a neighbouring cell.
|
|
49
|
+
*/
|
|
50
|
+
export class PseudoStateMarker {
|
|
51
|
+
stylesheets;
|
|
52
|
+
_applied = signal(null, /* @ts-ignore */
|
|
53
|
+
...(ngDevMode ? [{ debugName: "_applied" }] : /* istanbul ignore next */ []));
|
|
54
|
+
observer = null;
|
|
55
|
+
/**
|
|
56
|
+
* What the marks are in place for, `null` while nothing is forced and no
|
|
57
|
+
* state is active. A signal, so the renderer can hold back
|
|
58
|
+
* `data-prism-rendered` until the states it reports are the ones on screen.
|
|
59
|
+
* A state that does not fit keeps it set, with the reason in `fit`.
|
|
60
|
+
*/
|
|
61
|
+
applied = this._applied.asReadonly();
|
|
62
|
+
constructor(stylesheets) {
|
|
63
|
+
this.stylesheets = stylesheets;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Forces `states`, and `state` where it fits, under `root`, replacing
|
|
67
|
+
* whatever this marker forced before.
|
|
68
|
+
*/
|
|
69
|
+
apply(root, states, state) {
|
|
70
|
+
if (!root || (!forcesAnyState(states) && !state)) {
|
|
71
|
+
this.clear();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const previous = this._applied();
|
|
75
|
+
if (previous && previous.root !== root)
|
|
76
|
+
this.clear();
|
|
77
|
+
if (!this._applied()) {
|
|
78
|
+
this.stylesheets.acquire();
|
|
79
|
+
this.observe(root);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Same root, new variant: its styles may have arrived since.
|
|
83
|
+
this.stylesheets.sync();
|
|
84
|
+
}
|
|
85
|
+
this._applied.set({ root, states: states ?? null, state: state ?? null, fit: null });
|
|
86
|
+
this.mark();
|
|
87
|
+
}
|
|
88
|
+
/** Removes every mark, stops watching, and releases the stylesheets. */
|
|
89
|
+
clear() {
|
|
90
|
+
const applied = this._applied();
|
|
91
|
+
if (!applied)
|
|
92
|
+
return;
|
|
93
|
+
this.observer?.disconnect();
|
|
94
|
+
this.observer = null;
|
|
95
|
+
for (const el of markedElements(applied.root)) {
|
|
96
|
+
for (const state of PSEUDO_STATES)
|
|
97
|
+
el.classList.remove(pseudoStateClass(state));
|
|
98
|
+
}
|
|
99
|
+
this._applied.set(null);
|
|
100
|
+
this.stylesheets.release();
|
|
101
|
+
}
|
|
102
|
+
observe(root) {
|
|
103
|
+
if (typeof MutationObserver === 'undefined')
|
|
104
|
+
return;
|
|
105
|
+
// Inline styles alone cannot change what a selector matches, and an
|
|
106
|
+
// animation can write them every frame. The marker's own writes never
|
|
107
|
+
// get here, see the end of mark.
|
|
108
|
+
this.observer = new MutationObserver((records) => {
|
|
109
|
+
if (records.some((record) => record.attributeName !== 'style'))
|
|
110
|
+
this.mark();
|
|
111
|
+
});
|
|
112
|
+
this.observer.observe(root, { childList: true, subtree: true, attributes: true });
|
|
113
|
+
}
|
|
114
|
+
mark() {
|
|
115
|
+
const applied = this._applied();
|
|
116
|
+
if (!applied)
|
|
117
|
+
return;
|
|
118
|
+
const { root, states, state } = applied;
|
|
119
|
+
const forced = new Map();
|
|
120
|
+
const stateTargets = new Map();
|
|
121
|
+
// Every pass measures one DOM, whatever the previous pass left: the
|
|
122
|
+
// variant's classes, and the state's on every target it names, all at
|
|
123
|
+
// once. A target can take the pointer only under another forced class
|
|
124
|
+
// (a hover-reveal), and a mark must not depend on whether an unrelated
|
|
125
|
+
// write set off a second pass.
|
|
126
|
+
for (const name of PSEUDO_STATES) {
|
|
127
|
+
const variantTargets = resolveTargets(root, states?.[name]);
|
|
128
|
+
const targets = state ? resolveTargets(root, state[name]) : new Set();
|
|
129
|
+
forced.set(name, variantTargets);
|
|
130
|
+
stateTargets.set(name, targets);
|
|
131
|
+
this.write(root, name, new Set([...variantTargets, ...targets]));
|
|
132
|
+
}
|
|
133
|
+
const fit = state ? evaluateStateFit(root, state) : null;
|
|
134
|
+
// Read before the first class comes off, so no target is measured
|
|
135
|
+
// against a DOM another one's removal changed.
|
|
136
|
+
const reachable = PSEUDO_STATES.map((name) => new Set(fit?.fits ? reachableTargets(root, name, stateTargets.get(name)) : []));
|
|
137
|
+
// Only a change of the fit is news. The signal setting off its own
|
|
138
|
+
// effects is harmless, a new value on every mark is not.
|
|
139
|
+
if (!sameFit(applied.fit, fit))
|
|
140
|
+
this._applied.set({ ...applied, fit });
|
|
141
|
+
// The state's class comes off what it cannot reach, and off all of its
|
|
142
|
+
// targets when it does not fit. The variant's classes stay.
|
|
143
|
+
PSEUDO_STATES.forEach((name, i) => this.write(root, name, new Set([...forced.get(name), ...reachable[i]])));
|
|
144
|
+
// The records of the writes above are ours. Acting on them would only
|
|
145
|
+
// repeat this pass, and a state whose class takes away its own reach
|
|
146
|
+
// (`pointer-events: none`) would rewrite its class on every one. Anything
|
|
147
|
+
// the component changed before this pass was read by it, so nothing
|
|
148
|
+
// pending is lost.
|
|
149
|
+
this.observer?.takeRecords();
|
|
150
|
+
}
|
|
151
|
+
/** Puts the class of `name` on exactly `targets` under `root`. */
|
|
152
|
+
write(root, name, targets) {
|
|
153
|
+
const cls = pseudoStateClass(name);
|
|
154
|
+
// `classList.remove` writes the attribute even when the class is absent,
|
|
155
|
+
// and the write would come back through the observer as a mutation.
|
|
156
|
+
for (const el of markedElements(root)) {
|
|
157
|
+
if (!targets.has(el) && el.classList.contains(cls))
|
|
158
|
+
el.classList.remove(cls);
|
|
159
|
+
}
|
|
160
|
+
for (const el of targets) {
|
|
161
|
+
if (!el.classList.contains(cls))
|
|
162
|
+
el.classList.add(cls);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** A stylesheet or a grouping rule: anything that holds rules. */
|
|
2
|
+
interface RuleContainer {
|
|
3
|
+
readonly cssRules: CSSRuleList;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Widens every selector in `container` that uses a forced pseudo-class, so it
|
|
7
|
+
* also matches the pseudo-class's stand-in class: `:hover` becomes
|
|
8
|
+
* `:is(:hover, .prism-pseudo--hover)` ({@link rewritePseudoSelector}).
|
|
9
|
+
*
|
|
10
|
+
* In place, through `selectorText`. The rule keeps its position in the sheet
|
|
11
|
+
* and its specificity, so it wins and loses against the rules around it exactly
|
|
12
|
+
* as it does for the real state, and no index another script holds moves.
|
|
13
|
+
* Without the class on an element the widened selector matches what the
|
|
14
|
+
* original matched, which keeps the shell and every other variant untouched.
|
|
15
|
+
* A copy of the rule could not keep `:not(:hover)` right: it would either
|
|
16
|
+
* match a really hovered element or leave the original matching a forced one.
|
|
17
|
+
*
|
|
18
|
+
* Idempotent: a selector widened before is not widened again.
|
|
19
|
+
* Returns the number of selectors widened.
|
|
20
|
+
*/
|
|
21
|
+
export declare function rewriteRules(container: RuleContainer): number;
|
|
22
|
+
/**
|
|
23
|
+
* The document's stylesheets, rewritten for forced pseudo states.
|
|
24
|
+
*
|
|
25
|
+
* Lazy: nothing is touched until a variant forces a state ({@link rewriteRules}
|
|
26
|
+
* says what changes). Every sheet is rewritten once, tracked by object, which also covers a `<style>` whose
|
|
27
|
+
* content is replaced (HMR, Angular removing and re-adding component styles):
|
|
28
|
+
* the browser gives it a new sheet, and the new sheet is rewritten again.
|
|
29
|
+
*
|
|
30
|
+
* `document.head` is watched only while at least one marker holds the sheets
|
|
31
|
+
* ({@link acquire}), so styles that arrive later, through a lazily rendered
|
|
32
|
+
* child component or a hot reload, are rewritten too.
|
|
33
|
+
*/
|
|
34
|
+
export declare class PseudoStyleSheets {
|
|
35
|
+
private readonly doc;
|
|
36
|
+
private readonly rewritten;
|
|
37
|
+
private readonly awaitedLinks;
|
|
38
|
+
private observer;
|
|
39
|
+
private holders;
|
|
40
|
+
constructor(doc: Document);
|
|
41
|
+
/** Rewrites what has not been rewritten yet, and keeps doing so for new styles until {@link release}. */
|
|
42
|
+
acquire(): void;
|
|
43
|
+
release(): void;
|
|
44
|
+
/** Rewrites every sheet of the document that has not been rewritten yet. */
|
|
45
|
+
sync(): void;
|
|
46
|
+
rewriteSheet(sheet: CSSStyleSheet): void;
|
|
47
|
+
}
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=pseudo-stylesheets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pseudo-stylesheets.d.ts","sourceRoot":"","sources":["../../../src/app/pseudo/pseudo-stylesheets.ts"],"names":[],"mappings":"AAGA,kEAAkE;AAClE,UAAU,aAAa;IACnB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;CAClC;AAoBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,aAAa,GAAG,MAAM,CAmB7D;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAiB;IAMd,OAAO,CAAC,QAAQ,CAAC,GAAG;IALhC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0B;IACvD,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,OAAO,CAAK;gBAES,GAAG,EAAE,QAAQ;IAE1C,yGAAyG;IACzG,OAAO,IAAI,IAAI;IAQf,OAAO,IAAI,IAAI;IAQf,4EAA4E;IAC5E,IAAI,IAAI,IAAI;IAkBZ,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;CA0B3C"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { isDevMode } from '@angular/core';
|
|
2
|
+
import { rewritePseudoSelector } from './pseudo-selector.js';
|
|
3
|
+
// Duck-typed rather than `instanceof`: the constructors belong to the window
|
|
4
|
+
// that owns the sheet, and not every engine has all of them (`CSSContainerRule`,
|
|
5
|
+
// `CSSLayerBlockRule`).
|
|
6
|
+
function isStyleRule(rule) {
|
|
7
|
+
return typeof rule.selectorText === 'string' && 'style' in rule;
|
|
8
|
+
}
|
|
9
|
+
// `@media`, `@supports`, `@layer`, `@container`, and a style rule with nested
|
|
10
|
+
// rules. `@keyframes` holds rules too, but no selectors: it is the one that
|
|
11
|
+
// takes new rules through `appendRule` instead of `insertRule`.
|
|
12
|
+
function isRuleContainer(rule) {
|
|
13
|
+
return 'cssRules' in rule && typeof rule.insertRule === 'function';
|
|
14
|
+
}
|
|
15
|
+
function isImportRule(rule) {
|
|
16
|
+
return 'styleSheet' in rule && 'href' in rule;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Widens every selector in `container` that uses a forced pseudo-class, so it
|
|
20
|
+
* also matches the pseudo-class's stand-in class: `:hover` becomes
|
|
21
|
+
* `:is(:hover, .prism-pseudo--hover)` ({@link rewritePseudoSelector}).
|
|
22
|
+
*
|
|
23
|
+
* In place, through `selectorText`. The rule keeps its position in the sheet
|
|
24
|
+
* and its specificity, so it wins and loses against the rules around it exactly
|
|
25
|
+
* as it does for the real state, and no index another script holds moves.
|
|
26
|
+
* Without the class on an element the widened selector matches what the
|
|
27
|
+
* original matched, which keeps the shell and every other variant untouched.
|
|
28
|
+
* A copy of the rule could not keep `:not(:hover)` right: it would either
|
|
29
|
+
* match a really hovered element or leave the original matching a forced one.
|
|
30
|
+
*
|
|
31
|
+
* Idempotent: a selector widened before is not widened again.
|
|
32
|
+
* Returns the number of selectors widened.
|
|
33
|
+
*/
|
|
34
|
+
export function rewriteRules(container) {
|
|
35
|
+
let widened = 0;
|
|
36
|
+
for (const rule of Array.from(container.cssRules)) {
|
|
37
|
+
if (isStyleRule(rule)) {
|
|
38
|
+
const original = rule.selectorText;
|
|
39
|
+
const selector = rewritePseudoSelector(original);
|
|
40
|
+
if (selector !== null) {
|
|
41
|
+
rule.selectorText = selector;
|
|
42
|
+
// The setter ignores a selector the engine does not accept.
|
|
43
|
+
if (rule.selectorText !== original)
|
|
44
|
+
widened++;
|
|
45
|
+
else if (isDevMode())
|
|
46
|
+
console.warn(`[ng-prism] Could not force a pseudo state for "${original}".`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// A nested rule can force a state of its own (`.a { &:hover {} }`).
|
|
50
|
+
if (isRuleContainer(rule))
|
|
51
|
+
widened += rewriteRules(rule);
|
|
52
|
+
}
|
|
53
|
+
return widened;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The document's stylesheets, rewritten for forced pseudo states.
|
|
57
|
+
*
|
|
58
|
+
* Lazy: nothing is touched until a variant forces a state ({@link rewriteRules}
|
|
59
|
+
* says what changes). Every sheet is rewritten once, tracked by object, which also covers a `<style>` whose
|
|
60
|
+
* content is replaced (HMR, Angular removing and re-adding component styles):
|
|
61
|
+
* the browser gives it a new sheet, and the new sheet is rewritten again.
|
|
62
|
+
*
|
|
63
|
+
* `document.head` is watched only while at least one marker holds the sheets
|
|
64
|
+
* ({@link acquire}), so styles that arrive later, through a lazily rendered
|
|
65
|
+
* child component or a hot reload, are rewritten too.
|
|
66
|
+
*/
|
|
67
|
+
export class PseudoStyleSheets {
|
|
68
|
+
doc;
|
|
69
|
+
rewritten = new WeakSet();
|
|
70
|
+
awaitedLinks = new WeakSet();
|
|
71
|
+
observer = null;
|
|
72
|
+
holders = 0;
|
|
73
|
+
constructor(doc) {
|
|
74
|
+
this.doc = doc;
|
|
75
|
+
}
|
|
76
|
+
/** Rewrites what has not been rewritten yet, and keeps doing so for new styles until {@link release}. */
|
|
77
|
+
acquire() {
|
|
78
|
+
this.holders++;
|
|
79
|
+
this.sync();
|
|
80
|
+
if (this.observer || typeof MutationObserver === 'undefined' || !this.doc.head)
|
|
81
|
+
return;
|
|
82
|
+
this.observer = new MutationObserver(() => this.sync());
|
|
83
|
+
this.observer.observe(this.doc.head, { childList: true, subtree: true, characterData: true });
|
|
84
|
+
}
|
|
85
|
+
release() {
|
|
86
|
+
if (this.holders === 0)
|
|
87
|
+
return;
|
|
88
|
+
this.holders--;
|
|
89
|
+
if (this.holders > 0)
|
|
90
|
+
return;
|
|
91
|
+
this.observer?.disconnect();
|
|
92
|
+
this.observer = null;
|
|
93
|
+
}
|
|
94
|
+
/** Rewrites every sheet of the document that has not been rewritten yet. */
|
|
95
|
+
sync() {
|
|
96
|
+
for (const sheet of Array.from(this.doc.styleSheets))
|
|
97
|
+
this.rewriteSheet(sheet);
|
|
98
|
+
for (const sheet of this.doc.adoptedStyleSheets ?? [])
|
|
99
|
+
this.rewriteSheet(sheet);
|
|
100
|
+
// A `<link>` has no sheet until it has loaded.
|
|
101
|
+
for (const link of Array.from(this.doc.querySelectorAll('link[rel~="stylesheet"]'))) {
|
|
102
|
+
if (link.sheet || this.awaitedLinks.has(link))
|
|
103
|
+
continue;
|
|
104
|
+
this.awaitedLinks.add(link);
|
|
105
|
+
link.addEventListener('load', () => {
|
|
106
|
+
this.awaitedLinks.delete(link);
|
|
107
|
+
if (this.holders > 0)
|
|
108
|
+
this.sync();
|
|
109
|
+
}, { once: true });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
rewriteSheet(sheet) {
|
|
113
|
+
if (this.rewritten.has(sheet))
|
|
114
|
+
return;
|
|
115
|
+
let rules;
|
|
116
|
+
try {
|
|
117
|
+
rules = sheet.cssRules;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
// Anything else means the sheet has not loaded yet; the link's load listener comes back to it.
|
|
121
|
+
if (!(error instanceof DOMException) || error.name !== 'SecurityError')
|
|
122
|
+
return;
|
|
123
|
+
this.rewritten.add(sheet);
|
|
124
|
+
if (isDevMode()) {
|
|
125
|
+
console.warn(`[ng-prism] Cannot force pseudo states in ${sheet.href ?? 'a stylesheet'}: its rules are cross-origin and cannot be read. ` +
|
|
126
|
+
'Serve it from the same origin, or with CORS and a crossorigin attribute.');
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
this.rewritten.add(sheet);
|
|
131
|
+
for (const rule of Array.from(rules)) {
|
|
132
|
+
if (isImportRule(rule) && rule.styleSheet)
|
|
133
|
+
this.rewriteSheet(rule.styleSheet);
|
|
134
|
+
}
|
|
135
|
+
rewriteRules(sheet);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ForcedPseudoStates, type PseudoTarget } from '../../shared/pseudo-state.type.js';
|
|
2
|
+
/** True when `states` forces at least one state on at least one target. */
|
|
3
|
+
export declare function forcesAnyState(states: ForcedPseudoStates | null | undefined): states is ForcedPseudoStates;
|
|
4
|
+
/** True when `target` names something: `true`, or a selector that is not blank. */
|
|
5
|
+
export declare function hasTarget(target: PseudoTarget | undefined): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* The elements under `root` a target names. `root` counts: a selector can name
|
|
8
|
+
* the component's host, and `true` includes it.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveTargets(root: Element, target: PseudoTarget | undefined): Set<Element>;
|
|
11
|
+
//# sourceMappingURL=pseudo-targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pseudo-targets.d.ts","sourceRoot":"","sources":["../../../src/app/pseudo/pseudo-targets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAiB,KAAK,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAE9G,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,IAAI,kBAAkB,CAE1G;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,GAAG,OAAO,CAInE;AAID;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,GAAG,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,CAuB5F"}
|