@printwithsynergy/artwork-pdf-editor 0.2.0 → 0.3.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.
Files changed (236) hide show
  1. package/LICENSE +62 -0
  2. package/dist/components/AccessibilityHintsPanel.d.ts +142 -0
  3. package/dist/components/AccessibilityHintsPanel.d.ts.map +1 -0
  4. package/dist/components/AccessibilityHintsPanel.js +158 -0
  5. package/dist/components/AccessibilityHintsPanel.js.map +1 -0
  6. package/dist/components/AnnotationOverlay.d.ts +142 -0
  7. package/dist/components/AnnotationOverlay.d.ts.map +1 -0
  8. package/dist/components/AnnotationOverlay.js +141 -0
  9. package/dist/components/AnnotationOverlay.js.map +1 -0
  10. package/dist/components/AnnotationsSidebar.d.ts +98 -0
  11. package/dist/components/AnnotationsSidebar.d.ts.map +1 -0
  12. package/dist/components/AnnotationsSidebar.js +100 -0
  13. package/dist/components/AnnotationsSidebar.js.map +1 -0
  14. package/dist/components/BarcodeGeneratorPanel.d.ts +58 -0
  15. package/dist/components/BarcodeGeneratorPanel.d.ts.map +1 -0
  16. package/dist/components/BarcodeGeneratorPanel.js +91 -0
  17. package/dist/components/BarcodeGeneratorPanel.js.map +1 -0
  18. package/dist/components/BraillePanel.d.ts +99 -0
  19. package/dist/components/BraillePanel.d.ts.map +1 -0
  20. package/dist/components/BraillePanel.js +221 -0
  21. package/dist/components/BraillePanel.js.map +1 -0
  22. package/dist/components/BrandAssetsPanel.d.ts +130 -0
  23. package/dist/components/BrandAssetsPanel.d.ts.map +1 -0
  24. package/dist/components/BrandAssetsPanel.js +125 -0
  25. package/dist/components/BrandAssetsPanel.js.map +1 -0
  26. package/dist/components/BrandConsistencyPanel.d.ts +140 -0
  27. package/dist/components/BrandConsistencyPanel.d.ts.map +1 -0
  28. package/dist/components/BrandConsistencyPanel.js +158 -0
  29. package/dist/components/BrandConsistencyPanel.js.map +1 -0
  30. package/dist/components/ComplianceFindingsPanel.d.ts +62 -0
  31. package/dist/components/ComplianceFindingsPanel.d.ts.map +1 -0
  32. package/dist/components/ComplianceFindingsPanel.js +118 -0
  33. package/dist/components/ComplianceFindingsPanel.js.map +1 -0
  34. package/dist/components/DesignSuggestionsPanel.d.ts +148 -0
  35. package/dist/components/DesignSuggestionsPanel.d.ts.map +1 -0
  36. package/dist/components/DesignSuggestionsPanel.js +154 -0
  37. package/dist/components/DesignSuggestionsPanel.js.map +1 -0
  38. package/dist/components/DielineParametersPanel.d.ts +62 -0
  39. package/dist/components/DielineParametersPanel.d.ts.map +1 -0
  40. package/dist/components/DielineParametersPanel.js +170 -0
  41. package/dist/components/DielineParametersPanel.js.map +1 -0
  42. package/dist/components/DielinePreview.d.ts +150 -0
  43. package/dist/components/DielinePreview.d.ts.map +1 -0
  44. package/dist/components/DielinePreview.js +146 -0
  45. package/dist/components/DielinePreview.js.map +1 -0
  46. package/dist/components/EditorApp.d.ts +18 -3
  47. package/dist/components/EditorApp.d.ts.map +1 -1
  48. package/dist/components/EditorApp.js +42 -7
  49. package/dist/components/EditorApp.js.map +1 -1
  50. package/dist/components/EditorCanvas.d.ts +31 -2
  51. package/dist/components/EditorCanvas.d.ts.map +1 -1
  52. package/dist/components/EditorCanvas.js +97 -16
  53. package/dist/components/EditorCanvas.js.map +1 -1
  54. package/dist/components/EmailNotifyPanel.d.ts +165 -0
  55. package/dist/components/EmailNotifyPanel.d.ts.map +1 -0
  56. package/dist/components/EmailNotifyPanel.js +211 -0
  57. package/dist/components/EmailNotifyPanel.js.map +1 -0
  58. package/dist/components/FileDropZone.d.ts +9 -1
  59. package/dist/components/FileDropZone.d.ts.map +1 -1
  60. package/dist/components/FileDropZone.js +53 -5
  61. package/dist/components/FileDropZone.js.map +1 -1
  62. package/dist/components/FoldEditorPanel.d.ts +68 -0
  63. package/dist/components/FoldEditorPanel.d.ts.map +1 -0
  64. package/dist/components/FoldEditorPanel.js +65 -0
  65. package/dist/components/FoldEditorPanel.js.map +1 -0
  66. package/dist/components/FoldPreviewOverlay.d.ts +48 -0
  67. package/dist/components/FoldPreviewOverlay.d.ts.map +1 -0
  68. package/dist/components/FoldPreviewOverlay.js +182 -0
  69. package/dist/components/FoldPreviewOverlay.js.map +1 -0
  70. package/dist/components/Gs1DigitalLinkPanel.d.ts +103 -0
  71. package/dist/components/Gs1DigitalLinkPanel.d.ts.map +1 -0
  72. package/dist/components/Gs1DigitalLinkPanel.js +199 -0
  73. package/dist/components/Gs1DigitalLinkPanel.js.map +1 -0
  74. package/dist/components/HistoryPanel.d.ts +39 -0
  75. package/dist/components/HistoryPanel.d.ts.map +1 -0
  76. package/dist/components/HistoryPanel.js +72 -0
  77. package/dist/components/HistoryPanel.js.map +1 -0
  78. package/dist/components/IccSoftProofOverlay.d.ts +67 -0
  79. package/dist/components/IccSoftProofOverlay.d.ts.map +1 -0
  80. package/dist/components/IccSoftProofOverlay.js +119 -0
  81. package/dist/components/IccSoftProofOverlay.js.map +1 -0
  82. package/dist/components/ImposePanel.d.ts +71 -0
  83. package/dist/components/ImposePanel.d.ts.map +1 -0
  84. package/dist/components/ImposePanel.js +127 -0
  85. package/dist/components/ImposePanel.js.map +1 -0
  86. package/dist/components/InksPanel.d.ts +61 -0
  87. package/dist/components/InksPanel.d.ts.map +1 -0
  88. package/dist/components/InksPanel.js +84 -0
  89. package/dist/components/InksPanel.js.map +1 -0
  90. package/dist/components/JobSetupPanel.d.ts +118 -0
  91. package/dist/components/JobSetupPanel.d.ts.map +1 -0
  92. package/dist/components/JobSetupPanel.js +169 -0
  93. package/dist/components/JobSetupPanel.js.map +1 -0
  94. package/dist/components/LayersPanel.d.ts.map +1 -1
  95. package/dist/components/LayersPanel.js +1 -0
  96. package/dist/components/LayersPanel.js.map +1 -1
  97. package/dist/components/MarkLibraryPanel.d.ts +131 -0
  98. package/dist/components/MarkLibraryPanel.d.ts.map +1 -0
  99. package/dist/components/MarkLibraryPanel.js +184 -0
  100. package/dist/components/MarkLibraryPanel.js.map +1 -0
  101. package/dist/components/MisEstimateButton.d.ts +73 -0
  102. package/dist/components/MisEstimateButton.d.ts.map +1 -0
  103. package/dist/components/MisEstimateButton.js +57 -0
  104. package/dist/components/MisEstimateButton.js.map +1 -0
  105. package/dist/components/NutritionPanel.d.ts +118 -0
  106. package/dist/components/NutritionPanel.d.ts.map +1 -0
  107. package/dist/components/NutritionPanel.js +169 -0
  108. package/dist/components/NutritionPanel.js.map +1 -0
  109. package/dist/components/PageNavigator.d.ts.map +1 -1
  110. package/dist/components/PageNavigator.js +6 -1
  111. package/dist/components/PageNavigator.js.map +1 -1
  112. package/dist/components/PaletteManager.d.ts +32 -0
  113. package/dist/components/PaletteManager.d.ts.map +1 -0
  114. package/dist/components/PaletteManager.js +89 -0
  115. package/dist/components/PaletteManager.js.map +1 -0
  116. package/dist/components/PaletteToSpotPanel.d.ts +122 -0
  117. package/dist/components/PaletteToSpotPanel.d.ts.map +1 -0
  118. package/dist/components/PaletteToSpotPanel.js +160 -0
  119. package/dist/components/PaletteToSpotPanel.js.map +1 -0
  120. package/dist/components/PreflightAutoFixPanel.d.ts +110 -0
  121. package/dist/components/PreflightAutoFixPanel.d.ts.map +1 -0
  122. package/dist/components/PreflightAutoFixPanel.js +119 -0
  123. package/dist/components/PreflightAutoFixPanel.js.map +1 -0
  124. package/dist/components/PreflightDiffPanel.d.ts +127 -0
  125. package/dist/components/PreflightDiffPanel.d.ts.map +1 -0
  126. package/dist/components/PreflightDiffPanel.js +0 -0
  127. package/dist/components/PreflightDiffPanel.js.map +1 -0
  128. package/dist/components/ProcessRulesPanel.d.ts +81 -0
  129. package/dist/components/ProcessRulesPanel.d.ts.map +1 -0
  130. package/dist/components/ProcessRulesPanel.js +143 -0
  131. package/dist/components/ProcessRulesPanel.js.map +1 -0
  132. package/dist/components/SlackNotifyPanel.d.ts +139 -0
  133. package/dist/components/SlackNotifyPanel.d.ts.map +1 -0
  134. package/dist/components/SlackNotifyPanel.js +133 -0
  135. package/dist/components/SlackNotifyPanel.js.map +1 -0
  136. package/dist/components/SmartSpotMatchPanel.d.ts +143 -0
  137. package/dist/components/SmartSpotMatchPanel.d.ts.map +1 -0
  138. package/dist/components/SmartSpotMatchPanel.js +159 -0
  139. package/dist/components/SmartSpotMatchPanel.js.map +1 -0
  140. package/dist/components/SwatchesPicker.d.ts +83 -0
  141. package/dist/components/SwatchesPicker.d.ts.map +1 -0
  142. package/dist/components/SwatchesPicker.js +151 -0
  143. package/dist/components/SwatchesPicker.js.map +1 -0
  144. package/dist/components/TacOverlay.d.ts +47 -0
  145. package/dist/components/TacOverlay.d.ts.map +1 -0
  146. package/dist/components/TacOverlay.js +116 -0
  147. package/dist/components/TacOverlay.js.map +1 -0
  148. package/dist/components/TrapEditorPanel.d.ts +52 -0
  149. package/dist/components/TrapEditorPanel.d.ts.map +1 -0
  150. package/dist/components/TrapEditorPanel.js +64 -0
  151. package/dist/components/TrapEditorPanel.js.map +1 -0
  152. package/dist/components/TrapPreviewOverlay.d.ts +64 -0
  153. package/dist/components/TrapPreviewOverlay.d.ts.map +1 -0
  154. package/dist/components/TrapPreviewOverlay.js +120 -0
  155. package/dist/components/TrapPreviewOverlay.js.map +1 -0
  156. package/dist/components/VariantMatrixPanel.d.ts +61 -0
  157. package/dist/components/VariantMatrixPanel.d.ts.map +1 -0
  158. package/dist/components/VariantMatrixPanel.js +97 -0
  159. package/dist/components/VariantMatrixPanel.js.map +1 -0
  160. package/dist/components/VariantMatrixVersionPanel.d.ts +122 -0
  161. package/dist/components/VariantMatrixVersionPanel.d.ts.map +1 -0
  162. package/dist/components/VariantMatrixVersionPanel.js +162 -0
  163. package/dist/components/VariantMatrixVersionPanel.js.map +1 -0
  164. package/dist/components/WebhookNotifyPanel.d.ts +160 -0
  165. package/dist/components/WebhookNotifyPanel.d.ts.map +1 -0
  166. package/dist/components/WebhookNotifyPanel.js +100 -0
  167. package/dist/components/WebhookNotifyPanel.js.map +1 -0
  168. package/dist/components/WhiteUnderbasePanel.d.ts +107 -0
  169. package/dist/components/WhiteUnderbasePanel.d.ts.map +1 -0
  170. package/dist/components/WhiteUnderbasePanel.js +104 -0
  171. package/dist/components/WhiteUnderbasePanel.js.map +1 -0
  172. package/dist/hooks/useEditorMode.d.ts +25 -5
  173. package/dist/hooks/useEditorMode.d.ts.map +1 -1
  174. package/dist/hooks/useEditorMode.js +18 -5
  175. package/dist/hooks/useEditorMode.js.map +1 -1
  176. package/dist/index.d.ts +49 -2
  177. package/dist/index.d.ts.map +1 -1
  178. package/dist/index.js +49 -2
  179. package/dist/index.js.map +1 -1
  180. package/dist/lens/preflight-findings.d.ts.map +1 -1
  181. package/dist/lens/preflight-findings.js.map +1 -1
  182. package/dist/lib/barcode-scan.d.ts +154 -0
  183. package/dist/lib/barcode-scan.d.ts.map +1 -0
  184. package/dist/lib/barcode-scan.js +152 -0
  185. package/dist/lib/barcode-scan.js.map +1 -0
  186. package/dist/lib/color-math.d.ts +76 -0
  187. package/dist/lib/color-math.d.ts.map +1 -0
  188. package/dist/lib/color-math.js +96 -0
  189. package/dist/lib/color-math.js.map +1 -0
  190. package/dist/lib/dieline-template.d.ts +87 -0
  191. package/dist/lib/dieline-template.d.ts.map +1 -1
  192. package/dist/lib/dieline-template.js +163 -0
  193. package/dist/lib/dieline-template.js.map +1 -1
  194. package/dist/lib/editor-config.d.ts +384 -0
  195. package/dist/lib/editor-config.d.ts.map +1 -1
  196. package/dist/lib/editor-config.js +89 -0
  197. package/dist/lib/editor-config.js.map +1 -1
  198. package/dist/lib/fold-geometry.d.ts +144 -0
  199. package/dist/lib/fold-geometry.d.ts.map +1 -0
  200. package/dist/lib/fold-geometry.js +138 -0
  201. package/dist/lib/fold-geometry.js.map +1 -0
  202. package/dist/lib/merge-tokens.d.ts +81 -0
  203. package/dist/lib/merge-tokens.d.ts.map +1 -0
  204. package/dist/lib/merge-tokens.js +88 -0
  205. package/dist/lib/merge-tokens.js.map +1 -0
  206. package/dist/lib/palette-registry.d.ts +40 -0
  207. package/dist/lib/palette-registry.d.ts.map +1 -0
  208. package/dist/lib/palette-registry.js +49 -0
  209. package/dist/lib/palette-registry.js.map +1 -0
  210. package/dist/lib/panel-anchor.d.ts +101 -0
  211. package/dist/lib/panel-anchor.d.ts.map +1 -0
  212. package/dist/lib/panel-anchor.js +68 -0
  213. package/dist/lib/panel-anchor.js.map +1 -0
  214. package/dist/lib/preflight/checks.d.ts.map +1 -1
  215. package/dist/lib/preflight/checks.js +71 -0
  216. package/dist/lib/preflight/checks.js.map +1 -1
  217. package/dist/lib/preflight/types.d.ts.map +1 -1
  218. package/dist/lib/preflight/types.js +11 -0
  219. package/dist/lib/preflight/types.js.map +1 -1
  220. package/dist/lib/rasterize.d.ts +93 -0
  221. package/dist/lib/rasterize.d.ts.map +1 -0
  222. package/dist/lib/rasterize.js +117 -0
  223. package/dist/lib/rasterize.js.map +1 -0
  224. package/dist/lib/separations-registry.d.ts +99 -0
  225. package/dist/lib/separations-registry.d.ts.map +1 -0
  226. package/dist/lib/separations-registry.js +59 -0
  227. package/dist/lib/separations-registry.js.map +1 -0
  228. package/dist/lib/unwired.d.ts +29 -0
  229. package/dist/lib/unwired.d.ts.map +1 -0
  230. package/dist/lib/unwired.js +58 -0
  231. package/dist/lib/unwired.js.map +1 -0
  232. package/package.json +20 -11
  233. package/dist/components/SeparationsPanel.d.ts +0 -9
  234. package/dist/components/SeparationsPanel.d.ts.map +0 -1
  235. package/dist/components/SeparationsPanel.js +0 -168
  236. package/dist/components/SeparationsPanel.js.map +0 -1
@@ -0,0 +1,159 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ "use client";
3
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
4
+ import { useEffect, useMemo, useState } from "react";
5
+ /**
6
+ * Pure helper — sorts a `SpotMatch` list ascending on `deltaE`
7
+ * (best-first). Stable on ties: input order preserved. Returns a
8
+ * new array.
9
+ *
10
+ * @public
11
+ */
12
+ export function sortMatchesByDeltaE(matches) {
13
+ return [...matches]
14
+ .map((m, i) => ({ m, i }))
15
+ .sort((a, b) => a.m.deltaE - b.m.deltaE || a.i - b.i)
16
+ .map((x) => x.m);
17
+ }
18
+ /**
19
+ * Pure helper — maps a ΔE distance to a {@link DeltaEQuality} band
20
+ * using the CIE-1994 perceptual cut points (under 1 is
21
+ * imperceptible, 1–3 is noticeable, 3–5 is fair, ≥5 is poor). Used
22
+ * by the panel for the per-row severity chip; exported so hosts can
23
+ * surface the same banding outside the panel (e.g. in a print-proof
24
+ * audit). Returns `"poor"` for non-finite or negative inputs by
25
+ * threshold ordering — callers should pre-validate if they care.
26
+ *
27
+ * @public
28
+ */
29
+ export function deltaEQuality(deltaE) {
30
+ if (!Number.isFinite(deltaE) || deltaE < 0)
31
+ return "poor";
32
+ if (deltaE < 1)
33
+ return "imperceptible";
34
+ if (deltaE < 3)
35
+ return "noticeable";
36
+ if (deltaE < 5)
37
+ return "fair";
38
+ return "poor";
39
+ }
40
+ /**
41
+ * Pure helper — formats ΔE for chip / row display (e.g. `"ΔE 1.2"`).
42
+ * Two-decimal precision matches what most ΔE engines emit and what
43
+ * print shops quote.
44
+ *
45
+ * @public
46
+ */
47
+ export function formatDeltaE(deltaE) {
48
+ return `ΔE ${deltaE.toFixed(2)}`;
49
+ }
50
+ /**
51
+ * Pure helper — quickly checks whether a query has at least one
52
+ * color-space populated. Exported so hosts that drive the loader
53
+ * from outside the panel can gate their fetch on the same predicate.
54
+ *
55
+ * @public
56
+ */
57
+ export function isQueryReady(query) {
58
+ return Boolean(query.cmyk || query.lab || query.hex?.trim());
59
+ }
60
+ const DELTA_E_COLORS = {
61
+ imperceptible: "#080",
62
+ noticeable: "#0a8",
63
+ fair: "#a60",
64
+ poor: "#a00",
65
+ };
66
+ /**
67
+ * Stateful panel — accepts a CMYK or hex input, calls the host
68
+ * loader, and surfaces ranked matches with ΔE chips. Hosts wire
69
+ * `onSelect` to push the picked spot into the active object's fill
70
+ * / stroke or into the separations registry.
71
+ *
72
+ * @public
73
+ */
74
+ export function SmartSpotMatchPanel({ loader, initialQuery, limit, onSelect, }) {
75
+ const [hex, setHex] = useState(initialQuery?.hex ?? "");
76
+ const [matches, setMatches] = useState(null);
77
+ const [error, setError] = useState(null);
78
+ const [loading, setLoading] = useState(false);
79
+ // Keep the hex input in lockstep with `initialQuery.hex` when the
80
+ // host swaps the active selection — without this, a panel reused
81
+ // for a different object would mix new cmyk / lab with the old
82
+ // hex value in the input.
83
+ useEffect(() => {
84
+ setHex(initialQuery?.hex ?? "");
85
+ }, [initialQuery?.hex]);
86
+ // Stable query object — re-derived only when content changes, not
87
+ // when a parent re-render hands back a referentially-different
88
+ // but content-identical `initialQuery`. The join'd keys identity-
89
+ // compare on content; the raw refs are read inside but excluded
90
+ // from the dep list intentionally.
91
+ const cmykKey = initialQuery?.cmyk?.join(",") ?? "";
92
+ const labKey = initialQuery?.lab?.join(",") ?? "";
93
+ // biome-ignore lint/correctness/useExhaustiveDependencies: cmyk / lab are content-keyed via cmykKey / labKey
94
+ const query = useMemo(() => ({
95
+ ...(hex.trim() && { hex: hex.trim() }),
96
+ ...(initialQuery?.cmyk && { cmyk: initialQuery.cmyk }),
97
+ ...(initialQuery?.lab && { lab: initialQuery.lab }),
98
+ ...(limit !== undefined && { limit }),
99
+ }), [hex, cmykKey, labKey, limit]);
100
+ useEffect(() => {
101
+ if (!isQueryReady(query)) {
102
+ setMatches(null);
103
+ setError(null);
104
+ setLoading(false);
105
+ return;
106
+ }
107
+ let disposed = false;
108
+ setLoading(true);
109
+ setError(null);
110
+ // Drop the previous result eagerly so stale rows can't be
111
+ // selected for a query that's no longer current.
112
+ setMatches(null);
113
+ void (async () => {
114
+ try {
115
+ const next = await loader(query);
116
+ if (disposed)
117
+ return;
118
+ setMatches(sortMatchesByDeltaE(next));
119
+ }
120
+ catch (err) {
121
+ if (disposed)
122
+ return;
123
+ setMatches(null);
124
+ setError(err instanceof Error ? err.message : String(err));
125
+ }
126
+ finally {
127
+ if (!disposed)
128
+ setLoading(false);
129
+ }
130
+ })();
131
+ return () => {
132
+ disposed = true;
133
+ };
134
+ }, [loader, query]);
135
+ return (_jsxs("div", { "data-testid": "smart-spot-match-panel", style: { padding: "0.5rem" }, children: [_jsx("header", { style: { marginBottom: "0.5rem" }, children: _jsx("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: "Find PANTONE match" }) }), _jsxs("label", { style: { display: "block", fontSize: "0.75rem", marginBottom: "0.5rem" }, children: ["sRGB hex", _jsx("input", { type: "text", "aria-label": "sRGB hex", placeholder: "#ff5102", value: hex, onChange: (e) => setHex(e.target.value), style: { display: "block", marginTop: "0.125rem", width: "100%" } })] }), loading && _jsx("div", { style: { opacity: 0.6, fontSize: "0.75rem" }, children: "Searching\u2026" }), error && (_jsxs("div", { role: "alert", style: { color: "#a00", fontSize: "0.75rem" }, children: ["Couldn't fetch matches: ", error] })), matches && matches.length === 0 && !loading && !error && (_jsx("div", { style: { opacity: 0.6, fontSize: "0.75rem" }, children: "No matches." })), matches && matches.length > 0 && (_jsx("ul", { style: { listStyle: "none", padding: 0, margin: 0 }, children: matches.map((match) => (_jsx(SmartSpotMatchRow, { match: match, onSelect: onSelect }, `${match.spot.library ?? "-"}|${match.spot.name}`))) }))] }));
136
+ }
137
+ function SmartSpotMatchRow({ match, onSelect, }) {
138
+ const quality = deltaEQuality(match.deltaE);
139
+ const chipColor = DELTA_E_COLORS[quality];
140
+ const rowContents = (_jsxs(_Fragment, { children: [_jsx("span", { style: { flex: 1, fontSize: "0.8125rem" }, children: match.spot.name }), _jsx("span", { "aria-label": `${formatDeltaE(match.deltaE)} — ${quality}`, style: {
141
+ fontSize: "0.6875rem",
142
+ padding: "0.0625rem 0.375rem",
143
+ borderRadius: 999,
144
+ background: chipColor,
145
+ color: "#fff",
146
+ }, children: formatDeltaE(match.deltaE) })] }));
147
+ const rowStyle = {
148
+ display: "flex",
149
+ alignItems: "center",
150
+ gap: "0.5rem",
151
+ width: "100%",
152
+ padding: "0.25rem 0.5rem",
153
+ border: "1px solid transparent",
154
+ borderRadius: 4,
155
+ textAlign: "left",
156
+ };
157
+ return (_jsx("li", { children: onSelect ? (_jsx("button", { type: "button", onClick: () => onSelect(match), style: { ...rowStyle, cursor: "pointer", background: "transparent" }, "aria-label": match.spot.name, children: rowContents })) : (_jsx("div", { style: rowStyle, children: rowContents })) }));
158
+ }
159
+ //# sourceMappingURL=SmartSpotMatchPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmartSpotMatchPanel.js","sourceRoot":"","sources":["../../src/components/SmartSpotMatchPanel.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * One PANTONE catalogue entry from compile-pdf's `/v1/spots/*`
3
+ * endpoints. Mirrors `SpotEntry` on the apps/service
4
+ * `CompilePdfClient`, kept structural here so editor-app stays
5
+ * apps/service-dep-free.
6
+ *
7
+ * @public
8
+ */
9
+ export type Spot = {
10
+ name: string;
11
+ library?: string | null;
12
+ lab?: [number, number, number] | null;
13
+ cmyk_bridge?: [number, number, number, number] | null;
14
+ };
15
+ /**
16
+ * Search adapter — the editor passes in a function that fronts
17
+ * `CompilePdfClient.spotSearch()`. Threading the search via a prop
18
+ * (rather than calling fetch directly) keeps SwatchesPicker
19
+ * decoupled from the network — tests pass a stub, the demo can
20
+ * preload an in-memory fixture, etc.
21
+ *
22
+ * @public
23
+ */
24
+ export type SpotSearchFn = (opts: {
25
+ q?: string;
26
+ library?: string;
27
+ limit?: number;
28
+ }) => Promise<{
29
+ results: Spot[];
30
+ total: number;
31
+ limit: number;
32
+ }>;
33
+ /**
34
+ * Library descriptor — matches the wire shape of one entry in
35
+ * `/v1/spots/libraries`.
36
+ *
37
+ * @public
38
+ */
39
+ export type SpotLibrary = {
40
+ id: string;
41
+ count: number;
42
+ };
43
+ /**
44
+ * Props for the C3 SwatchesPicker palette.
45
+ *
46
+ * `search` is the only required prop; library filter + initial
47
+ * query are optional. `onSelect` fires when the user clicks a
48
+ * swatch — typically wired to AI4's `registerSpot` in the host.
49
+ *
50
+ * `enable_palettes: false` collapses the entire palette system off;
51
+ * hosts mount this component only when `isPanelVisible(config,
52
+ * "swatches")` returns true.
53
+ *
54
+ * @public
55
+ */
56
+ export type SwatchesPickerProps = {
57
+ search: SpotSearchFn;
58
+ /** Initial libraries-filter dropdown values. Hosts that already
59
+ * fetched `spotLibraries()` thread the result here. */
60
+ libraries?: SpotLibrary[];
61
+ /** Optional initial query. */
62
+ initialQuery?: string;
63
+ /** Click callback. Receives the full Spot row. */
64
+ onSelect: (spot: Spot) => void;
65
+ };
66
+ /**
67
+ * Right-rail palette for browsing compile-pdf's PANTONE catalogue
68
+ * (codex-pdf's public-domain reference set).
69
+ *
70
+ * UX:
71
+ * - Search input → debounced (250 ms) call to `search()`.
72
+ * - Optional library dropdown (when `libraries` is supplied).
73
+ * - Result list as colored chips with the canonical name; click
74
+ * fires `onSelect`.
75
+ * - Footer disclaimer ("public-domain reference, not licensed
76
+ * PANTONE data") — present per the trademark stance.
77
+ *
78
+ * @returns An `<aside>` element with search input, library filter,
79
+ * results list, and the trademark disclaimer footer.
80
+ * @public
81
+ */
82
+ export declare function SwatchesPicker({ search, libraries, initialQuery, onSelect, }: SwatchesPickerProps): import("react/jsx-runtime").JSX.Element;
83
+ //# sourceMappingURL=SwatchesPicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwatchesPicker.d.ts","sourceRoot":"","sources":["../../src/components/SwatchesPicker.tsx"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,MAAM,MAAM,IAAI,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACtC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CACvD,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE;IAChC,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,KAAK,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB;4DACwD;IACxD,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC;IAC1B,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CAChC,CAAC;AAoBF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,SAAS,EACT,YAAiB,EACjB,QAAQ,GACT,EAAE,mBAAmB,2CAuKrB"}
@@ -0,0 +1,151 @@
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
+ const PANEL_BG = "#1a0f08";
6
+ const BORDER = "#3d1a00";
7
+ const BRAND = "#fc5102";
8
+ const TEXT = "#f4ece6";
9
+ const MUTED = "#888";
10
+ const DEBOUNCE_MS = 250;
11
+ const inputStyle = {
12
+ flex: 1,
13
+ padding: "0.4rem 0.6rem",
14
+ background: "#0f0a05",
15
+ border: `1px solid ${BORDER}`,
16
+ borderRadius: 4,
17
+ color: TEXT,
18
+ fontSize: "0.8rem",
19
+ fontFamily: "inherit",
20
+ };
21
+ /**
22
+ * Right-rail palette for browsing compile-pdf's PANTONE catalogue
23
+ * (codex-pdf's public-domain reference set).
24
+ *
25
+ * UX:
26
+ * - Search input → debounced (250 ms) call to `search()`.
27
+ * - Optional library dropdown (when `libraries` is supplied).
28
+ * - Result list as colored chips with the canonical name; click
29
+ * fires `onSelect`.
30
+ * - Footer disclaimer ("public-domain reference, not licensed
31
+ * PANTONE data") — present per the trademark stance.
32
+ *
33
+ * @returns An `<aside>` element with search input, library filter,
34
+ * results list, and the trademark disclaimer footer.
35
+ * @public
36
+ */
37
+ export function SwatchesPicker({ search, libraries, initialQuery = "", onSelect, }) {
38
+ const [query, setQuery] = useState(initialQuery);
39
+ const [library, setLibrary] = useState("");
40
+ const [results, setResults] = useState([]);
41
+ const [loading, setLoading] = useState(false);
42
+ const [error, setError] = useState(null);
43
+ const reqIdRef = useRef(0);
44
+ useEffect(() => {
45
+ // Debounce — bump the request id and only commit results from
46
+ // the latest call. Prevents stale results overriding fresh ones
47
+ // when the user types quickly.
48
+ const id = ++reqIdRef.current;
49
+ const handle = setTimeout(() => {
50
+ setLoading(true);
51
+ setError(null);
52
+ const opts = { limit: 50 };
53
+ if (query)
54
+ opts.q = query;
55
+ if (library)
56
+ opts.library = library;
57
+ search(opts)
58
+ .then((res) => {
59
+ if (id !== reqIdRef.current)
60
+ return; // stale
61
+ setResults(res.results);
62
+ setLoading(false);
63
+ })
64
+ .catch((err) => {
65
+ if (id !== reqIdRef.current)
66
+ return;
67
+ const msg = err instanceof Error ? err.message : "spots search failed";
68
+ setError(msg);
69
+ setLoading(false);
70
+ });
71
+ }, DEBOUNCE_MS);
72
+ return () => clearTimeout(handle);
73
+ }, [query, library, search]);
74
+ return (_jsxs("aside", { style: {
75
+ width: 240,
76
+ background: PANEL_BG,
77
+ borderLeft: `1px solid ${BORDER}`,
78
+ color: TEXT,
79
+ display: "flex",
80
+ flexDirection: "column",
81
+ overflow: "hidden",
82
+ flexShrink: 0,
83
+ }, children: [_jsx("div", { style: {
84
+ fontSize: "0.7rem",
85
+ letterSpacing: "0.08em",
86
+ textTransform: "uppercase",
87
+ color: MUTED,
88
+ padding: "0.55rem 0.85rem",
89
+ borderBottom: `1px solid ${BORDER}`,
90
+ }, children: "Swatches" }), _jsx("div", { style: { padding: "0.55rem 0.65rem", display: "flex", gap: "0.4rem" }, children: _jsx("input", { value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Search PANTONE\u2026", "aria-label": "Search PANTONE catalogue", style: inputStyle }) }), libraries && libraries.length > 0 && (_jsx("div", { style: { padding: "0 0.65rem 0.55rem" }, children: _jsxs("select", { value: library, onChange: (e) => setLibrary(e.target.value), "aria-label": "Filter by library", style: { ...inputStyle, width: "100%" }, children: [_jsx("option", { value: "", children: "All libraries" }), libraries.map((lib) => (_jsxs("option", { value: lib.id, children: [lib.id, " (", lib.count, ")"] }, lib.id)))] }) })), _jsxs("div", { style: { flex: 1, overflow: "auto" }, children: [loading && (_jsx("div", { style: { padding: "0.55rem 0.85rem", color: MUTED, fontSize: "0.78rem" }, children: "Loading\u2026" })), error && !loading && (_jsx("div", { role: "alert", style: { padding: "0.55rem 0.85rem", color: "#ef4444", fontSize: "0.78rem" }, children: error })), !loading && !error && results.length === 0 && (_jsx("div", { style: { padding: "0.55rem 0.85rem", color: MUTED, fontSize: "0.78rem" }, children: "No matches." })), !loading &&
91
+ !error &&
92
+ results.map((spot) => {
93
+ const swatchColor = labToCssApprox(spot.lab) ?? "#666";
94
+ return (_jsxs("button", { type: "button", onClick: () => onSelect(spot), style: {
95
+ display: "flex",
96
+ alignItems: "center",
97
+ gap: "0.55rem",
98
+ width: "100%",
99
+ padding: "0.35rem 0.85rem",
100
+ background: "transparent",
101
+ border: "none",
102
+ borderLeft: "2px solid transparent",
103
+ cursor: "pointer",
104
+ color: TEXT,
105
+ fontSize: "0.78rem",
106
+ fontFamily: "inherit",
107
+ textAlign: "left",
108
+ }, onMouseEnter: (e) => {
109
+ e.currentTarget.style.borderLeftColor = BRAND;
110
+ }, onMouseLeave: (e) => {
111
+ e.currentTarget.style.borderLeftColor = "transparent";
112
+ }, children: [_jsx("span", { style: {
113
+ display: "inline-block",
114
+ width: 16,
115
+ height: 16,
116
+ borderRadius: 3,
117
+ background: swatchColor,
118
+ border: `1px solid ${BORDER}`,
119
+ flexShrink: 0,
120
+ } }), _jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: spot.name })] }, spot.name));
121
+ })] }), _jsx("div", { style: {
122
+ padding: "0.45rem 0.85rem",
123
+ borderTop: `1px solid ${BORDER}`,
124
+ color: MUTED,
125
+ fontSize: "0.65rem",
126
+ lineHeight: 1.35,
127
+ }, children: "Public-domain colour-science reference. Not licensed PANTONE data." })] }));
128
+ }
129
+ /**
130
+ * Crude Lab → CSS-color approximation for the swatch chips. Not a
131
+ * colorimetric conversion — just enough to give each row a
132
+ * recognizable tint in the picker. Returns `undefined` for entries
133
+ * without a Lab triplet (the chip falls back to a neutral grey).
134
+ *
135
+ * Lab L is 0-100 (perceptual lightness); we map directly to sRGB
136
+ * grey then shift slightly toward a/b axes. Future: replace with a
137
+ * proper Lab→sRGB conversion via culori or chroma-js if perceptual
138
+ * accuracy matters for the picker.
139
+ */
140
+ function labToCssApprox(lab) {
141
+ if (!lab)
142
+ return undefined;
143
+ const [L, a, b] = lab;
144
+ // Very rough — clamps to a tinted grey based on a/b sign.
145
+ const lum = Math.max(0, Math.min(255, Math.round((L / 100) * 255)));
146
+ const r = Math.max(0, Math.min(255, lum + Math.round(a * 1.5)));
147
+ const g = Math.max(0, Math.min(255, lum - Math.round(Math.abs(a) * 0.5)));
148
+ const bl = Math.max(0, Math.min(255, lum - Math.round(b * 1.5)));
149
+ return `rgb(${r}, ${g}, ${bl})`;
150
+ }
151
+ //# sourceMappingURL=SwatchesPicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwatchesPicker.js","sourceRoot":"","sources":["../../src/components/SwatchesPicker.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type Konva from "konva";
2
+ /**
3
+ * C4 live total-area-coverage overlay.
4
+ *
5
+ * Sits as an absolutely-positioned `<canvas>` on top of the Konva
6
+ * Stage, debouncing a rasterize-and-sample pass on every change to
7
+ * the watched objects array. Paints pixels whose TAC exceeds the
8
+ * configured threshold (default 300%) in translucent red — a "where
9
+ * the ink is going to pool" hint — and shows a `max / avg` chip in
10
+ * the bottom-left.
11
+ *
12
+ * Browser-side sanity check, not a colorimetric proof: the same
13
+ * caveats as {@link import("../lib/rasterize").sampleTACFromImageData}
14
+ * apply (subtractive sRGB → CMYK with K-extraction, alpha composited
15
+ * onto an opaque white background). Production TAC enforcement lives
16
+ * server-side in compile-pdf's `total_ink_coverage` preflight rule.
17
+ *
18
+ * @public
19
+ */
20
+ export type TacOverlayProps = {
21
+ /** Live Konva Stage. The overlay no-ops while this is `null` (the
22
+ * ref starts null on first render). */
23
+ stage: Konva.Stage | null;
24
+ /** Container width/height in CSS pixels — the overlay canvas
25
+ * matches these so it lines up with the Stage. */
26
+ width: number;
27
+ height: number;
28
+ /** Re-sample trigger. Any change to this value (by reference for
29
+ * arrays, by equality for primitives) debounces a new rasterize
30
+ * pass. The value itself isn't read — it just lets React's effect
31
+ * diffing detect editor changes. Pass `objects` (the canvas
32
+ * contents array) so every commit re-samples. */
33
+ trigger: unknown;
34
+ /** TAC threshold in percent (0-400). Pixels at or above the
35
+ * threshold are painted; pixels below are transparent. Defaults to
36
+ * 300% — the standard coated-stock preflight ceiling. */
37
+ thresholdPct?: number;
38
+ /** Debounce window in milliseconds before a new sample fires.
39
+ * Defaults to 250 ms — fast enough to feel live, slow enough that
40
+ * click-drag operations don't thrash the rasterizer. */
41
+ debounceMs?: number;
42
+ };
43
+ /**
44
+ * @public
45
+ */
46
+ export declare function TacOverlay({ stage, width, height, trigger, thresholdPct, debounceMs, }: TacOverlayProps): import("react/jsx-runtime").JSX.Element;
47
+ //# sourceMappingURL=TacOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TacOverlay.d.ts","sourceRoot":"","sources":["../../src/components/TacOverlay.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;4CACwC;IACxC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;IAC1B;uDACmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf;;;;sDAIkD;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB;;8DAE0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;6DAEyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,MAAM,EACN,OAAO,EACP,YAAkB,EAClB,UAAgB,GACjB,EAAE,eAAe,2CA0HjB"}
@@ -0,0 +1,116 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ "use client";
3
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
4
+ import { useEffect, useRef, useState } from "react";
5
+ import { rasterizeStage } from "../lib/rasterize";
6
+ /**
7
+ * @public
8
+ */
9
+ export function TacOverlay({ stage, width, height, trigger, thresholdPct = 300, debounceMs = 250, }) {
10
+ const canvasRef = useRef(null);
11
+ const [readout, setReadout] = useState(null);
12
+ useEffect(() => {
13
+ // `trigger` is intentionally read here (no-op `void` cast) so the
14
+ // exhaustive-deps lint sees it as used; the actual value is never
15
+ // consumed — only its identity change is meaningful.
16
+ void trigger;
17
+ if (!stage || width <= 0 || height <= 0) {
18
+ setReadout(null);
19
+ return;
20
+ }
21
+ const handle = setTimeout(() => {
22
+ let image;
23
+ try {
24
+ image = rasterizeStage(stage);
25
+ }
26
+ catch {
27
+ // Stage's 2d context occasionally fails to acquire during
28
+ // teardown (unmount race); silently skip — next change will
29
+ // try again.
30
+ return;
31
+ }
32
+ const canvas = canvasRef.current;
33
+ if (!canvas)
34
+ return;
35
+ // Match the source image so writes are 1:1 — the canvas CSS
36
+ // size is what scales it back to the displayed Stage area.
37
+ canvas.width = image.width;
38
+ canvas.height = image.height;
39
+ const ctx = canvas.getContext("2d");
40
+ if (!ctx)
41
+ return;
42
+ // One fused pass: sample TAC per pixel inline AND paint the
43
+ // overlay where TAC crosses the threshold. We can't reuse the
44
+ // shared sampler's `perPixelPct` for the threshold check
45
+ // because that array clamps the 0-400 % range to a byte
46
+ // (255 = ≥255 %), which collapses every pixel above the
47
+ // default 300 % threshold to a single bucket; honest threshold
48
+ // checks need the un-truncated percentage here.
49
+ const src = image.data;
50
+ const overlay = ctx.createImageData(image.width, image.height);
51
+ const dst = overlay.data;
52
+ const pixelCount = image.width * image.height;
53
+ let maxPct = 0;
54
+ let sumPct = 0;
55
+ for (let p = 0, i = 0; p < src.length; p += 4, i++) {
56
+ // Pre-multiply with opaque white background so semi-
57
+ // transparent pixels reflect printable ink. Mirrors the
58
+ // canonical sampler's composite step.
59
+ const a = (src[p + 3] ?? 255) / 255;
60
+ const inv = 1 - a;
61
+ const r = ((src[p] ?? 0) * a + 255 * inv) / 255;
62
+ const g = ((src[p + 1] ?? 0) * a + 255 * inv) / 255;
63
+ const b = ((src[p + 2] ?? 0) * a + 255 * inv) / 255;
64
+ const k = 1 - Math.max(r, g, b);
65
+ let c = 0;
66
+ let m = 0;
67
+ let y = 0;
68
+ if (k < 1) {
69
+ const scale = 1 - k;
70
+ c = (1 - r - k) / scale;
71
+ m = (1 - g - k) / scale;
72
+ y = (1 - b - k) / scale;
73
+ }
74
+ const tac = (c + m + y + k) * 100;
75
+ if (tac > maxPct)
76
+ maxPct = tac;
77
+ sumPct += tac;
78
+ if (tac >= thresholdPct) {
79
+ const j = i * 4;
80
+ dst[j] = 220; // R
81
+ dst[j + 1] = 38; // G
82
+ dst[j + 2] = 38; // B
83
+ // Alpha scales linearly from 64 at threshold to 192 at
84
+ // (threshold + 100 %), so a 305 % pixel barely glows but
85
+ // a 400 % pixel screams. Clamped to keep the red readable
86
+ // over busy artwork.
87
+ const intensity = Math.min(192, 64 + (tac - thresholdPct) * 1.28);
88
+ dst[j + 3] = intensity;
89
+ }
90
+ }
91
+ ctx.putImageData(overlay, 0, 0);
92
+ setReadout({ maxPct, avgPct: pixelCount > 0 ? sumPct / pixelCount : 0 });
93
+ }, debounceMs);
94
+ return () => clearTimeout(handle);
95
+ }, [stage, width, height, trigger, thresholdPct, debounceMs]);
96
+ return (_jsxs(_Fragment, { children: [_jsx("canvas", { ref: canvasRef, style: {
97
+ position: "absolute",
98
+ inset: 0,
99
+ width: `${width}px`,
100
+ height: `${height}px`,
101
+ pointerEvents: "none",
102
+ } }), readout !== null && (_jsxs("output", { "aria-label": "Total area coverage", style: {
103
+ position: "absolute",
104
+ bottom: 8,
105
+ left: 8,
106
+ padding: "0.25rem 0.5rem",
107
+ background: "rgba(15, 23, 42, 0.78)",
108
+ color: "#f8fafc",
109
+ fontSize: "0.7rem",
110
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
111
+ borderRadius: 4,
112
+ pointerEvents: "none",
113
+ lineHeight: 1.3,
114
+ }, children: [_jsxs("div", { children: ["TAC max ", readout.maxPct.toFixed(0), "%"] }), _jsxs("div", { style: { opacity: 0.75 }, children: ["avg ", readout.avgPct.toFixed(0), "%"] })] }))] }));
115
+ }
116
+ //# sourceMappingURL=TacOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TacOverlay.js","sourceRoot":"","sources":["../../src/components/TacOverlay.tsx"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,YAAY,CAAC;;AAGb,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AA4ClD;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,MAAM,EACN,OAAO,EACP,YAAY,GAAG,GAAG,EAClB,UAAU,GAAG,GAAG,GACA;IAChB,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAClD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAA4C,IAAI,CAAC,CAAC;IAExF,SAAS,CAAC,GAAG,EAAE;QACb,kEAAkE;QAClE,kEAAkE;QAClE,qDAAqD;QACrD,KAAK,OAAO,CAAC;QACb,IAAI,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;YACxC,UAAU,CAAC,IAAI,CAAC,CAAC;YACjB,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE;YAC7B,IAAI,KAAgB,CAAC;YACrB,IAAI,CAAC;gBACH,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,0DAA0D;gBAC1D,4DAA4D;gBAC5D,aAAa;gBACb,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC;YACjC,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,4DAA4D;YAC5D,2DAA2D;YAC3D,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;YAC3B,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YAC7B,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,GAAG;gBAAE,OAAO;YAEjB,4DAA4D;YAC5D,8DAA8D;YAC9D,yDAAyD;YACzD,wDAAwD;YACxD,wDAAwD;YACxD,+DAA+D;YAC/D,gDAAgD;YAChD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC;YACvB,MAAM,OAAO,GAAG,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;YAC/D,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;YACzB,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;YAC9C,IAAI,MAAM,GAAG,CAAC,CAAC;YACf,IAAI,MAAM,GAAG,CAAC,CAAC;YACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBACnD,qDAAqD;gBACrD,wDAAwD;gBACxD,sCAAsC;gBACtC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC;gBACpC,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;gBAClB,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;gBAChD,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;gBACpD,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;gBACpD,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;gBAChC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACV,IAAI,CAAC,GAAG,CAAC,CAAC;gBACV,IAAI,CAAC,GAAG,CAAC,CAAC;gBACV,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBACV,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;oBACpB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;oBACxB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;oBACxB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;gBAC1B,CAAC;gBACD,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;gBAClC,IAAI,GAAG,GAAG,MAAM;oBAAE,MAAM,GAAG,GAAG,CAAC;gBAC/B,MAAM,IAAI,GAAG,CAAC;gBACd,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;oBACxB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBAChB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI;oBAClB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI;oBACrB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI;oBACrB,uDAAuD;oBACvD,yDAAyD;oBACzD,0DAA0D;oBAC1D,qBAAqB;oBACrB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,GAAG,GAAG,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;oBAClE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC;gBACzB,CAAC;YACH,CAAC;YACD,GAAG,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAChC,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3E,CAAC,EAAE,UAAU,CAAC,CAAC;QACf,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;IAE9D,OAAO,CACL,8BACE,iBACE,GAAG,EAAE,SAAS,EACd,KAAK,EAAE;oBACL,QAAQ,EAAE,UAAU;oBACpB,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,GAAG,KAAK,IAAI;oBACnB,MAAM,EAAE,GAAG,MAAM,IAAI;oBACrB,aAAa,EAAE,MAAM;iBACtB,GACD,EACD,OAAO,KAAK,IAAI,IAAI,CACnB,gCACa,qBAAqB,EAChC,KAAK,EAAE;oBACL,QAAQ,EAAE,UAAU;oBACpB,MAAM,EAAE,CAAC;oBACT,IAAI,EAAE,CAAC;oBACP,OAAO,EAAE,gBAAgB;oBACzB,UAAU,EAAE,wBAAwB;oBACpC,KAAK,EAAE,SAAS;oBAChB,QAAQ,EAAE,QAAQ;oBAClB,UAAU,EAAE,gDAAgD;oBAC5D,YAAY,EAAE,CAAC;oBACf,aAAa,EAAE,MAAM;oBACrB,UAAU,EAAE,GAAG;iBAChB,aAED,sCAAc,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAQ,EAC/C,eAAK,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,qBAAO,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAQ,IAC9D,CACV,IACA,CACJ,CAAC;AACJ,CAAC"}