@printwithsynergy/artwork-pdf-editor 0.2.0 → 0.4.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 (244) 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/StreamingRenderProgress.d.ts +60 -0
  141. package/dist/components/StreamingRenderProgress.d.ts.map +1 -0
  142. package/dist/components/StreamingRenderProgress.js +99 -0
  143. package/dist/components/StreamingRenderProgress.js.map +1 -0
  144. package/dist/components/SwatchesPicker.d.ts +83 -0
  145. package/dist/components/SwatchesPicker.d.ts.map +1 -0
  146. package/dist/components/SwatchesPicker.js +151 -0
  147. package/dist/components/SwatchesPicker.js.map +1 -0
  148. package/dist/components/TacOverlay.d.ts +47 -0
  149. package/dist/components/TacOverlay.d.ts.map +1 -0
  150. package/dist/components/TacOverlay.js +116 -0
  151. package/dist/components/TacOverlay.js.map +1 -0
  152. package/dist/components/TrapEditorPanel.d.ts +52 -0
  153. package/dist/components/TrapEditorPanel.d.ts.map +1 -0
  154. package/dist/components/TrapEditorPanel.js +64 -0
  155. package/dist/components/TrapEditorPanel.js.map +1 -0
  156. package/dist/components/TrapPreviewOverlay.d.ts +64 -0
  157. package/dist/components/TrapPreviewOverlay.d.ts.map +1 -0
  158. package/dist/components/TrapPreviewOverlay.js +120 -0
  159. package/dist/components/TrapPreviewOverlay.js.map +1 -0
  160. package/dist/components/VariantMatrixPanel.d.ts +61 -0
  161. package/dist/components/VariantMatrixPanel.d.ts.map +1 -0
  162. package/dist/components/VariantMatrixPanel.js +97 -0
  163. package/dist/components/VariantMatrixPanel.js.map +1 -0
  164. package/dist/components/VariantMatrixVersionPanel.d.ts +122 -0
  165. package/dist/components/VariantMatrixVersionPanel.d.ts.map +1 -0
  166. package/dist/components/VariantMatrixVersionPanel.js +162 -0
  167. package/dist/components/VariantMatrixVersionPanel.js.map +1 -0
  168. package/dist/components/WebhookNotifyPanel.d.ts +160 -0
  169. package/dist/components/WebhookNotifyPanel.d.ts.map +1 -0
  170. package/dist/components/WebhookNotifyPanel.js +100 -0
  171. package/dist/components/WebhookNotifyPanel.js.map +1 -0
  172. package/dist/components/WhiteUnderbasePanel.d.ts +107 -0
  173. package/dist/components/WhiteUnderbasePanel.d.ts.map +1 -0
  174. package/dist/components/WhiteUnderbasePanel.js +104 -0
  175. package/dist/components/WhiteUnderbasePanel.js.map +1 -0
  176. package/dist/hooks/useEditorMode.d.ts +25 -5
  177. package/dist/hooks/useEditorMode.d.ts.map +1 -1
  178. package/dist/hooks/useEditorMode.js +18 -5
  179. package/dist/hooks/useEditorMode.js.map +1 -1
  180. package/dist/index.d.ts +51 -2
  181. package/dist/index.d.ts.map +1 -1
  182. package/dist/index.js +51 -2
  183. package/dist/index.js.map +1 -1
  184. package/dist/lens/preflight-findings.d.ts.map +1 -1
  185. package/dist/lens/preflight-findings.js.map +1 -1
  186. package/dist/lib/barcode-scan.d.ts +154 -0
  187. package/dist/lib/barcode-scan.d.ts.map +1 -0
  188. package/dist/lib/barcode-scan.js +152 -0
  189. package/dist/lib/barcode-scan.js.map +1 -0
  190. package/dist/lib/color-math.d.ts +76 -0
  191. package/dist/lib/color-math.d.ts.map +1 -0
  192. package/dist/lib/color-math.js +96 -0
  193. package/dist/lib/color-math.js.map +1 -0
  194. package/dist/lib/dieline-template.d.ts +87 -0
  195. package/dist/lib/dieline-template.d.ts.map +1 -1
  196. package/dist/lib/dieline-template.js +163 -0
  197. package/dist/lib/dieline-template.js.map +1 -1
  198. package/dist/lib/editor-config.d.ts +390 -0
  199. package/dist/lib/editor-config.d.ts.map +1 -1
  200. package/dist/lib/editor-config.js +90 -0
  201. package/dist/lib/editor-config.js.map +1 -1
  202. package/dist/lib/fold-geometry.d.ts +144 -0
  203. package/dist/lib/fold-geometry.d.ts.map +1 -0
  204. package/dist/lib/fold-geometry.js +138 -0
  205. package/dist/lib/fold-geometry.js.map +1 -0
  206. package/dist/lib/merge-tokens.d.ts +81 -0
  207. package/dist/lib/merge-tokens.d.ts.map +1 -0
  208. package/dist/lib/merge-tokens.js +88 -0
  209. package/dist/lib/merge-tokens.js.map +1 -0
  210. package/dist/lib/palette-registry.d.ts +40 -0
  211. package/dist/lib/palette-registry.d.ts.map +1 -0
  212. package/dist/lib/palette-registry.js +50 -0
  213. package/dist/lib/palette-registry.js.map +1 -0
  214. package/dist/lib/panel-anchor.d.ts +101 -0
  215. package/dist/lib/panel-anchor.d.ts.map +1 -0
  216. package/dist/lib/panel-anchor.js +68 -0
  217. package/dist/lib/panel-anchor.js.map +1 -0
  218. package/dist/lib/preflight/checks.d.ts.map +1 -1
  219. package/dist/lib/preflight/checks.js +71 -0
  220. package/dist/lib/preflight/checks.js.map +1 -1
  221. package/dist/lib/preflight/types.d.ts.map +1 -1
  222. package/dist/lib/preflight/types.js +11 -0
  223. package/dist/lib/preflight/types.js.map +1 -1
  224. package/dist/lib/rasterize.d.ts +93 -0
  225. package/dist/lib/rasterize.d.ts.map +1 -0
  226. package/dist/lib/rasterize.js +117 -0
  227. package/dist/lib/rasterize.js.map +1 -0
  228. package/dist/lib/separations-registry.d.ts +99 -0
  229. package/dist/lib/separations-registry.d.ts.map +1 -0
  230. package/dist/lib/separations-registry.js +59 -0
  231. package/dist/lib/separations-registry.js.map +1 -0
  232. package/dist/lib/streaming-render.d.ts +100 -0
  233. package/dist/lib/streaming-render.d.ts.map +1 -0
  234. package/dist/lib/streaming-render.js +132 -0
  235. package/dist/lib/streaming-render.js.map +1 -0
  236. package/dist/lib/unwired.d.ts +29 -0
  237. package/dist/lib/unwired.d.ts.map +1 -0
  238. package/dist/lib/unwired.js +58 -0
  239. package/dist/lib/unwired.js.map +1 -0
  240. package/package.json +20 -11
  241. package/dist/components/SeparationsPanel.d.ts +0 -9
  242. package/dist/components/SeparationsPanel.d.ts.map +0 -1
  243. package/dist/components/SeparationsPanel.js +0 -168
  244. package/dist/components/SeparationsPanel.js.map +0 -1
@@ -1,17 +1,58 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  "use client";
3
3
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
+ import { parseARD, parseCF2, parseDDES } from "@artworkpdf/dieline-parser";
4
5
  import { useCallback, useRef, useState } from "react";
5
- export function FileDropZone({ onFile }) {
6
+ /**
7
+ * Detect which dieline-parser to invoke for a given filename.
8
+ * Returns `null` for non-dieline files (caller falls back to the
9
+ * normal PDF / image path).
10
+ */
11
+ function dielineParserFor(name) {
12
+ const lower = name.toLowerCase();
13
+ if (lower.endsWith(".cf2"))
14
+ return parseCF2;
15
+ if (lower.endsWith(".ddes"))
16
+ return parseDDES;
17
+ if (lower.endsWith(".ard"))
18
+ return parseARD;
19
+ return null;
20
+ }
21
+ export function FileDropZone({ onFile, onDieline }) {
6
22
  const [dragging, setDragging] = useState(false);
23
+ const [parseError, setParseError] = useState(null);
7
24
  const inputRef = useRef(null);
8
- const handle = useCallback((file) => {
25
+ const dielineSupported = onDieline !== undefined;
26
+ const handle = useCallback(async (file) => {
27
+ setParseError(null);
28
+ // Try the dieline-parser path first when the host supports it
29
+ // (onDieline provided). PDF / image still flows through the
30
+ // legacy `onFile` → preflight path. When dielines aren't
31
+ // supported, .cf2 / .ddes / .ard files fall through to the
32
+ // PDF/image check below and are silently rejected.
33
+ const dielineParser = dielineSupported ? dielineParserFor(file.name) : null;
34
+ if (dielineParser && onDieline) {
35
+ try {
36
+ const text = await file.text();
37
+ const dieline = dielineParser(text);
38
+ if (dieline.paths.length === 0) {
39
+ setParseError(`${file.name}: no recognizable paths in this dieline file.`);
40
+ return;
41
+ }
42
+ onDieline(dieline);
43
+ }
44
+ catch (err) {
45
+ const msg = err instanceof Error ? err.message : String(err);
46
+ setParseError(`${file.name}: ${msg}`);
47
+ }
48
+ return;
49
+ }
9
50
  if (file.type === "application/pdf" ||
10
51
  file.name.toLowerCase().endsWith(".pdf") ||
11
52
  file.type.startsWith("image/")) {
12
53
  onFile(file);
13
54
  }
14
- }, [onFile]);
55
+ }, [onFile, onDieline, dielineSupported]);
15
56
  return (_jsxs("button", { type: "button", onDragOver: (e) => {
16
57
  e.preventDefault();
17
58
  setDragging(true);
@@ -33,7 +74,7 @@ export function FileDropZone({ onFile }) {
33
74
  width: "100%",
34
75
  fontFamily: "inherit",
35
76
  display: "block",
36
- }, children: [_jsx("input", { ref: inputRef, type: "file", accept: ".pdf,image/*", style: { display: "none" }, onChange: (e) => {
77
+ }, children: [_jsx("input", { ref: inputRef, type: "file", accept: dielineSupported ? ".pdf,.cf2,.ddes,.ard,image/*" : ".pdf,image/*", style: { display: "none" }, onChange: (e) => {
37
78
  const file = e.target.files?.[0];
38
79
  if (file)
39
80
  handle(file);
@@ -43,6 +84,13 @@ export function FileDropZone({ onFile }) {
43
84
  fontWeight: 600,
44
85
  marginBottom: "0.5rem",
45
86
  fontSize: "1rem",
46
- }, children: "Drop artwork file here" }), _jsx("span", { style: { display: "block", color: "#666", fontSize: "0.82rem" }, children: "PDF or raster image \u2014 preflight checks run before the canvas opens" })] }));
87
+ }, children: dielineSupported ? "Drop artwork or dieline file here" : "Drop artwork file here" }), _jsx("span", { style: { display: "block", color: "#666", fontSize: "0.82rem" }, children: dielineSupported
88
+ ? "PDF / raster image (runs preflight) — or CF2 / DDES / ARD (seeds the canvas directly)"
89
+ : "PDF or raster image — preflight checks run before the canvas opens" }), parseError && (_jsx("span", { role: "alert", "aria-live": "polite", style: {
90
+ display: "block",
91
+ color: "#ef4444",
92
+ marginTop: "0.65rem",
93
+ fontSize: "0.8rem",
94
+ }, children: parseError }))] }));
47
95
  }
48
96
  //# sourceMappingURL=FileDropZone.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FileDropZone.js","sourceRoot":"","sources":["../../src/components/FileDropZone.tsx"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,YAAY,CAAC;;AACb,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAMtD,MAAM,UAAU,YAAY,CAAC,EAAE,MAAM,EAAS;IAC5C,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAC;IAEhD,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,IAAU,EAAE,EAAE;QACb,IACE,IAAI,CAAC,IAAI,KAAK,iBAAiB;YAC/B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;YACxC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAC9B,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,CAAC;QACf,CAAC;IACH,CAAC,EACD,CAAC,MAAM,CAAC,CACT,CAAC;IAEF,OAAO,CACL,kBACE,IAAI,EAAC,QAAQ,EACb,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE;YAChB,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,WAAW,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,EACD,WAAW,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,EACrC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;YACZ,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,WAAW,CAAC,KAAK,CAAC,CAAC;YACnB,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,IAAI;gBAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC,EACD,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,EACxC,KAAK,EAAE;YACL,MAAM,EAAE,cAAc,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE;YACxD,YAAY,EAAE,EAAE;YAChB,OAAO,EAAE,WAAW;YACpB,SAAS,EAAE,QAAQ;YACnB,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,aAAa;YAC5D,UAAU,EAAE,sCAAsC;YAClD,QAAQ,EAAE,GAAG;YACb,KAAK,EAAE,MAAM;YACb,UAAU,EAAE,SAAS;YACrB,OAAO,EAAE,OAAO;SACjB,aAED,gBACE,GAAG,EAAE,QAAQ,EACb,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAC1B,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;oBACd,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;oBACjC,IAAI,IAAI;wBAAE,MAAM,CAAC,IAAI,CAAC,CAAC;gBACzB,CAAC,GACD,EACF,eACE,KAAK,EAAE;oBACL,OAAO,EAAE,OAAO;oBAChB,KAAK,EAAE,SAAS;oBAChB,UAAU,EAAE,GAAG;oBACf,YAAY,EAAE,QAAQ;oBACtB,QAAQ,EAAE,MAAM;iBACjB,uCAGI,EACP,eAAM,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,wFAE9D,IACA,CACV,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"FileDropZone.js","sourceRoot":"","sources":["../../src/components/FileDropZone.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Wave 2 S4 (PR-4) — interactive fold editor.
3
+ *
4
+ * Surfaces each fold edge in `FoldConfig` as a row with an angle
5
+ * slider, plus an OCG-style "show folded" toggle that hosts wire to
6
+ * the {@link FoldPreviewOverlay}'s active vs. flat view. Editing is
7
+ * controlled (`value` / `onChange`); the panel never owns state.
8
+ *
9
+ * Pairs with PR-3's `FoldPreviewOverlay` — the slider here updates
10
+ * `FoldConfig.edges[*].angleDeg`, and the overlay re-renders the
11
+ * Three.js scene on every commit.
12
+ *
13
+ * Designed to stay consumable without `@artworkpdf/document-model`:
14
+ * the value shape (`FoldEditorPanelValue`) mirrors the document-model
15
+ * `FoldConfig` field-for-field, same convention as
16
+ * `EditorSeparation`, `FoldGeometryPanelMetadata`,
17
+ * `EditorDielinePanel`.
18
+ *
19
+ * @public
20
+ */
21
+ /**
22
+ * One fold edge between two panels.
23
+ *
24
+ * @public
25
+ */
26
+ export type FoldEditorEdge = {
27
+ id: string;
28
+ panelA: string;
29
+ panelB: string;
30
+ angleDeg: number;
31
+ direction?: "mountain" | "valley";
32
+ };
33
+ /**
34
+ * Controlled value — mirrors document-model's `FoldConfig`.
35
+ *
36
+ * @public
37
+ */
38
+ export type FoldEditorPanelValue = {
39
+ edges: FoldEditorEdge[];
40
+ defaultAngleDeg?: number;
41
+ };
42
+ /**
43
+ * @public
44
+ */
45
+ export type FoldEditorPanelProps = {
46
+ /** Current fold configuration. `undefined` means "no panels with
47
+ * fold metadata" — the panel renders a placeholder. */
48
+ value: FoldEditorPanelValue | undefined;
49
+ /** Fires on every slider tick. Hosts debounce externally if the
50
+ * 3D scene rebuild becomes expensive. */
51
+ onChange: (next: FoldEditorPanelValue) => void;
52
+ /** When `true`, the {@link FoldPreviewOverlay} should render the
53
+ * *folded* state; when `false`, the flat unfolded state. Pure UI
54
+ * state — the value-side is unaffected. */
55
+ showFolded?: boolean;
56
+ /** Fires when the user toggles the show-folded switch. Hosts thread
57
+ * this back into a top-level UI flag and pass it to the overlay. */
58
+ onShowFoldedChange?: (next: boolean) => void;
59
+ /** Range bounds on the angle slider, in degrees. Defaults to
60
+ * `[-180, 180]` — the same range `FoldConfig` permits. */
61
+ minAngleDeg?: number;
62
+ maxAngleDeg?: number;
63
+ };
64
+ /**
65
+ * @public
66
+ */
67
+ export declare function FoldEditorPanel({ value, onChange, showFolded, onShowFoldedChange, minAngleDeg, maxAngleDeg, }: FoldEditorPanelProps): import("react/jsx-runtime").JSX.Element;
68
+ //# sourceMappingURL=FoldEditorPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FoldEditorPanel.d.ts","sourceRoot":"","sources":["../../src/components/FoldEditorPanel.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;CACnC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC;4DACwD;IACxD,KAAK,EAAE,oBAAoB,GAAG,SAAS,CAAC;IACxC;8CAC0C;IAC1C,QAAQ,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC/C;;gDAE4C;IAC5C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;yEACqE;IACrE,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C;+DAC2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAKF;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,WAAW,GACZ,EAAE,oBAAoB,2CAoHtB"}
@@ -0,0 +1,65 @@
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
+ const DEFAULT_MIN = -180;
5
+ const DEFAULT_MAX = 180;
6
+ /**
7
+ * @public
8
+ */
9
+ export function FoldEditorPanel({ value, onChange, showFolded, onShowFoldedChange, minAngleDeg, maxAngleDeg, }) {
10
+ const min = minAngleDeg ?? DEFAULT_MIN;
11
+ const max = maxAngleDeg ?? DEFAULT_MAX;
12
+ if (!value || value.edges.length === 0) {
13
+ return (_jsx("div", { "data-testid": "fold-editor-panel", style: { padding: "0.5rem", opacity: 0.6 }, children: "Load a dieline with fold metadata to edit panel angles." }));
14
+ }
15
+ const setEdgeAngle = (id, raw) => {
16
+ // In-progress edits ("", "-", "1e") parse to `NaN` / partial
17
+ // values — silently keep the last good angle so the user can
18
+ // type through to a valid one. The browser owns its `<input>`
19
+ // DOM value mid-edit, so the field still shows whatever they
20
+ // typed even though we haven't propagated it.
21
+ if (raw === "" || raw === "-" || raw === "+")
22
+ return;
23
+ const n = Number(raw);
24
+ if (!Number.isFinite(n))
25
+ return;
26
+ const clamped = Math.min(Math.max(n, min), max);
27
+ onChange({
28
+ ...value,
29
+ edges: value.edges.map((e) => (e.id === id ? { ...e, angleDeg: clamped } : e)),
30
+ });
31
+ };
32
+ const setEdgeDirection = (id, direction) => {
33
+ onChange({
34
+ ...value,
35
+ edges: value.edges.map((e) => {
36
+ if (e.id !== id)
37
+ return e;
38
+ // Clearing the select drops the field entirely — restores the
39
+ // "no direction declared" state so the renderer can fall back
40
+ // to its own heuristic.
41
+ if (direction === undefined) {
42
+ const { direction: _omit, ...rest } = e;
43
+ return rest;
44
+ }
45
+ return { ...e, direction };
46
+ }),
47
+ });
48
+ };
49
+ return (_jsxs("div", { "data-testid": "fold-editor-panel", style: { padding: "0.5rem" }, children: [_jsxs("header", { style: { display: "flex", alignItems: "baseline", gap: "0.5rem" }, children: [_jsx("h3", { style: { margin: 0 }, children: "Fold angles" }), onShowFoldedChange && (_jsxs("label", { style: { marginLeft: "auto", fontSize: "0.85rem" }, children: [_jsx("input", { type: "checkbox", checked: !!showFolded, onChange: (e) => onShowFoldedChange(e.target.checked), "aria-label": "Show folded preview" }), " ", "Show folded"] }))] }), _jsx("ul", { style: { listStyle: "none", padding: 0, margin: "0.5rem 0 0 0" }, children: value.edges.map((edge) => (_jsxs("li", { style: {
50
+ display: "grid",
51
+ gridTemplateColumns: "auto 1fr auto auto",
52
+ gap: "0.5rem",
53
+ alignItems: "center",
54
+ padding: "0.25rem 0",
55
+ }, children: [_jsxs("span", { style: { fontFamily: "monospace", fontSize: "0.85rem" }, children: [edge.panelA, " \u2194 ", edge.panelB] }), _jsx("input", { type: "range", min: min, max: max, step: 1, value: edge.angleDeg, onChange: (e) => setEdgeAngle(edge.id, e.target.value), "aria-label": `Angle for ${edge.id}` }), _jsx("input", { type: "number", min: min, max: max, step: 1, value: edge.angleDeg, onChange: (e) => setEdgeAngle(edge.id, e.target.value), "aria-label": `Numeric angle for ${edge.id}`, style: { width: "4rem" } }), _jsxs("select", { value: edge.direction ?? "", onChange: (e) => {
56
+ const v = e.target.value;
57
+ if (v === "mountain" || v === "valley") {
58
+ setEdgeDirection(edge.id, v);
59
+ }
60
+ else if (v === "") {
61
+ setEdgeDirection(edge.id, undefined);
62
+ }
63
+ }, "aria-label": `Fold direction for ${edge.id}`, children: [_jsx("option", { value: "", children: "\u2014" }), _jsx("option", { value: "mountain", children: "mountain" }), _jsx("option", { value: "valley", children: "valley" })] })] }, edge.id))) })] }));
64
+ }
65
+ //# sourceMappingURL=FoldEditorPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FoldEditorPanel.js","sourceRoot":"","sources":["../../src/components/FoldEditorPanel.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { type FoldGeometryConfig, type FoldGeometryPanelMetadata } from "../lib/fold-geometry";
2
+ /**
3
+ * S4 — 3D fold preview overlay (Wave 2 PR-3 scaffold).
4
+ *
5
+ * Renders a Three.js scene of the dieline's panels in 3D space.
6
+ * The PR-3 scaffold ships a *flat* preview (every panel at Z=0)
7
+ * with the hinge axes drawn in colored lines so the operator can
8
+ * see where folds will happen. Interactive fold-angle scrubbing
9
+ * lands in PR-4.
10
+ *
11
+ * Bundle note: Three.js is a hard dependency (~150 KB) so hosts
12
+ * paying for the editor get fold preview out of the box. Hosts that
13
+ * never need it can disable via {@link EditorConfig.enable_3d_fold_preview}
14
+ * — when the flag is `false`, this component is never rendered and
15
+ * the Three.js code path stays cold, but the symbols still ship
16
+ * with the bundle. A future refactor may switch to a dynamic
17
+ * `import("three")` for tighter chunking; that's deferred until the
18
+ * editor's bundle profile shows it's worth the complexity.
19
+ *
20
+ * The Three.js scene is owned by this component — it creates the
21
+ * renderer / scene / camera on mount, recomputes geometry on prop
22
+ * change, and disposes on unmount. Hosts get a controlled component:
23
+ * pass `panelMetadata` + `foldConfig`, get a rendered scene.
24
+ *
25
+ * @public
26
+ */
27
+ export type FoldPreviewOverlayProps = {
28
+ /** Panel registry derived from the active page's dieline.
29
+ * Structurally compatible with `document-model`'s `PanelMetadata`.
30
+ * When `undefined`, the overlay no-ops (renders an empty container). */
31
+ panelMetadata: FoldGeometryPanelMetadata | undefined;
32
+ /** Fold-edge config for the active page. Structurally compatible
33
+ * with `document-model`'s `FoldConfig`. When `undefined`, panels
34
+ * are still rendered (flat layout), but no hinge lines appear. */
35
+ foldConfig?: FoldGeometryConfig | undefined;
36
+ /** Container dimensions in CSS pixels. */
37
+ width: number;
38
+ height: number;
39
+ /** Optional background color for the 3D viewport (CSS color
40
+ * string). Defaults to a transparent canvas so the overlay can
41
+ * layer over the editor's existing chrome. */
42
+ backgroundColor?: string;
43
+ };
44
+ /**
45
+ * @public
46
+ */
47
+ export declare function FoldPreviewOverlay({ panelMetadata, foldConfig, width, height, backgroundColor, }: FoldPreviewOverlayProps): import("react/jsx-runtime").JSX.Element;
48
+ //# sourceMappingURL=FoldPreviewOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FoldPreviewOverlay.d.ts","sourceRoot":"","sources":["../../src/components/FoldPreviewOverlay.tsx"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAG/B,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC;;6EAEyE;IACzE,aAAa,EAAE,yBAAyB,GAAG,SAAS,CAAC;IACrD;;uEAEmE;IACnE,UAAU,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAC5C,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf;;mDAE+C;IAC/C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,aAAa,EACb,UAAU,EACV,KAAK,EACL,MAAM,EACN,eAAe,GAChB,EAAE,uBAAuB,2CA6FzB"}
@@ -0,0 +1,182 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ "use client";
3
+ import { jsx as _jsx } from "react/jsx-runtime";
4
+ import { useEffect, useRef } from "react";
5
+ import { buildFoldScene, } from "../lib/fold-geometry";
6
+ /**
7
+ * @public
8
+ */
9
+ export function FoldPreviewOverlay({ panelMetadata, foldConfig, width, height, backgroundColor, }) {
10
+ const containerRef = useRef(null);
11
+ const sceneRef = useRef(null);
12
+ // Hold the latest props in a ref so the mount effect's initial
13
+ // scene picks them up without depending on them — depending on
14
+ // `panelMetadata` / `foldConfig` here would tear down + recreate
15
+ // the renderer on every edit, defeating the per-update apply path
16
+ // in the second effect.
17
+ const propsRef = useRef({ panelMetadata, foldConfig });
18
+ propsRef.current = { panelMetadata, foldConfig };
19
+ useEffect(() => {
20
+ const container = containerRef.current;
21
+ if (!container)
22
+ return;
23
+ // Guard zero / negative dimensions — `setSize(0, 0)` produces a
24
+ // degenerate canvas and `width / height` on the camera becomes
25
+ // NaN/Infinity. Layout transitions can briefly hit this during
26
+ // mount; defer scene creation until both dims are positive.
27
+ if (width <= 0 || height <= 0)
28
+ return;
29
+ let runtime = null;
30
+ let disposed = false;
31
+ (async () => {
32
+ const three = await import("three");
33
+ if (disposed)
34
+ return;
35
+ const created = await createScene(three, container, width, height, backgroundColor);
36
+ // Re-check after the second await — cleanup may have fired
37
+ // during `await createScene(...)`. At that point `runtime` was
38
+ // still null in the cleanup closure, so it couldn't dispose;
39
+ // do it here ourselves before the renderer / canvas escape.
40
+ if (disposed) {
41
+ disposeScene(created);
42
+ return;
43
+ }
44
+ runtime = created;
45
+ sceneRef.current = runtime;
46
+ const { panelMetadata: pm, foldConfig: fc } = propsRef.current;
47
+ const spec = pm ? buildFoldScene(pm, fc) : EMPTY_SCENE;
48
+ applyScene(three, runtime, spec);
49
+ // Render-on-change: PR-3's scaffold is static, so one draw per
50
+ // mutation is enough. PR-4 swaps this for a RAF loop driven by
51
+ // user interaction (drag-to-fold), so the loop machinery isn't
52
+ // worth keeping cold here.
53
+ runtime.renderer.render(runtime.scene, runtime.camera);
54
+ })().catch((err) => {
55
+ // Swallow rejections after unmount; surface real errors during
56
+ // mount (chunk-load failures from `import("three")`, WebGL
57
+ // context creation failure, etc.) via console so devtools can
58
+ // catch them.
59
+ if (!disposed)
60
+ console.error("[FoldPreviewOverlay] scene init failed", err);
61
+ });
62
+ return () => {
63
+ disposed = true;
64
+ sceneRef.current = null;
65
+ if (runtime)
66
+ disposeScene(runtime);
67
+ };
68
+ }, [width, height, backgroundColor]);
69
+ useEffect(() => {
70
+ const runtime = sceneRef.current;
71
+ if (!runtime)
72
+ return;
73
+ let disposed = false;
74
+ (async () => {
75
+ const three = await import("three");
76
+ if (disposed)
77
+ return;
78
+ // When panelMetadata becomes undefined, apply an empty scene
79
+ // so previously rendered meshes / hinges clear off the canvas —
80
+ // matches the documented no-op behaviour for absent metadata.
81
+ const spec = panelMetadata ? buildFoldScene(panelMetadata, foldConfig) : EMPTY_SCENE;
82
+ applyScene(three, runtime, spec);
83
+ runtime.renderer.render(runtime.scene, runtime.camera);
84
+ })().catch((err) => {
85
+ if (!disposed)
86
+ console.error("[FoldPreviewOverlay] scene update failed", err);
87
+ });
88
+ return () => {
89
+ disposed = true;
90
+ };
91
+ }, [panelMetadata, foldConfig]);
92
+ return (_jsx("div", { ref: containerRef, "data-testid": "fold-preview-overlay", style: {
93
+ position: "relative",
94
+ width,
95
+ height,
96
+ pointerEvents: "auto",
97
+ } }));
98
+ }
99
+ /** Empty scene spec used to clear the canvas when `panelMetadata`
100
+ * is absent. Keeps the meshes / hinges from a previous render off
101
+ * the screen. */
102
+ const EMPTY_SCENE = {
103
+ panels: [],
104
+ hinges: [],
105
+ bounds: { min: [0, 0, 0], max: [0, 0, 0] },
106
+ };
107
+ async function createScene(three, container, width, height, backgroundColor) {
108
+ const renderer = new three.WebGLRenderer({ antialias: true, alpha: !backgroundColor });
109
+ renderer.setSize(width, height);
110
+ renderer.setPixelRatio(typeof window !== "undefined" ? window.devicePixelRatio : 1);
111
+ container.replaceChildren(renderer.domElement);
112
+ const scene = new three.Scene();
113
+ if (backgroundColor) {
114
+ scene.background = new three.Color(backgroundColor);
115
+ }
116
+ const camera = new three.PerspectiveCamera(45, width / height, 0.1, 10000);
117
+ camera.position.set(0, 0, 500);
118
+ const light = new three.HemisphereLight(0xffffff, 0x202020, 1);
119
+ scene.add(light);
120
+ const panelGroup = new three.Group();
121
+ const hingeGroup = new three.Group();
122
+ scene.add(panelGroup, hingeGroup);
123
+ const runtime = {
124
+ renderer,
125
+ scene,
126
+ camera,
127
+ panelGroup,
128
+ hingeGroup,
129
+ resources: [],
130
+ };
131
+ return runtime;
132
+ }
133
+ function applyScene(three, runtime, spec) {
134
+ // Tear down previous geometry without disposing the renderer.
135
+ runtime.panelGroup.clear();
136
+ runtime.hingeGroup.clear();
137
+ for (const r of runtime.resources)
138
+ r.dispose?.();
139
+ runtime.resources = [];
140
+ for (const panel of spec.panels) {
141
+ const geo = new three.BufferGeometry();
142
+ const positions = new Float32Array(panel.corners.flatMap((c) => [c[0], c[1], c[2]]));
143
+ geo.setAttribute("position", new three.BufferAttribute(positions, 3));
144
+ geo.setIndex([0, 1, 2, 0, 2, 3]);
145
+ geo.computeVertexNormals();
146
+ const mat = new three.MeshStandardMaterial({
147
+ color: 0xe6e6e6,
148
+ side: three.DoubleSide,
149
+ roughness: 0.6,
150
+ metalness: 0.0,
151
+ });
152
+ runtime.panelGroup.add(new three.Mesh(geo, mat));
153
+ runtime.resources.push(geo, mat);
154
+ }
155
+ for (const hinge of spec.hinges) {
156
+ const geo = new three.BufferGeometry().setFromPoints([
157
+ new three.Vector3(hinge.from[0], hinge.from[1], hinge.from[2]),
158
+ new three.Vector3(hinge.to[0], hinge.to[1], hinge.to[2]),
159
+ ]);
160
+ const mat = new three.LineBasicMaterial({
161
+ color: hinge.direction === "mountain" ? 0x2563eb : 0xdc2626,
162
+ linewidth: 2,
163
+ });
164
+ runtime.hingeGroup.add(new three.Line(geo, mat));
165
+ runtime.resources.push(geo, mat);
166
+ }
167
+ // Frame the camera around the scene bounds.
168
+ const { min, max } = spec.bounds;
169
+ const cx = (min[0] + max[0]) / 2;
170
+ const cy = (min[1] + max[1]) / 2;
171
+ const span = Math.max(max[0] - min[0], max[1] - min[1], 1);
172
+ runtime.camera.position.set(cx, cy, span * 1.2);
173
+ runtime.camera.lookAt(cx, cy, 0);
174
+ }
175
+ function disposeScene(runtime) {
176
+ for (const r of runtime.resources)
177
+ r.dispose?.();
178
+ runtime.resources = [];
179
+ runtime.renderer.dispose?.();
180
+ runtime.renderer.domElement?.parentElement?.removeChild(runtime.renderer.domElement);
181
+ }
182
+ //# sourceMappingURL=FoldPreviewOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FoldPreviewOverlay.js","sourceRoot":"","sources":["../../src/components/FoldPreviewOverlay.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ import type { BarcodeRenderFn, BarcodeRenderResult } from "./BarcodeGeneratorPanel";
2
+ /**
3
+ * One additional GS1 Application Identifier carried in either the URL
4
+ * path or query string. `ai` is the numeric AI (e.g. `"10"` for lot,
5
+ * `"17"` for expiration date `YYMMDD`); `value` is the raw payload
6
+ * before percent-encoding.
7
+ *
8
+ * The composer percent-encodes `value` automatically; callers should
9
+ * pass the human-readable form.
10
+ *
11
+ * @public
12
+ */
13
+ export type Gs1AiEntry = {
14
+ ai: string;
15
+ value: string;
16
+ };
17
+ /**
18
+ * Result returned by {@link composeGs1DigitalLink}. `url` is the
19
+ * canonical GS1 Digital Link form ready to be QR-encoded;
20
+ * `pathSegment` and `querySegment` are the split halves the host can
21
+ * surface separately (e.g. a "preview" UI that highlights mandatory
22
+ * vs. optional segments).
23
+ *
24
+ * @public
25
+ */
26
+ export type Gs1DigitalLinkResult = {
27
+ url: string;
28
+ pathSegment: string;
29
+ querySegment: string;
30
+ };
31
+ /**
32
+ * @public
33
+ */
34
+ export type Gs1DigitalLinkPanelProps = {
35
+ /** Optional renderer (typically the same adapter wired for
36
+ * {@link import("./BarcodeGeneratorPanel").BarcodeGeneratorPanel}).
37
+ * When supplied, "Generate QR" calls it with `format: "QR"` and the
38
+ * composed Digital Link URL; the bitmap flows to `onRendered`. When
39
+ * absent, the panel only emits the URL via `onLink`. */
40
+ renderer?: BarcodeRenderFn;
41
+ /** Fired when the user clicks **Preview URL** or **Generate QR**
42
+ * with the composed URL. The panel does not fire on every
43
+ * keystroke — hosts that want live preview should poll the
44
+ * current form values via their own state or wrap
45
+ * {@link composeGs1DigitalLink} themselves. */
46
+ onLink?: (result: Gs1DigitalLinkResult) => void;
47
+ /** Fired with the rendered bitmap when the host has wired a
48
+ * `renderer` and the user clicks "Generate QR". */
49
+ onRendered?: (result: BarcodeRenderResult) => void;
50
+ /** Default resolver domain — typically `"id.gs1.org"` or a
51
+ * brand-owned alternate. Defaults to `"id.gs1.org"` (the GS1
52
+ * community default) when omitted. */
53
+ defaultDomain?: string;
54
+ };
55
+ /**
56
+ * The GS1 community-default resolver domain. Re-exported for hosts
57
+ * that want to display it as a hint or seed a settings UI.
58
+ *
59
+ * @public
60
+ */
61
+ export declare const DEFAULT_GS1_DOMAIN = "id.gs1.org";
62
+ /**
63
+ * Validate a GS1 AI 17 (expiration date) value: must be exactly six
64
+ * digits in `YYMMDD` order with month 1-12 and a real calendar day.
65
+ * Year is two digits per the GS1 spec so the validator checks the
66
+ * day against an arbitrary 21st-century year — the year value itself
67
+ * does not constrain the calendar.
68
+ *
69
+ * Exported alongside {@link composeGs1DigitalLink} so server-side
70
+ * callers can reject invalid expiries before composing.
71
+ *
72
+ * @public
73
+ */
74
+ export declare function isValidGs1Ai17(value: string): boolean;
75
+ /**
76
+ * Compose a canonical GS1 Digital Link URL from a GTIN + optional
77
+ * path-AIs + optional query-AIs. Pure function — exported so server
78
+ * components (Next.js RSC, Astro frontmatter) can pre-compute URLs
79
+ * without bundling the panel.
80
+ *
81
+ * Path-AI order is `22 → 10 → 21` per the GS1 Digital Link Standard;
82
+ * any other AIs flow into the query string in the order supplied.
83
+ *
84
+ * @public
85
+ */
86
+ export declare function composeGs1DigitalLink(input: {
87
+ domain: string;
88
+ gtin: string;
89
+ pathAis?: readonly Gs1AiEntry[];
90
+ queryAis?: readonly Gs1AiEntry[];
91
+ }): Gs1DigitalLinkResult;
92
+ /**
93
+ * GS1 Digital Link composer panel. The user picks a domain, types a
94
+ * GTIN, optionally adds CPV / lot / serial path-AIs and free-form
95
+ * query-AIs; the panel emits the composed URL via `onLink`. When the
96
+ * host wires a `renderer`, a "Generate QR" button hands the URL to
97
+ * the adapter with `format: "QR"` and forwards the bitmap to
98
+ * `onRendered`.
99
+ *
100
+ * @public
101
+ */
102
+ export declare function Gs1DigitalLinkPanel({ renderer, onLink, onRendered, defaultDomain, }: Gs1DigitalLinkPanelProps): import("react/jsx-runtime").JSX.Element;
103
+ //# sourceMappingURL=Gs1DigitalLinkPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Gs1DigitalLinkPanel.d.ts","sourceRoot":"","sources":["../../src/components/Gs1DigitalLinkPanel.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEpF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;;6DAIyD;IACzD,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B;;;;oDAIgD;IAChD,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAChD;wDACoD;IACpD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACnD;;2CAEuC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAI/C;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAUrD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;CAClC,GAAG,oBAAoB,CA6BvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,UAAU,EACV,aAAkC,GACnC,EAAE,wBAAwB,2CA6K1B"}