@printwithsynergy/artwork-pdf-editor 0.3.0 → 0.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/dist/components/ContrastLegibilityPanel.d.ts +71 -0
- package/dist/components/ContrastLegibilityPanel.d.ts.map +1 -0
- package/dist/components/ContrastLegibilityPanel.js +123 -0
- package/dist/components/ContrastLegibilityPanel.js.map +1 -0
- package/dist/components/DirectionIndicatorsOverlay.d.ts +55 -0
- package/dist/components/DirectionIndicatorsOverlay.d.ts.map +1 -0
- package/dist/components/DirectionIndicatorsOverlay.js +126 -0
- package/dist/components/DirectionIndicatorsOverlay.js.map +1 -0
- package/dist/components/StreamingRenderProgress.d.ts +60 -0
- package/dist/components/StreamingRenderProgress.d.ts.map +1 -0
- package/dist/components/StreamingRenderProgress.js +99 -0
- package/dist/components/StreamingRenderProgress.js.map +1 -0
- package/dist/components/SubstrateSimOverlay.d.ts +56 -0
- package/dist/components/SubstrateSimOverlay.d.ts.map +1 -0
- package/dist/components/SubstrateSimOverlay.js +39 -0
- package/dist/components/SubstrateSimOverlay.js.map +1 -0
- package/dist/components/wave4-extras.d.ts +326 -0
- package/dist/components/wave4-extras.d.ts.map +1 -0
- package/dist/components/wave4-extras.js +264 -0
- package/dist/components/wave4-extras.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/editor-config.d.ts +41 -1
- package/dist/lib/editor-config.d.ts.map +1 -1
- package/dist/lib/editor-config.js +15 -0
- package/dist/lib/editor-config.js.map +1 -1
- package/dist/lib/palette-registry.d.ts.map +1 -1
- package/dist/lib/palette-registry.js +14 -0
- package/dist/lib/palette-registry.js.map +1 -1
- package/dist/lib/streaming-render.d.ts +100 -0
- package/dist/lib/streaming-render.d.ts.map +1 -0
- package/dist/lib/streaming-render.js +132 -0
- package/dist/lib/streaming-render.js.map +1 -0
- package/dist/lib/structural-export.d.ts +84 -0
- package/dist/lib/structural-export.d.ts.map +1 -0
- package/dist/lib/structural-export.js +100 -0
- package/dist/lib/structural-export.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wave 4 P4 — Print contrast / legibility panel.
|
|
3
|
+
*
|
|
4
|
+
* Print contrast and screen contrast are different problems —
|
|
5
|
+
* what passes WCAG digital can fail on uncoated kraft. P4
|
|
6
|
+
* surfaces ink-vs-substrate Lab ΔE / neutral-density contrast,
|
|
7
|
+
* min legible text size, and reverse-on-busy-image warnings
|
|
8
|
+
* sourced from a host-supplied loader (typically lint-pdf's
|
|
9
|
+
* print-contrast analyzer).
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
import type { ReactElement } from "react";
|
|
14
|
+
/** @public */
|
|
15
|
+
export type ContrastLegibilitySeverity = "error" | "warn" | "info";
|
|
16
|
+
/** @public */
|
|
17
|
+
export type ContrastLegibilityCategory = "contrast" | "text-size" | "reverse-on-image" | "neutral-density" | "other";
|
|
18
|
+
/** @public */
|
|
19
|
+
export type ContrastLegibilityFinding = {
|
|
20
|
+
id: string;
|
|
21
|
+
category: ContrastLegibilityCategory;
|
|
22
|
+
severity: ContrastLegibilitySeverity;
|
|
23
|
+
summary: string;
|
|
24
|
+
recommendation?: string;
|
|
25
|
+
objectId?: string;
|
|
26
|
+
deltaE?: number;
|
|
27
|
+
};
|
|
28
|
+
/** @public */
|
|
29
|
+
export type ContrastLegibilityLoaderFn = () => Promise<readonly ContrastLegibilityFinding[]>;
|
|
30
|
+
/** @public */
|
|
31
|
+
export type ContrastLegibilityFilter = {
|
|
32
|
+
severity?: ContrastLegibilitySeverity;
|
|
33
|
+
category?: ContrastLegibilityCategory;
|
|
34
|
+
};
|
|
35
|
+
/** @public */
|
|
36
|
+
export type ContrastLegibilityGroup = {
|
|
37
|
+
severity: ContrastLegibilitySeverity;
|
|
38
|
+
findings: readonly ContrastLegibilityFinding[];
|
|
39
|
+
};
|
|
40
|
+
/** @public */
|
|
41
|
+
export declare const CONTRAST_LEGIBILITY_SEVERITY_ORDER: readonly ContrastLegibilitySeverity[];
|
|
42
|
+
/**
|
|
43
|
+
* Pure helper — filters by severity / category. Returns a new
|
|
44
|
+
* array preserving input order. Pure function.
|
|
45
|
+
*
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
export declare function filterContrastLegibilityFindings(findings: readonly ContrastLegibilityFinding[], filter: ContrastLegibilityFilter): readonly ContrastLegibilityFinding[];
|
|
49
|
+
/**
|
|
50
|
+
* Pure helper — groups findings by severity in
|
|
51
|
+
* {@link CONTRAST_LEGIBILITY_SEVERITY_ORDER}. Always returns a
|
|
52
|
+
* stable three-bucket shape. Pure function.
|
|
53
|
+
*
|
|
54
|
+
* @public
|
|
55
|
+
*/
|
|
56
|
+
export declare function groupContrastLegibilityFindingsBySeverity(findings: readonly ContrastLegibilityFinding[]): readonly ContrastLegibilityGroup[];
|
|
57
|
+
/** @public */
|
|
58
|
+
export type ContrastLegibilityPanelProps = {
|
|
59
|
+
loader: ContrastLegibilityLoaderFn;
|
|
60
|
+
filterSeverity?: ContrastLegibilitySeverity;
|
|
61
|
+
filterCategory?: ContrastLegibilityCategory;
|
|
62
|
+
onSelect?: (finding: ContrastLegibilityFinding) => void;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Stateful panel — loads finding stream, surfaces filtered +
|
|
66
|
+
* grouped list, emits onSelect on row click.
|
|
67
|
+
*
|
|
68
|
+
* @public
|
|
69
|
+
*/
|
|
70
|
+
export declare function ContrastLegibilityPanel({ loader, filterSeverity, filterCategory, onSelect, }: ContrastLegibilityPanelProps): ReactElement;
|
|
71
|
+
//# sourceMappingURL=ContrastLegibilityPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContrastLegibilityPanel.d.ts","sourceRoot":"","sources":["../../src/components/ContrastLegibilityPanel.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C,cAAc;AACd,MAAM,MAAM,0BAA0B,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AACnE,cAAc;AACd,MAAM,MAAM,0BAA0B,GAClC,UAAU,GACV,WAAW,GACX,kBAAkB,GAClB,iBAAiB,GACjB,OAAO,CAAC;AACZ,cAAc;AACd,MAAM,MAAM,yBAAyB,GAAG;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,0BAA0B,CAAC;IACrC,QAAQ,EAAE,0BAA0B,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AACF,cAAc;AACd,MAAM,MAAM,0BAA0B,GAAG,MAAM,OAAO,CAAC,SAAS,yBAAyB,EAAE,CAAC,CAAC;AAC7F,cAAc;AACd,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,CAAC,EAAE,0BAA0B,CAAC;IACtC,QAAQ,CAAC,EAAE,0BAA0B,CAAC;CACvC,CAAC;AACF,cAAc;AACd,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,0BAA0B,CAAC;IACrC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,CAAC;CAChD,CAAC;AAEF,cAAc;AACd,eAAO,MAAM,kCAAkC,EAAE,SAAS,0BAA0B,EAInF,CAAC;AAQF;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,SAAS,yBAAyB,EAAE,EAC9C,MAAM,EAAE,wBAAwB,GAC/B,SAAS,yBAAyB,EAAE,CAMtC;AAED;;;;;;GAMG;AACH,wBAAgB,yCAAyC,CACvD,QAAQ,EAAE,SAAS,yBAAyB,EAAE,GAC7C,SAAS,uBAAuB,EAAE,CASpC;AAED,cAAc;AACd,MAAM,MAAM,4BAA4B,GAAG;IACzC,MAAM,EAAE,0BAA0B,CAAC;IACnC,cAAc,CAAC,EAAE,0BAA0B,CAAC;IAC5C,cAAc,CAAC,EAAE,0BAA0B,CAAC;IAC5C,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,IAAI,CAAC;CACzD,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,MAAM,EACN,cAAc,EACd,cAAc,EACd,QAAQ,GACT,EAAE,4BAA4B,GAAG,YAAY,CAgI7C"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
"use client";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useEffect, useMemo, useState } from "react";
|
|
5
|
+
/** @public */
|
|
6
|
+
export const CONTRAST_LEGIBILITY_SEVERITY_ORDER = [
|
|
7
|
+
"error",
|
|
8
|
+
"warn",
|
|
9
|
+
"info",
|
|
10
|
+
];
|
|
11
|
+
const SEVERITY_COLORS = {
|
|
12
|
+
error: "#a00",
|
|
13
|
+
warn: "#a60",
|
|
14
|
+
info: "#06a",
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Pure helper — filters by severity / category. Returns a new
|
|
18
|
+
* array preserving input order. Pure function.
|
|
19
|
+
*
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
export function filterContrastLegibilityFindings(findings, filter) {
|
|
23
|
+
return findings.filter((f) => {
|
|
24
|
+
if (filter.severity && f.severity !== filter.severity)
|
|
25
|
+
return false;
|
|
26
|
+
if (filter.category && f.category !== filter.category)
|
|
27
|
+
return false;
|
|
28
|
+
return true;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Pure helper — groups findings by severity in
|
|
33
|
+
* {@link CONTRAST_LEGIBILITY_SEVERITY_ORDER}. Always returns a
|
|
34
|
+
* stable three-bucket shape. Pure function.
|
|
35
|
+
*
|
|
36
|
+
* @public
|
|
37
|
+
*/
|
|
38
|
+
export function groupContrastLegibilityFindingsBySeverity(findings) {
|
|
39
|
+
const buckets = new Map(CONTRAST_LEGIBILITY_SEVERITY_ORDER.map((s) => [s, []]));
|
|
40
|
+
for (const f of findings)
|
|
41
|
+
buckets.get(f.severity)?.push(f);
|
|
42
|
+
return CONTRAST_LEGIBILITY_SEVERITY_ORDER.map((severity) => ({
|
|
43
|
+
severity,
|
|
44
|
+
findings: buckets.get(severity) ?? [],
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Stateful panel — loads finding stream, surfaces filtered +
|
|
49
|
+
* grouped list, emits onSelect on row click.
|
|
50
|
+
*
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
export function ContrastLegibilityPanel({ loader, filterSeverity, filterCategory, onSelect, }) {
|
|
54
|
+
const [findings, setFindings] = useState(null);
|
|
55
|
+
const [error, setError] = useState(null);
|
|
56
|
+
const [loading, setLoading] = useState(true);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
let disposed = false;
|
|
59
|
+
setLoading(true);
|
|
60
|
+
setError(null);
|
|
61
|
+
setFindings(null);
|
|
62
|
+
void (async () => {
|
|
63
|
+
try {
|
|
64
|
+
const next = await loader();
|
|
65
|
+
if (!disposed)
|
|
66
|
+
setFindings(next);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
if (!disposed)
|
|
70
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
if (!disposed)
|
|
74
|
+
setLoading(false);
|
|
75
|
+
}
|
|
76
|
+
})();
|
|
77
|
+
return () => {
|
|
78
|
+
disposed = true;
|
|
79
|
+
};
|
|
80
|
+
}, [loader]);
|
|
81
|
+
const groups = useMemo(() => {
|
|
82
|
+
if (!findings)
|
|
83
|
+
return null;
|
|
84
|
+
const filtered = filterContrastLegibilityFindings(findings, {
|
|
85
|
+
...(filterSeverity && { severity: filterSeverity }),
|
|
86
|
+
...(filterCategory && { category: filterCategory }),
|
|
87
|
+
});
|
|
88
|
+
return groupContrastLegibilityFindingsBySeverity(filtered);
|
|
89
|
+
}, [findings, filterSeverity, filterCategory]);
|
|
90
|
+
if (loading) {
|
|
91
|
+
return (_jsx("output", { "data-testid": "contrast-legibility-panel", "aria-live": "polite", style: { display: "block", padding: "0.5rem", opacity: 0.6 }, children: "Loading contrast / legibility findings\u2026" }));
|
|
92
|
+
}
|
|
93
|
+
if (error) {
|
|
94
|
+
return (_jsxs("div", { "data-testid": "contrast-legibility-panel", role: "alert", style: { padding: "0.5rem", color: "#a00" }, children: ["Couldn't load contrast / legibility findings: ", error] }));
|
|
95
|
+
}
|
|
96
|
+
if (!groups)
|
|
97
|
+
return _jsx("div", { "data-testid": "contrast-legibility-panel" });
|
|
98
|
+
const total = groups.reduce((s, g) => s + g.findings.length, 0);
|
|
99
|
+
return (_jsxs("div", { "data-testid": "contrast-legibility-panel", style: { padding: "0.5rem" }, children: [_jsx("header", { style: { marginBottom: "0.5rem" }, children: _jsxs("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: ["Contrast & legibility (", total, ")"] }) }), total === 0 && (_jsx("div", { style: { opacity: 0.6, fontSize: "0.875rem" }, children: findings && findings.length > 0
|
|
100
|
+
? "No findings match the current filter."
|
|
101
|
+
: "No contrast or legibility issues detected." })), groups.map((group) => {
|
|
102
|
+
if (group.findings.length === 0)
|
|
103
|
+
return null;
|
|
104
|
+
return (_jsxs("section", { "data-testid": `contrast-legibility-group-${group.severity}`, style: { marginBottom: "0.75rem" }, children: [_jsxs("h4", { style: {
|
|
105
|
+
margin: "0 0 0.25rem 0",
|
|
106
|
+
fontSize: "0.75rem",
|
|
107
|
+
color: SEVERITY_COLORS[group.severity],
|
|
108
|
+
textTransform: "uppercase",
|
|
109
|
+
letterSpacing: "0.05em",
|
|
110
|
+
}, children: [group.severity, " (", group.findings.length, ")"] }), _jsx("ul", { style: { listStyle: "none", padding: 0, margin: 0 }, children: group.findings.map((finding) => (_jsx("li", { style: { marginBottom: "0.25rem" }, children: onSelect ? (_jsxs("button", { type: "button", onClick: () => onSelect(finding), style: {
|
|
111
|
+
display: "block",
|
|
112
|
+
width: "100%",
|
|
113
|
+
padding: "0.375rem 0.5rem",
|
|
114
|
+
background: "transparent",
|
|
115
|
+
border: "1px solid #ddd",
|
|
116
|
+
borderRadius: 4,
|
|
117
|
+
textAlign: "left",
|
|
118
|
+
cursor: "pointer",
|
|
119
|
+
fontSize: "0.8125rem",
|
|
120
|
+
}, children: [finding.summary, finding.deltaE !== undefined && (_jsxs("span", { style: { color: "#595959", marginLeft: "0.375rem" }, children: ["(\u0394E ", finding.deltaE.toFixed(2), ")"] }))] })) : (_jsx("div", { style: { padding: "0.375rem 0.5rem", fontSize: "0.8125rem" }, children: finding.summary })) }, finding.id))) })] }, group.severity));
|
|
121
|
+
})] }));
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=ContrastLegibilityPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContrastLegibilityPanel.js","sourceRoot":"","sources":["../../src/components/ContrastLegibilityPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wave 4 S6 — Direction indicators overlay.
|
|
3
|
+
*
|
|
4
|
+
* Production needs to see non-printing context indicators that
|
|
5
|
+
* never make it into the final artwork: corrugated-flute axis,
|
|
6
|
+
* paper-grain axis, web-direction arrow, and an
|
|
7
|
+
* inside-vs-outside-print badge. None of these get written into
|
|
8
|
+
* the PDF — they're a non-printing overlay the editor renders on
|
|
9
|
+
* top of the canvas so the operator catches mirroring / grain
|
|
10
|
+
* mismatches before the file leaves the design seat.
|
|
11
|
+
*
|
|
12
|
+
* Pure-render component. Hosts pass in a
|
|
13
|
+
* {@link DirectionIndicatorsSpec}; the overlay positions a small
|
|
14
|
+
* legend chip + the four indicator markers at the page extents.
|
|
15
|
+
*
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
import { type ReactElement } from "react";
|
|
19
|
+
/**
|
|
20
|
+
* Direction-context spec emitted by the host (typically derived
|
|
21
|
+
* from `printContext.substrate` + per-page metadata).
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export type DirectionIndicatorsSpec = {
|
|
26
|
+
/** Page extents in pixels — matches the canvas viewport. */
|
|
27
|
+
widthPx: number;
|
|
28
|
+
heightPx: number;
|
|
29
|
+
/** Flute / grain axis. Absent = unknown (not rendered). */
|
|
30
|
+
fluteAxis?: "horizontal" | "vertical";
|
|
31
|
+
grainAxis?: "horizontal" | "vertical";
|
|
32
|
+
/** Web direction — the direction the substrate travels through
|
|
33
|
+
* the press. Absent = unknown (not rendered). */
|
|
34
|
+
webDirection?: "left-to-right" | "right-to-left" | "top-to-bottom" | "bottom-to-top";
|
|
35
|
+
/** Print side. When `"inside"`, the canvas should render the
|
|
36
|
+
* page mirrored — the editor surfaces this badge so the
|
|
37
|
+
* operator can confirm the right side is being authored. */
|
|
38
|
+
printSide?: "outside" | "inside";
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Props for the {@link DirectionIndicatorsOverlay}.
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
export type DirectionIndicatorsOverlayProps = {
|
|
46
|
+
spec: DirectionIndicatorsSpec;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Pure-render overlay. Anchored absolutely; consumers wrap the
|
|
50
|
+
* canvas + this in a relatively-positioned container.
|
|
51
|
+
*
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
export declare function DirectionIndicatorsOverlay({ spec, }: DirectionIndicatorsOverlayProps): ReactElement;
|
|
55
|
+
//# sourceMappingURL=DirectionIndicatorsOverlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DirectionIndicatorsOverlay.d.ts","sourceRoot":"","sources":["../../src/components/DirectionIndicatorsOverlay.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,OAAO,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACtC,SAAS,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACtC;sDACkD;IAClD,YAAY,CAAC,EAAE,eAAe,GAAG,eAAe,GAAG,eAAe,GAAG,eAAe,CAAC;IACrF;;iEAE6D;IAC7D,SAAS,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;CAClC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,uBAAuB,CAAC;CAC/B,CAAC;AAKF;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,IAAI,GACL,EAAE,+BAA+B,GAAG,YAAY,CAoFhD"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
"use client";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
/**
|
|
5
|
+
* Wave 4 S6 — Direction indicators overlay.
|
|
6
|
+
*
|
|
7
|
+
* Production needs to see non-printing context indicators that
|
|
8
|
+
* never make it into the final artwork: corrugated-flute axis,
|
|
9
|
+
* paper-grain axis, web-direction arrow, and an
|
|
10
|
+
* inside-vs-outside-print badge. None of these get written into
|
|
11
|
+
* the PDF — they're a non-printing overlay the editor renders on
|
|
12
|
+
* top of the canvas so the operator catches mirroring / grain
|
|
13
|
+
* mismatches before the file leaves the design seat.
|
|
14
|
+
*
|
|
15
|
+
* Pure-render component. Hosts pass in a
|
|
16
|
+
* {@link DirectionIndicatorsSpec}; the overlay positions a small
|
|
17
|
+
* legend chip + the four indicator markers at the page extents.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
import { useId } from "react";
|
|
22
|
+
const BADGE_BG = "rgba(20, 20, 20, 0.78)";
|
|
23
|
+
const BADGE_FG = "#f4ece6";
|
|
24
|
+
/**
|
|
25
|
+
* Pure-render overlay. Anchored absolutely; consumers wrap the
|
|
26
|
+
* canvas + this in a relatively-positioned container.
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export function DirectionIndicatorsOverlay({ spec, }) {
|
|
31
|
+
const { widthPx, heightPx, fluteAxis, grainAxis, webDirection, printSide, } = spec;
|
|
32
|
+
// Compose the legend line by line, skipping rows the host left
|
|
33
|
+
// unset so dieless-print jobs don't see a stub legend.
|
|
34
|
+
const legend = [];
|
|
35
|
+
if (fluteAxis)
|
|
36
|
+
legend.push(`flute: ${fluteAxis}`);
|
|
37
|
+
if (grainAxis)
|
|
38
|
+
legend.push(`grain: ${grainAxis}`);
|
|
39
|
+
if (webDirection)
|
|
40
|
+
legend.push(`web: ${webDirection}`);
|
|
41
|
+
if (printSide)
|
|
42
|
+
legend.push(`side: ${printSide}-print`);
|
|
43
|
+
return (_jsxs("div", { "data-testid": "direction-indicators-overlay", "aria-hidden": "true", style: {
|
|
44
|
+
position: "absolute",
|
|
45
|
+
top: 0,
|
|
46
|
+
left: 0,
|
|
47
|
+
width: widthPx,
|
|
48
|
+
height: heightPx,
|
|
49
|
+
pointerEvents: "none",
|
|
50
|
+
}, children: [fluteAxis && (_jsx(FluteHatch, { axis: fluteAxis, widthPx: widthPx, heightPx: heightPx })), webDirection && (_jsx(WebArrow, { direction: webDirection, widthPx: widthPx, heightPx: heightPx })), printSide === "inside" && (_jsx("div", { "data-testid": "direction-indicators-mirror-warning", style: {
|
|
51
|
+
position: "absolute",
|
|
52
|
+
top: 12,
|
|
53
|
+
right: 12,
|
|
54
|
+
padding: "0.25rem 0.5rem",
|
|
55
|
+
fontSize: "0.6875rem",
|
|
56
|
+
background: "#a00",
|
|
57
|
+
color: "#fff",
|
|
58
|
+
borderRadius: 4,
|
|
59
|
+
fontWeight: 600,
|
|
60
|
+
letterSpacing: "0.04em",
|
|
61
|
+
textTransform: "uppercase",
|
|
62
|
+
}, children: "INSIDE-PRINT \u2014 mirror before output" })), legend.length > 0 && (_jsx("div", { "data-testid": "direction-indicators-legend", style: {
|
|
63
|
+
position: "absolute",
|
|
64
|
+
bottom: 12,
|
|
65
|
+
left: 12,
|
|
66
|
+
padding: "0.375rem 0.5rem",
|
|
67
|
+
background: BADGE_BG,
|
|
68
|
+
color: BADGE_FG,
|
|
69
|
+
fontSize: "0.6875rem",
|
|
70
|
+
lineHeight: 1.4,
|
|
71
|
+
borderRadius: 4,
|
|
72
|
+
fontFamily: "monospace",
|
|
73
|
+
}, children: legend.map((row) => (_jsx("div", { children: row }, row))) }))] }));
|
|
74
|
+
}
|
|
75
|
+
function FluteHatch({ axis, widthPx, heightPx, }) {
|
|
76
|
+
// 16-line hatch across the page, faint enough not to obscure
|
|
77
|
+
// artwork. Horizontal flute → vertical hatch (perpendicular)
|
|
78
|
+
// and vice-versa — the hatch direction tracks the corrugated
|
|
79
|
+
// peak ridges, not the channel-axis.
|
|
80
|
+
const lines = 16;
|
|
81
|
+
const isVerticalHatch = axis === "horizontal";
|
|
82
|
+
return (_jsxs("svg", { "data-testid": "direction-indicators-flute-hatch", width: widthPx, height: heightPx, style: { position: "absolute", top: 0, left: 0, opacity: 0.18 }, children: [_jsx("title", { children: `flute hatch (${axis})` }), Array.from({ length: lines }, (_, i) => {
|
|
83
|
+
const t = (i + 0.5) / lines;
|
|
84
|
+
if (isVerticalHatch) {
|
|
85
|
+
const x = t * widthPx;
|
|
86
|
+
return (_jsx("line", { x1: x, y1: 0, x2: x, y2: heightPx, stroke: "#06a", strokeWidth: 1 }, i));
|
|
87
|
+
}
|
|
88
|
+
const y = t * heightPx;
|
|
89
|
+
return (_jsx("line", { x1: 0, y1: y, x2: widthPx, y2: y, stroke: "#06a", strokeWidth: 1 }, i));
|
|
90
|
+
})] }));
|
|
91
|
+
}
|
|
92
|
+
function WebArrow({ direction, widthPx, heightPx, }) {
|
|
93
|
+
// Per-instance marker id so multiple overlays in the same DOM
|
|
94
|
+
// (e.g. a multi-page editor with one indicator per page) don't
|
|
95
|
+
// collide on a shared `id="web-arrowhead"` — only one definition
|
|
96
|
+
// would be honoured and the rest would render unarrowed lines.
|
|
97
|
+
const rawId = useId();
|
|
98
|
+
const markerId = `web-arrowhead-${rawId.replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
99
|
+
const cx = widthPx / 2;
|
|
100
|
+
const cy = heightPx / 2;
|
|
101
|
+
const len = Math.min(widthPx, heightPx) * 0.5;
|
|
102
|
+
let x1 = cx;
|
|
103
|
+
let y1 = cy;
|
|
104
|
+
let x2 = cx;
|
|
105
|
+
let y2 = cy;
|
|
106
|
+
switch (direction) {
|
|
107
|
+
case "left-to-right":
|
|
108
|
+
x1 = cx - len / 2;
|
|
109
|
+
x2 = cx + len / 2;
|
|
110
|
+
break;
|
|
111
|
+
case "right-to-left":
|
|
112
|
+
x1 = cx + len / 2;
|
|
113
|
+
x2 = cx - len / 2;
|
|
114
|
+
break;
|
|
115
|
+
case "top-to-bottom":
|
|
116
|
+
y1 = cy - len / 2;
|
|
117
|
+
y2 = cy + len / 2;
|
|
118
|
+
break;
|
|
119
|
+
case "bottom-to-top":
|
|
120
|
+
y1 = cy + len / 2;
|
|
121
|
+
y2 = cy - len / 2;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
return (_jsxs("svg", { "data-testid": "direction-indicators-web-arrow", width: widthPx, height: heightPx, style: { position: "absolute", top: 0, left: 0, opacity: 0.5 }, children: [_jsx("title", { children: `web direction (${direction})` }), _jsx("defs", { children: _jsx("marker", { id: markerId, viewBox: "0 0 10 10", refX: 8, refY: 5, markerWidth: 6, markerHeight: 6, orient: "auto", children: _jsx("path", { d: "M0 0 L10 5 L0 10 z", fill: "#fc5102" }) }) }), _jsx("line", { x1: x1, y1: y1, x2: x2, y2: y2, stroke: "#fc5102", strokeWidth: 3, markerEnd: `url(#${markerId})` })] }));
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=DirectionIndicatorsOverlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DirectionIndicatorsOverlay.js","sourceRoot":"","sources":["../../src/components/DirectionIndicatorsOverlay.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wave 3 O3 — Streaming render progress panel.
|
|
3
|
+
*
|
|
4
|
+
* Shows live per-page progress for a long render that returns
|
|
5
|
+
* `text/event-stream` via `POST /v1/compose/stream`. The host wires
|
|
6
|
+
* a {@link StreamingRenderConnectFn} adapter (typically backed by an
|
|
7
|
+
* `EventSource` or a stubbed `AsyncIterable` for tests); the panel
|
|
8
|
+
* owns the event accumulator and renders the summary returned by
|
|
9
|
+
* {@link summarizeStreamingProgress}.
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
import type { ReactElement } from "react";
|
|
14
|
+
import { type StreamingRenderEvent } from "../lib/streaming-render";
|
|
15
|
+
/**
|
|
16
|
+
* Host adapter — opens a stream and returns an async iterable of
|
|
17
|
+
* events plus a `close()` to abort. The shape lets a host wire an
|
|
18
|
+
* `EventSource` over `/v1/compose/stream`, a `fetch()` with
|
|
19
|
+
* `ReadableStream`, or a test mock interchangeably.
|
|
20
|
+
*
|
|
21
|
+
* The panel iterates events until the stream ends; on unmount it
|
|
22
|
+
* calls `close()` to abort.
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export type StreamingRenderConnectFn = () => {
|
|
27
|
+
events: AsyncIterable<StreamingRenderEvent>;
|
|
28
|
+
close: () => void;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Configuration for the {@link StreamingRenderProgress}.
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export type StreamingRenderProgressProps = {
|
|
36
|
+
/** Connect adapter. When absent the panel renders in
|
|
37
|
+
* "ready to connect" mode and never opens a stream. */
|
|
38
|
+
connect?: StreamingRenderConnectFn;
|
|
39
|
+
/** Fires when the stream's `done` event lands — typically used
|
|
40
|
+
* to redirect to the rendered PDF or refresh the job list. */
|
|
41
|
+
onDone?: (info: {
|
|
42
|
+
pdfSha256: string;
|
|
43
|
+
cacheKey: string;
|
|
44
|
+
}) => void;
|
|
45
|
+
/** Fires when the stream emits an error event — typically used
|
|
46
|
+
* for telemetry / fallback to non-streaming render. */
|
|
47
|
+
onError?: (info: {
|
|
48
|
+
message: string;
|
|
49
|
+
code: string;
|
|
50
|
+
}) => void;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Stateful streaming-progress panel. Connects on mount when
|
|
54
|
+
* `connect` is supplied, accumulates events, surfaces summary +
|
|
55
|
+
* per-page badge list, and calls `onDone` / `onError` once.
|
|
56
|
+
*
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
export declare function StreamingRenderProgress({ connect, onDone, onError, }: StreamingRenderProgressProps): ReactElement;
|
|
60
|
+
//# sourceMappingURL=StreamingRenderProgress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StreamingRenderProgress.d.ts","sourceRoot":"","sources":["../../src/components/StreamingRenderProgress.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE1C,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;GAUG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM;IAC3C,MAAM,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;IAC5C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC;4DACwD;IACxD,OAAO,CAAC,EAAE,wBAAwB,CAAC;IACnC;mEAC+D;IAC/D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACjE;4DACwD;IACxD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC7D,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,OAAO,EACP,MAAM,EACN,OAAO,GACR,EAAE,4BAA4B,GAAG,YAAY,CAwI7C"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
"use client";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
import { summarizeStreamingProgress, } from "../lib/streaming-render";
|
|
6
|
+
/**
|
|
7
|
+
* Stateful streaming-progress panel. Connects on mount when
|
|
8
|
+
* `connect` is supplied, accumulates events, surfaces summary +
|
|
9
|
+
* per-page badge list, and calls `onDone` / `onError` once.
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export function StreamingRenderProgress({ connect, onDone, onError, }) {
|
|
14
|
+
const [events, setEvents] = useState([]);
|
|
15
|
+
const handlersRef = useRef({ onDone, onError });
|
|
16
|
+
handlersRef.current = { onDone, onError };
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!connect)
|
|
19
|
+
return;
|
|
20
|
+
const handle = connect();
|
|
21
|
+
let disposed = false;
|
|
22
|
+
void (async () => {
|
|
23
|
+
try {
|
|
24
|
+
for await (const ev of handle.events) {
|
|
25
|
+
if (disposed)
|
|
26
|
+
return;
|
|
27
|
+
setEvents((prev) => [...prev, ev]);
|
|
28
|
+
if (ev.kind === "done") {
|
|
29
|
+
handlersRef.current.onDone?.({
|
|
30
|
+
pdfSha256: ev.pdfSha256,
|
|
31
|
+
cacheKey: ev.cacheKey,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
else if (ev.kind === "error") {
|
|
35
|
+
handlersRef.current.onError?.({ message: ev.message, code: ev.code });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Stream tear-down — surface as a synthetic error event so
|
|
41
|
+
// the summarizer flips to "error" status without the
|
|
42
|
+
// consumer having to special-case missing events.
|
|
43
|
+
if (!disposed) {
|
|
44
|
+
setEvents((prev) => [
|
|
45
|
+
...prev,
|
|
46
|
+
{ kind: "error", message: "Stream closed unexpectedly.", code: "E_STREAM_ABORTED" },
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
})();
|
|
51
|
+
return () => {
|
|
52
|
+
disposed = true;
|
|
53
|
+
handle.close();
|
|
54
|
+
};
|
|
55
|
+
}, [connect]);
|
|
56
|
+
const summary = summarizeStreamingProgress(events);
|
|
57
|
+
return (_jsxs("div", { "data-testid": "streaming-render-progress", style: { padding: "0.5rem" }, children: [_jsxs("header", { style: {
|
|
58
|
+
display: "flex",
|
|
59
|
+
justifyContent: "space-between",
|
|
60
|
+
alignItems: "baseline",
|
|
61
|
+
marginBottom: "0.375rem",
|
|
62
|
+
}, children: [_jsx("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: "Render progress" }), _jsxs("span", { style: { fontSize: "0.75rem", color: "#595959" }, children: [summary.percent, "% \u00B7 ", summary.completedPages, "/", summary.totalPages || "?"] })] }), _jsx("div", { "aria-label": "Render progress", role: "progressbar", "aria-valuenow": summary.percent, "aria-valuemin": 0, "aria-valuemax": 100, style: {
|
|
63
|
+
background: "#eee",
|
|
64
|
+
height: 6,
|
|
65
|
+
borderRadius: 3,
|
|
66
|
+
overflow: "hidden",
|
|
67
|
+
marginBottom: "0.5rem",
|
|
68
|
+
}, children: _jsx("div", { style: {
|
|
69
|
+
width: `${summary.percent}%`,
|
|
70
|
+
height: "100%",
|
|
71
|
+
background: summary.status === "error"
|
|
72
|
+
? "#a00"
|
|
73
|
+
: summary.status === "done"
|
|
74
|
+
? "#080"
|
|
75
|
+
: "#06a",
|
|
76
|
+
transition: "width 200ms linear",
|
|
77
|
+
} }) }), summary.status === "error" && summary.errorMessage && (_jsx("div", { role: "alert", style: { fontSize: "0.75rem", color: "#a00", marginBottom: "0.375rem" }, children: summary.errorMessage })), summary.status !== "error" && summary.totalPages > 0 && (_jsx("ul", { "aria-label": "Per-page status", style: {
|
|
78
|
+
display: "flex",
|
|
79
|
+
flexWrap: "wrap",
|
|
80
|
+
gap: "0.25rem",
|
|
81
|
+
listStyle: "none",
|
|
82
|
+
padding: 0,
|
|
83
|
+
margin: 0,
|
|
84
|
+
}, children: Array.from({ length: summary.totalPages }, (_, i) => {
|
|
85
|
+
// O(1) lookup against the pre-computed Set so we don't
|
|
86
|
+
// re-scan the raw events array on every badge.
|
|
87
|
+
const done = summary.completedPageIndices.has(i);
|
|
88
|
+
const active = summary.currentPage === i;
|
|
89
|
+
const bg = done ? "#080" : active ? "#06a" : "#ccc";
|
|
90
|
+
return (_jsx("li", { title: `Page ${i + 1}: ${done ? "done" : active ? "rendering" : "pending"}`, style: {
|
|
91
|
+
width: 16,
|
|
92
|
+
height: 16,
|
|
93
|
+
borderRadius: 2,
|
|
94
|
+
background: bg,
|
|
95
|
+
border: "1px solid #999",
|
|
96
|
+
} }, i));
|
|
97
|
+
}) })), summary.receivedBytes > 0 && (_jsxs("div", { style: { fontSize: "0.6875rem", color: "#595959", marginTop: "0.375rem" }, children: [(summary.receivedBytes / 1024).toFixed(1), " KB received"] })), !connect && (_jsx("div", { style: { fontSize: "0.75rem", color: "#595959" }, children: "Streaming adapter not wired." }))] }));
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=StreamingRenderProgress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StreamingRenderProgress.js","sourceRoot":"","sources":["../../src/components/StreamingRenderProgress.tsx"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,YAAY,CAAC;;AAgBb,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAGL,0BAA0B,GAC3B,MAAM,yBAAyB,CAAC;AAmCjC;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,EACtC,OAAO,EACP,MAAM,EACN,OAAO,GACsB;IAC7B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAkC,EAAE,CAAC,CAAC;IAC1E,MAAM,WAAW,GAAG,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAChD,WAAW,CAAC,OAAO,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAE1C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,MAAM,GAAG,OAAO,EAAE,CAAC;QACzB,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC;gBACH,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBACrC,IAAI,QAAQ;wBAAE,OAAO;oBACrB,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;oBACnC,IAAI,EAAE,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;wBACvB,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;4BAC3B,SAAS,EAAE,EAAE,CAAC,SAAS;4BACvB,QAAQ,EAAE,EAAE,CAAC,QAAQ;yBACtB,CAAC,CAAC;oBACL,CAAC;yBAAM,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;wBAC/B,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;oBACxE,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,2DAA2D;gBAC3D,qDAAqD;gBACrD,kDAAkD;gBAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;wBAClB,GAAG,IAAI;wBACP,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,6BAA6B,EAAE,IAAI,EAAE,kBAAkB,EAAE;qBACpF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,GAAG,EAAE;YACV,QAAQ,GAAG,IAAI,CAAC;YAChB,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,MAAM,OAAO,GAAsB,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACtE,OAAO,CACL,8BAAiB,2BAA2B,EAAC,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,aACvE,kBACE,KAAK,EAAE;oBACL,OAAO,EAAE,MAAM;oBACf,cAAc,EAAE,eAAe;oBAC/B,UAAU,EAAE,UAAU;oBACtB,YAAY,EAAE,UAAU;iBACzB,aAED,aAAI,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,gCAAsB,EACpE,gBAAM,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,aACnD,OAAO,CAAC,OAAO,eAAM,OAAO,CAAC,cAAc,OAAG,OAAO,CAAC,UAAU,IAAI,GAAG,IACnE,IACA,EACT,4BACa,iBAAiB,EAC5B,IAAI,EAAC,aAAa,mBACH,OAAO,CAAC,OAAO,mBACf,CAAC,mBACD,GAAG,EAClB,KAAK,EAAE;oBACL,UAAU,EAAE,MAAM;oBAClB,MAAM,EAAE,CAAC;oBACT,YAAY,EAAE,CAAC;oBACf,QAAQ,EAAE,QAAQ;oBAClB,YAAY,EAAE,QAAQ;iBACvB,YAED,cACE,KAAK,EAAE;wBACL,KAAK,EAAE,GAAG,OAAO,CAAC,OAAO,GAAG;wBAC5B,MAAM,EAAE,MAAM;wBACd,UAAU,EACR,OAAO,CAAC,MAAM,KAAK,OAAO;4BACxB,CAAC,CAAC,MAAM;4BACR,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM;gCACzB,CAAC,CAAC,MAAM;gCACR,CAAC,CAAC,MAAM;wBACd,UAAU,EAAE,oBAAoB;qBACjC,GACD,GACE,EACL,OAAO,CAAC,MAAM,KAAK,OAAO,IAAI,OAAO,CAAC,YAAY,IAAI,CACrD,cAAK,IAAI,EAAC,OAAO,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,YACtF,OAAO,CAAC,YAAY,GACjB,CACP,EACA,OAAO,CAAC,MAAM,KAAK,OAAO,IAAI,OAAO,CAAC,UAAU,GAAG,CAAC,IAAI,CACvD,2BACa,iBAAiB,EAC5B,KAAK,EAAE;oBACL,OAAO,EAAE,MAAM;oBACf,QAAQ,EAAE,MAAM;oBAChB,GAAG,EAAE,SAAS;oBACd,SAAS,EAAE,MAAM;oBACjB,OAAO,EAAE,CAAC;oBACV,MAAM,EAAE,CAAC;iBACV,YAEA,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;oBACnD,uDAAuD;oBACvD,+CAA+C;oBAC/C,MAAM,IAAI,GAAG,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBACjD,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,KAAK,CAAC,CAAC;oBACzC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;oBACpD,OAAO,CACL,aAEE,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,EAAE,EAC3E,KAAK,EAAE;4BACL,KAAK,EAAE,EAAE;4BACT,MAAM,EAAE,EAAE;4BACV,YAAY,EAAE,CAAC;4BACf,UAAU,EAAE,EAAE;4BACd,MAAM,EAAE,gBAAgB;yBACzB,IARI,CAAC,CASN,CACH,CAAC;gBACJ,CAAC,CAAC,GACC,CACN,EACA,OAAO,CAAC,aAAa,GAAG,CAAC,IAAI,CAC5B,eAAK,KAAK,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,aAC3E,CAAC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,oBACtC,CACP,EACA,CAAC,OAAO,IAAI,CACX,cAAK,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,6CAE/C,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wave 4 P2 — Substrate show-through simulation overlay.
|
|
3
|
+
*
|
|
4
|
+
* White artboards hide everything the substrate will affect:
|
|
5
|
+
* kraft tints unprinted regions brown, metallised film reflects
|
|
6
|
+
* through low-opacity art, clear PE shows nothing where ink
|
|
7
|
+
* doesn't cover. P2 paints a substrate-coloured rectangle
|
|
8
|
+
* underneath the canvas so the operator sees what the press will
|
|
9
|
+
* actually deliver before exporting. Pairs with C2 (white
|
|
10
|
+
* underbase) — host can toggle the underbase on/off above this
|
|
11
|
+
* overlay to confirm masking.
|
|
12
|
+
*
|
|
13
|
+
* Pure-render component — host passes the substrate descriptor
|
|
14
|
+
* (mirrors `printContext.substrate`); the overlay is anchored
|
|
15
|
+
* absolutely. Consumers wrap canvas + overlay in a
|
|
16
|
+
* relatively-positioned container with the substrate sim *behind*
|
|
17
|
+
* the canvas (lower z-index).
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
import type { ReactElement } from "react";
|
|
22
|
+
/**
|
|
23
|
+
* Substrate descriptor that drives the simulation. Four fields
|
|
24
|
+
* map directly to `printContext.substrate`.
|
|
25
|
+
*
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
export type SubstrateSimSpec = {
|
|
29
|
+
widthPx: number;
|
|
30
|
+
heightPx: number;
|
|
31
|
+
/** CSS color of the substrate (e.g. `"#d2b48c"` kraft,
|
|
32
|
+
* `"#c0c0c0"` metallised, `"transparent"` clear PE). */
|
|
33
|
+
color: string;
|
|
34
|
+
/** 0..1. 1 = fully opaque (paper); < 1 = substrate colour
|
|
35
|
+
* shows through unprinted regions but ink dominates printed. */
|
|
36
|
+
opacity: number;
|
|
37
|
+
/** Finish modifier — gloss adds a subtle sheen, satin a
|
|
38
|
+
* weaker one, matte / uncoated render flat (uncoated adds
|
|
39
|
+
* faint pulp-paper noise). */
|
|
40
|
+
finish: "matte" | "gloss" | "satin" | "uncoated";
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Props for the {@link SubstrateSimOverlay}.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
export type SubstrateSimOverlayProps = {
|
|
48
|
+
spec: SubstrateSimSpec;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Pure-render substrate simulation overlay.
|
|
52
|
+
*
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
export declare function SubstrateSimOverlay({ spec }: SubstrateSimOverlayProps): ReactElement;
|
|
56
|
+
//# sourceMappingURL=SubstrateSimOverlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubstrateSimOverlay.d.ts","sourceRoot":"","sources":["../../src/components/SubstrateSimOverlay.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB;6DACyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd;qEACiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB;;mCAE+B;IAC/B,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC;CAClD,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,gBAAgB,CAAC;CACxB,CAAC;AAeF;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,EAAE,wBAAwB,GAAG,YAAY,CA4BpF"}
|