@bluepic/embed 0.4.0-next.99 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/bluepic-embed.iife.js +402 -178
  2. package/dist/bluepic-embed.umd.js +402 -178
  3. package/dist/components/AssetViewer/AssetViewer.vue.d.ts +71 -0
  4. package/dist/components/BxAudioPlayButton.vue.d.ts +24 -0
  5. package/dist/components/BxCard.vue.d.ts +35 -0
  6. package/dist/components/BxInput.vue.d.ts +7 -1
  7. package/dist/components/BxList.vue.d.ts +9 -0
  8. package/dist/components/BxListItem.vue.d.ts +13 -1
  9. package/dist/components/BxPopover.vue.d.ts +7 -0
  10. package/dist/components/BxPreviewLayer.vue.d.ts +18 -0
  11. package/dist/components/BxScrollbar.vue.d.ts +7 -0
  12. package/dist/components/BxSelect.vue.d.ts +16 -2
  13. package/dist/components/BxTable.vue.d.ts +109 -0
  14. package/dist/components/BxTabs.vue.d.ts +7 -0
  15. package/dist/components/BxWaveformThumb.vue.d.ts +27 -0
  16. package/dist/components/CollectionFieldPopup.vue.d.ts +4 -0
  17. package/dist/components/PopoverElement.vue.d.ts +10 -1
  18. package/dist/components/TemplateEditor/BatchCell.vue.d.ts +18 -0
  19. package/dist/components/TemplateEditor/BatchEditor.vue.d.ts +264 -0
  20. package/dist/components/TemplateEditor/BatchExportPopup.vue.d.ts +68 -0
  21. package/dist/components/TemplateEditor/BatchImportPopup.vue.d.ts +25 -0
  22. package/dist/components/TemplateEditor/BxLiveTemplate.vue.d.ts +8 -0
  23. package/dist/components/TemplateEditor/BxTemplateEditor.vue.d.ts +285 -16
  24. package/dist/components/TemplateEditor/FieldHintsLayer.vue.d.ts +86 -0
  25. package/dist/components/TemplateEditor/TemplateView.vue.d.ts +77 -2
  26. package/dist/components/User/UserInfo.vue.d.ts +12 -1
  27. package/dist/components/directives/usePopup.d.ts +5 -0
  28. package/dist/components/fields/Collection.vue.d.ts +3 -0
  29. package/dist/components/fields/Image.vue.d.ts +19 -5
  30. package/dist/components/fields/ImageEdit.vue.d.ts +6 -1
  31. package/dist/components/fields/Text.vue.d.ts +1 -1
  32. package/dist/embed/embed.d.ts +1024 -228
  33. package/dist/{index-CWm6zOv7.js → index-C99_zLhc.js} +9 -9
  34. package/dist/index-D8N6IfRw.cjs +1 -0
  35. package/dist/main.cjs +240 -162
  36. package/dist/main.d.ts +20 -0
  37. package/dist/main.mjs +79043 -68465
  38. package/dist/markdown-it-5-ieF6Bh.js +3790 -0
  39. package/dist/markdown-it-CLB5Jta6.cjs +16 -0
  40. package/dist/postal-mime-Df-WB8Vq.js +3337 -0
  41. package/dist/postal-mime-_7WF5UBe.cjs +28 -0
  42. package/dist/style.css +1 -1
  43. package/dist/theme/bridge.d.ts +14 -0
  44. package/dist/theme/color.d.ts +80 -0
  45. package/dist/theme/css.d.ts +8 -0
  46. package/dist/theme/index.d.ts +19 -0
  47. package/dist/theme/legacy.d.ts +3 -0
  48. package/dist/theme/resolve.d.ts +10 -0
  49. package/dist/theme/tokens.d.ts +129 -0
  50. package/dist/theme/types-contract.d.ts +13 -0
  51. package/dist/theme.cjs +1 -0
  52. package/dist/theme.mjs +1313 -0
  53. package/dist/util/assetAuth.d.ts +35 -0
  54. package/dist/util/audioPreview.d.ts +8 -0
  55. package/dist/util/batch/csv.d.ts +58 -0
  56. package/dist/util/batch/export.d.ts +92 -0
  57. package/dist/util/batch/fields.d.ts +22 -0
  58. package/dist/util/batch/parseCSV.d.ts +72 -0
  59. package/dist/util/batch/useBatchRows.d.ts +67 -0
  60. package/dist/util/cloneDeep.d.ts +5 -5
  61. package/dist/util/cloudflareImages.d.ts +8 -1
  62. package/dist/util/contextCapture.d.ts +19 -0
  63. package/dist/util/export.d.ts +65 -18
  64. package/dist/util/fieldHints/chipAction.d.ts +23 -0
  65. package/dist/util/fieldHints/fieldFocus.d.ts +81 -0
  66. package/dist/util/fieldHints/geometry.d.ts +52 -0
  67. package/dist/util/fieldHints/index.d.ts +20 -0
  68. package/dist/util/fieldHints/probe.d.ts +84 -0
  69. package/dist/util/fieldHints/resolve.d.ts +55 -0
  70. package/dist/util/fieldHints/textProbe.d.ts +71 -0
  71. package/dist/util/fieldHints/useCanvasTextEditing.d.ts +125 -0
  72. package/dist/util/fieldHints/useChipHighlight.d.ts +29 -0
  73. package/dist/util/fieldHints/useFieldHitboxes.d.ts +5601 -0
  74. package/dist/util/fieldHints/useHintReveal.d.ts +10 -0
  75. package/dist/util/fieldTree.d.ts +20 -0
  76. package/dist/util/fields.d.ts +1 -1
  77. package/dist/util/gallery.d.ts +78 -30
  78. package/dist/util/popoverArrow.d.ts +33 -0
  79. package/dist/util/popupHeaderTools.d.ts +26 -0
  80. package/dist/util/scrollPassthrough.d.ts +9 -0
  81. package/dist/util/useTheme.d.ts +36 -1
  82. package/dist/util/visualViewport.d.ts +47 -0
  83. package/dist/xlsx-BopDBbWb.js +24176 -0
  84. package/dist/xlsx-qn1xoUuv.cjs +105 -0
  85. package/package.json +18 -5
  86. package/dist/index-DFXQWOGQ.cjs +0 -1
  87. package/dist/util/backgroundRemoval.d.ts +0 -51
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Credentials for the GATED brand-portal asset routes
3
+ * (`/api/public/campaigns/:uid/assets/:assetId/{download|preview|document}`).
4
+ *
5
+ * A protected campaign is unlocked either with its password or by signing in;
6
+ * the config and serial fetches already carry that proof, but the asset bytes
7
+ * are requested separately — by a `fetch()` (download, viewer parsing) or by a
8
+ * media element's `src` (audio, video, image), which cannot carry headers at
9
+ * all. This module is the ONE place that knows how to attach the proof to
10
+ * either kind of request, so the two can never drift apart:
11
+ *
12
+ * - `assetRequestHeaders` → `X-Bluepic-Password` / `Authorization: Bearer …`
13
+ * - `withAssetAuthQuery` → `?password=…` / `?access_token=…`
14
+ *
15
+ * Prefer the headers wherever a `fetch()` is used; the query form exists only
16
+ * for `src` attributes. An empty auth object leaves headers and URLs untouched,
17
+ * so a public campaign behaves exactly as before.
18
+ */
19
+ export type AssetAuth = {
20
+ /** The campaign password the visitor unlocked with, if any. */
21
+ password?: string;
22
+ /** The signed-in visitor's Auth0 access token, if any. */
23
+ accessToken?: string;
24
+ };
25
+ /** Query parameter names the API accepts for media `src` URLs. */
26
+ export declare const ASSET_AUTH_QUERY_PASSWORD = "password";
27
+ export declare const ASSET_AUTH_QUERY_ACCESS_TOKEN = "access_token";
28
+ /** Headers for a `fetch()` of gated asset bytes. `{}` when nothing to attach. */
29
+ export declare function assetRequestHeaders(auth?: AssetAuth | null): Record<string, string>;
30
+ /**
31
+ * The same proof as query parameters, for `<img>`/`<video>`/`<audio>` sources
32
+ * that cannot carry headers. Returns `url` unchanged when there is nothing to
33
+ * attach. Existing query parameters (and a hash) are preserved.
34
+ */
35
+ export declare function withAssetAuthQuery(url: string, auth?: AssetAuth | null): string;
@@ -0,0 +1,8 @@
1
+ export declare function useAudioPlayback(): {
2
+ toggle: (src: string | (() => string | Promise<string>), mediaEl?: HTMLMediaElement) => Promise<void>;
3
+ stop: () => void;
4
+ playing: import("vue").Ref<boolean, boolean>;
5
+ loading: import("vue").Ref<boolean, boolean>;
6
+ progress: import("vue").Ref<number, number>;
7
+ ended: import("vue").Ref<boolean, boolean>;
8
+ };
@@ -0,0 +1,58 @@
1
+ import { Studio } from '@bluepic/types';
2
+ import type { BatchRow } from './useBatchRows';
3
+ import { type BatchColumnField } from './fields';
4
+ /** The formats a CSV result link can point at, plus the prepopulated editor link. */
5
+ export type BatchCsvFormat = Studio.UrlRenderFormat | 'template-link';
6
+ /** Header of the result column. Stable: re-imports recognise and ignore it. */
7
+ export declare const BATCH_CSV_RESULT_COLUMN = "bluepic_result";
8
+ export interface BatchCsvOptions {
9
+ format: BatchCsvFormat;
10
+ /** `https://image.bluepic.io` / `https://image-staging.bluepic.io` (no trailing slash). */
11
+ urlRenderBaseUrl: string;
12
+ templateId: string;
13
+ /** Readable URL form when both are known: `/<orgSlug>/<alias>.<ext>`. */
14
+ orgSlug?: string;
15
+ templateAlias?: string | null;
16
+ /** Multi-canvas: the canvas the editor shows — becomes the extra path segment. */
17
+ canvasId?: string;
18
+ /** The editor's own URL without query (`https://template.bluepic.io/<slug>/<templateId>[/<canvas>]`). */
19
+ templateLinkBaseUrl: string;
20
+ /** `,` (default) or `;` for spreadsheets in `;` locales. */
21
+ delimiter?: ',' | ';';
22
+ }
23
+ export interface BatchCsvResult {
24
+ csv: string;
25
+ /** The per-row result links, in row order. */
26
+ links: string[];
27
+ /** Rows whose URL-render query exceeds the API's byte budget (1-based indices). */
28
+ overBudget: number[];
29
+ /** `bluepic_result` header + one binding key per data column. */
30
+ header: string[];
31
+ }
32
+ /** A binding value as a CSV cell: image objects become their src, other objects JSON. */
33
+ export declare function cellValue(value: unknown): string;
34
+ /** Path of the render URL: alias form when the team + alias are known, else the id form. */
35
+ export declare function urlRenderPath(opts: Pick<BatchCsvOptions, 'templateId' | 'orgSlug' | 'templateAlias' | 'canvasId'>, ext: string): string;
36
+ /** The result link for one row, or null when the format has no link (never happens today). */
37
+ export declare function buildResultLink(row: BatchRow, columns: BatchColumnField[], opts: BatchCsvOptions): {
38
+ url: string;
39
+ overBudget: boolean;
40
+ };
41
+ /**
42
+ * The batch as a spreadsheet: one column per binding key (so a re-import maps
43
+ * 1:1), image values flattened to their src, and a last column with the
44
+ * result link per row. UTF-8 with BOM so Excel opens it correctly.
45
+ */
46
+ export declare function buildBatchCsv(rows: BatchRow[], columns: BatchColumnField[], opts: BatchCsvOptions): BatchCsvResult;
47
+ export interface PrewarmProgress {
48
+ done: number;
49
+ total: number;
50
+ failed: number;
51
+ }
52
+ /**
53
+ * Request every link once so the render lands in the API's cache (and is
54
+ * billed) now, not when a recipient first opens the sheet. Videos one at a
55
+ * time, images four at a time. `no-cors`: we only need the request to happen,
56
+ * not to read the bytes.
57
+ */
58
+ export declare function prewarmLinks(links: string[], isVideo: boolean, onProgress?: (progress: PrewarmProgress) => void, signal?: AbortSignal): Promise<PrewarmProgress>;
@@ -0,0 +1,92 @@
1
+ import { type Template } from '@bluepic/types';
2
+ import { imageFormats, videoFormats, type RenderRemoteOptions, type RenderRemoteVideoOptions } from '../export';
3
+ import type { BatchRow } from './useBatchRows';
4
+ export type BatchImageFormat = keyof typeof imageFormats;
5
+ export type BatchVideoFormat = keyof typeof videoFormats;
6
+ export type BatchFileFormat = BatchImageFormat | BatchVideoFormat;
7
+ /** How exported files are named: by their 1-based index, or by a Text binding's value. */
8
+ export type BatchNaming = {
9
+ kind: 'index';
10
+ } | {
11
+ kind: 'binding';
12
+ key: string;
13
+ };
14
+ export interface BatchFileExportContext {
15
+ serial: Template.Serial;
16
+ campaignId: number;
17
+ templateId: string;
18
+ canvasId?: string;
19
+ /** Template name — the zip name and the index-naming prefix. */
20
+ name: string;
21
+ remoteOptions: RenderRemoteOptions;
22
+ remoteVideoOptions: RenderRemoteVideoOptions;
23
+ /**
24
+ * Called once per successfully rendered row with that row's data and the
25
+ * media it produced. The editor binds it to its per-output credit consumer,
26
+ * so each row is charged exactly once per session (and never twice for the
27
+ * same content) at the batch rate for that medium.
28
+ */
29
+ consumeOutput: (data: Record<string, unknown>, kind: 'image' | 'video') => Promise<void>;
30
+ /** Cooperative cancellation: checked before every row starts. */
31
+ signal?: AbortSignal;
32
+ }
33
+ export interface BatchExportProgress {
34
+ /** Rows finished (rendered + consumed). */
35
+ done: number;
36
+ total: number;
37
+ /** 0..1 progress inside the row being rendered (videos stream it; images jump). */
38
+ current: number;
39
+ /** 1-based index of the row being rendered. */
40
+ currentIndex: number;
41
+ /** Rows that threw (rendering or consuming) and were skipped. */
42
+ failed: number;
43
+ }
44
+ /** A row that did not make it into the output. `index` is 0-based (row 1 is index 0). */
45
+ export interface BatchFailedRow {
46
+ index: number;
47
+ message: string;
48
+ }
49
+ export interface BatchFileExportResult {
50
+ /** One blob per exported file (a multi-frame template yields several per row). */
51
+ files: {
52
+ name: string;
53
+ blob: Blob;
54
+ }[];
55
+ /** The zip (or the single file) ready to hand out, plus its file name. */
56
+ output: {
57
+ blob: Blob;
58
+ fileName: string;
59
+ };
60
+ cancelled: boolean;
61
+ /**
62
+ * Rows missing from `output` because they threw. Successful rows were still
63
+ * consumed (charged) and packed; a failed row was never consumed.
64
+ */
65
+ failedRows: BatchFailedRow[];
66
+ }
67
+ /** Image rows render four at a time, videos strictly one after the other (decision 2026-09-02). */
68
+ export declare const BATCH_IMAGE_CONCURRENCY = 4;
69
+ export declare const BATCH_VIDEO_CONCURRENCY = 1;
70
+ /** A file-system-safe base name from a binding value; empty when nothing usable remains. */
71
+ export declare function sanitizeFileName(value: unknown): string;
72
+ /** Base names for every row, unique (`name`, `name_2`, `name_3`, …). */
73
+ export declare function batchFileBaseNames(rows: BatchRow[], naming: BatchNaming, prefix: string): string[];
74
+ /**
75
+ * Render every row server-side and pack the results.
76
+ *
77
+ * Images go through the campaign render endpoint (which does not charge — the
78
+ * per-row `consumeOutput` does), videos through the video render service.
79
+ * Rows are rendered in order and isolated from each other: a row that throws
80
+ * is recorded in `failedRows` (never consumed, never packed) and the rest
81
+ * carry on, so one bad row cannot discard the already-charged good ones. Only
82
+ * when every row failed is there nothing to hand out, and the export throws.
83
+ */
84
+ export declare function exportBatchFiles(rows: BatchRow[], format: BatchFileFormat, naming: BatchNaming, ctx: BatchFileExportContext, onProgress?: (progress: BatchExportProgress) => void): Promise<BatchFileExportResult>;
85
+ /** One file stays a file; several become a zip named after the template. */
86
+ export declare function packFiles(files: {
87
+ name: string;
88
+ blob: Blob;
89
+ }[], zipBaseName: string): Promise<{
90
+ blob: Blob;
91
+ fileName: string;
92
+ }>;
@@ -0,0 +1,22 @@
1
+ import type { BluepicField, Template } from '@bluepic/types';
2
+ /** A field as a batch-table column: the field plus where it came from. */
3
+ export interface BatchColumnField {
4
+ field: BluepicField;
5
+ /** Stable key for the column (the field's first binding, else its index path). */
6
+ key: string;
7
+ /** Group breadcrumb the field lives in, for the header caption. */
8
+ groupPath: string[];
9
+ /** 1-based slide the field belongs to on multi-slide templates, else undefined. */
10
+ slide?: number;
11
+ }
12
+ /**
13
+ * Every value-bearing field of a serial as a flat column list. Groups are
14
+ * flattened (their children become columns, the group's description is kept
15
+ * as a breadcrumb); instructions are dropped.
16
+ */
17
+ export declare function flattenBatchFields(serial: Template.Serial | undefined): BatchColumnField[];
18
+ /** The binding keys a field writes, in model order. */
19
+ export declare function bindingKeysOf(field: BluepicField): string[];
20
+ export declare function isImageField(field: BluepicField): boolean;
21
+ /** A Text binding a file name / CSV column can be derived from. */
22
+ export declare function isTextField(field: BluepicField): boolean;
@@ -0,0 +1,72 @@
1
+ export type LocaleConfig = 'de' | 'en' | 'auto';
2
+ export type CSVDelimiter = ',' | ';' | 'auto';
3
+ type StringDescriptor = {
4
+ type: 'string';
5
+ value: string;
6
+ };
7
+ type NumberDescriptor = {
8
+ type: 'number';
9
+ value: number;
10
+ unit?: string;
11
+ };
12
+ type BooleanDescriptor = {
13
+ type: 'boolean';
14
+ value: boolean;
15
+ };
16
+ type DateDescriptor = {
17
+ type: 'date';
18
+ value: Date;
19
+ format: string;
20
+ };
21
+ type URLDescriptor = {
22
+ type: 'url';
23
+ value: string;
24
+ protocol: string;
25
+ };
26
+ type ColorDescriptor = {
27
+ type: 'color';
28
+ value: string;
29
+ rgb: {
30
+ r: number;
31
+ g: number;
32
+ b: number;
33
+ };
34
+ hex: string;
35
+ hsl: {
36
+ h: number;
37
+ s: number;
38
+ l: number;
39
+ };
40
+ alpha: number;
41
+ format: 'hex' | 'rgb' | 'rgba' | 'hsl' | 'hsla' | 'name' | 'keyword';
42
+ };
43
+ type JSONObjectDescriptor = {
44
+ type: 'json-object';
45
+ value: Record<string, unknown>;
46
+ };
47
+ type JSONArrayDescriptor = {
48
+ type: 'json-array';
49
+ value: unknown[];
50
+ };
51
+ type NullDescriptor = {
52
+ type: 'null';
53
+ value: null;
54
+ };
55
+ export type CellDescriptor = StringDescriptor | NumberDescriptor | BooleanDescriptor | DateDescriptor | URLDescriptor | ColorDescriptor | JSONObjectDescriptor | JSONArrayDescriptor | NullDescriptor;
56
+ export type InferredTable = CellDescriptor[][];
57
+ export declare function isString(cell: CellDescriptor): cell is StringDescriptor;
58
+ export declare function isNumber(cell: CellDescriptor): cell is NumberDescriptor;
59
+ export declare function isBoolean(cell: CellDescriptor): cell is BooleanDescriptor;
60
+ export declare function isDate(cell: CellDescriptor): cell is DateDescriptor;
61
+ export declare function isURL(cell: CellDescriptor): cell is URLDescriptor;
62
+ export declare function isColor(cell: CellDescriptor): cell is ColorDescriptor;
63
+ export declare function isJSONObject(cell: CellDescriptor): cell is JSONObjectDescriptor;
64
+ export declare function isJSONArray(cell: CellDescriptor): cell is JSONArrayDescriptor;
65
+ export declare function isNull(cell: CellDescriptor): cell is NullDescriptor;
66
+ export declare function exampleUsage(inferredTable: InferredTable): void;
67
+ export declare function inferredCellToString(cell: CellDescriptor): string;
68
+ export declare function heuristicInferTable(rawTable: string[][], locale: LocaleConfig): InferredTable;
69
+ export declare function detectCSVDelimiter(raw: string): ',' | ';';
70
+ export declare function parseCSVRaw(raw: string, delimiter?: ',' | ';'): string[][];
71
+ export declare function parseCSV(raw: string, locale: LocaleConfig, delimiter?: CSVDelimiter): InferredTable;
72
+ export {};
@@ -0,0 +1,67 @@
1
+ import { type Ref } from 'vue';
2
+ /**
3
+ * Batch editor data model.
4
+ *
5
+ * A row is one set of binding values — exactly the object the live template
6
+ * and the renderer consume as `data` — plus a stable id. Ids (not indices) are
7
+ * what selection and the active row point at, so deleting or reordering rows
8
+ * never shifts the meaning of "row 3 is selected".
9
+ */
10
+ export interface BatchRow {
11
+ id: string;
12
+ data: Record<string, unknown>;
13
+ }
14
+ /** Hard cap on rows per batch (decision 2026-09-02). */
15
+ export declare const BATCH_MAX_ROWS = 1024;
16
+ export interface UseBatchRowsOptions {
17
+ /** The bindings every row starts from (`serial.bindings`). */
18
+ seed: () => Record<string, unknown>;
19
+ /**
20
+ * sessionStorage key. Rows survive a reload / a canvas switch (the editor
21
+ * re-mounts per canvas) under it. Undefined = no persistence.
22
+ */
23
+ storageKey: Ref<string | undefined>;
24
+ /** Rows the host hands in (`v-model:batchRows`); take precedence over storage. */
25
+ initial?: BatchRow[];
26
+ }
27
+ export declare function useBatchRows(opts: UseBatchRowsOptions): {
28
+ rows: Ref<{
29
+ id: string;
30
+ data: Record<string, unknown>;
31
+ }[], BatchRow[] | {
32
+ id: string;
33
+ data: Record<string, unknown>;
34
+ }[]>;
35
+ activeRowId: Ref<string, string>;
36
+ activeIndex: import("vue").ComputedRef<number>;
37
+ activeRow: import("vue").ComputedRef<{
38
+ id: string;
39
+ data: Record<string, unknown>;
40
+ }>;
41
+ selectedIds: Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
42
+ selectedRows: import("vue").ComputedRef<{
43
+ id: string;
44
+ data: Record<string, unknown>;
45
+ }[]>;
46
+ targetRows: import("vue").ComputedRef<{
47
+ id: string;
48
+ data: Record<string, unknown>;
49
+ }[]>;
50
+ allSelected: import("vue").ComputedRef<boolean>;
51
+ atCapacity: import("vue").ComputedRef<boolean>;
52
+ setActive: (id: string) => void;
53
+ activateOffset: (delta: number) => void;
54
+ addRow: (sourceId?: string) => BatchRow | undefined;
55
+ removeRows: (ids: string[]) => void;
56
+ moveRow: (id: string, delta: -1 | 1) => void;
57
+ toggleSelected: (id: string, on?: boolean) => void;
58
+ selectAll: (on: boolean) => void;
59
+ ensureRowsFrom: (fromIndex: number, count: number) => BatchRow[];
60
+ importRows: (datasets: Record<string, unknown>[], mode: "append" | "replace") => {
61
+ imported: number;
62
+ dropped: number;
63
+ };
64
+ replaceAll: (next: BatchRow[]) => void;
65
+ makeRow: (data?: Record<string, unknown>) => BatchRow;
66
+ };
67
+ export type BatchRowsModel = ReturnType<typeof useBatchRows>;
@@ -3,11 +3,11 @@
3
3
  *
4
4
  * Uses the native `structuredClone`, which handles plain objects, arrays,
5
5
  * Dates, Maps, Sets, typed arrays and circular references. Vue reactive
6
- * proxies are unwrapped via `toRaw` first so the clone is a plain,
7
- * non-reactive copy (and to avoid cloning through reactivity metadata).
6
+ * proxies are unwrapped first — at every depth, see `toRawDeep` — so the
7
+ * clone is a plain, non-reactive copy.
8
8
  *
9
- * Note: `structuredClone` throws on non-cloneable values (functions, DOM
10
- * nodes, class instances with methods). All call sites clone JSON-like data
11
- * models, so this is safe here.
9
+ * Note: `structuredClone` still throws on genuinely non-cloneable values
10
+ * (functions, DOM nodes). All call sites clone JSON-like data models, so this
11
+ * is safe here.
12
12
  */
13
13
  export declare function cloneDeep<T>(value: T): T;
@@ -16,4 +16,11 @@ export declare function parseCloudflareImagesDeliveryUrl(src: string): {
16
16
  };
17
17
  export declare function uploadImage(apiBaseUrl: string, templateId: string, context: {
18
18
  field?: Template.Fields.BluepicField;
19
- }, blob: Blob, name: string, onUploadProgress: (uploaded: number, total: number) => void): Promise<any>;
19
+ }, blob: Blob, name: string, onUploadProgress: (uploaded: number, total: number) => void): Promise<{
20
+ key: string;
21
+ type: string;
22
+ url: string;
23
+ uploadedAt: string;
24
+ imageId?: string | undefined;
25
+ deliveryBase?: string | undefined;
26
+ }>;
@@ -1 +1,20 @@
1
+ /**
2
+ * Everything the host app injects, flattened so a popup — which renders in a
3
+ * SEPARATE Vue app (see PopupProvider) — can be given the same context.
4
+ *
5
+ * APP-LEVEL PROVIDES ARE THE HALF THIS USED TO MISS, and they are the half
6
+ * that matters most. Vue builds a component's provides as
7
+ *
8
+ * provides: parent ? parent.provides : Object.create(appContext.provides)
9
+ *
10
+ * so anything installed with `app.use(...)` or `app.provide(...)` — the router
11
+ * above all, but equally a store or an i18n instance — lives on
12
+ * `appContext.provides` and reaches components through the PROTOTYPE chain.
13
+ * `Object.assign` copies own properties only, so walking the parent chain
14
+ * never saw them: `useRouter()` inside any popup returned undefined, and every
15
+ * `router.push` in a dialog, drawer or toast silently did nothing.
16
+ *
17
+ * Merged FIRST, so a component-level `provide()` closer to the caller still
18
+ * wins over an app-level one of the same key.
19
+ */
1
20
  export declare function captureCurrentContext(): Record<string | symbol, any>;
@@ -1,4 +1,4 @@
1
- import { FieldsBridge, Render, Studio, Template } from '@bluepic/types';
1
+ import { BillingV3, FieldsBridge, Render, Studio, Template } from '@bluepic/types';
2
2
  import { Ref } from 'vue';
3
3
  import { z } from '@hono/zod-openapi';
4
4
  import BxLiveTemplate from '../components/TemplateEditor/BxLiveTemplate.vue';
@@ -16,41 +16,56 @@ export declare const videoFormats: {
16
16
  export type RenderRemoteOptions = {
17
17
  apiBaseUrl: string;
18
18
  env: 'dev' | 'prod';
19
- enforceFallbackService: boolean;
20
19
  bearerToken?: string;
21
20
  password?: string;
22
21
  };
23
22
  export declare function renderSerialRemote(campaignId: number, templateId: string, data: {
24
23
  [k: string]: unknown;
25
- }, width: number, height: number, framesX: number, framesY: number, format: keyof typeof imageFormats, opts: RenderRemoteOptions): Promise<Blob>;
24
+ }, width: number, height: number, framesX: number, framesY: number, format: keyof typeof imageFormats, opts: RenderRemoteOptions,
25
+ /**
26
+ * Multi-canvas templates (canvases v2): the canvas to render. The server
27
+ * refetches the persisted serial (root = Default canvas) by templateId, so
28
+ * without this it would render the Default format regardless of what the
29
+ * user selected. OMITTED (not sent at all) when unset — the request stays
30
+ * byte-identical for single-format templates.
31
+ */
32
+ canvasId?: string): Promise<Blob>;
33
+ /** @deprecated Video renders go through the bx-studio-api campaign route now; kept so hosts passing it keep compiling. */
26
34
  export type RenderRemoteVideoOptions = {
27
35
  remoteVideoRenderBaseUrl: string;
28
36
  };
29
- export declare function renderVideoRemote(serial: Template.Serial, data: {
37
+ /**
38
+ * Server-side video export via `POST {api}/api/public/render/campaign` with a
39
+ * video format. The API resolves the template's canvas/animation itself, picks
40
+ * the backend (elya first, the Cloudflare container fan-out as the fallback)
41
+ * and meters the credit once the render succeeds — so the client never charges
42
+ * a server-rendered video. The response is the render service's SSE
43
+ * (keyframe / encode_video progress, then `end{result}` with the hosted URL).
44
+ */
45
+ export declare function renderVideoRemote(campaignId: number, templateId: string, data: {
30
46
  [k: string]: unknown;
31
- }, width: number, height: number, format: z.infer<typeof Render.videoFormatSchema>, duration: number, videoOpts: {
32
- fps: number;
33
- vcodec: z.infer<typeof Render.vcodecSchema>;
34
- acodec: z.infer<typeof Render.acodecSchema>;
35
- pix_fmt: z.infer<typeof Render.pixFmtSchema>;
36
- audio: {
37
- itsoffset: number;
38
- src: string;
39
- }[];
40
- }, options: RenderRemoteVideoOptions, onProgress: (progress: Render.RenderProgressEvent) => void): Promise<{
47
+ }, format: z.infer<typeof Render.videoFormatSchema>, opts: RenderRemoteOptions, onProgress: (progress: Render.RenderProgressEvent) => void,
48
+ /** Multi-canvas: the selected canvas, omitted for single-format templates. */
49
+ canvasId?: string): Promise<{
41
50
  files: string[];
42
51
  creditsConsumed: number;
43
52
  }>;
44
53
  export declare function renderSerialAsImages(bxLiveTemplateComponent: InstanceType<typeof BxLiveTemplate>, serial: Template.Serial, data: {
45
54
  [k: string]: unknown;
46
- }, format: keyof typeof imageFormats, campaignId: number, templateId: string, remoteOptions: RenderRemoteOptions, enforceServerSideRendering: boolean, watermark: boolean, sessionState: string): Promise<{
55
+ }, format: keyof typeof imageFormats, campaignId: number, templateId: string, remoteOptions: RenderRemoteOptions, enforceServerSideRendering: boolean, watermark: boolean, sessionState: string,
56
+ /** Multi-canvas: the selected canvas — remote render only; the LOCAL path already renders the materialized `serial`. */
57
+ canvasId?: string,
58
+ /** Local render only: see the option of the same name on `BxLiveTemplate.render`. */
59
+ svgLoadWaitDelay?: number): Promise<{
47
60
  files: Blob[];
48
61
  renderLocation: RenderLocation;
49
62
  clientRenderFailed: boolean;
50
63
  }>;
51
64
  export declare function useTemplateExport(serial: Ref<Template.Serial | undefined>, data: Ref<{
52
65
  [k: string]: unknown;
53
- }>, exportOptions: Ref<z.infer<typeof Studio.campaignConfigSchema>['export']>, templateId: Ref<string | undefined>, name: Ref<string | undefined>, bxLiveTemplateComponentRef: Ref<InstanceType<typeof BxLiveTemplate> | undefined>, campaignId: Ref<number | undefined>, remoteOptions: RenderRemoteOptions, remoteVideoOptions: RenderRemoteVideoOptions, enforceServerSideRendering: Ref<boolean>, enforceVideoServerSideRendering: Ref<boolean>, timecode: Ref<number>, consumeCreditsOnRender: Ref<boolean>, watermark: Ref<boolean>, bridge: Ref<FieldsBridge>, preCacheLocalRendering: Ref<boolean>,
66
+ }>, exportOptions: Ref<z.infer<typeof Studio.campaignConfigSchema>['export']>, templateId: Ref<string | undefined>, name: Ref<string | undefined>, bxLiveTemplateComponentRef: Ref<InstanceType<typeof BxLiveTemplate> | undefined>, campaignId: Ref<number | undefined>, remoteOptions: RenderRemoteOptions,
67
+ /** @deprecated unused — video renders go through the API campaign route (see renderVideoRemote). */
68
+ _remoteVideoOptions: RenderRemoteVideoOptions, enforceServerSideRendering: Ref<boolean>, enforceVideoServerSideRendering: Ref<boolean>, timecode: Ref<number>, consumeCreditsOnRender: Ref<boolean>, watermark: Ref<boolean>, bridge: Ref<FieldsBridge>, preCacheLocalRendering: Ref<boolean>,
54
69
  /** Host-provided abstract analytics sink. When absent, all analytics calls are no-ops. */
55
70
  analytics: Ref<ExportAnalyticsSink | undefined>,
56
71
  /**
@@ -58,13 +73,45 @@ analytics: Ref<ExportAnalyticsSink | undefined>,
58
73
  * already resolved by the caller. When undefined, we fall back to the
59
74
  * template's serial caption (today's behavior).
60
75
  */
61
- campaignCaption?: Ref<string | undefined>): {
76
+ campaignCaption?: Ref<string | undefined>,
77
+ /**
78
+ * Multi-canvas templates (canvases v2): the id of the canvas the editor is
79
+ * showing. `serial` is already the MATERIALIZED serial for it (local renders
80
+ * need nothing extra); this only rides on the remote render request so the
81
+ * server materializes the same canvas from the serial it refetches.
82
+ * Undefined (the default) = single-format / Default canvas = today's payload.
83
+ */
84
+ canvasId?: Ref<string | undefined>,
85
+ /**
86
+ * Milliseconds `renderSVG` sleeps between the serialized SVG's `load` event and
87
+ * drawing it (see `BxLiveTemplate.render`). Undefined = the raster default of
88
+ * 150ms, i.e. today's behaviour. A host can lower it to reclaim a flat per-render
89
+ * tax that matters most where renders are repeated — batch export, local video
90
+ * frames — at the risk of drawing before an engine has decoded the inlined
91
+ * fonts/images. Kept host-settable precisely so that trade-off can be measured
92
+ * rather than guessed.
93
+ */
94
+ svgLoadWaitDelay?: Ref<number | undefined>): {
62
95
  triggerExport: () => Promise<void>;
96
+ consumeOutputFor: (rowData: {
97
+ [k: string]: unknown;
98
+ }, kind?: "image" | "video") => Promise<void>;
63
99
  preCacheLocalRender: () => Promise<void>;
64
100
  rendering: Ref<boolean, boolean>;
65
101
  videoRenderingProgress: Ref<number | undefined, number | undefined>;
66
102
  };
67
- export declare function consumeCredits(apiBaseUrl: string, env: 'dev' | 'prod', campaignId: number, templateId: string, sessionState: string, billingKey: number): Promise<void>;
103
+ /**
104
+ * Report ONE delivered output to the server.
105
+ *
106
+ * The SDK names the surface (`usage`) and describes what it produced
107
+ * (`assets`) — it never sends, and never learns, a price. The rate table lives
108
+ * server-side in `@bluepic/types` (`BillingV3.calculateCenticreditConsumption`).
109
+ */
110
+ export declare function consumeCredits(apiBaseUrl: string, env: 'dev' | 'prod', campaignId: number, templateId: string, sessionState: string, billingKey: number,
111
+ /** Which surface produced this. Omitted = a single editor export. */
112
+ usage?: Studio.ConsumeRenderCreditsUsage,
113
+ /** One entry per delivered file — an array of one for a single export. */
114
+ assets?: BillingV3.BillableUsageAsset[]): Promise<void>;
68
115
  export declare function hasMobileShareCapability(files: File[]): boolean;
69
116
  export declare function blobsToShareFiles(files: Blob[], baseName: string): File[];
70
117
  export declare function performDownload(files: Blob[], baseName: string): Promise<void>;
@@ -0,0 +1,23 @@
1
+ import type { BluepicField } from '@bluepic/types';
2
+ /**
3
+ * What clicking a chip does.
4
+ *
5
+ * There is no per-field hint MODE — hints are simply on or off for the whole
6
+ * campaign (`config.hints`). What a chip does is inferred from the field itself:
7
+ *
8
+ * - `upload` — the field accepts a device upload. Clicking goes straight to the
9
+ * file picker, which is the only thing anyone wants from a chip sitting on a
10
+ * picture. Other sources stay one tap away through the field itself.
11
+ * - `focus` — everything else, including image fields restricted to libraries.
12
+ * The chip then does what the hitbox around it does: scroll the field into
13
+ * view and focus its control, so the next keystroke already types into it.
14
+ */
15
+ export type ChipAction = 'upload' | 'focus';
16
+ export declare function fieldHasChip(fieldType: BluepicField['type']): boolean;
17
+ /**
18
+ * `field.props` entries may be author expressions (functions) rather than
19
+ * literals, so a prop can only be read through the host's evaluator — the same
20
+ * `wrapFieldProps` treatment `FieldsList` gives every field component.
21
+ */
22
+ export declare function readFieldProp<T>(value: T | (() => T), evaluate?: (fn: Function) => unknown): T | undefined;
23
+ export declare function chipActionFor(field: BluepicField, evaluate?: (fn: Function) => unknown): ChipAction;
@@ -0,0 +1,81 @@
1
+ import { type InjectionKey } from 'vue';
2
+ import type { BluepicField } from '@bluepic/types';
3
+ /**
4
+ * Opens a field's own primary editing flow — for an image field, the "Select
5
+ * image" popup (or the device file picker, when that's all it offers).
6
+ *
7
+ * Registered BY the field component, because only it knows that flow. Having the
8
+ * overlay reproduce it would mean duplicating image libraries, cropping,
9
+ * background removal and auto-crop up there, and then watching the two copies
10
+ * drift.
11
+ */
12
+ export type FieldActivator = () => void;
13
+ /**
14
+ * Connects a hint on the preview to the field control that drives it.
15
+ *
16
+ * The two halves live far apart — the hint renders inside zoompinch's matrix
17
+ * slot, the control somewhere down a recursive `FieldsList` — so this is
18
+ * provided by `BxTemplateEditor` and injected at both ends rather than threaded
19
+ * through props.
20
+ *
21
+ * BOTH layouts register their elements here, because both end up focusing one:
22
+ * mobile mounts every swiper slide at once, so the control exists even while the
23
+ * swiper is still travelling to it. What differs is how it is brought on screen
24
+ * — desktop scrolls the panel, mobile swipes — and only `BxTemplateEditor` can
25
+ * do the latter, which is why `focus()` is a controller method and not just a
26
+ * lookup.
27
+ */
28
+ export type FieldFocusController = {
29
+ register(field: BluepicField, el: HTMLElement | null): void;
30
+ focus(field: BluepicField): void;
31
+ /** Field components self-register; pass `null` on unmount. */
32
+ registerActivator(field: BluepicField, activate: FieldActivator | null): void;
33
+ /**
34
+ * Runs the field's own flow. Returns false when the field never registered
35
+ * one, so the caller can fall back to plain focus instead of doing nothing.
36
+ */
37
+ activate(field: BluepicField): boolean;
38
+ };
39
+ export declare const FIELD_FOCUS_KEY: InjectionKey<FieldFocusController>;
40
+ export declare function provideFieldFocus(controller: FieldFocusController): void;
41
+ /** Absent whenever the fields tree is rendered outside `BxTemplateEditor`. */
42
+ export declare function useFieldFocus(): FieldFocusController | undefined;
43
+ /** Marks the focused field for a moment so the eye can follow the jump. */
44
+ export declare const FIELD_FOCUS_FLASH_CLASS = "bx-field-hint-target";
45
+ /** Held while the pointer rests on the field's hitbox in the live preview. */
46
+ export declare const FIELD_HOVER_CLASS = "bx-field-hint-hover";
47
+ /**
48
+ * Scroll a field's control into view, flash it, and focus what you type into —
49
+ * falling back to whatever else in it can take focus.
50
+ *
51
+ * `block: 'nearest'` rather than 'center': the fields panel is a scroll
52
+ * container, and centering yanks the whole list even when the target was
53
+ * already comfortably visible.
54
+ *
55
+ * `scroll: false` for the MOBILE layout. Every slide is mounted at once inside
56
+ * swiper's transformed track, so a field that is off screen is off screen by
57
+ * TRANSFORM, not by scroll position — asking the browser to scroll it into view
58
+ * shifts the track's own scroller and leaves swiper's idea of the offset wrong.
59
+ * There, `slideTo` does the travelling and this only has to focus.
60
+ */
61
+ export declare function revealFieldElement(el: HTMLElement | null | undefined, { scroll }?: {
62
+ scroll?: boolean;
63
+ }): HTMLElement | undefined;
64
+ /**
65
+ * The element/activator registry, keyed by the field object itself.
66
+ *
67
+ * A WeakMap (not a Map) because fields are plain objects off the serial — when
68
+ * the serial is swapped the old field objects should simply be collectable,
69
+ * with no unregister bookkeeping to get wrong.
70
+ */
71
+ export declare function createFieldElementRegistry(): {
72
+ register(field: BluepicField, el: HTMLElement | null): void;
73
+ get(field: BluepicField): HTMLElement | undefined;
74
+ registerActivator(field: BluepicField, activate: FieldActivator | null): void;
75
+ activate(field: BluepicField): boolean;
76
+ };
77
+ /**
78
+ * Registers a field component's own editing flow for the lifetime of that
79
+ * component. A no-op outside `BxTemplateEditor`, where no controller is provided.
80
+ */
81
+ export declare function useFieldActivator(field: () => BluepicField | undefined, activate: FieldActivator): void;