@ng-prism/core 22.4.0 → 22.5.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 +1 -1
- package/dist/app/canvas/prism-canvas-toolbar.component.d.ts +12 -2
- package/dist/app/canvas/prism-canvas-toolbar.component.d.ts.map +1 -1
- package/dist/app/canvas/prism-canvas-toolbar.component.js +55 -21
- package/dist/app/discovery-manifest.d.ts.map +1 -1
- package/dist/app/discovery-manifest.js +8 -2
- package/dist/app/overview/prism-overview-cell.component.d.ts +6 -0
- package/dist/app/overview/prism-overview-cell.component.d.ts.map +1 -1
- package/dist/app/overview/prism-overview-cell.component.js +14 -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 +44 -0
- package/dist/app/pseudo/pseudo-state-marker.d.ts.map +1 -0
- package/dist/app/pseudo/pseudo-state-marker.js +149 -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/renderer/prism-renderer.component.d.ts +11 -1
- package/dist/app/renderer/prism-renderer.component.d.ts.map +1 -1
- package/dist/app/renderer/prism-renderer.component.js +39 -15
- package/dist/app/renderer/rendered-key.d.ts +24 -0
- package/dist/app/renderer/rendered-key.d.ts.map +1 -0
- package/dist/app/renderer/rendered-key.js +17 -0
- 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 +48 -0
- package/dist/app/services/prism-pseudo-state.service.d.ts.map +1 -0
- package/dist/app/services/prism-pseudo-state.service.js +98 -0
- package/dist/app/shell/prism-shell.component.js +2 -2
- package/dist/builder/scanner/component.scanner.d.ts.map +1 -1
- package/dist/builder/scanner/component.scanner.js +8 -0
- package/dist/builder/scanner/pseudo-states.d.ts +11 -0
- package/dist/builder/scanner/pseudo-states.d.ts.map +1 -0
- package/dist/builder/scanner/pseudo-states.js +58 -0
- package/dist/decorator/showcase.types.d.ts +10 -0
- package/dist/decorator/showcase.types.d.ts.map +1 -1
- package/dist/plugin/index.d.ts +2 -0
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1 -0
- package/dist/plugin/plugin.types.d.ts +9 -2
- 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 +4 -4
|
@@ -0,0 +1,149 @@
|
|
|
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
|
+
/** True when `states` forces at least one state on at least one target. */
|
|
5
|
+
export function forcesAnyState(states) {
|
|
6
|
+
return !!states && PSEUDO_STATES.some((state) => hasTarget(states[state]));
|
|
7
|
+
}
|
|
8
|
+
function hasTarget(target) {
|
|
9
|
+
if (target === true)
|
|
10
|
+
return true;
|
|
11
|
+
if (typeof target === 'string')
|
|
12
|
+
return target.trim() !== '';
|
|
13
|
+
return Array.isArray(target) && target.some((selector) => typeof selector === 'string' && selector.trim() !== '');
|
|
14
|
+
}
|
|
15
|
+
const warnedSelectors = new Set();
|
|
16
|
+
/**
|
|
17
|
+
* The elements under `root` a target names. `root` counts: a selector can name
|
|
18
|
+
* the component's host, and `true` includes it.
|
|
19
|
+
*/
|
|
20
|
+
function resolveTargets(root, target) {
|
|
21
|
+
const targets = new Set();
|
|
22
|
+
if (target === undefined)
|
|
23
|
+
return targets;
|
|
24
|
+
if (target === true) {
|
|
25
|
+
targets.add(root);
|
|
26
|
+
for (const el of Array.from(root.querySelectorAll('*')))
|
|
27
|
+
targets.add(el);
|
|
28
|
+
return targets;
|
|
29
|
+
}
|
|
30
|
+
for (const selector of typeof target === 'string' ? [target] : target) {
|
|
31
|
+
if (typeof selector !== 'string' || selector.trim() === '')
|
|
32
|
+
continue;
|
|
33
|
+
try {
|
|
34
|
+
if (root.matches(selector))
|
|
35
|
+
targets.add(root);
|
|
36
|
+
for (const el of Array.from(root.querySelectorAll(selector)))
|
|
37
|
+
targets.add(el);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
if (!warnedSelectors.has(selector)) {
|
|
41
|
+
warnedSelectors.add(selector);
|
|
42
|
+
console.warn(`[ng-prism] "${selector}" in a variant's pseudo states is not a valid selector, skipping it.`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return targets;
|
|
47
|
+
}
|
|
48
|
+
/** Every element under `root`, `root` included, that carries a forced-state class. */
|
|
49
|
+
function markedElements(root) {
|
|
50
|
+
const marked = Array.from(root.querySelectorAll(`[class*="${PSEUDO_CLASS_PREFIX}"]`));
|
|
51
|
+
return Array.from(root.classList).some((cls) => cls.startsWith(PSEUDO_CLASS_PREFIX)) ? [root, ...marked] : marked;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Forces a variant's pseudo states on one rendered component.
|
|
55
|
+
*
|
|
56
|
+
* Puts the stand-in class of each state ({@link pseudoStateClass}) on the
|
|
57
|
+
* targeted elements, and holds the document's {@link PseudoStyleSheets} so that
|
|
58
|
+
* every selector using the pseudo-class also matches that class. The
|
|
59
|
+
* component's own CSS then applies, with no special case for sibling
|
|
60
|
+
* combinators, pseudo-elements, `:has()` or `:not()`.
|
|
61
|
+
*
|
|
62
|
+
* The root is watched while states are forced: an element rendered later
|
|
63
|
+
* (`@if`), or one whose classes or attributes change so that it starts or
|
|
64
|
+
* stops matching a selector (`button:not([disabled])`), is marked again.
|
|
65
|
+
*
|
|
66
|
+
* One marker per rendered component: the Playground canvas has one, each
|
|
67
|
+
* Overview cell has its own, so a state never leaks into a neighbouring cell.
|
|
68
|
+
*/
|
|
69
|
+
export class PseudoStateMarker {
|
|
70
|
+
stylesheets;
|
|
71
|
+
_applied = signal(null, /* @ts-ignore */
|
|
72
|
+
...(ngDevMode ? [{ debugName: "_applied" }] : /* istanbul ignore next */ []));
|
|
73
|
+
observer = null;
|
|
74
|
+
/**
|
|
75
|
+
* What the marks are in place for, `null` while nothing is forced. A
|
|
76
|
+
* signal, so the renderer can hold back `data-prism-rendered` until the
|
|
77
|
+
* states it reports are the ones on screen.
|
|
78
|
+
*/
|
|
79
|
+
applied = this._applied.asReadonly();
|
|
80
|
+
constructor(stylesheets) {
|
|
81
|
+
this.stylesheets = stylesheets;
|
|
82
|
+
}
|
|
83
|
+
/** Forces `states` under `root`, replacing whatever this marker forced before. */
|
|
84
|
+
apply(root, states) {
|
|
85
|
+
if (!root || !forcesAnyState(states)) {
|
|
86
|
+
this.clear();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const previous = this._applied();
|
|
90
|
+
if (previous && previous.root !== root)
|
|
91
|
+
this.clear();
|
|
92
|
+
if (!this._applied()) {
|
|
93
|
+
this.stylesheets.acquire();
|
|
94
|
+
this.observe(root);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// Same root, new variant: its styles may have arrived since.
|
|
98
|
+
this.stylesheets.sync();
|
|
99
|
+
}
|
|
100
|
+
this._applied.set({ root, states });
|
|
101
|
+
this.mark();
|
|
102
|
+
}
|
|
103
|
+
/** Removes every mark, stops watching, and releases the stylesheets. */
|
|
104
|
+
clear() {
|
|
105
|
+
const applied = this._applied();
|
|
106
|
+
if (!applied)
|
|
107
|
+
return;
|
|
108
|
+
this.observer?.disconnect();
|
|
109
|
+
this.observer = null;
|
|
110
|
+
for (const el of markedElements(applied.root)) {
|
|
111
|
+
for (const state of PSEUDO_STATES)
|
|
112
|
+
el.classList.remove(pseudoStateClass(state));
|
|
113
|
+
}
|
|
114
|
+
this._applied.set(null);
|
|
115
|
+
this.stylesheets.release();
|
|
116
|
+
}
|
|
117
|
+
observe(root) {
|
|
118
|
+
if (typeof MutationObserver === 'undefined')
|
|
119
|
+
return;
|
|
120
|
+
// Our own class changes come back through here too; the second pass finds
|
|
121
|
+
// nothing to change. Inline styles alone cannot change what a selector
|
|
122
|
+
// matches, and an animation can write them every frame.
|
|
123
|
+
this.observer = new MutationObserver((records) => {
|
|
124
|
+
if (records.some((record) => record.attributeName !== 'style'))
|
|
125
|
+
this.mark();
|
|
126
|
+
});
|
|
127
|
+
this.observer.observe(root, { childList: true, subtree: true, attributes: true });
|
|
128
|
+
}
|
|
129
|
+
mark() {
|
|
130
|
+
const applied = this._applied();
|
|
131
|
+
if (!applied)
|
|
132
|
+
return;
|
|
133
|
+
const { root, states } = applied;
|
|
134
|
+
for (const state of PSEUDO_STATES) {
|
|
135
|
+
const cls = pseudoStateClass(state);
|
|
136
|
+
const targets = resolveTargets(root, states[state]);
|
|
137
|
+
// `classList.remove` writes the attribute even when the class is absent,
|
|
138
|
+
// and the write would come back through the observer as a mutation.
|
|
139
|
+
for (const el of markedElements(root)) {
|
|
140
|
+
if (!targets.has(el) && el.classList.contains(cls))
|
|
141
|
+
el.classList.remove(cls);
|
|
142
|
+
}
|
|
143
|
+
for (const el of targets) {
|
|
144
|
+
if (!el.classList.contains(cls))
|
|
145
|
+
el.classList.add(cls);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -11,6 +11,7 @@ export declare class PrismRendererComponent {
|
|
|
11
11
|
protected readonly canvasService: PrismCanvasService;
|
|
12
12
|
protected readonly capture: PrismCaptureService;
|
|
13
13
|
protected readonly variantBg: PrismVariantBgService;
|
|
14
|
+
private readonly pseudoState;
|
|
14
15
|
/**
|
|
15
16
|
* The width the canvas is actually constrained to, `null` for unconstrained.
|
|
16
17
|
*
|
|
@@ -44,6 +45,7 @@ export declare class PrismRendererComponent {
|
|
|
44
45
|
private readonly rendererHooks;
|
|
45
46
|
private readonly panelService;
|
|
46
47
|
private readonly pluginService;
|
|
48
|
+
private readonly pseudoMarker;
|
|
47
49
|
private readonly outlet;
|
|
48
50
|
private componentRef;
|
|
49
51
|
private outputSubscriptions;
|
|
@@ -51,8 +53,16 @@ export declare class PrismRendererComponent {
|
|
|
51
53
|
private isRenderPage;
|
|
52
54
|
private readonly overlayCache;
|
|
53
55
|
readonly activeOverlay: import("@angular/core").WritableSignal<Type<unknown> | null>;
|
|
54
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Identifier of the currently rendered component/variant (for audit tooling / e2e).
|
|
58
|
+
* Held back until the variant's forced pseudo states are in place, see {@link resolveRenderedKey}.
|
|
59
|
+
*/
|
|
55
60
|
protected readonly renderedKey: import("@angular/core").Signal<string | null>;
|
|
61
|
+
/**
|
|
62
|
+
* The states forced on the canvas, space-separated, `null` for none. Capture
|
|
63
|
+
* mode keys the room it leaves for focus rings on it.
|
|
64
|
+
*/
|
|
65
|
+
protected readonly forcedStates: import("@angular/core").Signal<string | null>;
|
|
56
66
|
/** Resolved canvas layout for the active variant. Variant overrides component config; defaults to 'fit'. */
|
|
57
67
|
protected readonly canvasLayout: import("@angular/core").Signal<import("../../shared/canvas-layout.type.js").CanvasLayout>;
|
|
58
68
|
protected readonly overlayInputs: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prism-renderer.component.d.ts","sourceRoot":"","sources":["../../../src/app/renderer/prism-renderer.component.ts"],"names":[],"mappings":"AACA,OAAO,EASH,QAAQ,EAER,KAAK,IAAI,EAIZ,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"prism-renderer.component.d.ts","sourceRoot":"","sources":["../../../src/app/renderer/prism-renderer.component.ts"],"names":[],"mappings":"AACA,OAAO,EASH,QAAQ,EAER,KAAK,IAAI,EAIZ,MAAM,eAAe,CAAC;AAYvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAG3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AAIjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;;AAOhF,qBASa,sBAAsB;IAC/B,SAAS,CAAC,QAAQ,CAAC,iBAAiB,yBAAkC;IACtE,SAAS,CAAC,QAAQ,CAAC,eAAe,uBAAgC;IAClE,SAAS,CAAC,QAAQ,CAAC,aAAa,qBAA8B;IAC9D,SAAS,CAAC,QAAQ,CAAC,OAAO,sBAA+B;IACzD,SAAS,CAAC,QAAQ,CAAC,SAAS,wBAAiC;IAC7D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmC;IAE/D;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,gDAAuF;IAEvH,SAAS,CAAC,QAAQ,CAAC,YAAY,OAAgB;IAC/C,SAAS,CAAC,QAAQ,CAAC,YAAY,QAAgB;IAE/C;;;;;;;OAOG;IACH,SAAS,CAAC,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI/C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAChE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAChE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAE3B;IAEH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA8B;IAC5D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmC;IAEhE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAEpB;IACH,OAAO,CAAC,YAAY,CAAsC;IAC1D,OAAO,CAAC,mBAAmB,CAAsC;IACjE,OAAO,CAAC,oBAAoB,CAA0D;IACtF,OAAO,CAAC,YAAY,CAAS;IAE7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoC;IACjE,QAAQ,CAAC,aAAa,+DAAsC;IAC5D;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,WAAW,gDAQ5B;IACF;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,gDAI5B;IACH,4GAA4G;IAC5G,SAAS,CAAC,QAAQ,CAAC,YAAY,4FAO5B;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa;;MAA6C;IAC7E,SAAS,CAAC,QAAQ,CAAC,eAAe,yFAI/B;;IA2FH,OAAO,CAAC,eAAe;IA8EvB,OAAO,CAAC,OAAO;yCA1QN,sBAAsB;2CAAtB,sBAAsB;CAyRlC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NgComponentOutlet } from '@angular/common';
|
|
2
2
|
import { ChangeDetectionStrategy, Component, computed, DestroyRef, effect, ElementRef, inject, Injector, signal, untracked, viewChild, ViewContainerRef } from '@angular/core';
|
|
3
|
+
import { PSEUDO_STATES } from '../../shared/pseudo-state.type.js';
|
|
3
4
|
import { VIEWPORT_MAX, VIEWPORT_MIN } from '../../shared/viewport.type.js';
|
|
4
5
|
import { CANVAS_BG_STYLES } from '../canvas/canvas-bg.styles.js';
|
|
5
6
|
import { PrismCanvasBgPillComponent } from '../canvas/prism-canvas-bg-pill.component.js';
|
|
@@ -15,12 +16,14 @@ import { PrismManifestService } from '../services/prism-manifest.service.js';
|
|
|
15
16
|
import { PrismNavigationService } from '../services/prism-navigation.service.js';
|
|
16
17
|
import { PrismPanelService } from '../services/prism-panel.service.js';
|
|
17
18
|
import { PrismPluginService } from '../services/prism-plugin.service.js';
|
|
19
|
+
import { PrismPseudoStateService } from '../services/prism-pseudo-state.service.js';
|
|
18
20
|
import { PrismRendererService } from '../services/prism-renderer.service.js';
|
|
19
21
|
import { PrismVariantBgService } from '../services/prism-variant-bg.service.js';
|
|
20
22
|
import { PRISM_RENDERER_HOOKS } from '../tokens/prism-tokens.js';
|
|
21
23
|
import { buildKnownInputs } from './known-inputs.js';
|
|
22
24
|
import { resolveOverlay } from './overlay-resolver.js';
|
|
23
25
|
import { parseContentToNodes } from './projectable-content.js';
|
|
26
|
+
import { resolveRenderedKey } from './rendered-key.js';
|
|
24
27
|
import * as i0 from "@angular/core";
|
|
25
28
|
const _c0 = ["outlet"];
|
|
26
29
|
function PrismRendererComponent_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -82,6 +85,7 @@ export class PrismRendererComponent {
|
|
|
82
85
|
canvasService = inject(PrismCanvasService);
|
|
83
86
|
capture = inject(PrismCaptureService);
|
|
84
87
|
variantBg = inject(PrismVariantBgService);
|
|
88
|
+
pseudoState = inject(PrismPseudoStateService);
|
|
85
89
|
/**
|
|
86
90
|
* The width the canvas is actually constrained to, `null` for unconstrained.
|
|
87
91
|
*
|
|
@@ -120,6 +124,7 @@ export class PrismRendererComponent {
|
|
|
120
124
|
});
|
|
121
125
|
panelService = inject(PrismPanelService);
|
|
122
126
|
pluginService = inject(PrismPluginService);
|
|
127
|
+
pseudoMarker = this.pseudoState.createMarker();
|
|
123
128
|
outlet = viewChild.required('outlet', { ...(ngDevMode ? { debugName: "outlet" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
124
129
|
componentRef = null;
|
|
125
130
|
outputSubscriptions = [];
|
|
@@ -128,17 +133,27 @@ export class PrismRendererComponent {
|
|
|
128
133
|
overlayCache = new Map();
|
|
129
134
|
activeOverlay = signal(null, /* @ts-ignore */
|
|
130
135
|
...(ngDevMode ? [{ debugName: "activeOverlay" }] : /* istanbul ignore next */ []));
|
|
131
|
-
/**
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Identifier of the currently rendered component/variant (for audit tooling / e2e).
|
|
138
|
+
* Held back until the variant's forced pseudo states are in place, see {@link resolveRenderedKey}.
|
|
139
|
+
*/
|
|
140
|
+
renderedKey = computed(() => resolveRenderedKey({
|
|
141
|
+
component: this.navigationService.activeComponent(),
|
|
142
|
+
variantIndex: this.rendererService.activeVariantIndex(),
|
|
143
|
+
element: this.rendererService.renderedElement(),
|
|
144
|
+
pseudo: this.pseudoState.effective(),
|
|
145
|
+
pseudoApplied: this.pseudoMarker.applied()
|
|
146
|
+
}), /* @ts-ignore */
|
|
141
147
|
...(ngDevMode ? [{ debugName: "renderedKey" }] : /* istanbul ignore next */ []));
|
|
148
|
+
/**
|
|
149
|
+
* The states forced on the canvas, space-separated, `null` for none. Capture
|
|
150
|
+
* mode keys the room it leaves for focus rings on it.
|
|
151
|
+
*/
|
|
152
|
+
forcedStates = computed(() => {
|
|
153
|
+
const states = this.pseudoMarker.applied()?.states;
|
|
154
|
+
return states ? PSEUDO_STATES.filter((state) => states[state] !== undefined).join(' ') : null;
|
|
155
|
+
}, /* @ts-ignore */
|
|
156
|
+
...(ngDevMode ? [{ debugName: "forcedStates" }] : /* istanbul ignore next */ []));
|
|
142
157
|
/** Resolved canvas layout for the active variant. Variant overrides component config; defaults to 'fit'. */
|
|
143
158
|
canvasLayout = computed(() => {
|
|
144
159
|
const comp = this.navigationService.activeComponent();
|
|
@@ -218,7 +233,16 @@ export class PrismRendererComponent {
|
|
|
218
233
|
}
|
|
219
234
|
});
|
|
220
235
|
});
|
|
221
|
-
|
|
236
|
+
// `renderedKey` waits for what this applies.
|
|
237
|
+
effect(() => {
|
|
238
|
+
const element = this.rendererService.renderedElement();
|
|
239
|
+
const states = this.pseudoState.effective();
|
|
240
|
+
untracked(() => this.pseudoMarker.apply(element, states));
|
|
241
|
+
});
|
|
242
|
+
this.destroyRef.onDestroy(() => {
|
|
243
|
+
this.cleanup();
|
|
244
|
+
this.pseudoMarker.clear();
|
|
245
|
+
});
|
|
222
246
|
}
|
|
223
247
|
createComponent(comp) {
|
|
224
248
|
this.cleanup();
|
|
@@ -295,7 +319,7 @@ export class PrismRendererComponent {
|
|
|
295
319
|
i0.ɵɵviewQuerySignal(ctx.outlet, _c0, 5, ViewContainerRef);
|
|
296
320
|
} if (rf & 2) {
|
|
297
321
|
i0.ɵɵqueryAdvance();
|
|
298
|
-
} }, decls: 6, vars:
|
|
322
|
+
} }, decls: 6, vars: 15, consts: [["outlet", ""], [1, "prism-canvas-stage"], [1, "demo-wrap"], [1, "stage-crosshair"], [1, "vp-dim"], [1, "vp-dim__rule"], [1, "vp-dim__v"], ["prismResizer", "", "axis", "x", "aria-label", "Viewport width, left edge", 1, "vp-grip", 3, "valueChange", "scale", "min", "max", "value"], [1, "vp-grip__bar"], ["prismResizer", "", "axis", "x", "aria-label", "Viewport width, right edge", 1, "vp-grip", "vp-grip--end", 3, "valueChange", "scale", "min", "max", "value"], [4, "ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector"]], template: function PrismRendererComponent_Template(rf, ctx) { if (rf & 1) {
|
|
299
323
|
i0.ɵɵelementStart(0, "div", 1);
|
|
300
324
|
i0.ɵɵconditionalCreate(1, PrismRendererComponent_Conditional_1_Template, 5, 4);
|
|
301
325
|
i0.ɵɵelementStart(2, "div", 2);
|
|
@@ -309,15 +333,15 @@ export class PrismRendererComponent {
|
|
|
309
333
|
i0.ɵɵconditional(!ctx.capture.active() ? 1 : -1);
|
|
310
334
|
i0.ɵɵadvance();
|
|
311
335
|
i0.ɵɵstyleProp("--%NS%zoom", ctx.canvasService.zoom());
|
|
312
|
-
i0.ɵɵattribute("data-prism-rendered", ctx.renderedKey())("data-canvas-layout", ctx.canvasLayout())("data-viewport", ctx.viewportWidth() !== null ? "" : null);
|
|
336
|
+
i0.ɵɵattribute("data-prism-rendered", ctx.renderedKey())("data-canvas-layout", ctx.canvasLayout())("data-viewport", ctx.viewportWidth() !== null ? "" : null)("data-pseudo", ctx.forcedStates());
|
|
313
337
|
i0.ɵɵadvance(3);
|
|
314
338
|
i0.ɵɵconditional(ctx.activeOverlay() ? 5 : -1);
|
|
315
339
|
} }, dependencies: [PrismCanvasRulersComponent, PrismCanvasBgPillComponent, PrismCanvasMeasureComponent, NgComponentOutlet, PrismResizerDirective], styles: ["[_nghost-%COMP%] {\n display: block;\n flex: 1;\n min-height: 0;\n}\n\n.prism-canvas-stage[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 200px;\n padding: 32px;\n overflow: auto;\n\n \n\n\n\n\n\n\n\n\n\n\n outline: 1px solid var(--%NS%prism-stage-edge);\n outline-offset: -1px;\n background-color: var(--%NS%prism-stage);\n box-shadow:\n 0 1px 3px rgb(0 0 0 / 10%),\n 0 8px 24px -12px rgb(0 0 0 / 18%);\n transition: filter var(--%NS%dur-base);\n\n --%NS%prism-canvas-overlay-top: 12px;\n --%NS%prism-canvas-overlay-inline: 20px;\n}\n\n.prism-canvas-stage[data-rulers][_ngcontent-%COMP%] {\n --%NS%prism-canvas-overlay-top: 28px;\n --%NS%prism-canvas-overlay-inline: 28px;\n}\n\n.stage-crosshair[_ngcontent-%COMP%] {\n position: absolute;\n inset: 0;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--%NS%dur-base);\n}\n\n.stage-crosshair.visible[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.stage-crosshair[_ngcontent-%COMP%]::before, \n.stage-crosshair[_ngcontent-%COMP%]::after {\n position: absolute;\n content: '';\n background: color-mix(in srgb, var(--%NS%prism-primary) 20%, transparent);\n}\n\n.stage-crosshair[_ngcontent-%COMP%]::before {\n top: 50%;\n right: 0;\n left: 0;\n height: 1px;\n}\n\n.stage-crosshair[_ngcontent-%COMP%]::after {\n top: 0;\n bottom: 0;\n left: 50%;\n width: 1px;\n}\n\n.demo-wrap[_ngcontent-%COMP%] {\n position: relative;\n display: inline-block;\n transform: scale(var(--%NS%zoom, 1));\n transition: transform 0.18s;\n}\n\n.demo-wrap[data-canvas-layout='stretch'][_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n max-width: 800px;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.demo-wrap[data-viewport][_ngcontent-%COMP%] {\n display: grid;\n\n \n\n\n\n\n\n\n\n\n flex: none;\n\n \n\n\n\n\n\n\n justify-items: safe center;\n width: var(--%NS%prism-vp-w);\n max-width: none;\n container-type: inline-size;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.vp-grip[_ngcontent-%COMP%] {\n position: absolute;\n top: var(--%NS%prism-canvas-overlay-top, 12px);\n bottom: 0;\n left: calc(50% - var(--%NS%prism-vp-w) * var(--%NS%zoom, 1) / 2 - 4.5px);\n z-index: 4;\n display: grid;\n width: 9px;\n\n \n\n\n\n\n\n pointer-events: none;\n background: transparent;\n}\n\n.vp-grip--end[_ngcontent-%COMP%] {\n right: calc(50% - var(--%NS%prism-vp-w) * var(--%NS%zoom, 1) / 2 - 4.5px);\n left: auto;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n.vp-grip__bar[_ngcontent-%COMP%] {\n z-index: 1;\n box-sizing: content-box;\n grid-area: 1 / 1;\n place-self: center center;\n width: 3px;\n height: 34px;\n padding: 5px 3px;\n pointer-events: auto;\n background: color-mix(in srgb, var(--%NS%prism-measure) 80%, transparent);\n background-clip: content-box;\n border-radius: 2px;\n transition: background var(--%NS%dur-fast);\n}\n\n\n\n\n\n\n.vp-grip[_ngcontent-%COMP%]::after {\n grid-area: 1 / 1;\n place-self: stretch center;\n width: 1px;\n content: '';\n background: color-mix(in srgb, var(--%NS%prism-measure) 75%, transparent);\n transition: background var(--%NS%dur-fast);\n}\n\n.vp-grip[_ngcontent-%COMP%]:hover::after, \n.vp-grip.active[_ngcontent-%COMP%]::after, \n.vp-grip[_ngcontent-%COMP%]:focus-visible::after {\n background: color-mix(in srgb, var(--%NS%prism-measure) 55%, transparent);\n}\n\n.vp-grip[_ngcontent-%COMP%]:hover .vp-grip__bar[_ngcontent-%COMP%], \n.vp-grip.active[_ngcontent-%COMP%] .vp-grip__bar[_ngcontent-%COMP%], \n.vp-grip[_ngcontent-%COMP%]:focus-visible .vp-grip__bar[_ngcontent-%COMP%] {\n background: var(--%NS%prism-measure);\n background-clip: content-box;\n}\n\n\n\n\n.vp-grip[_ngcontent-%COMP%]:focus-visible {\n outline: none;\n}\n\n.vp-grip[_ngcontent-%COMP%]:focus-visible .vp-grip__bar[_ngcontent-%COMP%] {\n outline: 2px solid var(--%NS%prism-primary);\n outline-offset: 1px;\n}\n\n\n\n\n\n\n\n\n\n\n.vp-dim[_ngcontent-%COMP%] {\n position: absolute;\n top: var(--%NS%prism-canvas-overlay-top, 12px);\n left: 50%;\n z-index: 4;\n display: flex;\n gap: var(--%NS%sp-3);\n align-items: center;\n width: calc(var(--%NS%prism-vp-w) * var(--%NS%zoom, 1));\n pointer-events: none;\n transform: translateX(-50%);\n}\n\n\n\n\n.vp-dim__rule[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n height: 1px;\n background: color-mix(in srgb, var(--%NS%prism-measure) 70%, transparent);\n}\n\n\n\n\n.vp-dim__rule[_ngcontent-%COMP%]::before {\n position: absolute;\n top: -3px;\n width: 1px;\n height: 7px;\n content: '';\n background: color-mix(in srgb, var(--%NS%prism-measure) 90%, transparent);\n}\n\n.vp-dim__rule[_ngcontent-%COMP%]:first-child::before {\n left: 0;\n}\n\n.vp-dim__rule[_ngcontent-%COMP%]:last-child::before {\n right: 0;\n}\n\n.vp-dim__v[_ngcontent-%COMP%] {\n flex: none;\n font-family: var(--%NS%font-mono);\n font-size: 9px;\n color: var(--%NS%prism-measure);\n white-space: nowrap;\n}", "[data-bg=\"dots\"][_ngcontent-%COMP%] {\n background-image: radial-gradient(circle, var(--%NS%prism-dot) 1px, transparent 1px);\n background-size: 20px 20px;\n }\n\n [data-bg=\"plain\"][_ngcontent-%COMP%] {\n background-image: none;\n }\n\n \n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n [data-bg=\"light\"][_ngcontent-%COMP%] {\n background-color: var(--%NS%prism-void-light, #f7f5fc);\n background-image: none;\n --%NS%prism-measure: #ca00c1;\n --%NS%prism-measure-plate: var(--%NS%prism-void-light, #f7f5fc);\n }\n [data-bg=\"dark\"][_ngcontent-%COMP%] {\n background-color: var(--%NS%prism-void-dark, #07050f);\n background-image: none;\n --%NS%prism-measure: #f632ff;\n --%NS%prism-measure-plate: var(--%NS%prism-void-dark, #07050f);\n }\n\n \n\n\n [data-bg=\"checker\"][_ngcontent-%COMP%], \n [data-bg=\"transparent\"][_ngcontent-%COMP%] {\n background-image:\n linear-gradient(45deg, var(--%NS%prism-border) 25%, transparent 25%),\n linear-gradient(-45deg, var(--%NS%prism-border) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--%NS%prism-border) 75%),\n linear-gradient(-45deg, transparent 75%, var(--%NS%prism-border) 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n }"] });
|
|
316
340
|
}
|
|
317
341
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PrismRendererComponent, [{
|
|
318
342
|
type: Component,
|
|
319
|
-
args: [{ selector: 'prism-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [PrismCanvasRulersComponent, PrismCanvasBgPillComponent, PrismCanvasMeasureComponent, NgComponentOutlet, PrismResizerDirective], template: "<div\n class=\"prism-canvas-stage\"\n [attr.data-bg]=\"variantBg.effective()\"\n [attr.data-rulers]=\"canvasService.rulers() ? '' : null\"\n [attr.data-viewport]=\"viewportWidth() !== null ? '' : null\"\n [style.--prism-vp-w.px]=\"viewportWidth()\"\n [style.--zoom]=\"canvasService.zoom()\">\n @if (!capture.active()) {\n <div\n class=\"stage-crosshair\"\n [class.visible]=\"canvasService.guides()\"></div>\n <prism-canvas-rulers />\n @if (canvasService.measure()) {\n <prism-canvas-measure />\n }\n <prism-canvas-bg-pill />\n @if (viewportWidth() !== null) {\n <!-- Grips and the dimension line are siblings of .demo-wrap, never\n children of it: .demo-wrap is what plugin-visual-regression\n screenshots, and anything inside it composites into every baseline.\n They sit inside the capture guard for the same reason the rulers and\n the pill do. -->\n <span class=\"vp-dim\">\n <span class=\"vp-dim__rule\"></span>\n <span class=\"vp-dim__v\">{{ viewportWidth() }} px</span>\n <span class=\"vp-dim__rule\"></span>\n </span>\n <div\n class=\"vp-grip\"\n prismResizer\n axis=\"x\"\n [scale]=\"-2 / (canvasService.zoom() || 1)\"\n [min]=\"VIEWPORT_MIN\"\n [max]=\"VIEWPORT_MAX\"\n [value]=\"viewportWidth()!\"\n (valueChange)=\"onViewportResize($event)\"\n aria-label=\"Viewport width, left edge\"\n [attr.aria-valuenow]=\"viewportWidth()\"\n [attr.aria-valuemin]=\"VIEWPORT_MIN\"\n [attr.aria-valuemax]=\"VIEWPORT_MAX\">\n <span class=\"vp-grip__bar\"></span>\n </div>\n <div\n class=\"vp-grip vp-grip--end\"\n prismResizer\n axis=\"x\"\n [scale]=\"2 / (canvasService.zoom() || 1)\"\n [min]=\"VIEWPORT_MIN\"\n [max]=\"VIEWPORT_MAX\"\n [value]=\"viewportWidth()!\"\n (valueChange)=\"onViewportResize($event)\"\n aria-label=\"Viewport width, right edge\"\n [attr.aria-valuenow]=\"viewportWidth()\"\n [attr.aria-valuemin]=\"VIEWPORT_MIN\"\n [attr.aria-valuemax]=\"VIEWPORT_MAX\">\n <span class=\"vp-grip__bar\"></span>\n </div>\n }\n }\n\n <div\n class=\"demo-wrap\"\n [style.--zoom]=\"canvasService.zoom()\"\n [attr.data-prism-rendered]=\"renderedKey()\"\n [attr.data-canvas-layout]=\"canvasLayout()\"\n [attr.data-viewport]=\"viewportWidth() !== null ? '' : null\">\n <ng-container #outlet />\n @if (activeOverlay()) {\n <ng-container *ngComponentOutlet=\"activeOverlay()!; inputs: overlayInputs; injector: overlayInjector()\" />\n }\n </div>\n</div>\n", styles: [":host {\n display: block;\n flex: 1;\n min-height: 0;\n}\n\n.prism-canvas-stage {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 200px;\n padding: 32px;\n overflow: auto;\n\n /* The edge is outline + shadow, never border and never extra padding.\n plugin-visual-regression screenshots .demo-wrap, which is centred in\n this element; a border would shrink the content box by 2px and move\n that centre, shifting all 15 baselines in test-workspace/vrt/baseline\n without a single component having changed. Capture mode resets this\n element's padding but not its border, and this repo has no VRT runner\n to catch the drift. outline and box-shadow do not participate in\n layout, so the box is provably unchanged. Keep it that way.\n They do still paint, and outline-offset is negative, so the line lands\n inside the box: CAPTURE_STYLES in prism-capture.service.ts sets both\n to none, which is only safe because neither affects layout here. */\n outline: 1px solid var(--prism-stage-edge);\n outline-offset: -1px;\n background-color: var(--prism-stage);\n box-shadow:\n 0 1px 3px rgb(0 0 0 / 10%),\n 0 8px 24px -12px rgb(0 0 0 / 18%);\n transition: filter var(--dur-base);\n\n --prism-canvas-overlay-top: 12px;\n --prism-canvas-overlay-inline: 20px;\n}\n\n.prism-canvas-stage[data-rulers] {\n --prism-canvas-overlay-top: 28px;\n --prism-canvas-overlay-inline: 28px;\n}\n\n.stage-crosshair {\n position: absolute;\n inset: 0;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--dur-base);\n}\n\n.stage-crosshair.visible {\n opacity: 1;\n}\n\n.stage-crosshair::before,\n.stage-crosshair::after {\n position: absolute;\n content: '';\n background: color-mix(in srgb, var(--prism-primary) 20%, transparent);\n}\n\n.stage-crosshair::before {\n top: 50%;\n right: 0;\n left: 0;\n height: 1px;\n}\n\n.stage-crosshair::after {\n top: 0;\n bottom: 0;\n left: 50%;\n width: 1px;\n}\n\n.demo-wrap {\n position: relative;\n display: inline-block;\n transform: scale(var(--zoom, 1));\n transition: transform 0.18s;\n}\n\n.demo-wrap[data-canvas-layout='stretch'] {\n display: block;\n width: 100%;\n max-width: 800px;\n}\n\n/* max-width: none rather than min(800px, var(--prism-vp-w)): an explicitly\n requested width beats a layout default, and min() would silently cap a\n 1024 viewport at 800 on any component declaring canvasLayout:\n 'stretch'.\n\n container-type must stay confined to this rule. It implies contain: inline-size, which on the width:auto\n inline-block .demo-wrap is at rest would decouple its width from its\n contents, collapsing the box and shifting every baseline in\n test-workspace/vrt/baseline without a component having changed. Here\n the width is explicit, so containment costs nothing and is what makes\n a component's own @container rules respond. Media queries do not and\n cannot: they read the real browser viewport.\n\n grid + justify-items: center, and not text-align: center, which is the\n obvious way to centre an inline-level child and the wrong one. The\n showcase component is created through ViewContainerRef, so its host\n element carries none of this component's _ngcontent attribute and no\n scoped rule here can reach it to undo an inherited value. text-align\n would therefore leak all the way into the specimen and silently\n re-align its own text the moment the viewport is switched on. That is a\n canvas that lies about what it is showing. Centring at the container\n instead touches nothing inside.\n\n Shrinking is not a side effect of that choice, it is the resting\n behaviour preserved: at rest .demo-wrap is an inline-block that\n already shrink-wraps its child, so a block-level specimen sizes to its\n content here the same as with the constraint off. The implicit\n auto column still fills the declared width, so a component that asks\n for width: 100% (the canvasLayout: 'stretch' case) keeps getting the\n whole viewport. */\n.demo-wrap[data-viewport] {\n display: grid;\n\n /* flex: none is required. The stage is a flex container\n and this is its only item, so the default flex-shrink: 1 lets the\n box render narrower than the width just asked for whenever the\n canvas is the smaller of the two, and container-type below drops\n the automatic minimum size to zero, so nothing stops the shrink.\n The result is the one failure this whole feature cannot afford:\n the dimension line states 1024 while every @container rule in the\n specimen answers whatever the canvas happened to allow. The stage\n is overflow: auto, so refusing to shrink scrolls instead. */\n flex: none;\n\n /* safe center, not bare center. Centring is right while the specimen\n fits and wrong the moment it does not: bare centring spills an\n over-wide specimen equally past both edges, where a real viewport of\n that width clips at zero and scrolls in one direction. The safe\n keyword falls back to start only when the item overflows, which\n is the browser making a case distinction CSS cannot otherwise\n express. */\n justify-items: safe center;\n width: var(--prism-vp-w);\n max-width: none;\n container-type: inline-size;\n}\n\n/* Both grips derive their position arithmetically, because .demo-wrap is\n centred by the stage's own flexbox and then scaled in place by\n transform: scale(var(--zoom)): the transform preserves that centre, so\n each edge sits half the *painted* width (--prism-vp-w times --zoom) away\n from the middle. No measurement, no ResizeObserver, and nothing to\n fall out of step when either the width or the zoom changes.\n\n The grip's own [scale] input (in the template) undoes the same factor\n in the other direction: a pointer that has moved dx across the painted\n box must change --prism-vp-w by dx / zoom for the grip to stay under the\n cursor, so the directive multiplier is 2 / zoom on the right grip and\n -2 / zoom on the left, not the flat \u00B12 a permanent zoom of 1 would\n need. */\n.vp-grip {\n position: absolute;\n top: var(--prism-canvas-overlay-top, 12px);\n bottom: 0;\n left: calc(50% - var(--prism-vp-w) * var(--zoom, 1) / 2 - 4.5px);\n z-index: 4;\n display: grid;\n width: 9px;\n\n /* The element is the guide line's full-height track and must not be\n clickable. It runs from the overlay band to the\n bottom of the stage at z-index 4, straight over prism-canvas-bg-pill\n at z-index 2, so leaving it hit-testable made part of the pill's\n Reset button unreachable whenever a viewport was on. Only the bar\n below takes pointer events back. */\n pointer-events: none;\n background: transparent;\n}\n\n.vp-grip--end {\n right: calc(50% - var(--prism-vp-w) * var(--zoom, 1) / 2 - 4.5px);\n left: auto;\n}\n\n/* The part you grab, and the only part of the grip that takes pointer\n events back. It shares the guide line's grid cell (hence the matching\n grid-area) and is raised above it so the 1px rule does not paint a\n seam down the middle of the 3px bar.\n\n The padding is the hit box and the background is the bar: content-box\n sizing plus background-clip: content-box paints 3x34 while leaving\n 9x44 clickable, so the target is comfortable without the mark growing\n to match. It is still narrow for WCAG 2.5.8, which the Width chooser\n in the tools menu answers: the same widths are reachable there, and\n both grips take Home/End and the arrow keys. */\n.vp-grip__bar {\n z-index: 1;\n box-sizing: content-box;\n grid-area: 1 / 1;\n place-self: center center;\n width: 3px;\n height: 34px;\n padding: 5px 3px;\n pointer-events: auto;\n background: color-mix(in srgb, var(--prism-measure) 80%, transparent);\n background-clip: content-box;\n border-radius: 2px;\n transition: background var(--dur-fast);\n}\n\n/* The edge itself, carried the whole height of the stage. Without it a\n grip is a floating nub that says where you may pull but not what it is\n pulling: the line is what makes the constrained region legible as a\n region rather than as two loose handles. Kept faint because it crosses\n the specimen, so it has to stay readable as chrome. */\n.vp-grip::after {\n grid-area: 1 / 1;\n place-self: stretch center;\n width: 1px;\n content: '';\n background: color-mix(in srgb, var(--prism-measure) 75%, transparent);\n transition: background var(--dur-fast);\n}\n\n.vp-grip:hover::after,\n.vp-grip.active::after,\n.vp-grip:focus-visible::after {\n background: color-mix(in srgb, var(--prism-measure) 55%, transparent);\n}\n\n.vp-grip:hover .vp-grip__bar,\n.vp-grip.active .vp-grip__bar,\n.vp-grip:focus-visible .vp-grip__bar {\n background: var(--prism-measure);\n background-clip: content-box;\n}\n\n/* The ring goes on the bar, not on the host: the host is the full-height\n track, and outlining that would draw a rule the length of the stage\n for a control 34px tall. */\n.vp-grip:focus-visible {\n outline: none;\n}\n\n.vp-grip:focus-visible .vp-grip__bar {\n outline: 2px solid var(--prism-primary);\n outline-offset: 1px;\n}\n\n/* The third resident of the overlay band: pill left, dimension centre,\n rail right. It reads the same --prism-canvas-overlay-top the other two\n do, so switching rulers on moves all three together.\n\n Spans the painted width rather than sitting in the middle of it as a\n badge, and carries the same --prism-vp-w * --zoom the grips do so the\n three stay locked together. A badge states a number; a dimension line\n states which distance the number measures, and that is the whole\n claim this overlay makes. */\n.vp-dim {\n position: absolute;\n top: var(--prism-canvas-overlay-top, 12px);\n left: 50%;\n z-index: 4;\n display: flex;\n gap: var(--sp-3);\n align-items: center;\n width: calc(var(--prism-vp-w) * var(--zoom, 1));\n pointer-events: none;\n transform: translateX(-50%);\n}\n\n/* Two halves with the value in the gap, rather than one rule behind it:\n a line running under the digits would need a background plate to stay\n readable, and the plate is the badge this replaced. */\n.vp-dim__rule {\n position: relative;\n flex: 1;\n height: 1px;\n background: color-mix(in srgb, var(--prism-measure) 70%, transparent);\n}\n\n/* The end ticks. They are what make the rule read as a measurement of\n the span between them instead of as a divider laid across the canvas,\n and they mark the two edges the grips can be dragged to. */\n.vp-dim__rule::before {\n position: absolute;\n top: -3px;\n width: 1px;\n height: 7px;\n content: '';\n background: color-mix(in srgb, var(--prism-measure) 90%, transparent);\n}\n\n.vp-dim__rule:first-child::before {\n left: 0;\n}\n\n.vp-dim__rule:last-child::before {\n right: 0;\n}\n\n.vp-dim__v {\n flex: none;\n font-family: var(--font-mono);\n font-size: 9px;\n color: var(--prism-measure);\n white-space: nowrap;\n}\n", "\n [data-bg=\"dots\"] {\n background-image: radial-gradient(circle, var(--prism-dot) 1px, transparent 1px);\n background-size: 20px 20px;\n }\n\n [data-bg=\"plain\"] {\n background-image: none;\n }\n\n /* Flat, not dotted. \"light\" and \"dark\" name the surface a component was\n designed against, and their colour is absolute rather than a theme token,\n which makes them the values to declare for a screenshot baseline. Use\n \"dots\" for the grid. */\n /* These two also re-point --prism-measure. Other overlays use theme colours\n on theme surfaces, but these grounds ignore the theme: \"light\" stays\n near-white in the dark theme and \"dark\" stays near-black in the light one.\n The dark theme's magenta reaches only 2.85:1 on the light ground, under the\n 4.5:1 its 9px readout needs, so the measurement colour has to follow the\n ground, not the theme.\n\n --prism-measure-plate follows it for the same reason. It is the surface\n the measuring tool's value label paints itself on, so the label reads as a\n gap in the measurement line rather than a badge on top of it. At its\n --prism-stage fallback it would be the theme's stage under a re-pointed\n foreground: the light theme's magenta on the dark theme's stage reads\n 3.71:1, the dark theme's on white 3.08:1. Pinned to the ground the same way,\n the pairs reach 4.54:1 and 6.57:1. A color-mix against the ground would\n work too, but this file already states both grounds literally, and one\n mechanism per decision is enough.\n\n Literal values because this file is theme-independent, like the two\n grounds below. Keep them in step with --prism-measure in\n prism-default-theme.ts; semantic-colours.spec.ts fails if they drift. */\n [data-bg=\"light\"] {\n background-color: var(--prism-void-light, #f7f5fc);\n background-image: none;\n --prism-measure: #ca00c1;\n --prism-measure-plate: var(--prism-void-light, #f7f5fc);\n }\n [data-bg=\"dark\"] {\n background-color: var(--prism-void-dark, #07050f);\n background-image: none;\n --prism-measure: #f632ff;\n --prism-measure-plate: var(--prism-void-dark, #07050f);\n }\n\n /* \"transparent\" shares the checkerboard. In the app the checkerboard is\n already the UI's sign for \"no surface\", and a see-through stage would only\n show the shell behind it. Only CAPTURE_STYLES tells the two apart. */\n [data-bg=\"checker\"],\n [data-bg=\"transparent\"] {\n background-image:\n linear-gradient(45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(-45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--prism-border) 75%),\n linear-gradient(-45deg, transparent 75%, var(--prism-border) 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n }\n"] }]
|
|
343
|
+
args: [{ selector: 'prism-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [PrismCanvasRulersComponent, PrismCanvasBgPillComponent, PrismCanvasMeasureComponent, NgComponentOutlet, PrismResizerDirective], template: "<div\n class=\"prism-canvas-stage\"\n [attr.data-bg]=\"variantBg.effective()\"\n [attr.data-rulers]=\"canvasService.rulers() ? '' : null\"\n [attr.data-viewport]=\"viewportWidth() !== null ? '' : null\"\n [style.--prism-vp-w.px]=\"viewportWidth()\"\n [style.--zoom]=\"canvasService.zoom()\">\n @if (!capture.active()) {\n <div\n class=\"stage-crosshair\"\n [class.visible]=\"canvasService.guides()\"></div>\n <prism-canvas-rulers />\n @if (canvasService.measure()) {\n <prism-canvas-measure />\n }\n <prism-canvas-bg-pill />\n @if (viewportWidth() !== null) {\n <!-- Grips and the dimension line are siblings of .demo-wrap, never\n children of it: .demo-wrap is what plugin-visual-regression\n screenshots, and anything inside it composites into every baseline.\n They sit inside the capture guard for the same reason the rulers and\n the pill do. -->\n <span class=\"vp-dim\">\n <span class=\"vp-dim__rule\"></span>\n <span class=\"vp-dim__v\">{{ viewportWidth() }} px</span>\n <span class=\"vp-dim__rule\"></span>\n </span>\n <div\n class=\"vp-grip\"\n prismResizer\n axis=\"x\"\n [scale]=\"-2 / (canvasService.zoom() || 1)\"\n [min]=\"VIEWPORT_MIN\"\n [max]=\"VIEWPORT_MAX\"\n [value]=\"viewportWidth()!\"\n (valueChange)=\"onViewportResize($event)\"\n aria-label=\"Viewport width, left edge\"\n [attr.aria-valuenow]=\"viewportWidth()\"\n [attr.aria-valuemin]=\"VIEWPORT_MIN\"\n [attr.aria-valuemax]=\"VIEWPORT_MAX\">\n <span class=\"vp-grip__bar\"></span>\n </div>\n <div\n class=\"vp-grip vp-grip--end\"\n prismResizer\n axis=\"x\"\n [scale]=\"2 / (canvasService.zoom() || 1)\"\n [min]=\"VIEWPORT_MIN\"\n [max]=\"VIEWPORT_MAX\"\n [value]=\"viewportWidth()!\"\n (valueChange)=\"onViewportResize($event)\"\n aria-label=\"Viewport width, right edge\"\n [attr.aria-valuenow]=\"viewportWidth()\"\n [attr.aria-valuemin]=\"VIEWPORT_MIN\"\n [attr.aria-valuemax]=\"VIEWPORT_MAX\">\n <span class=\"vp-grip__bar\"></span>\n </div>\n }\n }\n\n <div\n class=\"demo-wrap\"\n [style.--zoom]=\"canvasService.zoom()\"\n [attr.data-prism-rendered]=\"renderedKey()\"\n [attr.data-canvas-layout]=\"canvasLayout()\"\n [attr.data-viewport]=\"viewportWidth() !== null ? '' : null\"\n [attr.data-pseudo]=\"forcedStates()\">\n <ng-container #outlet />\n @if (activeOverlay()) {\n <ng-container *ngComponentOutlet=\"activeOverlay()!; inputs: overlayInputs; injector: overlayInjector()\" />\n }\n </div>\n</div>\n", styles: [":host {\n display: block;\n flex: 1;\n min-height: 0;\n}\n\n.prism-canvas-stage {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 200px;\n padding: 32px;\n overflow: auto;\n\n /* The edge is outline + shadow, never border and never extra padding.\n plugin-visual-regression screenshots .demo-wrap, which is centred in\n this element; a border would shrink the content box by 2px and move\n that centre, shifting all 15 baselines in test-workspace/vrt/baseline\n without a single component having changed. Capture mode resets this\n element's padding but not its border, and this repo has no VRT runner\n to catch the drift. outline and box-shadow do not participate in\n layout, so the box is provably unchanged. Keep it that way.\n They do still paint, and outline-offset is negative, so the line lands\n inside the box: CAPTURE_STYLES in prism-capture.service.ts sets both\n to none, which is only safe because neither affects layout here. */\n outline: 1px solid var(--prism-stage-edge);\n outline-offset: -1px;\n background-color: var(--prism-stage);\n box-shadow:\n 0 1px 3px rgb(0 0 0 / 10%),\n 0 8px 24px -12px rgb(0 0 0 / 18%);\n transition: filter var(--dur-base);\n\n --prism-canvas-overlay-top: 12px;\n --prism-canvas-overlay-inline: 20px;\n}\n\n.prism-canvas-stage[data-rulers] {\n --prism-canvas-overlay-top: 28px;\n --prism-canvas-overlay-inline: 28px;\n}\n\n.stage-crosshair {\n position: absolute;\n inset: 0;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--dur-base);\n}\n\n.stage-crosshair.visible {\n opacity: 1;\n}\n\n.stage-crosshair::before,\n.stage-crosshair::after {\n position: absolute;\n content: '';\n background: color-mix(in srgb, var(--prism-primary) 20%, transparent);\n}\n\n.stage-crosshair::before {\n top: 50%;\n right: 0;\n left: 0;\n height: 1px;\n}\n\n.stage-crosshair::after {\n top: 0;\n bottom: 0;\n left: 50%;\n width: 1px;\n}\n\n.demo-wrap {\n position: relative;\n display: inline-block;\n transform: scale(var(--zoom, 1));\n transition: transform 0.18s;\n}\n\n.demo-wrap[data-canvas-layout='stretch'] {\n display: block;\n width: 100%;\n max-width: 800px;\n}\n\n/* max-width: none rather than min(800px, var(--prism-vp-w)): an explicitly\n requested width beats a layout default, and min() would silently cap a\n 1024 viewport at 800 on any component declaring canvasLayout:\n 'stretch'.\n\n container-type must stay confined to this rule. It implies contain: inline-size, which on the width:auto\n inline-block .demo-wrap is at rest would decouple its width from its\n contents, collapsing the box and shifting every baseline in\n test-workspace/vrt/baseline without a component having changed. Here\n the width is explicit, so containment costs nothing and is what makes\n a component's own @container rules respond. Media queries do not and\n cannot: they read the real browser viewport.\n\n grid + justify-items: center, and not text-align: center, which is the\n obvious way to centre an inline-level child and the wrong one. The\n showcase component is created through ViewContainerRef, so its host\n element carries none of this component's _ngcontent attribute and no\n scoped rule here can reach it to undo an inherited value. text-align\n would therefore leak all the way into the specimen and silently\n re-align its own text the moment the viewport is switched on. That is a\n canvas that lies about what it is showing. Centring at the container\n instead touches nothing inside.\n\n Shrinking is not a side effect of that choice, it is the resting\n behaviour preserved: at rest .demo-wrap is an inline-block that\n already shrink-wraps its child, so a block-level specimen sizes to its\n content here the same as with the constraint off. The implicit\n auto column still fills the declared width, so a component that asks\n for width: 100% (the canvasLayout: 'stretch' case) keeps getting the\n whole viewport. */\n.demo-wrap[data-viewport] {\n display: grid;\n\n /* flex: none is required. The stage is a flex container\n and this is its only item, so the default flex-shrink: 1 lets the\n box render narrower than the width just asked for whenever the\n canvas is the smaller of the two, and container-type below drops\n the automatic minimum size to zero, so nothing stops the shrink.\n The result is the one failure this whole feature cannot afford:\n the dimension line states 1024 while every @container rule in the\n specimen answers whatever the canvas happened to allow. The stage\n is overflow: auto, so refusing to shrink scrolls instead. */\n flex: none;\n\n /* safe center, not bare center. Centring is right while the specimen\n fits and wrong the moment it does not: bare centring spills an\n over-wide specimen equally past both edges, where a real viewport of\n that width clips at zero and scrolls in one direction. The safe\n keyword falls back to start only when the item overflows, which\n is the browser making a case distinction CSS cannot otherwise\n express. */\n justify-items: safe center;\n width: var(--prism-vp-w);\n max-width: none;\n container-type: inline-size;\n}\n\n/* Both grips derive their position arithmetically, because .demo-wrap is\n centred by the stage's own flexbox and then scaled in place by\n transform: scale(var(--zoom)): the transform preserves that centre, so\n each edge sits half the *painted* width (--prism-vp-w times --zoom) away\n from the middle. No measurement, no ResizeObserver, and nothing to\n fall out of step when either the width or the zoom changes.\n\n The grip's own [scale] input (in the template) undoes the same factor\n in the other direction: a pointer that has moved dx across the painted\n box must change --prism-vp-w by dx / zoom for the grip to stay under the\n cursor, so the directive multiplier is 2 / zoom on the right grip and\n -2 / zoom on the left, not the flat \u00B12 a permanent zoom of 1 would\n need. */\n.vp-grip {\n position: absolute;\n top: var(--prism-canvas-overlay-top, 12px);\n bottom: 0;\n left: calc(50% - var(--prism-vp-w) * var(--zoom, 1) / 2 - 4.5px);\n z-index: 4;\n display: grid;\n width: 9px;\n\n /* The element is the guide line's full-height track and must not be\n clickable. It runs from the overlay band to the\n bottom of the stage at z-index 4, straight over prism-canvas-bg-pill\n at z-index 2, so leaving it hit-testable made part of the pill's\n Reset button unreachable whenever a viewport was on. Only the bar\n below takes pointer events back. */\n pointer-events: none;\n background: transparent;\n}\n\n.vp-grip--end {\n right: calc(50% - var(--prism-vp-w) * var(--zoom, 1) / 2 - 4.5px);\n left: auto;\n}\n\n/* The part you grab, and the only part of the grip that takes pointer\n events back. It shares the guide line's grid cell (hence the matching\n grid-area) and is raised above it so the 1px rule does not paint a\n seam down the middle of the 3px bar.\n\n The padding is the hit box and the background is the bar: content-box\n sizing plus background-clip: content-box paints 3x34 while leaving\n 9x44 clickable, so the target is comfortable without the mark growing\n to match. It is still narrow for WCAG 2.5.8, which the Width chooser\n in the tools menu answers: the same widths are reachable there, and\n both grips take Home/End and the arrow keys. */\n.vp-grip__bar {\n z-index: 1;\n box-sizing: content-box;\n grid-area: 1 / 1;\n place-self: center center;\n width: 3px;\n height: 34px;\n padding: 5px 3px;\n pointer-events: auto;\n background: color-mix(in srgb, var(--prism-measure) 80%, transparent);\n background-clip: content-box;\n border-radius: 2px;\n transition: background var(--dur-fast);\n}\n\n/* The edge itself, carried the whole height of the stage. Without it a\n grip is a floating nub that says where you may pull but not what it is\n pulling: the line is what makes the constrained region legible as a\n region rather than as two loose handles. Kept faint because it crosses\n the specimen, so it has to stay readable as chrome. */\n.vp-grip::after {\n grid-area: 1 / 1;\n place-self: stretch center;\n width: 1px;\n content: '';\n background: color-mix(in srgb, var(--prism-measure) 75%, transparent);\n transition: background var(--dur-fast);\n}\n\n.vp-grip:hover::after,\n.vp-grip.active::after,\n.vp-grip:focus-visible::after {\n background: color-mix(in srgb, var(--prism-measure) 55%, transparent);\n}\n\n.vp-grip:hover .vp-grip__bar,\n.vp-grip.active .vp-grip__bar,\n.vp-grip:focus-visible .vp-grip__bar {\n background: var(--prism-measure);\n background-clip: content-box;\n}\n\n/* The ring goes on the bar, not on the host: the host is the full-height\n track, and outlining that would draw a rule the length of the stage\n for a control 34px tall. */\n.vp-grip:focus-visible {\n outline: none;\n}\n\n.vp-grip:focus-visible .vp-grip__bar {\n outline: 2px solid var(--prism-primary);\n outline-offset: 1px;\n}\n\n/* The third resident of the overlay band: pill left, dimension centre,\n rail right. It reads the same --prism-canvas-overlay-top the other two\n do, so switching rulers on moves all three together.\n\n Spans the painted width rather than sitting in the middle of it as a\n badge, and carries the same --prism-vp-w * --zoom the grips do so the\n three stay locked together. A badge states a number; a dimension line\n states which distance the number measures, and that is the whole\n claim this overlay makes. */\n.vp-dim {\n position: absolute;\n top: var(--prism-canvas-overlay-top, 12px);\n left: 50%;\n z-index: 4;\n display: flex;\n gap: var(--sp-3);\n align-items: center;\n width: calc(var(--prism-vp-w) * var(--zoom, 1));\n pointer-events: none;\n transform: translateX(-50%);\n}\n\n/* Two halves with the value in the gap, rather than one rule behind it:\n a line running under the digits would need a background plate to stay\n readable, and the plate is the badge this replaced. */\n.vp-dim__rule {\n position: relative;\n flex: 1;\n height: 1px;\n background: color-mix(in srgb, var(--prism-measure) 70%, transparent);\n}\n\n/* The end ticks. They are what make the rule read as a measurement of\n the span between them instead of as a divider laid across the canvas,\n and they mark the two edges the grips can be dragged to. */\n.vp-dim__rule::before {\n position: absolute;\n top: -3px;\n width: 1px;\n height: 7px;\n content: '';\n background: color-mix(in srgb, var(--prism-measure) 90%, transparent);\n}\n\n.vp-dim__rule:first-child::before {\n left: 0;\n}\n\n.vp-dim__rule:last-child::before {\n right: 0;\n}\n\n.vp-dim__v {\n flex: none;\n font-family: var(--font-mono);\n font-size: 9px;\n color: var(--prism-measure);\n white-space: nowrap;\n}\n", "\n [data-bg=\"dots\"] {\n background-image: radial-gradient(circle, var(--prism-dot) 1px, transparent 1px);\n background-size: 20px 20px;\n }\n\n [data-bg=\"plain\"] {\n background-image: none;\n }\n\n /* Flat, not dotted. \"light\" and \"dark\" name the surface a component was\n designed against, and their colour is absolute rather than a theme token,\n which makes them the values to declare for a screenshot baseline. Use\n \"dots\" for the grid. */\n /* These two also re-point --prism-measure. Other overlays use theme colours\n on theme surfaces, but these grounds ignore the theme: \"light\" stays\n near-white in the dark theme and \"dark\" stays near-black in the light one.\n The dark theme's magenta reaches only 2.85:1 on the light ground, under the\n 4.5:1 its 9px readout needs, so the measurement colour has to follow the\n ground, not the theme.\n\n --prism-measure-plate follows it for the same reason. It is the surface\n the measuring tool's value label paints itself on, so the label reads as a\n gap in the measurement line rather than a badge on top of it. At its\n --prism-stage fallback it would be the theme's stage under a re-pointed\n foreground: the light theme's magenta on the dark theme's stage reads\n 3.71:1, the dark theme's on white 3.08:1. Pinned to the ground the same way,\n the pairs reach 4.54:1 and 6.57:1. A color-mix against the ground would\n work too, but this file already states both grounds literally, and one\n mechanism per decision is enough.\n\n Literal values because this file is theme-independent, like the two\n grounds below. Keep them in step with --prism-measure in\n prism-default-theme.ts; semantic-colours.spec.ts fails if they drift. */\n [data-bg=\"light\"] {\n background-color: var(--prism-void-light, #f7f5fc);\n background-image: none;\n --prism-measure: #ca00c1;\n --prism-measure-plate: var(--prism-void-light, #f7f5fc);\n }\n [data-bg=\"dark\"] {\n background-color: var(--prism-void-dark, #07050f);\n background-image: none;\n --prism-measure: #f632ff;\n --prism-measure-plate: var(--prism-void-dark, #07050f);\n }\n\n /* \"transparent\" shares the checkerboard. In the app the checkerboard is\n already the UI's sign for \"no surface\", and a see-through stage would only\n show the shell behind it. Only CAPTURE_STYLES tells the two apart. */\n [data-bg=\"checker\"],\n [data-bg=\"transparent\"] {\n background-image:\n linear-gradient(45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(-45deg, var(--prism-border) 25%, transparent 25%),\n linear-gradient(45deg, transparent 75%, var(--prism-border) 75%),\n linear-gradient(-45deg, transparent 75%, var(--prism-border) 75%);\n background-size: 16px 16px;\n background-position: 0 0, 0 8px, 8px -8px, -8px 0;\n }\n"] }]
|
|
320
344
|
}], () => [], { outlet: [{ type: i0.ViewChild, args: ['outlet', { ...{
|
|
321
345
|
read: ViewContainerRef
|
|
322
346
|
}, isSignal: true }] }] }); })();
|
|
323
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PrismRendererComponent, { className: "PrismRendererComponent", filePath: "app/renderer/prism-renderer.component.ts", lineNumber:
|
|
347
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PrismRendererComponent, { className: "PrismRendererComponent", filePath: "app/renderer/prism-renderer.component.ts", lineNumber: 54 }); })();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RuntimeComponent } from '../../plugin/plugin.types.js';
|
|
2
|
+
import type { ForcedPseudoStates } from '../../shared/pseudo-state.type.js';
|
|
3
|
+
import { type AppliedPseudoStates } from '../pseudo/pseudo-state-marker.js';
|
|
4
|
+
export interface RenderedKeyInput {
|
|
5
|
+
component: RuntimeComponent | null;
|
|
6
|
+
variantIndex: number;
|
|
7
|
+
/** The rendered component's host element, `null` while nothing is rendered. */
|
|
8
|
+
element: Element | null;
|
|
9
|
+
/** The pseudo states the variant forces, `null` when it forces none. */
|
|
10
|
+
pseudo: ForcedPseudoStates | null;
|
|
11
|
+
/** What the canvas marker has the states in place for. */
|
|
12
|
+
pseudoApplied: AppliedPseudoStates | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The value of `data-prism-rendered` on `.demo-wrap`, or `null` while the
|
|
16
|
+
* variant is not ready to be inspected.
|
|
17
|
+
*
|
|
18
|
+
* Screenshot runners wait on this marker, so a variant that forces pseudo
|
|
19
|
+
* states only gets it once those exact states are in place on this exact
|
|
20
|
+
* element. A runner then captures the forced state with no change on its side.
|
|
21
|
+
* A variant without forced states is not held back.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveRenderedKey({ component, variantIndex, element, pseudo, pseudoApplied }: RenderedKeyInput): string | null;
|
|
24
|
+
//# sourceMappingURL=rendered-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rendered-key.d.ts","sourceRoot":"","sources":["../../../src/app/renderer/rendered-key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,KAAK,mBAAmB,EAAkB,MAAM,kCAAkC,CAAC;AAE5F,MAAM,WAAW,gBAAgB;IAC7B,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,wEAAwE;IACxE,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAClC,0DAA0D;IAC1D,aAAa,EAAE,mBAAmB,GAAG,IAAI,CAAC;CAC7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,gBAAgB,GAAG,MAAM,GAAG,IAAI,CAI/H"}
|