@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 @@
1
+ {"version":3,"file":"ProcessRulesPanel.d.ts","sourceRoot":"","sources":["../../src/components/ProcessRulesPanel.tsx"],"names":[],"mappings":"AA0BA;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB;sEACkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,KAAK,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAAC;AAEtC;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;CAC/B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC;qCACiC;IACjC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC;sEACkE;IAClE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,6DAA6D;IAC7D,MAAM,EAAE,oBAAoB,CAAC;IAC7B;iEAC6D;IAC7D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC;;;;iCAI6B;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,SAAS,gBAAgB,EAAE,CAa9F;AAQD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,WAAW,EACX,OAAO,EACP,MAAM,EACN,QAAQ,EACR,cAAc,GACf,EAAE,sBAAsB,2CA+FxB"}
@@ -0,0 +1,143 @@
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
+ /**
5
+ * Wave 4 P2 — Process-specific preflight panel.
6
+ *
7
+ * Surfaces process-physics findings — flexo white-knockout, gravure
8
+ * max line frequency, screen-print halftone limits, offset overprint
9
+ * traps — separately from generic preflight (which covers
10
+ * "does this PDF parse / render") and from {@link ComplianceFindingsPanel}
11
+ * (which covers "is this artwork *allowed* on the chosen substrate /
12
+ * market"). The three-way split keeps the audiences focused: a press
13
+ * operator wants the physics, a brand lead wants the compliance, a
14
+ * support engineer wants the parse errors.
15
+ *
16
+ * Adapter pattern: hosts wire an async function that POSTs the
17
+ * document + active process to lint-pdf's `/v1/preflight/process`
18
+ * endpoint and filters to process-physics rules. The editor stays
19
+ * free of any runtime dep on lint-pdf's HTTP client; same approach
20
+ * as {@link ComplianceFindingsPanel}, {@link InksPanel}, etc.
21
+ *
22
+ * @public
23
+ */
24
+ import { useEffect, useState } from "react";
25
+ /**
26
+ * Group a flat list of findings by `process` key in first-occurrence
27
+ * order. Pure function; exposed for hosts that want their own
28
+ * rendering on top of the same grouping.
29
+ *
30
+ * @public
31
+ */
32
+ export function groupRulesByProcess(rules) {
33
+ const order = [];
34
+ const buckets = new Map();
35
+ for (const r of rules) {
36
+ let bucket = buckets.get(r.process);
37
+ if (!bucket) {
38
+ bucket = [];
39
+ buckets.set(r.process, bucket);
40
+ order.push(r.process);
41
+ }
42
+ bucket.push(r);
43
+ }
44
+ return order.map((process) => ({ process, rules: buckets.get(process) ?? [] }));
45
+ }
46
+ const SEVERITY_COLORS = {
47
+ error: "#a00",
48
+ warn: "#a60",
49
+ info: "#06a",
50
+ };
51
+ /**
52
+ * @public
53
+ */
54
+ export function ProcessRulesPanel({ documentB64, process, loader, onSelect, groupByProcess, }) {
55
+ const [rules, setRules] = useState(null);
56
+ const [error, setError] = useState(null);
57
+ const [loading, setLoading] = useState(false);
58
+ useEffect(() => {
59
+ if (!documentB64 || !process) {
60
+ setRules(null);
61
+ setError(null);
62
+ return;
63
+ }
64
+ let disposed = false;
65
+ setLoading(true);
66
+ setError(null);
67
+ // Clear stale findings while the next fetch is in flight — if a
68
+ // caller ever bypasses the `loading` guard, we don't want the
69
+ // previous process's rules to flash through.
70
+ setRules(null);
71
+ // Wrap in an async IIFE so a *synchronous* throw from the adapter
72
+ // (e.g. a host validating inputs before constructing fetch) flows
73
+ // through the same `setError` path as a rejected Promise.
74
+ void (async () => {
75
+ try {
76
+ const next = await loader({ documentB64, process });
77
+ if (disposed)
78
+ return;
79
+ setRules(next);
80
+ }
81
+ catch (err) {
82
+ if (disposed)
83
+ return;
84
+ setError(err instanceof Error ? err.message : String(err));
85
+ }
86
+ finally {
87
+ if (!disposed)
88
+ setLoading(false);
89
+ }
90
+ })();
91
+ return () => {
92
+ disposed = true;
93
+ };
94
+ }, [documentB64, process, loader]);
95
+ if (!documentB64 || !process) {
96
+ return (_jsx("div", { "data-testid": "process-rules-panel", style: { padding: "0.5rem", opacity: 0.6 }, children: "Set process in Job Setup, then export to see process-specific findings." }));
97
+ }
98
+ if (loading) {
99
+ return (_jsx("div", { "data-testid": "process-rules-panel", style: { padding: "0.5rem", opacity: 0.6 }, children: "Checking process rules\u2026" }));
100
+ }
101
+ if (error) {
102
+ return (_jsxs("div", { "data-testid": "process-rules-panel", role: "alert", style: { padding: "0.5rem", color: "#a00" }, children: ["Couldn't load process rules: ", error] }));
103
+ }
104
+ if (!rules || rules.length === 0) {
105
+ return (_jsxs("div", { "data-testid": "process-rules-panel", style: { padding: "0.5rem", opacity: 0.6 }, children: ["No process-specific issues for ", process, "."] }));
106
+ }
107
+ const groups = groupByProcess ? groupRulesByProcess(rules) : null;
108
+ return (_jsxs("div", { "data-testid": "process-rules-panel", style: { padding: "0.5rem" }, children: [_jsxs("h3", { style: { margin: "0 0 0.5rem 0" }, children: ["Process rules (", rules.length, ")"] }), groups ? (groups.map((g) => (_jsxs("section", { style: { marginBottom: "0.75rem" }, children: [_jsxs("h4", { style: {
109
+ margin: "0 0 0.25rem 0",
110
+ fontSize: "0.875rem",
111
+ textTransform: "capitalize",
112
+ }, children: [g.process, " (", g.rules.length, ")"] }), _jsx(ProcessRulesList, { rules: g.rules, onSelect: onSelect })] }, g.process)))) : (_jsx(ProcessRulesList, { rules: rules, onSelect: onSelect }))] }));
113
+ }
114
+ function ProcessRulesList({ rules, onSelect, }) {
115
+ return (_jsx("ul", { style: { listStyle: "none", padding: 0, margin: 0 }, children: rules.map((r, i) => {
116
+ // Append the array index so duplicate (ruleId, pageIndex,
117
+ // objectId, process) tuples still get unique React keys.
118
+ const key = `${r.ruleId}-${r.process}-${r.pageIndex ?? "doc"}-${r.objectId ?? ""}-${i}`;
119
+ const rowContents = (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", style: {
120
+ display: "inline-block",
121
+ width: "0.5rem",
122
+ height: "0.5rem",
123
+ borderRadius: "50%",
124
+ background: SEVERITY_COLORS[r.severity],
125
+ flexShrink: 0,
126
+ } }), _jsx("span", { style: { flex: 1 }, children: r.message }), _jsxs("small", { style: { opacity: 0.6, fontFamily: "monospace" }, children: [r.ruleId, r.pageIndex !== undefined ? ` · p${r.pageIndex + 1}` : ""] })] }));
127
+ const rowStyle = {
128
+ display: "flex",
129
+ alignItems: "baseline",
130
+ gap: "0.5rem",
131
+ width: "100%",
132
+ padding: "0.25rem 0.5rem",
133
+ };
134
+ return (_jsx("li", { children: onSelect ? (_jsx("button", { type: "button", onClick: () => onSelect(r), "aria-label": `Process rule: ${r.message} (${r.ruleId}${r.pageIndex !== undefined ? `, page ${r.pageIndex + 1}` : ""})`, style: {
135
+ ...rowStyle,
136
+ background: "transparent",
137
+ border: "none",
138
+ cursor: "pointer",
139
+ textAlign: "left",
140
+ }, children: rowContents })) : (_jsx("div", { style: rowStyle, children: rowContents })) }, key));
141
+ }) }));
142
+ }
143
+ //# sourceMappingURL=ProcessRulesPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessRulesPanel.js","sourceRoot":"","sources":["../../src/components/ProcessRulesPanel.tsx"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,YAAY,CAAC;;AAEb;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AA0E5C;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAA6B;IAC/D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IACjD,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,eAAe,GAA4C;IAC/D,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;CACb,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,WAAW,EACX,OAAO,EACP,MAAM,EACN,QAAQ,EACR,cAAc,GACS;IACvB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgC,IAAI,CAAC,CAAC;IACxE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,WAAW,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,OAAO;QACT,CAAC;QACD,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,gEAAgE;QAChE,8DAA8D;QAC9D,6CAA6C;QAC7C,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,kEAAkE;QAClE,kEAAkE;QAClE,0DAA0D;QAC1D,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;gBACpD,IAAI,QAAQ;oBAAE,OAAO;gBACrB,QAAQ,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,IAAI,QAAQ;oBAAE,OAAO;gBACrB,QAAQ,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7D,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC,QAAQ;oBAAE,UAAU,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,GAAG,EAAE;YACV,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAEnC,IAAI,CAAC,WAAW,IAAI,CAAC,OAAO,EAAE,CAAC;QAC7B,OAAO,CACL,6BAAiB,qBAAqB,EAAC,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,wFAE3E,CACP,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CACL,6BAAiB,qBAAqB,EAAC,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,6CAE3E,CACP,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CACL,8BACc,qBAAqB,EACjC,IAAI,EAAC,OAAO,EACZ,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,8CAEb,KAAK,IAC/B,CACP,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,CACL,8BAAiB,qBAAqB,EAAC,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,gDAC/C,OAAO,SACnC,CACP,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClE,OAAO,CACL,8BAAiB,qBAAqB,EAAC,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,aACjE,cAAI,KAAK,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,gCAAkB,KAAK,CAAC,MAAM,SAAO,EACzE,MAAM,CAAC,CAAC,CAAC,CACR,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAChB,mBAAyB,KAAK,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,aACzD,cACE,KAAK,EAAE;4BACL,MAAM,EAAE,eAAe;4BACvB,QAAQ,EAAE,UAAU;4BACpB,aAAa,EAAE,YAAY;yBAC5B,aAEA,CAAC,CAAC,OAAO,QAAI,CAAC,CAAC,KAAK,CAAC,MAAM,SACzB,EACL,KAAC,gBAAgB,IAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAI,KAV5C,CAAC,CAAC,OAAO,CAWb,CACX,CAAC,CACH,CAAC,CAAC,CAAC,CACF,KAAC,gBAAgB,IAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAI,CACvD,IACG,CACP,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,QAAQ,GAIT;IACC,OAAO,CACL,aAAI,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,YACpD,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAClB,0DAA0D;YAC1D,yDAAyD;YACzD,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,SAAS,IAAI,KAAK,IAAI,CAAC,CAAC,QAAQ,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACxF,MAAM,WAAW,GAAG,CAClB,8BACE,8BACc,MAAM,EAClB,KAAK,EAAE;4BACL,OAAO,EAAE,cAAc;4BACvB,KAAK,EAAE,QAAQ;4BACf,MAAM,EAAE,QAAQ;4BAChB,YAAY,EAAE,KAAK;4BACnB,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC;4BACvC,UAAU,EAAE,CAAC;yBACd,GACD,EACF,eAAM,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,YAAG,CAAC,CAAC,OAAO,GAAQ,EAC5C,iBAAO,KAAK,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,aACpD,CAAC,CAAC,MAAM,EACR,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IACpD,IACP,CACJ,CAAC;YACF,MAAM,QAAQ,GAAG;gBACf,OAAO,EAAE,MAAM;gBACf,UAAU,EAAE,UAAU;gBACtB,GAAG,EAAE,QAAQ;gBACb,KAAK,EAAE,MAAM;gBACb,OAAO,EAAE,gBAAgB;aACjB,CAAC;YACX,OAAO,CACL,uBACG,QAAQ,CAAC,CAAC,CAAC,CACV,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,gBACd,iBAAiB,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GACjD,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAC5D,GAAG,EACH,KAAK,EAAE;wBACL,GAAG,QAAQ;wBACX,UAAU,EAAE,aAAa;wBACzB,MAAM,EAAE,MAAM;wBACd,MAAM,EAAE,SAAS;wBACjB,SAAS,EAAE,MAAM;qBAClB,YAEA,WAAW,GACL,CACV,CAAC,CAAC,CAAC,CACF,cAAK,KAAK,EAAE,QAAQ,YAAG,WAAW,GAAO,CAC1C,IApBM,GAAG,CAqBP,CACN,CAAC;QACJ,CAAC,CAAC,GACC,CACN,CAAC;AACJ,CAAC"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Wave 4 I3 — Slack-notify panel.
3
+ *
4
+ * A small panel that lets the user emit a Slack notification keyed
5
+ * to a typed editor event (preflight cleared, job submitted, variant
6
+ * approved, …). The panel handles the UI; the actual webhook POST
7
+ * is host-wired via a {@link SlackNotifyFn} adapter so the editor
8
+ * stays runtime-free of any Slack SDK / fetch wrapper.
9
+ *
10
+ * Pairs with the synergy `slack.notify` workflow node when one is
11
+ * deployed — the host typically wires `notify` to that node so the
12
+ * webhook URL stays server-side. Hosts without a synergy bridge can
13
+ * also POST straight to a Slack incoming-webhook URL from their own
14
+ * client code; the adapter shape is intentionally agnostic.
15
+ *
16
+ * Designed around the same loader/adapter pattern as
17
+ * {@link MisEstimateButton}, {@link SwatchesPicker}, etc.
18
+ *
19
+ * @public
20
+ */
21
+ import type { ReactElement } from "react";
22
+ /**
23
+ * The set of editor events that map to canonical Slack message
24
+ * templates. `"custom"` is the escape hatch — when the user wants to
25
+ * send a free-form message that isn't tied to an event,
26
+ * {@link composeSlackMessage} renders just `context.text` and ignores
27
+ * the rest of the context.
28
+ *
29
+ * @public
30
+ */
31
+ export type SlackNotificationEventKind = "preflight-blocked" | "preflight-cleared" | "job-submitted" | "variant-approved" | "approval-requested" | "custom";
32
+ /**
33
+ * Context passed to {@link composeSlackMessage}. Most fields are
34
+ * optional and only render when the chosen event template references
35
+ * them — e.g. `findingCount` is consulted by `"preflight-blocked"` and
36
+ * `"preflight-cleared"` and ignored otherwise.
37
+ *
38
+ * @public
39
+ */
40
+ export type SlackNotificationContext = {
41
+ /** Human-readable document name surfaced as the message subject. */
42
+ documentName?: string;
43
+ /** Stable identifier the host uses to link back to the document. */
44
+ documentId?: string;
45
+ /** Optional clickable URL — Slack renders this as a link below the
46
+ * subject line so reviewers can jump straight into the editor. */
47
+ documentUrl?: string;
48
+ /** Preflight finding count (errors only for `"preflight-blocked"`,
49
+ * total resolved for `"preflight-cleared"`). */
50
+ findingCount?: number;
51
+ /** Variant id for `"variant-approved"`. */
52
+ variantId?: string;
53
+ /** Reviewer / submitter display name surfaced as the message
54
+ * byline. */
55
+ actor?: string;
56
+ /** Free-form additional text appended to the canonical template
57
+ * (or, for `"custom"`, used as the entire body). */
58
+ text?: string;
59
+ };
60
+ /**
61
+ * Canonical Slack incoming-webhook payload shape (subset: only the
62
+ * fields the panel emits). Hosts that need richer payloads (`blocks`,
63
+ * `attachments`, threading) wrap their own adapter that augments the
64
+ * panel output before POSTing.
65
+ *
66
+ * @public
67
+ */
68
+ export type SlackNotificationPayload = {
69
+ /** Optional channel override (e.g. `"#preflight"`). When absent the
70
+ * host's webhook URL determines the channel. */
71
+ channel?: string;
72
+ /** Message text. Slack's webhook treats this as the fallback /
73
+ * notification text and the main body when no `blocks` are
74
+ * supplied. */
75
+ text: string;
76
+ };
77
+ /**
78
+ * Pure helper — renders a {@link SlackNotificationContext} into a
79
+ * canonical Slack message payload. The mapping is intentionally
80
+ * simple (one short line per event template) so hosts that want
81
+ * richer messages can post-process the output. Pure function; no I/O.
82
+ *
83
+ * `"custom"` returns `context.text` verbatim (or a placeholder when
84
+ * empty) — the helper never silently drops the message.
85
+ *
86
+ * @public
87
+ */
88
+ export declare function composeSlackMessage(kind: SlackNotificationEventKind, context: SlackNotificationContext): SlackNotificationPayload;
89
+ /**
90
+ * Host adapter — POSTs the composed payload to Slack (typically via
91
+ * a server-side proxy or the synergy `slack.notify` node). Resolves
92
+ * on accept; rejects on transport / validation errors and the panel
93
+ * surfaces the message inline.
94
+ *
95
+ * @public
96
+ */
97
+ export type SlackNotifyFn = (payload: SlackNotificationPayload) => Promise<void>;
98
+ /**
99
+ * Human-readable labels for each event kind, in the order they
100
+ * appear in the dropdown. Exported so hosts that re-use the picker
101
+ * shape (e.g. in a settings page) stay in lockstep with the panel.
102
+ *
103
+ * @public
104
+ */
105
+ export declare const SLACK_NOTIFICATION_EVENT_LABELS: Readonly<Record<SlackNotificationEventKind, string>>;
106
+ /**
107
+ * @public
108
+ */
109
+ export type SlackNotifyPanelProps = {
110
+ /** Host adapter, see {@link SlackNotifyFn}. */
111
+ notify: SlackNotifyFn;
112
+ /** Context the panel renders into the chosen event template. The
113
+ * host typically wires this to the active document. */
114
+ context: SlackNotificationContext;
115
+ /** Optional initial event selection. Defaults to
116
+ * `"preflight-blocked"` — the most common trigger. */
117
+ defaultEvent?: SlackNotificationEventKind;
118
+ /** Optional channel override. When absent, the panel's "Channel"
119
+ * input is empty and the host's webhook URL decides routing. */
120
+ defaultChannel?: string;
121
+ /** Optional mapper that turns a notify error into a user-facing
122
+ * message. The default avoids leaking internal `Error.message`
123
+ * strings; hosts that want richer surfaces (e.g. validation-error
124
+ * toasts) pass their own mapper. The original error is still
125
+ * passed in so hosts can log it. */
126
+ errorMessage?: (err: unknown) => string;
127
+ /** Optional callback fired on successful notify so the host can
128
+ * show a confirmation toast / log analytics. */
129
+ onSuccess?: (payload: SlackNotificationPayload) => void;
130
+ };
131
+ /**
132
+ * Stateful panel — picks an event template, lets the user override
133
+ * channel + append a custom note, composes the payload via
134
+ * {@link composeSlackMessage}, and POSTs through the host adapter.
135
+ *
136
+ * @public
137
+ */
138
+ export declare function SlackNotifyPanel({ notify, context, defaultEvent, defaultChannel, errorMessage, onSuccess, }: SlackNotifyPanelProps): ReactElement;
139
+ //# sourceMappingURL=SlackNotifyPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlackNotifyPanel.d.ts","sourceRoot":"","sources":["../../src/components/SlackNotifyPanel.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C;;;;;;;;GAQG;AACH,MAAM,MAAM,0BAA0B,GAClC,mBAAmB,GACnB,mBAAmB,GACnB,eAAe,GACf,kBAAkB,GAClB,oBAAoB,GACpB,QAAQ,CAAC;AAEb;;;;;;;GAOG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;uEACmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;qDACiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;kBACc;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;yDACqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;qDACiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;oBAEgB;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,0BAA0B,EAChC,OAAO,EAAE,wBAAwB,GAChC,wBAAwB,CAyC1B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEjF;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B,EAAE,QAAQ,CAAC,MAAM,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAQ9F,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,+CAA+C;IAC/C,MAAM,EAAE,aAAa,CAAC;IACtB;4DACwD;IACxD,OAAO,EAAE,wBAAwB,CAAC;IAClC;2DACuD;IACvD,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAC1C;qEACiE;IACjE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;yCAIqC;IACrC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAC;IACxC;qDACiD;IACjD,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACzD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,OAAO,EACP,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,SAAS,GACV,EAAE,qBAAqB,GAAG,YAAY,CAuHtC"}
@@ -0,0 +1,133 @@
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 { useState } from "react";
5
+ /**
6
+ * Pure helper — renders a {@link SlackNotificationContext} into a
7
+ * canonical Slack message payload. The mapping is intentionally
8
+ * simple (one short line per event template) so hosts that want
9
+ * richer messages can post-process the output. Pure function; no I/O.
10
+ *
11
+ * `"custom"` returns `context.text` verbatim (or a placeholder when
12
+ * empty) — the helper never silently drops the message.
13
+ *
14
+ * @public
15
+ */
16
+ export function composeSlackMessage(kind, context) {
17
+ const subject = context.documentName ?? context.documentId ?? "an artwork document";
18
+ const actor = context.actor ? ` by ${context.actor}` : "";
19
+ const link = context.documentUrl ? ` <${context.documentUrl}|open>` : "";
20
+ const trailer = context.text ? ` — ${context.text}` : "";
21
+ switch (kind) {
22
+ case "preflight-blocked": {
23
+ // Treat undefined / unknown counts as "no number to show" rather
24
+ // than "0" — "Preflight blocked: 0 findings" reads as a
25
+ // contradiction even though it's how a number-less template
26
+ // would default.
27
+ const n = context.findingCount;
28
+ const findingsFragment = typeof n === "number" ? `: ${n} finding${n === 1 ? "" : "s"}` : "";
29
+ return {
30
+ text: `Preflight blocked on ${subject}${actor}${findingsFragment}${link}${trailer}`,
31
+ };
32
+ }
33
+ case "preflight-cleared":
34
+ return {
35
+ text: `Preflight cleared on ${subject}${actor}${link}${trailer}`,
36
+ };
37
+ case "job-submitted":
38
+ return {
39
+ text: `Job submitted for ${subject}${actor}${link}${trailer}`,
40
+ };
41
+ case "variant-approved": {
42
+ const v = context.variantId ? ` (${context.variantId})` : "";
43
+ return {
44
+ text: `Variant approved on ${subject}${v}${actor}${link}${trailer}`,
45
+ };
46
+ }
47
+ case "approval-requested":
48
+ return {
49
+ text: `Approval requested on ${subject}${actor}${link}${trailer}`,
50
+ };
51
+ case "custom":
52
+ return {
53
+ text: context.text?.trim() ? context.text : `Update on ${subject}${actor}${link}`,
54
+ };
55
+ }
56
+ }
57
+ /**
58
+ * Human-readable labels for each event kind, in the order they
59
+ * appear in the dropdown. Exported so hosts that re-use the picker
60
+ * shape (e.g. in a settings page) stay in lockstep with the panel.
61
+ *
62
+ * @public
63
+ */
64
+ export const SLACK_NOTIFICATION_EVENT_LABELS = {
65
+ "preflight-blocked": "Preflight blocked",
66
+ "preflight-cleared": "Preflight cleared",
67
+ "job-submitted": "Job submitted",
68
+ "variant-approved": "Variant approved",
69
+ "approval-requested": "Approval requested",
70
+ custom: "Custom message",
71
+ };
72
+ /**
73
+ * Stateful panel — picks an event template, lets the user override
74
+ * channel + append a custom note, composes the payload via
75
+ * {@link composeSlackMessage}, and POSTs through the host adapter.
76
+ *
77
+ * @public
78
+ */
79
+ export function SlackNotifyPanel({ notify, context, defaultEvent, defaultChannel, errorMessage, onSuccess, }) {
80
+ const [event, setEvent] = useState(defaultEvent ?? "preflight-blocked");
81
+ const [channel, setChannel] = useState(defaultChannel ?? "");
82
+ const [note, setNote] = useState("");
83
+ const [state, setState] = useState({ kind: "idle" });
84
+ // Clear the success / error chip when the user edits any input —
85
+ // a "Sent" indicator next to an unsent payload reads as a lie. The
86
+ // wrapper keeps the original setter ergonomic at every call site.
87
+ const resetOutcome = () => {
88
+ setState((prev) => (prev.kind === "ok" || prev.kind === "error" ? { kind: "idle" } : prev));
89
+ };
90
+ const onClick = async () => {
91
+ setState({ kind: "sending" });
92
+ const composed = composeSlackMessage(event, {
93
+ ...context,
94
+ ...(note.trim() && { text: note }),
95
+ });
96
+ const payload = {
97
+ ...composed,
98
+ ...(channel.trim() && { channel: channel.trim() }),
99
+ };
100
+ try {
101
+ await notify(payload);
102
+ setState({ kind: "ok" });
103
+ onSuccess?.(payload);
104
+ }
105
+ catch (err) {
106
+ // Guard against a host-supplied errorMessage that throws (e.g.
107
+ // makes assumptions about `err`'s shape) — without the inner
108
+ // try/catch the panel would silently swallow the failure and
109
+ // never enter the `error` state.
110
+ let message = "Couldn't send Slack notification.";
111
+ if (errorMessage) {
112
+ try {
113
+ message = errorMessage(err);
114
+ }
115
+ catch {
116
+ // fall back to the default message
117
+ }
118
+ }
119
+ setState({ kind: "error", message });
120
+ }
121
+ };
122
+ return (_jsxs("div", { "data-testid": "slack-notify-panel", style: { padding: "0.5rem" }, children: [_jsx("header", { style: { marginBottom: "0.5rem" }, children: _jsx("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: "Slack notify" }) }), _jsxs("label", { style: { display: "block", fontSize: "0.75rem", marginBottom: "0.5rem" }, children: ["Event", _jsx("select", { "aria-label": "Event", value: event, onChange: (e) => {
123
+ setEvent(e.target.value);
124
+ resetOutcome();
125
+ }, style: { display: "block", marginTop: "0.125rem", width: "100%" }, children: Object.entries(SLACK_NOTIFICATION_EVENT_LABELS).map(([k, label]) => (_jsx("option", { value: k, children: label }, k))) })] }), _jsxs("label", { style: { display: "block", fontSize: "0.75rem", marginBottom: "0.5rem" }, children: ["Channel", _jsx("input", { type: "text", "aria-label": "Channel", placeholder: "#preflight (optional)", value: channel, onChange: (e) => {
126
+ setChannel(e.target.value);
127
+ resetOutcome();
128
+ }, style: { display: "block", marginTop: "0.125rem", width: "100%" } })] }), _jsxs("label", { style: { display: "block", fontSize: "0.75rem", marginBottom: "0.5rem" }, children: ["Note", _jsx("textarea", { "aria-label": "Note", placeholder: "Optional \u2014 appended to the message", value: note, onChange: (e) => {
129
+ setNote(e.target.value);
130
+ resetOutcome();
131
+ }, rows: 2, style: { display: "block", marginTop: "0.125rem", width: "100%" } })] }), _jsxs("div", { style: { display: "flex", gap: "0.5rem", alignItems: "center" }, children: [_jsx("button", { type: "button", onClick: onClick, disabled: state.kind === "sending", "aria-busy": state.kind === "sending", children: state.kind === "sending" ? "Sending…" : "Notify Slack" }), state.kind === "ok" && (_jsx("output", { style: { color: "#080", fontSize: "0.75rem" }, children: "Sent" })), state.kind === "error" && (_jsx("span", { role: "alert", style: { color: "#a00", fontSize: "0.75rem" }, children: state.message }))] })] }));
132
+ }
133
+ //# sourceMappingURL=SlackNotifyPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlackNotifyPanel.js","sourceRoot":"","sources":["../../src/components/SlackNotifyPanel.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Wave 4 AI2 — Smart spot-match panel.
3
+ *
4
+ * Resolves a user-picked CMYK / Lab / hex color to a ranked list of
5
+ * nearest-PANTONE candidates via a host-supplied loader (typically
6
+ * fronting compile-pdf's `/v1/spots/match` endpoint or a tenant-local
7
+ * ΔE engine). Each match carries the canonical {@link Spot} entry +
8
+ * its ΔE distance from the query so the picker can render
9
+ * "good / borderline / poor" cues without the editor doing color
10
+ * math itself.
11
+ *
12
+ * Sibling of {@link SwatchesPicker} — that one searches the PANTONE
13
+ * catalogue by name, this one searches it by color value. Pairs with
14
+ * the AI4 `registerSpot` flow (Wave 1) — clicking a match feeds the
15
+ * selected `Spot` into the host's separations registry.
16
+ *
17
+ * @public
18
+ */
19
+ import type { ReactElement } from "react";
20
+ import type { Spot } from "./SwatchesPicker";
21
+ /**
22
+ * One color-space query the loader recognizes. At least one of
23
+ * `cmyk` / `lab` / `hex` must be present. The host's loader picks
24
+ * the most accurate space available (Lab > CMYK > hex) when more
25
+ * than one is supplied.
26
+ *
27
+ * @public
28
+ */
29
+ export type SpotMatchQuery = {
30
+ /** Percent CMYK in `[0, 100]` per channel. */
31
+ cmyk?: readonly [number, number, number, number];
32
+ /** CIE Lab — L in `[0, 100]`, a/b roughly `[-128, 128]`. */
33
+ lab?: readonly [number, number, number];
34
+ /** 7-char sRGB hex including the leading `#` (e.g. `"#ff5102"`). */
35
+ hex?: string;
36
+ /** Optional cap on the number of returned matches; loaders that
37
+ * ignore it must still return a stable ordering. */
38
+ limit?: number;
39
+ };
40
+ /**
41
+ * One ranked match — the canonical PANTONE entry + its ΔE distance
42
+ * from the query. The panel sorts matches ascending on `deltaE`
43
+ * (best first) via {@link sortMatchesByDeltaE}.
44
+ *
45
+ * @public
46
+ */
47
+ export type SpotMatch = {
48
+ spot: Spot;
49
+ /** CIE ΔE distance. Smaller is better; under ~1 is "imperceptible",
50
+ * 1–3 is "noticeable", >5 is "poor". */
51
+ deltaE: number;
52
+ };
53
+ /**
54
+ * Host adapter — resolves a {@link SpotMatchQuery} to a ranked list
55
+ * of {@link SpotMatch} candidates. Rejects on transport / validation
56
+ * errors and the panel surfaces the message inline. Hosts should
57
+ * memoize the function with `useCallback` so an unrelated parent
58
+ * re-render doesn't trigger a spurious refetch.
59
+ *
60
+ * @public
61
+ */
62
+ export type SpotMatchLoaderFn = (query: SpotMatchQuery) => Promise<readonly SpotMatch[]>;
63
+ /**
64
+ * Configuration for the {@link SmartSpotMatchPanel}. The host always
65
+ * supplies the {@link SpotMatchLoaderFn}; the other three props are
66
+ * optional and shape the panel's initial state and selection
67
+ * behaviour. Hosts that want to drive the query from outside the
68
+ * panel (e.g. wire the active fill colour straight in) flow that
69
+ * through `initialQuery`; the panel re-derives its query whenever
70
+ * `initialQuery`'s content changes.
71
+ *
72
+ * @public
73
+ */
74
+ export type SmartSpotMatchPanelProps = {
75
+ /** Host adapter, see {@link SpotMatchLoaderFn}. */
76
+ loader: SpotMatchLoaderFn;
77
+ /** Optional initial query — pre-fills the form. Hosts wire this to
78
+ * the active object's fill / stroke color when the user opens the
79
+ * panel from a swatch chip. */
80
+ initialQuery?: SpotMatchQuery;
81
+ /** Optional cap on returned matches. Defaults to 12 — enough to
82
+ * cover the standard `5 ΔE` neighborhood without overwhelming the
83
+ * scroll surface. */
84
+ limit?: number;
85
+ /** Click callback. Receives the full {@link SpotMatch} so hosts
86
+ * can wire it into a separations registry / fill picker. */
87
+ onSelect?: (match: SpotMatch) => void;
88
+ };
89
+ /**
90
+ * Pure helper — sorts a `SpotMatch` list ascending on `deltaE`
91
+ * (best-first). Stable on ties: input order preserved. Returns a
92
+ * new array.
93
+ *
94
+ * @public
95
+ */
96
+ export declare function sortMatchesByDeltaE(matches: readonly SpotMatch[]): readonly SpotMatch[];
97
+ /**
98
+ * Pure helper — classifies a ΔE distance into the conventional
99
+ * print-industry quality band so renderers can color-code matches
100
+ * consistently. Thresholds are the standard CIE-1994 perceptual cut
101
+ * points; the panel uses them for the result-row severity chip.
102
+ *
103
+ * @public
104
+ */
105
+ export type DeltaEQuality = "imperceptible" | "noticeable" | "fair" | "poor";
106
+ /**
107
+ * Pure helper — maps a ΔE distance to a {@link DeltaEQuality} band
108
+ * using the CIE-1994 perceptual cut points (under 1 is
109
+ * imperceptible, 1–3 is noticeable, 3–5 is fair, ≥5 is poor). Used
110
+ * by the panel for the per-row severity chip; exported so hosts can
111
+ * surface the same banding outside the panel (e.g. in a print-proof
112
+ * audit). Returns `"poor"` for non-finite or negative inputs by
113
+ * threshold ordering — callers should pre-validate if they care.
114
+ *
115
+ * @public
116
+ */
117
+ export declare function deltaEQuality(deltaE: number): DeltaEQuality;
118
+ /**
119
+ * Pure helper — formats ΔE for chip / row display (e.g. `"ΔE 1.2"`).
120
+ * Two-decimal precision matches what most ΔE engines emit and what
121
+ * print shops quote.
122
+ *
123
+ * @public
124
+ */
125
+ export declare function formatDeltaE(deltaE: number): string;
126
+ /**
127
+ * Pure helper — quickly checks whether a query has at least one
128
+ * color-space populated. Exported so hosts that drive the loader
129
+ * from outside the panel can gate their fetch on the same predicate.
130
+ *
131
+ * @public
132
+ */
133
+ export declare function isQueryReady(query: SpotMatchQuery): boolean;
134
+ /**
135
+ * Stateful panel — accepts a CMYK or hex input, calls the host
136
+ * loader, and surfaces ranked matches with ΔE chips. Hosts wire
137
+ * `onSelect` to push the picked spot into the active object's fill
138
+ * / stroke or into the separations registry.
139
+ *
140
+ * @public
141
+ */
142
+ export declare function SmartSpotMatchPanel({ loader, initialQuery, limit, onSelect, }: SmartSpotMatchPanelProps): ReactElement;
143
+ //# sourceMappingURL=SmartSpotMatchPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmartSpotMatchPanel.d.ts","sourceRoot":"","sources":["../../src/components/SmartSpotMatchPanel.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE1C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,8CAA8C;IAC9C,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,4DAA4D;IAC5D,GAAG,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;yDACqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,IAAI,CAAC;IACX;6CACyC;IACzC,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;AAEzF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,mDAAmD;IACnD,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;oCAEgC;IAChC,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B;;0BAEsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;iEAC6D;IAC7D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,SAAS,EAAE,CAKvF;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7E;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAM3D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAE3D;AASD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,YAAY,EACZ,KAAK,EACL,QAAQ,GACT,EAAE,wBAAwB,GAAG,YAAY,CAqGzC"}