@printwithsynergy/artwork-pdf-editor 0.4.0 → 0.5.1

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.
Files changed (32) hide show
  1. package/dist/components/ContrastLegibilityPanel.d.ts +71 -0
  2. package/dist/components/ContrastLegibilityPanel.d.ts.map +1 -0
  3. package/dist/components/ContrastLegibilityPanel.js +123 -0
  4. package/dist/components/ContrastLegibilityPanel.js.map +1 -0
  5. package/dist/components/DirectionIndicatorsOverlay.d.ts +55 -0
  6. package/dist/components/DirectionIndicatorsOverlay.d.ts.map +1 -0
  7. package/dist/components/DirectionIndicatorsOverlay.js +126 -0
  8. package/dist/components/DirectionIndicatorsOverlay.js.map +1 -0
  9. package/dist/components/SubstrateSimOverlay.d.ts +56 -0
  10. package/dist/components/SubstrateSimOverlay.d.ts.map +1 -0
  11. package/dist/components/SubstrateSimOverlay.js +39 -0
  12. package/dist/components/SubstrateSimOverlay.js.map +1 -0
  13. package/dist/components/wave4-extras.d.ts +326 -0
  14. package/dist/components/wave4-extras.d.ts.map +1 -0
  15. package/dist/components/wave4-extras.js +264 -0
  16. package/dist/components/wave4-extras.js.map +1 -0
  17. package/dist/index.d.ts +5 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +5 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/lib/editor-config.d.ts +35 -1
  22. package/dist/lib/editor-config.d.ts.map +1 -1
  23. package/dist/lib/editor-config.js +14 -0
  24. package/dist/lib/editor-config.js.map +1 -1
  25. package/dist/lib/palette-registry.d.ts.map +1 -1
  26. package/dist/lib/palette-registry.js +13 -0
  27. package/dist/lib/palette-registry.js.map +1 -1
  28. package/dist/lib/structural-export.d.ts +84 -0
  29. package/dist/lib/structural-export.d.ts.map +1 -0
  30. package/dist/lib/structural-export.js +100 -0
  31. package/dist/lib/structural-export.js.map +1 -0
  32. 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,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"}
@@ -0,0 +1,39 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ "use client";
3
+ import { jsx as _jsx } from "react/jsx-runtime";
4
+ function finishOverlay(finish) {
5
+ switch (finish) {
6
+ case "gloss":
7
+ return "linear-gradient(135deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0) 60%)";
8
+ case "satin":
9
+ return "linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0) 70%)";
10
+ case "matte":
11
+ return "none";
12
+ case "uncoated":
13
+ return "radial-gradient(circle at 30% 20%, rgba(0,0,0,0.04) 0%, transparent 70%)";
14
+ }
15
+ }
16
+ /**
17
+ * Pure-render substrate simulation overlay.
18
+ *
19
+ * @public
20
+ */
21
+ export function SubstrateSimOverlay({ spec }) {
22
+ const { widthPx, heightPx, color, opacity, finish } = spec;
23
+ return (_jsx("div", { "data-testid": "substrate-sim-overlay", "aria-hidden": "true", style: {
24
+ position: "absolute",
25
+ top: 0,
26
+ left: 0,
27
+ width: widthPx,
28
+ height: heightPx,
29
+ background: color,
30
+ opacity,
31
+ pointerEvents: "none",
32
+ }, children: _jsx("div", { "data-testid": "substrate-sim-finish-layer", style: {
33
+ position: "absolute",
34
+ inset: 0,
35
+ background: finishOverlay(finish),
36
+ pointerEvents: "none",
37
+ } }) }));
38
+ }
39
+ //# sourceMappingURL=SubstrateSimOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubstrateSimOverlay.js","sourceRoot":"","sources":["../../src/components/SubstrateSimOverlay.tsx"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,YAAY,CAAC;;AAuDb,SAAS,aAAa,CAAC,MAAkC;IACvD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO;YACV,OAAO,6EAA6E,CAAC;QACvF,KAAK,OAAO;YACV,OAAO,6EAA6E,CAAC;QACvF,KAAK,OAAO;YACV,OAAO,MAAM,CAAC;QAChB,KAAK,UAAU;YACb,OAAO,0EAA0E,CAAC;IACtF,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAE,IAAI,EAA4B;IACpE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC3D,OAAO,CACL,6BACc,uBAAuB,iBACvB,MAAM,EAClB,KAAK,EAAE;YACL,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,CAAC;YACN,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,KAAK;YACjB,OAAO;YACP,aAAa,EAAE,MAAM;SACtB,YAED,6BACc,4BAA4B,EACxC,KAAK,EAAE;gBACL,QAAQ,EAAE,UAAU;gBACpB,KAAK,EAAE,CAAC;gBACR,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC;gBACjC,aAAa,EAAE,MAAM;aACtB,GACD,GACE,CACP,CAAC;AACJ,CAAC"}