@printwithsynergy/artwork-pdf-editor 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ContrastLegibilityPanel.d.ts +71 -0
- package/dist/components/ContrastLegibilityPanel.d.ts.map +1 -0
- package/dist/components/ContrastLegibilityPanel.js +123 -0
- package/dist/components/ContrastLegibilityPanel.js.map +1 -0
- package/dist/components/DirectionIndicatorsOverlay.d.ts +55 -0
- package/dist/components/DirectionIndicatorsOverlay.d.ts.map +1 -0
- package/dist/components/DirectionIndicatorsOverlay.js +126 -0
- package/dist/components/DirectionIndicatorsOverlay.js.map +1 -0
- package/dist/components/StreamingRenderProgress.d.ts +60 -0
- package/dist/components/StreamingRenderProgress.d.ts.map +1 -0
- package/dist/components/StreamingRenderProgress.js +99 -0
- package/dist/components/StreamingRenderProgress.js.map +1 -0
- package/dist/components/SubstrateSimOverlay.d.ts +56 -0
- package/dist/components/SubstrateSimOverlay.d.ts.map +1 -0
- package/dist/components/SubstrateSimOverlay.js +39 -0
- package/dist/components/SubstrateSimOverlay.js.map +1 -0
- package/dist/components/wave4-extras.d.ts +326 -0
- package/dist/components/wave4-extras.d.ts.map +1 -0
- package/dist/components/wave4-extras.js +264 -0
- package/dist/components/wave4-extras.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/editor-config.d.ts +41 -1
- package/dist/lib/editor-config.d.ts.map +1 -1
- package/dist/lib/editor-config.js +15 -0
- package/dist/lib/editor-config.js.map +1 -1
- package/dist/lib/palette-registry.d.ts.map +1 -1
- package/dist/lib/palette-registry.js +14 -0
- package/dist/lib/palette-registry.js.map +1 -1
- package/dist/lib/streaming-render.d.ts +100 -0
- package/dist/lib/streaming-render.d.ts.map +1 -0
- package/dist/lib/streaming-render.js +132 -0
- package/dist/lib/streaming-render.js.map +1 -0
- package/dist/lib/structural-export.d.ts +84 -0
- package/dist/lib/structural-export.d.ts.map +1 -0
- package/dist/lib/structural-export.js +100 -0
- package/dist/lib/structural-export.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
"use client";
|
|
3
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
4
|
+
function finishOverlay(finish) {
|
|
5
|
+
switch (finish) {
|
|
6
|
+
case "gloss":
|
|
7
|
+
return "linear-gradient(135deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0) 60%)";
|
|
8
|
+
case "satin":
|
|
9
|
+
return "linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0) 70%)";
|
|
10
|
+
case "matte":
|
|
11
|
+
return "none";
|
|
12
|
+
case "uncoated":
|
|
13
|
+
return "radial-gradient(circle at 30% 20%, rgba(0,0,0,0.04) 0%, transparent 70%)";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Pure-render substrate simulation overlay.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export function SubstrateSimOverlay({ spec }) {
|
|
22
|
+
const { widthPx, heightPx, color, opacity, finish } = spec;
|
|
23
|
+
return (_jsx("div", { "data-testid": "substrate-sim-overlay", "aria-hidden": "true", style: {
|
|
24
|
+
position: "absolute",
|
|
25
|
+
top: 0,
|
|
26
|
+
left: 0,
|
|
27
|
+
width: widthPx,
|
|
28
|
+
height: heightPx,
|
|
29
|
+
background: color,
|
|
30
|
+
opacity,
|
|
31
|
+
pointerEvents: "none",
|
|
32
|
+
}, children: _jsx("div", { "data-testid": "substrate-sim-finish-layer", style: {
|
|
33
|
+
position: "absolute",
|
|
34
|
+
inset: 0,
|
|
35
|
+
background: finishOverlay(finish),
|
|
36
|
+
pointerEvents: "none",
|
|
37
|
+
} }) }));
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=SubstrateSimOverlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubstrateSimOverlay.js","sourceRoot":"","sources":["../../src/components/SubstrateSimOverlay.tsx"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,YAAY,CAAC;;AAuDb,SAAS,aAAa,CAAC,MAAkC;IACvD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO;YACV,OAAO,6EAA6E,CAAC;QACvF,KAAK,OAAO;YACV,OAAO,6EAA6E,CAAC;QACvF,KAAK,OAAO;YACV,OAAO,MAAM,CAAC;QAChB,KAAK,UAAU;YACb,OAAO,0EAA0E,CAAC;IACtF,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAE,IAAI,EAA4B;IACpE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC3D,OAAO,CACL,6BACc,uBAAuB,iBACvB,MAAM,EAClB,KAAK,EAAE;YACL,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,CAAC;YACN,IAAI,EAAE,CAAC;YACP,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,KAAK;YACjB,OAAO;YACP,aAAa,EAAE,MAAM;SACtB,YAED,6BACc,4BAA4B,EACxC,KAAK,EAAE;gBACL,QAAQ,EAAE,UAAU;gBACpB,KAAK,EAAE,CAAC;gBACR,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC;gBACjC,aAAa,EAAE,MAAM;aACtB,GACD,GACE,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wave 4 long-tail — consolidated panels for the playbook's
|
|
3
|
+
* remaining loader-adapter surfaces. Each export is a small,
|
|
4
|
+
* focused React panel + its adapter type, sharing the same
|
|
5
|
+
* load-on-mount / render-list / surface-error lifecycle as the
|
|
6
|
+
* rest of the AI / I family. Hosts wire one
|
|
7
|
+
* {@link FeatureLoaderFn} per panel; this module hosts no
|
|
8
|
+
* network calls of its own.
|
|
9
|
+
*
|
|
10
|
+
* Features in this bundle:
|
|
11
|
+
*
|
|
12
|
+
* - **B2** {@link DamAssetsPanel} (DAM hookup) — list of
|
|
13
|
+
* approved assets pulled from the host's DAM connector.
|
|
14
|
+
* - **X3** {@link ApprovedMasterDiffPanel} — visual diff vs the
|
|
15
|
+
* pinned master version.
|
|
16
|
+
* - **AI1** {@link CopyGenerationPanel} — Claude-style copy
|
|
17
|
+
* generation with length-to-fit constraint.
|
|
18
|
+
* - **AI2** {@link ImageGenerationPanel} — CMYK-aware image gen
|
|
19
|
+
* with DPI guarantees.
|
|
20
|
+
* - **AI3** {@link AutoLayoutPanel} — auto-arrange/fit solver.
|
|
21
|
+
* - **AI5** {@link OcrRebuildPanel} — OCR a reference pack
|
|
22
|
+
* image and reconstruct editable objects.
|
|
23
|
+
* - **V3** {@link LocalizationPanel} — per-language variants
|
|
24
|
+
* with text-expansion warnings.
|
|
25
|
+
* - **I1** {@link DesignHandoffPanel} — Figma / Adobe import.
|
|
26
|
+
* - **I2** {@link EcommerceConnectorPanel} — Shopify product
|
|
27
|
+
* pull / SKU variants.
|
|
28
|
+
* - **I3** {@link PimConnectorPanel} — PIM bind for merge
|
|
29
|
+
* fields.
|
|
30
|
+
*
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
import type { ReactElement } from "react";
|
|
34
|
+
/** @public */
|
|
35
|
+
export type DamAsset = {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
kind: "image" | "logo" | "font" | "swatch" | "other";
|
|
39
|
+
url?: string;
|
|
40
|
+
rights?: string;
|
|
41
|
+
};
|
|
42
|
+
/** @public */
|
|
43
|
+
export type DamAssetsLoaderFn = (query?: string) => Promise<readonly DamAsset[]>;
|
|
44
|
+
/** @public */
|
|
45
|
+
export type DamAssetsPanelProps = {
|
|
46
|
+
loader: DamAssetsLoaderFn;
|
|
47
|
+
onSelect?: (asset: DamAsset) => void;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* B2 — DAM assets browser. The host wires a
|
|
51
|
+
* {@link DamAssetsLoaderFn} adapter that fronts Bynder /
|
|
52
|
+
* Brandfolder / any DAM API; this panel renders the asset list
|
|
53
|
+
* with usage-rights chips when supplied.
|
|
54
|
+
*
|
|
55
|
+
* @public
|
|
56
|
+
*/
|
|
57
|
+
export declare function DamAssetsPanel({ loader, onSelect }: DamAssetsPanelProps): ReactElement;
|
|
58
|
+
/** @public */
|
|
59
|
+
export type ApprovedMasterDiffChange = {
|
|
60
|
+
id: string;
|
|
61
|
+
kind: "text" | "color" | "moved" | "added" | "removed";
|
|
62
|
+
summary: string;
|
|
63
|
+
objectId?: string;
|
|
64
|
+
};
|
|
65
|
+
/** @public */
|
|
66
|
+
export type ApprovedMasterDiffLoaderFn = () => Promise<readonly ApprovedMasterDiffChange[]>;
|
|
67
|
+
/** @public */
|
|
68
|
+
export type ApprovedMasterDiffPanelProps = {
|
|
69
|
+
loader: ApprovedMasterDiffLoaderFn;
|
|
70
|
+
onSelect?: (change: ApprovedMasterDiffChange) => void;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* X3 — Diff vs the pinned approved master. Each change row
|
|
74
|
+
* shows kind + summary; the host wires the actual diff
|
|
75
|
+
* computation (typically codex `vision/phash` + per-separation
|
|
76
|
+
* structural diff).
|
|
77
|
+
*
|
|
78
|
+
* @public
|
|
79
|
+
*/
|
|
80
|
+
export declare function ApprovedMasterDiffPanel({ loader, onSelect, }: ApprovedMasterDiffPanelProps): ReactElement;
|
|
81
|
+
/** @public */
|
|
82
|
+
export type CopyGenerationRequest = {
|
|
83
|
+
/** Prompt or seed text the LLM should expand/refine. */
|
|
84
|
+
prompt: string;
|
|
85
|
+
/** Max character count the generated copy must fit in
|
|
86
|
+
* (drives length-to-fit warnings). */
|
|
87
|
+
maxChars: number;
|
|
88
|
+
/** Optional brand-voice hints. */
|
|
89
|
+
voice?: string;
|
|
90
|
+
};
|
|
91
|
+
/** @public */
|
|
92
|
+
export type CopyGenerationResult = {
|
|
93
|
+
text: string;
|
|
94
|
+
/** Reasons the host should surface — typically risky-claim
|
|
95
|
+
* flags from the AI safety pass. */
|
|
96
|
+
warnings: readonly string[];
|
|
97
|
+
};
|
|
98
|
+
/** @public */
|
|
99
|
+
export type CopyGenerationFn = (req: CopyGenerationRequest) => Promise<CopyGenerationResult>;
|
|
100
|
+
/** @public */
|
|
101
|
+
export type CopyGenerationPanelProps = {
|
|
102
|
+
generator: CopyGenerationFn;
|
|
103
|
+
initialPrompt?: string;
|
|
104
|
+
maxChars?: number;
|
|
105
|
+
onResult?: (result: CopyGenerationResult) => void;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* AI1 — Copy generation panel. Wraps a host-supplied LLM
|
|
109
|
+
* adapter (typically codex `ai/claude` + `spell` + budget). The
|
|
110
|
+
* panel owns the prompt input + max-chars constraint and the
|
|
111
|
+
* generate-button lifecycle; the host wires the adapter.
|
|
112
|
+
*
|
|
113
|
+
* @public
|
|
114
|
+
*/
|
|
115
|
+
export declare function CopyGenerationPanel({ generator, initialPrompt, maxChars, onResult, }: CopyGenerationPanelProps): ReactElement;
|
|
116
|
+
/** @public */
|
|
117
|
+
export type ImageGenerationRequest = {
|
|
118
|
+
prompt: string;
|
|
119
|
+
/** Width in mm at the target print resolution. */
|
|
120
|
+
widthMm: number;
|
|
121
|
+
heightMm: number;
|
|
122
|
+
/** Target DPI — typically 300 for press; codex `ai/dispatcher`
|
|
123
|
+
* enforces. */
|
|
124
|
+
dpi: number;
|
|
125
|
+
/** Convert from sRGB to a CMYK profile? Host implementation. */
|
|
126
|
+
cmykProfile?: string;
|
|
127
|
+
};
|
|
128
|
+
/** @public */
|
|
129
|
+
export type ImageGenerationResult = {
|
|
130
|
+
/** Image data URL or external URL the host can use as the
|
|
131
|
+
* fill source. */
|
|
132
|
+
url: string;
|
|
133
|
+
widthPx: number;
|
|
134
|
+
heightPx: number;
|
|
135
|
+
/** Provenance tag (e.g. `"ai-generated"`) for downstream
|
|
136
|
+
* labelling per AI provenance rules. */
|
|
137
|
+
provenance: string;
|
|
138
|
+
};
|
|
139
|
+
/** @public */
|
|
140
|
+
export type ImageGenerationFn = (req: ImageGenerationRequest) => Promise<ImageGenerationResult>;
|
|
141
|
+
/** @public */
|
|
142
|
+
export type ImageGenerationPanelProps = {
|
|
143
|
+
generator: ImageGenerationFn;
|
|
144
|
+
defaultWidthMm?: number;
|
|
145
|
+
defaultHeightMm?: number;
|
|
146
|
+
onResult?: (result: ImageGenerationResult) => void;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* AI2 — Print-resolution image generation. Surface is minimal
|
|
150
|
+
* (prompt + dims); host adapter handles the CMYK conversion +
|
|
151
|
+
* provenance tagging.
|
|
152
|
+
*
|
|
153
|
+
* @public
|
|
154
|
+
*/
|
|
155
|
+
export declare function ImageGenerationPanel({ generator, defaultWidthMm, defaultHeightMm, onResult, }: ImageGenerationPanelProps): ReactElement;
|
|
156
|
+
/** @public */
|
|
157
|
+
export type AutoLayoutRequest = {
|
|
158
|
+
/** Object ids the solver may move / resize. */
|
|
159
|
+
objectIds: readonly string[];
|
|
160
|
+
/** Constraints — bleed safety, panel anchors (S3 ties in). */
|
|
161
|
+
respectBleed: boolean;
|
|
162
|
+
respectPanelAnchors: boolean;
|
|
163
|
+
};
|
|
164
|
+
/** @public */
|
|
165
|
+
export type AutoLayoutOperation = {
|
|
166
|
+
objectId: string;
|
|
167
|
+
/** Target translation in mm. */
|
|
168
|
+
dx?: number;
|
|
169
|
+
dy?: number;
|
|
170
|
+
/** Target scale factor. */
|
|
171
|
+
scale?: number;
|
|
172
|
+
};
|
|
173
|
+
/** @public */
|
|
174
|
+
export type AutoLayoutFn = (req: AutoLayoutRequest) => Promise<readonly AutoLayoutOperation[]>;
|
|
175
|
+
/** @public */
|
|
176
|
+
export type AutoLayoutPanelProps = {
|
|
177
|
+
solver: AutoLayoutFn;
|
|
178
|
+
objectIds: readonly string[];
|
|
179
|
+
onSolved?: (ops: readonly AutoLayoutOperation[]) => void;
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* AI3 — Auto-layout / auto-fit panel. Host wires the solver
|
|
183
|
+
* (typically codex geom + the rich document-model); the panel
|
|
184
|
+
* surfaces the run-and-preview affordance.
|
|
185
|
+
*
|
|
186
|
+
* @public
|
|
187
|
+
*/
|
|
188
|
+
export declare function AutoLayoutPanel({ solver, objectIds, onSolved, }: AutoLayoutPanelProps): ReactElement;
|
|
189
|
+
/** @public */
|
|
190
|
+
export type OcrRebuildRequest = {
|
|
191
|
+
/** Source image — base64-encoded PNG/JPEG bytes. */
|
|
192
|
+
imageB64: string;
|
|
193
|
+
/** Optional language hint for the OCR engine. */
|
|
194
|
+
language?: string;
|
|
195
|
+
};
|
|
196
|
+
/** @public */
|
|
197
|
+
export type OcrRebuildObject = {
|
|
198
|
+
id: string;
|
|
199
|
+
kind: "text" | "logo" | "barcode-placeholder" | "panel-rect";
|
|
200
|
+
/** Bounding box in mm. */
|
|
201
|
+
x: number;
|
|
202
|
+
y: number;
|
|
203
|
+
widthMm: number;
|
|
204
|
+
heightMm: number;
|
|
205
|
+
/** Recovered text / value, when applicable. */
|
|
206
|
+
text?: string;
|
|
207
|
+
};
|
|
208
|
+
/** @public */
|
|
209
|
+
export type OcrRebuildFn = (req: OcrRebuildRequest) => Promise<readonly OcrRebuildObject[]>;
|
|
210
|
+
/** @public */
|
|
211
|
+
export type OcrRebuildPanelProps = {
|
|
212
|
+
ocr: OcrRebuildFn;
|
|
213
|
+
onObjects?: (objs: readonly OcrRebuildObject[]) => void;
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* AI5 — Competitor-pack OCR rebuild. Host accepts an image
|
|
217
|
+
* upload, runs codex `extract` + `ai/logos` + `ai/symbols` +
|
|
218
|
+
* `ai/language`, and returns reconstructed editable objects.
|
|
219
|
+
* Surface here is the file-input + reconstruct trigger.
|
|
220
|
+
*
|
|
221
|
+
* @public
|
|
222
|
+
*/
|
|
223
|
+
export declare function OcrRebuildPanel({ ocr, onObjects }: OcrRebuildPanelProps): ReactElement;
|
|
224
|
+
/** @public */
|
|
225
|
+
export type LocalizationVariant = {
|
|
226
|
+
/** BCP-47 tag — e.g. `"en"`, `"fr-CA"`, `"ja"`. */
|
|
227
|
+
language: string;
|
|
228
|
+
/** Per-text-object override map: objectId → translated text. */
|
|
229
|
+
texts: Record<string, string>;
|
|
230
|
+
};
|
|
231
|
+
/** @public */
|
|
232
|
+
export type LocalizationExpansion = {
|
|
233
|
+
language: string;
|
|
234
|
+
objectId: string;
|
|
235
|
+
/** Original chars vs translated chars; > 1 = expanded. */
|
|
236
|
+
ratio: number;
|
|
237
|
+
};
|
|
238
|
+
/** @public */
|
|
239
|
+
export type LocalizationPanelProps = {
|
|
240
|
+
variants: readonly LocalizationVariant[];
|
|
241
|
+
/** Optional expansion warnings the host pre-computed (the
|
|
242
|
+
* ratio of translated chars vs the source's box area
|
|
243
|
+
* estimate). Rows with ratio > 1.2 render as warnings. */
|
|
244
|
+
expansions?: readonly LocalizationExpansion[];
|
|
245
|
+
onSelectVariant?: (language: string) => void;
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* V3 — Localization + text-expansion warnings. Renders the
|
|
249
|
+
* per-language variants list with click-to-preview + a
|
|
250
|
+
* warnings table for any expansion ratio > 1.2 (the rule of
|
|
251
|
+
* thumb for "translation needs more room").
|
|
252
|
+
*
|
|
253
|
+
* @public
|
|
254
|
+
*/
|
|
255
|
+
export declare function LocalizationPanel({ variants, expansions, onSelectVariant, }: LocalizationPanelProps): ReactElement;
|
|
256
|
+
/** @public */
|
|
257
|
+
export type DesignHandoffSource = "figma" | "illustrator" | "indesign" | "other";
|
|
258
|
+
/** @public */
|
|
259
|
+
export type DesignHandoffImportFn = (opts: {
|
|
260
|
+
source: DesignHandoffSource;
|
|
261
|
+
fileRef: string;
|
|
262
|
+
}) => Promise<{
|
|
263
|
+
objectsImported: number;
|
|
264
|
+
}>;
|
|
265
|
+
/** @public */
|
|
266
|
+
export type DesignHandoffPanelProps = {
|
|
267
|
+
importer: DesignHandoffImportFn;
|
|
268
|
+
onImported?: (info: {
|
|
269
|
+
objectsImported: number;
|
|
270
|
+
}) => void;
|
|
271
|
+
};
|
|
272
|
+
/**
|
|
273
|
+
* I1 — Figma / Adobe handoff panel. Host wires the actual file /
|
|
274
|
+
* frame / page resolver; this panel surfaces the source picker +
|
|
275
|
+
* file-ref input and the import-now affordance.
|
|
276
|
+
*
|
|
277
|
+
* @public
|
|
278
|
+
*/
|
|
279
|
+
export declare function DesignHandoffPanel({ importer, onImported, }: DesignHandoffPanelProps): ReactElement;
|
|
280
|
+
/** @public */
|
|
281
|
+
export type EcommerceProduct = {
|
|
282
|
+
id: string;
|
|
283
|
+
title: string;
|
|
284
|
+
gtin?: string;
|
|
285
|
+
imageUrl?: string;
|
|
286
|
+
/** Product attributes the editor can bind as merge fields. */
|
|
287
|
+
attrs: Record<string, string>;
|
|
288
|
+
};
|
|
289
|
+
/** @public */
|
|
290
|
+
export type EcommerceLoaderFn = () => Promise<readonly EcommerceProduct[]>;
|
|
291
|
+
/** @public */
|
|
292
|
+
export type EcommerceConnectorPanelProps = {
|
|
293
|
+
loader: EcommerceLoaderFn;
|
|
294
|
+
onSelect?: (product: EcommerceProduct) => void;
|
|
295
|
+
};
|
|
296
|
+
/**
|
|
297
|
+
* I2 — Ecommerce (Shopify) product picker. Pull a product list
|
|
298
|
+
* from the host's store connector and let the user pick one to
|
|
299
|
+
* prefill merge fields / generate SKU variants. Host adapter
|
|
300
|
+
* handles store auth.
|
|
301
|
+
*
|
|
302
|
+
* @public
|
|
303
|
+
*/
|
|
304
|
+
export declare function EcommerceConnectorPanel({ loader, onSelect, }: EcommerceConnectorPanelProps): ReactElement;
|
|
305
|
+
/** @public */
|
|
306
|
+
export type PimField = {
|
|
307
|
+
id: string;
|
|
308
|
+
label: string;
|
|
309
|
+
value: string;
|
|
310
|
+
};
|
|
311
|
+
/** @public */
|
|
312
|
+
export type PimLoaderFn = () => Promise<readonly PimField[]>;
|
|
313
|
+
/** @public */
|
|
314
|
+
export type PimConnectorPanelProps = {
|
|
315
|
+
loader: PimLoaderFn;
|
|
316
|
+
onBind?: (field: PimField) => void;
|
|
317
|
+
};
|
|
318
|
+
/**
|
|
319
|
+
* I3 — PIM connector panel. List of pull-able fields from the
|
|
320
|
+
* host's PIM connector; click a field to bind it as a merge
|
|
321
|
+
* token on the active object.
|
|
322
|
+
*
|
|
323
|
+
* @public
|
|
324
|
+
*/
|
|
325
|
+
export declare function PimConnectorPanel({ loader, onBind }: PimConnectorPanelProps): ReactElement;
|
|
326
|
+
//# sourceMappingURL=wave4-extras.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wave4-extras.d.ts","sourceRoot":"","sources":["../../src/components/wave4-extras.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
"use client";
|
|
3
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
/**
|
|
6
|
+
* B2 — DAM assets browser. The host wires a
|
|
7
|
+
* {@link DamAssetsLoaderFn} adapter that fronts Bynder /
|
|
8
|
+
* Brandfolder / any DAM API; this panel renders the asset list
|
|
9
|
+
* with usage-rights chips when supplied.
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export function DamAssetsPanel({ loader, onSelect }) {
|
|
14
|
+
return (_jsx(LoaderPanel, { testId: "dam-assets-panel", title: "DAM assets", loader: () => loader(), renderRow: (a) => (_jsxs("span", { children: [a.name, _jsxs("span", { style: { fontSize: "0.625rem", color: "#595959", marginLeft: "0.375rem" }, children: [a.kind, a.rights ? ` · ${a.rights}` : ""] })] })), onSelect: onSelect }));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* X3 — Diff vs the pinned approved master. Each change row
|
|
18
|
+
* shows kind + summary; the host wires the actual diff
|
|
19
|
+
* computation (typically codex `vision/phash` + per-separation
|
|
20
|
+
* structural diff).
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export function ApprovedMasterDiffPanel({ loader, onSelect, }) {
|
|
25
|
+
return (_jsx(LoaderPanel, { testId: "approved-master-diff-panel", title: "Master diff", loader: loader, renderRow: (c) => (_jsxs("span", { children: ["[", c.kind, "] ", c.summary] })), onSelect: onSelect }));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* AI1 — Copy generation panel. Wraps a host-supplied LLM
|
|
29
|
+
* adapter (typically codex `ai/claude` + `spell` + budget). The
|
|
30
|
+
* panel owns the prompt input + max-chars constraint and the
|
|
31
|
+
* generate-button lifecycle; the host wires the adapter.
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export function CopyGenerationPanel({ generator, initialPrompt = "", maxChars = 200, onResult, }) {
|
|
36
|
+
const [prompt, setPrompt] = useState(initialPrompt);
|
|
37
|
+
const [status, setStatus] = useState("idle");
|
|
38
|
+
const [result, setResult] = useState(null);
|
|
39
|
+
const [err, setErr] = useState(null);
|
|
40
|
+
const generate = async () => {
|
|
41
|
+
setStatus("loading");
|
|
42
|
+
setErr(null);
|
|
43
|
+
try {
|
|
44
|
+
const r = await generator({ prompt, maxChars });
|
|
45
|
+
setResult(r);
|
|
46
|
+
setStatus("done");
|
|
47
|
+
onResult?.(r);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
setErr(e instanceof Error ? e.message : "Generation failed.");
|
|
51
|
+
setStatus("error");
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
return (_jsxs("div", { "data-testid": "copy-generation-panel", style: { padding: "0.5rem" }, children: [_jsx("header", { style: { marginBottom: "0.375rem" }, children: _jsx("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: "Copy generator" }) }), _jsx("textarea", { value: prompt, onChange: (e) => setPrompt(e.target.value), placeholder: "Describe the copy\u2026", "aria-label": "Copy generation prompt", style: { width: "100%", minHeight: 60, fontSize: "0.8125rem", padding: "0.25rem" } }), _jsx("div", { style: { display: "flex", gap: "0.375rem", marginTop: "0.375rem" }, children: _jsx("button", { type: "button", onClick: generate, disabled: status === "loading" || !prompt.trim(), style: { fontSize: "0.75rem", padding: "0.25rem 0.5rem" }, children: status === "loading" ? "Generating…" : `Generate (≤${maxChars} chars)` }) }), result && (_jsxs("div", { style: { marginTop: "0.5rem", fontSize: "0.8125rem" }, children: [_jsx("div", { style: { padding: "0.375rem", background: "#f6f6f6", borderRadius: 4 }, children: result.text }), result.warnings.length > 0 && (_jsx("ul", { style: { marginTop: "0.25rem", paddingLeft: "1.25rem" }, children: result.warnings.map((w) => (_jsx("li", { style: { fontSize: "0.75rem", color: "#a60" }, children: w }, w))) }))] })), err && (_jsx("div", { role: "alert", style: { marginTop: "0.5rem", fontSize: "0.75rem", color: "#a00" }, children: err }))] }));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* AI2 — Print-resolution image generation. Surface is minimal
|
|
58
|
+
* (prompt + dims); host adapter handles the CMYK conversion +
|
|
59
|
+
* provenance tagging.
|
|
60
|
+
*
|
|
61
|
+
* @public
|
|
62
|
+
*/
|
|
63
|
+
export function ImageGenerationPanel({ generator, defaultWidthMm = 50, defaultHeightMm = 50, onResult, }) {
|
|
64
|
+
const [prompt, setPrompt] = useState("");
|
|
65
|
+
const [w, setW] = useState(defaultWidthMm);
|
|
66
|
+
const [h, setH] = useState(defaultHeightMm);
|
|
67
|
+
const [status, setStatus] = useState("idle");
|
|
68
|
+
const [result, setResult] = useState(null);
|
|
69
|
+
const [err, setErr] = useState(null);
|
|
70
|
+
const generate = async () => {
|
|
71
|
+
setStatus("loading");
|
|
72
|
+
setErr(null);
|
|
73
|
+
try {
|
|
74
|
+
const r = await generator({ prompt, widthMm: w, heightMm: h, dpi: 300 });
|
|
75
|
+
setResult(r);
|
|
76
|
+
setStatus("done");
|
|
77
|
+
onResult?.(r);
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
setErr(e instanceof Error ? e.message : "Image generation failed.");
|
|
81
|
+
setStatus("error");
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return (_jsxs("div", { "data-testid": "image-generation-panel", style: { padding: "0.5rem" }, children: [_jsx("header", { style: { marginBottom: "0.375rem" }, children: _jsx("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: "Image generator" }) }), _jsx("input", { type: "text", value: prompt, onChange: (e) => setPrompt(e.target.value), placeholder: "Describe the image\u2026", "aria-label": "Image generation prompt", style: { width: "100%", fontSize: "0.8125rem", padding: "0.25rem" } }), _jsxs("div", { style: { display: "flex", gap: "0.375rem", marginTop: "0.375rem" }, children: [_jsxs("label", { style: { fontSize: "0.75rem" }, children: ["W mm", _jsx("input", { type: "number", value: w, onChange: (e) => setW(Number(e.target.value) || 0), style: { width: 60, marginLeft: "0.25rem" } })] }), _jsxs("label", { style: { fontSize: "0.75rem" }, children: ["H mm", _jsx("input", { type: "number", value: h, onChange: (e) => setH(Number(e.target.value) || 0), style: { width: 60, marginLeft: "0.25rem" } })] }), _jsx("button", { type: "button", onClick: generate, disabled: status === "loading" || !prompt.trim(), style: { fontSize: "0.75rem", padding: "0.25rem 0.5rem" }, children: status === "loading" ? "…" : "Generate" })] }), result && (_jsxs("div", { style: { marginTop: "0.5rem", fontSize: "0.75rem", color: "#595959" }, children: [result.widthPx, "\u00D7", result.heightPx, "px \u00B7 ", result.provenance] })), err && (_jsx("div", { role: "alert", style: { marginTop: "0.375rem", fontSize: "0.75rem", color: "#a00" }, children: err }))] }));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* AI3 — Auto-layout / auto-fit panel. Host wires the solver
|
|
88
|
+
* (typically codex geom + the rich document-model); the panel
|
|
89
|
+
* surfaces the run-and-preview affordance.
|
|
90
|
+
*
|
|
91
|
+
* @public
|
|
92
|
+
*/
|
|
93
|
+
export function AutoLayoutPanel({ solver, objectIds, onSolved, }) {
|
|
94
|
+
const [respectBleed, setRespectBleed] = useState(true);
|
|
95
|
+
const [respectAnchors, setRespectAnchors] = useState(true);
|
|
96
|
+
const [status, setStatus] = useState("idle");
|
|
97
|
+
const [ops, setOps] = useState(null);
|
|
98
|
+
const [err, setErr] = useState(null);
|
|
99
|
+
const run = async () => {
|
|
100
|
+
setStatus("loading");
|
|
101
|
+
setErr(null);
|
|
102
|
+
try {
|
|
103
|
+
const next = await solver({
|
|
104
|
+
objectIds,
|
|
105
|
+
respectBleed,
|
|
106
|
+
respectPanelAnchors: respectAnchors,
|
|
107
|
+
});
|
|
108
|
+
setOps(next);
|
|
109
|
+
setStatus("done");
|
|
110
|
+
onSolved?.(next);
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
setErr(e instanceof Error ? e.message : "Auto-layout failed.");
|
|
114
|
+
setStatus("error");
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
return (_jsxs("div", { "data-testid": "auto-layout-panel", style: { padding: "0.5rem" }, children: [_jsx("header", { style: { marginBottom: "0.375rem" }, children: _jsx("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: "Auto layout" }) }), _jsxs("div", { style: { fontSize: "0.75rem", display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [_jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: respectBleed, onChange: (e) => setRespectBleed(e.target.checked) }), " ", "Respect bleed / safety"] }), _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: respectAnchors, onChange: (e) => setRespectAnchors(e.target.checked) }), " ", "Respect panel anchors"] })] }), _jsx("button", { type: "button", onClick: run, disabled: status === "loading" || objectIds.length === 0, style: { marginTop: "0.375rem", fontSize: "0.75rem", padding: "0.25rem 0.5rem" }, children: status === "loading" ? "Solving…" : `Auto-arrange ${objectIds.length} object(s)` }), ops && (_jsxs("div", { style: { marginTop: "0.375rem", fontSize: "0.75rem", color: "#595959" }, children: [ops.length, " operation(s) emitted"] })), err && (_jsx("div", { role: "alert", style: { marginTop: "0.375rem", fontSize: "0.75rem", color: "#a00" }, children: err }))] }));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Encode an ArrayBuffer to base64 in 32 KB chunks so we don't blow
|
|
121
|
+
* past `String.fromCharCode.apply` argument-length limits on large
|
|
122
|
+
* files. `btoa` is Latin-1, which is fine here because each byte
|
|
123
|
+
* of the buffer becomes one code unit ≤ 0xFF.
|
|
124
|
+
*
|
|
125
|
+
* @internal
|
|
126
|
+
*/
|
|
127
|
+
function arrayBufferToBase64(buf) {
|
|
128
|
+
const bytes = new Uint8Array(buf);
|
|
129
|
+
const chunk = 0x8000;
|
|
130
|
+
let binary = "";
|
|
131
|
+
for (let i = 0; i < bytes.length; i += chunk) {
|
|
132
|
+
const slice = bytes.subarray(i, Math.min(i + chunk, bytes.length));
|
|
133
|
+
binary += String.fromCharCode.apply(null, Array.from(slice));
|
|
134
|
+
}
|
|
135
|
+
return btoa(binary);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* AI5 — Competitor-pack OCR rebuild. Host accepts an image
|
|
139
|
+
* upload, runs codex `extract` + `ai/logos` + `ai/symbols` +
|
|
140
|
+
* `ai/language`, and returns reconstructed editable objects.
|
|
141
|
+
* Surface here is the file-input + reconstruct trigger.
|
|
142
|
+
*
|
|
143
|
+
* @public
|
|
144
|
+
*/
|
|
145
|
+
export function OcrRebuildPanel({ ocr, onObjects }) {
|
|
146
|
+
const [status, setStatus] = useState("idle");
|
|
147
|
+
const [count, setCount] = useState(0);
|
|
148
|
+
const onFile = async (file) => {
|
|
149
|
+
setStatus("loading");
|
|
150
|
+
try {
|
|
151
|
+
const buf = await file.arrayBuffer();
|
|
152
|
+
const b64 = arrayBufferToBase64(buf);
|
|
153
|
+
const objs = await ocr({ imageB64: b64 });
|
|
154
|
+
setCount(objs.length);
|
|
155
|
+
setStatus("done");
|
|
156
|
+
onObjects?.(objs);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
setStatus("error");
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
return (_jsxs("div", { "data-testid": "ocr-rebuild-panel", style: { padding: "0.5rem" }, children: [_jsx("header", { style: { marginBottom: "0.375rem" }, children: _jsx("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: "OCR rebuild" }) }), _jsx("input", { type: "file", accept: "image/*", "aria-label": "Reference image for OCR rebuild", onChange: (e) => {
|
|
163
|
+
const f = e.target.files?.[0];
|
|
164
|
+
if (f)
|
|
165
|
+
void onFile(f);
|
|
166
|
+
}, style: { fontSize: "0.75rem" } }), status === "done" && (_jsxs("div", { style: { marginTop: "0.375rem", fontSize: "0.75rem", color: "#595959" }, children: ["Reconstructed ", count, " object(s)."] })), status === "loading" && (_jsx("output", { style: { display: "block", fontSize: "0.75rem", marginTop: "0.375rem" }, children: "Running OCR\u2026" }))] }));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* V3 — Localization + text-expansion warnings. Renders the
|
|
170
|
+
* per-language variants list with click-to-preview + a
|
|
171
|
+
* warnings table for any expansion ratio > 1.2 (the rule of
|
|
172
|
+
* thumb for "translation needs more room").
|
|
173
|
+
*
|
|
174
|
+
* @public
|
|
175
|
+
*/
|
|
176
|
+
export function LocalizationPanel({ variants, expansions = [], onSelectVariant, }) {
|
|
177
|
+
const tight = expansions.filter((e) => e.ratio > 1.2);
|
|
178
|
+
return (_jsxs("div", { "data-testid": "localization-panel", style: { padding: "0.5rem" }, children: [_jsx("header", { style: { marginBottom: "0.375rem" }, children: _jsxs("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: ["Localization (", variants.length, ")"] }) }), _jsx("ul", { style: { listStyle: "none", padding: 0, margin: 0 }, children: variants.map((v) => (_jsx("li", { style: { marginBottom: "0.25rem" }, children: _jsxs("button", { type: "button", onClick: () => onSelectVariant?.(v.language), style: {
|
|
179
|
+
display: "block",
|
|
180
|
+
width: "100%",
|
|
181
|
+
padding: "0.375rem 0.5rem",
|
|
182
|
+
background: "transparent",
|
|
183
|
+
border: "1px solid #ddd",
|
|
184
|
+
borderRadius: 4,
|
|
185
|
+
textAlign: "left",
|
|
186
|
+
fontSize: "0.8125rem",
|
|
187
|
+
cursor: onSelectVariant ? "pointer" : "default",
|
|
188
|
+
}, children: [v.language, " ", _jsxs("span", { style: { color: "#595959" }, children: ["\u00B7 ", Object.keys(v.texts).length, " string(s)"] })] }) }, v.language))) }), tight.length > 0 && (_jsxs("div", { "data-testid": "localization-expansion-warnings", style: { marginTop: "0.5rem", fontSize: "0.75rem", color: "#a60" }, children: [tight.length, " translation(s) may overflow their box (ratio > 1.2)"] }))] }));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* I1 — Figma / Adobe handoff panel. Host wires the actual file /
|
|
192
|
+
* frame / page resolver; this panel surfaces the source picker +
|
|
193
|
+
* file-ref input and the import-now affordance.
|
|
194
|
+
*
|
|
195
|
+
* @public
|
|
196
|
+
*/
|
|
197
|
+
export function DesignHandoffPanel({ importer, onImported, }) {
|
|
198
|
+
const [source, setSource] = useState("figma");
|
|
199
|
+
const [ref, setRef] = useState("");
|
|
200
|
+
const [status, setStatus] = useState("idle");
|
|
201
|
+
const [count, setCount] = useState(0);
|
|
202
|
+
const run = async () => {
|
|
203
|
+
setStatus("loading");
|
|
204
|
+
const r = await importer({ source, fileRef: ref });
|
|
205
|
+
setCount(r.objectsImported);
|
|
206
|
+
setStatus("done");
|
|
207
|
+
onImported?.(r);
|
|
208
|
+
};
|
|
209
|
+
return (_jsxs("div", { "data-testid": "design-handoff-panel", style: { padding: "0.5rem" }, children: [_jsx("header", { style: { marginBottom: "0.375rem" }, children: _jsx("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: "Design handoff" }) }), _jsxs("select", { value: source, onChange: (e) => setSource(e.target.value), "aria-label": "Design handoff source", style: { fontSize: "0.8125rem", padding: "0.25rem", marginRight: "0.375rem" }, children: [_jsx("option", { value: "figma", children: "Figma" }), _jsx("option", { value: "illustrator", children: "Illustrator" }), _jsx("option", { value: "indesign", children: "InDesign" }), _jsx("option", { value: "other", children: "Other" })] }), _jsx("input", { type: "text", value: ref, onChange: (e) => setRef(e.target.value), placeholder: "File / frame URL", "aria-label": "File reference", style: { fontSize: "0.8125rem", padding: "0.25rem" } }), _jsx("button", { type: "button", onClick: run, disabled: status === "loading" || !ref.trim(), style: { marginLeft: "0.375rem", fontSize: "0.75rem", padding: "0.25rem 0.5rem" }, children: status === "loading" ? "…" : "Import" }), status === "done" && (_jsxs("div", { style: { marginTop: "0.375rem", fontSize: "0.75rem", color: "#595959" }, children: ["Imported ", count, " object(s) from ", source, "."] }))] }));
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* I2 — Ecommerce (Shopify) product picker. Pull a product list
|
|
213
|
+
* from the host's store connector and let the user pick one to
|
|
214
|
+
* prefill merge fields / generate SKU variants. Host adapter
|
|
215
|
+
* handles store auth.
|
|
216
|
+
*
|
|
217
|
+
* @public
|
|
218
|
+
*/
|
|
219
|
+
export function EcommerceConnectorPanel({ loader, onSelect, }) {
|
|
220
|
+
return (_jsx(LoaderPanel, { testId: "ecommerce-connector-panel", title: "Products", loader: loader, renderRow: (p) => (_jsxs("span", { children: [p.title, p.gtin && (_jsxs("span", { style: { fontSize: "0.625rem", color: "#595959", marginLeft: "0.375rem" }, children: ["GTIN ", p.gtin] }))] })), onSelect: onSelect }));
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* I3 — PIM connector panel. List of pull-able fields from the
|
|
224
|
+
* host's PIM connector; click a field to bind it as a merge
|
|
225
|
+
* token on the active object.
|
|
226
|
+
*
|
|
227
|
+
* @public
|
|
228
|
+
*/
|
|
229
|
+
export function PimConnectorPanel({ loader, onBind }) {
|
|
230
|
+
return (_jsx(LoaderPanel, { testId: "pim-connector-panel", title: "PIM fields", loader: loader, renderRow: (f) => (_jsxs("span", { children: [f.label, _jsx("span", { style: { fontSize: "0.625rem", color: "#595959", marginLeft: "0.375rem" }, children: f.value })] })), onSelect: onBind }));
|
|
231
|
+
}
|
|
232
|
+
function LoaderPanel({ testId, title, loader, renderRow, onSelect, }) {
|
|
233
|
+
const [items, setItems] = useState(null);
|
|
234
|
+
const [error, setError] = useState(null);
|
|
235
|
+
useEffect(() => {
|
|
236
|
+
let disposed = false;
|
|
237
|
+
void (async () => {
|
|
238
|
+
try {
|
|
239
|
+
const next = await loader();
|
|
240
|
+
if (!disposed)
|
|
241
|
+
setItems(next);
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
if (!disposed)
|
|
245
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
246
|
+
}
|
|
247
|
+
})();
|
|
248
|
+
return () => {
|
|
249
|
+
disposed = true;
|
|
250
|
+
};
|
|
251
|
+
}, [loader]);
|
|
252
|
+
return (_jsxs("div", { "data-testid": testId, style: { padding: "0.5rem" }, children: [_jsx("header", { style: { marginBottom: "0.375rem" }, children: _jsxs("h3", { style: { margin: 0, fontSize: "0.875rem" }, children: [title, items && ` (${items.length})`] }) }), error && (_jsx("div", { role: "alert", style: { fontSize: "0.75rem", color: "#a00" }, children: error })), !error && !items && (_jsx("output", { style: { display: "block", fontSize: "0.75rem", opacity: 0.6 }, children: "Loading\u2026" })), items && items.length === 0 && (_jsx("div", { style: { fontSize: "0.75rem", opacity: 0.6 }, children: "None." })), items && items.length > 0 && (_jsx("ul", { style: { listStyle: "none", padding: 0, margin: 0 }, children: items.map((item) => (_jsx("li", { style: { marginBottom: "0.25rem" }, children: onSelect ? (_jsx("button", { type: "button", onClick: () => onSelect(item), style: {
|
|
253
|
+
display: "block",
|
|
254
|
+
width: "100%",
|
|
255
|
+
padding: "0.375rem 0.5rem",
|
|
256
|
+
background: "transparent",
|
|
257
|
+
border: "1px solid #ddd",
|
|
258
|
+
borderRadius: 4,
|
|
259
|
+
textAlign: "left",
|
|
260
|
+
fontSize: "0.8125rem",
|
|
261
|
+
cursor: "pointer",
|
|
262
|
+
}, children: renderRow(item) })) : (_jsx("div", { style: { padding: "0.375rem 0.5rem", fontSize: "0.8125rem" }, children: renderRow(item) })) }, item.id))) }))] }));
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=wave4-extras.js.map
|