@snowcone-app/canvas 0.29.0 → 0.30.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/ERROR_CONTRACT.md +13 -0
- package/dist/{CanvasRenderer-_lFoIoz5.js → CanvasRenderer-BEf0hXeF.js} +4 -4
- package/dist/{CanvasRenderer-_lFoIoz5.js.map → CanvasRenderer-BEf0hXeF.js.map} +1 -1
- package/dist/{CanvasStateV1-BMxr6xb8.js → CanvasStateV1-BDSyYo4A.js} +868 -843
- package/dist/{CanvasStateV1-BMxr6xb8.js.map → CanvasStateV1-BDSyYo4A.js.map} +1 -1
- package/dist/ContextualToolbars-C3D_6sep.js +5960 -0
- package/dist/ContextualToolbars-C3D_6sep.js.map +1 -0
- package/dist/{EditorCanvasImpl-BNz8TPFs.js → EditorCanvasImpl-DXeBz2CX.js} +8 -8
- package/dist/{EditorCanvasImpl-BNz8TPFs.js.map → EditorCanvasImpl-DXeBz2CX.js.map} +1 -1
- package/dist/{ExportManager-B8Td7uR5.js → ExportManager-DUdis6se.js} +794 -536
- package/dist/ExportManager-DUdis6se.js.map +1 -0
- package/dist/{FontAnalyzer-D4Sg-P6_.js → FontAnalyzer-DKG5JK0x.js} +823 -808
- package/dist/FontAnalyzer-DKG5JK0x.js.map +1 -0
- package/dist/{ImagePanel-CN2Bu3hf.js → ImagePanel-CBgGqmVV.js} +53 -53
- package/dist/{ImagePanel-CN2Bu3hf.js.map → ImagePanel-CBgGqmVV.js.map} +1 -1
- package/dist/SnowconeCanvas-BWPBngvI.js +1192 -0
- package/dist/SnowconeCanvas-BWPBngvI.js.map +1 -0
- package/dist/{UnifiedFontService-CgYnYTj7.js → UnifiedFontService-Co9tQ59z.js} +869 -826
- package/dist/UnifiedFontService-Co9tQ59z.js.map +1 -0
- package/dist/advanced.mjs +14 -14
- package/dist/api/embed.d.ts +2 -0
- package/dist/api/stable.d.ts +2 -0
- package/dist/components/CanvasContextMenu.d.ts +15 -0
- package/dist/components/CanvasEditor/hooks/useCanvasInteraction.d.ts +27 -0
- package/dist/components/CanvasEditor.d.ts +8 -0
- package/dist/components/embed/SnowconeCanvas.d.ts +13 -0
- package/dist/components/embed/kernel.d.ts +8 -0
- package/dist/components/ui/icons.d.ts +2 -0
- package/dist/contexts/CanvasServicesContext.d.ts +17 -0
- package/dist/contexts/EditorContext.d.ts +7 -0
- package/dist/{custom-icons-B5TRC1Ed.js → custom-icons-BIaRovwG.js} +2 -2
- package/dist/{custom-icons-B5TRC1Ed.js.map → custom-icons-BIaRovwG.js.map} +1 -1
- package/dist/{design-builder-COj0zkxu.js → design-builder-JYLO_Hyi.js} +2 -2
- package/dist/{design-builder-COj0zkxu.js.map → design-builder-JYLO_Hyi.js.map} +1 -1
- package/dist/{editorErrors-CCvoKj_P.js → editorErrors-WzaNxU1Y.js} +181 -194
- package/dist/editorErrors-WzaNxU1Y.js.map +1 -0
- package/dist/{embed-BTRtoktw.js → embed-Csez1hui.js} +113 -112
- package/dist/{embed-BTRtoktw.js.map → embed-Csez1hui.js.map} +1 -1
- package/dist/embed.mjs +51 -45
- package/dist/embed.mjs.map +1 -1
- package/dist/errors/editorError.d.ts +8 -0
- package/dist/{guards-uQtEQJbs.js → guards-BSoX73yg.js} +2 -2
- package/dist/{guards-uQtEQJbs.js.map → guards-BSoX73yg.js.map} +1 -1
- package/dist/hooks/useKeyboardShortcuts.d.ts +15 -2
- package/dist/hooks/useLayers.d.ts +2 -0
- package/dist/index.mjs +42 -37
- package/dist/index.mjs.map +1 -1
- package/dist/internals.mjs +47 -47
- package/dist/state/CanvasStateV1.d.ts +31 -3
- package/dist/state/index.d.ts +2 -2
- package/dist/{template-fields-BLRp84Ny.js → template-fields-DYPW7bVU.js} +40 -40
- package/dist/{template-fields-BLRp84Ny.js.map → template-fields-DYPW7bVU.js.map} +1 -1
- package/dist/testing.mjs +13 -13
- package/dist/{usePieceGuideBundle-CTQszfKA.js → usePieceGuideBundle-CRLY2iQa.js} +2 -2
- package/dist/{usePieceGuideBundle-CTQszfKA.js.map → usePieceGuideBundle-CRLY2iQa.js.map} +1 -1
- package/dist/utils/custom-fonts.d.ts +99 -0
- package/dist/validation-BGEl9rrE.js +8686 -0
- package/dist/validation-BGEl9rrE.js.map +1 -0
- package/dist/workers/export-protocol.d.ts +13 -0
- package/dist/workers/export-worker.bundle.string.d.ts +1 -1
- package/example/package.json +1 -1
- package/package.json +1 -1
- package/dist/ContextualToolbars-0jWvnQgp.js +0 -5833
- package/dist/ContextualToolbars-0jWvnQgp.js.map +0 -1
- package/dist/ExportManager-B8Td7uR5.js.map +0 -1
- package/dist/FontAnalyzer-D4Sg-P6_.js.map +0 -1
- package/dist/SnowconeCanvas-CR_LdRFP.js +0 -1173
- package/dist/SnowconeCanvas-CR_LdRFP.js.map +0 -1
- package/dist/UnifiedFontService-CgYnYTj7.js.map +0 -1
- package/dist/editorErrors-CCvoKj_P.js.map +0 -1
- package/dist/validation-eCebhplp.js +0 -8402
- package/dist/validation-eCebhplp.js.map +0 -1
package/dist/testing.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { E as A
|
|
2
|
-
import {
|
|
1
|
+
import { E as A } from "./editorErrors-WzaNxU1Y.js";
|
|
2
|
+
import { i as ie, j as oe, k as ae } from "./editorErrors-WzaNxU1Y.js";
|
|
3
3
|
import { fetchMockupImage as S, isSnowconeSdkError as b, RenderSession as _, mintRealtimeGrant as R } from "@snowcone-app/sdk";
|
|
4
|
-
import { s as I, d as y } from "./design-builder-
|
|
4
|
+
import { s as I, d as y } from "./design-builder-JYLO_Hyi.js";
|
|
5
|
+
import { K as D, A as k, g as T, I as F, E as m } from "./FontAnalyzer-DKG5JK0x.js";
|
|
5
6
|
import { jsx as u } from "react/jsx-runtime";
|
|
6
|
-
import { useState as
|
|
7
|
+
import { useState as x } from "react";
|
|
7
8
|
import { T as p } from "./ThemeContext-Rjz25x9X.js";
|
|
8
|
-
import { E as T, A as k, g as F, I as x } from "./FontAnalyzer-D4Sg-P6_.js";
|
|
9
9
|
const G = ({
|
|
10
10
|
children: t,
|
|
11
11
|
initialElements: n = [],
|
|
@@ -14,8 +14,8 @@ const G = ({
|
|
|
14
14
|
initialMultiSelection: i = [],
|
|
15
15
|
initialArtboardConfig: o = {}
|
|
16
16
|
}) => {
|
|
17
|
-
const [l] =
|
|
18
|
-
const a = new
|
|
17
|
+
const [l] = x(() => {
|
|
18
|
+
const a = new D();
|
|
19
19
|
return e && e.length > 0 ? e.forEach((c) => {
|
|
20
20
|
a.createArtboard({
|
|
21
21
|
name: c.name,
|
|
@@ -45,8 +45,8 @@ const G = ({
|
|
|
45
45
|
initialMultiSelection: r = [],
|
|
46
46
|
initialArtboardConfig: i = {}
|
|
47
47
|
}) => /* @__PURE__ */ u(p, { children: /* @__PURE__ */ u(A, { initialArtboardConfig: i, children: t }) });
|
|
48
|
-
function
|
|
49
|
-
const e =
|
|
48
|
+
function j(t = "custom", n = {}) {
|
|
49
|
+
const e = T(t);
|
|
50
50
|
if (!e || !e.Component)
|
|
51
51
|
throw new Error(`Transform type "${t}" not found in registry`);
|
|
52
52
|
return new e.Component({
|
|
@@ -62,8 +62,8 @@ function W(t = "custom", n = {}) {
|
|
|
62
62
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- test utility: overrides merge Partial<TextElement> properties with config, which are structurally compatible but not type-assignable
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
|
-
function
|
|
66
|
-
return new
|
|
65
|
+
function W(t = {}) {
|
|
66
|
+
return new F({
|
|
67
67
|
imageUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
|
|
68
68
|
imageAspectRatio: 1,
|
|
69
69
|
x: 100,
|
|
@@ -239,8 +239,8 @@ export {
|
|
|
239
239
|
X as assertRenders,
|
|
240
240
|
z as createMockArtboard,
|
|
241
241
|
Y as createMockCanvas,
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
j as createMockElement,
|
|
243
|
+
W as createMockImageElement,
|
|
244
244
|
ie as expectNoEditorErrors,
|
|
245
245
|
te as failingGrant,
|
|
246
246
|
oe as getContainedEditorErrors,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z as r } from "./FontAnalyzer-DKG5JK0x.js";
|
|
2
2
|
import { useState as a, useEffect as d } from "react";
|
|
3
3
|
const u = "https://api.snowcone.app";
|
|
4
4
|
function h(e) {
|
|
@@ -58,4 +58,4 @@ export {
|
|
|
58
58
|
l as p,
|
|
59
59
|
p as u
|
|
60
60
|
};
|
|
61
|
-
//# sourceMappingURL=usePieceGuideBundle-
|
|
61
|
+
//# sourceMappingURL=usePieceGuideBundle-CRLY2iQa.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePieceGuideBundle-
|
|
1
|
+
{"version":3,"file":"usePieceGuideBundle-CRLY2iQa.js","sources":["../src/components/embed-realtime/usePieceGuideBundle.ts"],"sourcesContent":["'use client';\n\n/**\n * usePieceGuideBundle — fetch a product's printable-area guides for the embed.\n *\n * Some products hide part of the print file under hardware (a phone case's\n * camera module, a notebook's spine). snowcone.app's own editor draws the\n * printable-area / dead-zone overlay from the product's piece guides;\n * `<RealtimeEmbed>` uses this hook so embedders get the same overlay with\n * zero config — without it, a buyer can edit artwork the mockup will never\n * show, with no signal anywhere (#566).\n *\n * The endpoint is a public read (geometry only — piece rects, safe areas,\n * authored guides; same exposure class as the public catalog). Errors degrade\n * silently to \"no guides\": the editor keeps working, the overlay just doesn't\n * appear — same posture as snowcone.app's own loader.\n *\n * @module\n */\n\nimport { useEffect, useState } from 'react';\nimport type { PieceGuidesConfig } from '../embed/SnowconeCanvas.js';\nimport type {\n PieceGuide,\n PieceGuideRendererPiece,\n PieceGuideRendererStyle,\n} from '../../rendering/PieceGuideRenderer.js';\n\n/** Backend base hosting `GET /printables/by-gvid/:gvid/piece-guides`. */\nexport const PIECE_GUIDES_API_BASE = 'https://api.snowcone.app';\n\n/** Wire shape of the piece-guides endpoint (the consumer-safe subset). */\ninterface RawPieceGuidesResponse {\n artboardWidth: number;\n artboardHeight: number;\n /** Inches→px conversion factor for `safeAreaInsetInches`. */\n templateDpi: number;\n pieces: Array<{\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n rotation?: number;\n safeAreaInsetInches?: number;\n }>;\n pieceGuides?: Record<string, PieceGuide>;\n pieceGuidesStyle?: PieceGuideRendererStyle;\n}\n\n/** A fetched bundle: the overlay config plus the artboard frame it was authored in. */\nexport interface PieceGuideBundle {\n /** The print-file frame the piece coords live in. */\n artboardWidth: number;\n artboardHeight: number;\n config: PieceGuidesConfig;\n}\n\n/** Convert the wire response into a renderer-ready bundle (inches → px, etc.). */\nexport function transformPieceGuides(raw: RawPieceGuidesResponse): PieceGuideBundle {\n const pieces: PieceGuideRendererPiece[] = raw.pieces.map((p) => ({\n id: p.id,\n x: p.x,\n y: p.y,\n width: p.width,\n height: p.height,\n rotation: typeof p.rotation === 'number' ? p.rotation : undefined,\n safeAreaInsetPx:\n typeof p.safeAreaInsetInches === 'number' && p.safeAreaInsetInches > 0\n ? p.safeAreaInsetInches * raw.templateDpi\n : undefined,\n }));\n return {\n artboardWidth: raw.artboardWidth,\n artboardHeight: raw.artboardHeight,\n config: {\n pieces,\n guides: raw.pieceGuides ?? {},\n style: raw.pieceGuidesStyle,\n },\n };\n}\n\n/**\n * Gate the bundle on the design's artboard matching the print-file frame the\n * guides were authored in — the same gate snowcone.app's editor applies. A\n * design authored at other dims would render the overlay misaligned, so it's\n * skipped (with a dev hint, since the fix — author at the placement's dims —\n * is on the embedder's side).\n */\nexport function pieceGuidesForArtboard(\n bundle: PieceGuideBundle,\n artboard: { width: number; height: number } | undefined,\n): PieceGuidesConfig | undefined {\n if (!artboard) return undefined;\n if (artboard.width !== bundle.artboardWidth || artboard.height !== bundle.artboardHeight) {\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.warn(\n `[RealtimeEmbed] This product has printable-area guides (authored at ` +\n `${bundle.artboardWidth}×${bundle.artboardHeight}), but the design's artboard is ` +\n `${artboard.width}×${artboard.height} — the dead-zone overlay is skipped because the ` +\n `coordinates wouldn't line up. Author the design at the placement's dimensions to get it.`,\n );\n }\n return undefined;\n }\n return bundle.config;\n}\n\n/**\n * Fetch the piece-guide bundle for a variant (gvid). Returns null while\n * loading, when `gvid` is undefined, and on any error (silent degrade).\n */\nexport function usePieceGuideBundle(\n gvid: string | undefined,\n apiBase: string = PIECE_GUIDES_API_BASE,\n): PieceGuideBundle | null {\n const [bundle, setBundle] = useState<PieceGuideBundle | null>(null);\n\n useEffect(() => {\n if (!gvid) {\n setBundle(null);\n return;\n }\n let cancelled = false;\n fetch(`${apiBase}/printables/by-gvid/${encodeURIComponent(gvid)}/piece-guides`)\n .then(async (res) => {\n if (!res.ok) throw new Error(`status ${res.status}`);\n return (await res.json()) as RawPieceGuidesResponse;\n })\n .then((raw) => {\n if (!cancelled) setBundle(transformPieceGuides(raw));\n })\n .catch(() => {\n // No guides is a degraded state, not a failure — the editor keeps\n // working, the overlay just doesn't appear.\n if (!cancelled) setBundle(null);\n });\n return () => {\n cancelled = true;\n };\n }, [gvid, apiBase]);\n\n return bundle;\n}\n"],"names":["PIECE_GUIDES_API_BASE","transformPieceGuides","raw","pieces","p","pieceGuidesForArtboard","bundle","artboard","process","usePieceGuideBundle","gvid","apiBase","setBundle","useState","useEffect","cancelled","res"],"mappings":";;AA6BO,MAAMA,IAAwB;AA8B9B,SAASC,EAAqBC,GAA+C;AAClF,QAAMC,IAAoCD,EAAI,OAAO,IAAI,CAACE,OAAO;AAAA,IAC/D,IAAIA,EAAE;AAAA,IACN,GAAGA,EAAE;AAAA,IACL,GAAGA,EAAE;AAAA,IACL,OAAOA,EAAE;AAAA,IACT,QAAQA,EAAE;AAAA,IACV,UAAU,OAAOA,EAAE,YAAa,WAAWA,EAAE,WAAW;AAAA,IACxD,iBACE,OAAOA,EAAE,uBAAwB,YAAYA,EAAE,sBAAsB,IACjEA,EAAE,sBAAsBF,EAAI,cAC5B;AAAA,EAAA,EACN;AACF,SAAO;AAAA,IACL,eAAeA,EAAI;AAAA,IACnB,gBAAgBA,EAAI;AAAA,IACpB,QAAQ;AAAA,MACN,QAAAC;AAAA,MACA,QAAQD,EAAI,eAAe,CAAA;AAAA,MAC3B,OAAOA,EAAI;AAAA,IAAA;AAAA,EACb;AAEJ;AASO,SAASG,EACdC,GACAC,GAC+B;;AAC/B,MAAKA,GACL;AAAA,QAAIA,EAAS,UAAUD,EAAO,iBAAiBC,EAAS,WAAWD,EAAO,gBAAgB;AACxF,MAAI,OAAOE,IAAY,SAAeA,IAAAA,EAAQ,QAARA,gBAAAA,EAAa,cAAa,gBAC9D,QAAQ;AAAA,QACN,uEACKF,EAAO,aAAa,IAAIA,EAAO,cAAc,mCAC7CC,EAAS,KAAK,IAAIA,EAAS,MAAM;AAAA,MAAA;AAI1C;AAAA,IACF;AACA,WAAOD,EAAO;AAAA;AAChB;AAMO,SAASG,EACdC,GACAC,IAAkBX,GACO;AACzB,QAAM,CAACM,GAAQM,CAAS,IAAIC,EAAkC,IAAI;AAElE,SAAAC,EAAU,MAAM;AACd,QAAI,CAACJ,GAAM;AACT,MAAAE,EAAU,IAAI;AACd;AAAA,IACF;AACA,QAAIG,IAAY;AAChB,iBAAM,GAAGJ,CAAO,uBAAuB,mBAAmBD,CAAI,CAAC,eAAe,EAC3E,KAAK,OAAOM,MAAQ;AACnB,UAAI,CAACA,EAAI,GAAI,OAAM,IAAI,MAAM,UAAUA,EAAI,MAAM,EAAE;AACnD,aAAQ,MAAMA,EAAI,KAAA;AAAA,IACpB,CAAC,EACA,KAAK,CAACd,MAAQ;AACb,MAAKa,KAAWH,EAAUX,EAAqBC,CAAG,CAAC;AAAA,IACrD,CAAC,EACA,MAAM,MAAM;AAGX,MAAKa,KAAWH,EAAU,IAAI;AAAA,IAChC,CAAC,GACI,MAAM;AACX,MAAAG,IAAY;AAAA,IACd;AAAA,EACF,GAAG,CAACL,GAAMC,CAAO,CAAC,GAEXL;AACT;"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { EditorError } from '../errors/editorError.js';
|
|
2
|
+
/**
|
|
3
|
+
* A custom (brand) font dependency of a design. Stored in
|
|
4
|
+
* `CanvasStateV1.customFonts`; `url` must be a plain-CORS-GET-fetchable
|
|
5
|
+
* font binary (woff2/woff/ttf/otf) — the export worker fetches it too.
|
|
6
|
+
*/
|
|
7
|
+
export interface CustomFont {
|
|
8
|
+
/** Family name, registered as-is (see the shadowing contract above). */
|
|
9
|
+
family: string;
|
|
10
|
+
/** Host-stored font binary URL (must allow cross-origin GET). */
|
|
11
|
+
url: string;
|
|
12
|
+
/** CSS font-weight the file provides. Defaults to 400. */
|
|
13
|
+
weight?: number;
|
|
14
|
+
/** CSS font-style the file provides. Defaults to 'normal'. */
|
|
15
|
+
style?: 'normal' | 'italic';
|
|
16
|
+
}
|
|
17
|
+
type RegistryListener = () => void;
|
|
18
|
+
/**
|
|
19
|
+
* Runtime registry of custom fonts — the resolution authority for the
|
|
20
|
+
* deterministic-shadowing contract (file docblock). Module singleton on
|
|
21
|
+
* purpose: the export path (`WorkerExportManager`) and the picker UI need
|
|
22
|
+
* the same answer to "is this family custom?" without prop-threading
|
|
23
|
+
* through 2000-line components.
|
|
24
|
+
*/
|
|
25
|
+
declare class CustomFontRegistryClass {
|
|
26
|
+
private fonts;
|
|
27
|
+
private listeners;
|
|
28
|
+
/** Stable snapshot for `useSyncExternalStore` — replaced only on change. */
|
|
29
|
+
private snapshot;
|
|
30
|
+
/**
|
|
31
|
+
* Register fonts (idempotent; re-registering the same family/weight/style
|
|
32
|
+
* replaces the URL). Returns true when anything changed.
|
|
33
|
+
*/
|
|
34
|
+
register(fonts: readonly CustomFont[]): boolean;
|
|
35
|
+
/** Is this family registered as a custom font? (Shadowing check.) */
|
|
36
|
+
has(family: string): boolean;
|
|
37
|
+
/** All registered faces of one family (possibly several weights/styles). */
|
|
38
|
+
facesOf(family: string): CustomFont[];
|
|
39
|
+
/** Registered faces whose family appears in `families` — what the export
|
|
40
|
+
* path sends to the worker alongside the used-font list. */
|
|
41
|
+
forFamilies(families: readonly string[]): CustomFont[];
|
|
42
|
+
/** All registered custom fonts (stable reference until a change). */
|
|
43
|
+
list: () => readonly CustomFont[];
|
|
44
|
+
subscribe: (listener: RegistryListener) => (() => void);
|
|
45
|
+
/** @internal Test helper — wipe registry state between tests. */
|
|
46
|
+
clear(): void;
|
|
47
|
+
}
|
|
48
|
+
/** The singleton registry (see class docs). */
|
|
49
|
+
export declare const customFontRegistry: CustomFontRegistryClass;
|
|
50
|
+
/**
|
|
51
|
+
* Register custom fonts with the runtime registry so every load site
|
|
52
|
+
* resolves them custom-first (the deterministic-shadowing contract).
|
|
53
|
+
* Idempotent. Called by `deserializeState`, the `customFonts` prop path,
|
|
54
|
+
* and the picker's upload flow.
|
|
55
|
+
*/
|
|
56
|
+
export declare function registerCustomFonts(fonts: readonly CustomFont[]): void;
|
|
57
|
+
export interface LoadCustomFontOptions {
|
|
58
|
+
/** Injected for tests (mirrors `google-fonts-loader` test seams). */
|
|
59
|
+
fetchImpl?: typeof fetch;
|
|
60
|
+
/**
|
|
61
|
+
* FontFaceSet to activate the face into. Defaults to `document.fonts`
|
|
62
|
+
* in a window context; the export worker passes `self.fonts`.
|
|
63
|
+
*/
|
|
64
|
+
fonts?: FontFaceSet;
|
|
65
|
+
}
|
|
66
|
+
/** @internal Test helper — forget which faces were loaded. */
|
|
67
|
+
export declare function resetLoadedCustomFonts(): void;
|
|
68
|
+
/**
|
|
69
|
+
* Load one custom font, bytes-first (gotcha #29): fetch the binary with
|
|
70
|
+
* `mode: 'cors'`, construct `FontFace` from the ArrayBuffer, add it to the
|
|
71
|
+
* target FontFaceSet.
|
|
72
|
+
*
|
|
73
|
+
* THROWS `EditorError('E_FONT_LOAD_FAILED')` when the fetch or FontFace
|
|
74
|
+
* activation fails — dev AND prod. There is deliberately no silent serif
|
|
75
|
+
* fallback: a saved design's text metrics depend on this exact file, so a
|
|
76
|
+
* quiet fallback renders a *different design*, which is worse than a loud
|
|
77
|
+
* stop with the URL in hand.
|
|
78
|
+
*/
|
|
79
|
+
export declare function loadCustomFont(font: CustomFont, options?: LoadCustomFontOptions): Promise<FontFace>;
|
|
80
|
+
/**
|
|
81
|
+
* Load every face of `fonts` into `fontFaceSet` — the worker-side path
|
|
82
|
+
* (`export-worker.ts > loadFonts` delegates here for custom families).
|
|
83
|
+
* Rejects with the FIRST `E_FONT_LOAD_FAILED` so the export fails loudly
|
|
84
|
+
* instead of rendering a serif placeholder into a saved placement PNG.
|
|
85
|
+
*/
|
|
86
|
+
export declare function loadCustomFontFaces(fonts: readonly CustomFont[], fontFaceSet: FontFaceSet, fetchImpl?: typeof fetch): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Ensure each font is registered AND loaded in this context (idempotent —
|
|
89
|
+
* already-loaded faces are skipped). Per-font failures are delivered to
|
|
90
|
+
* `onLoadError` (machine channel — e.g. the embed kernel's `emitError`)
|
|
91
|
+
* instead of aborting the batch: when OPENING a design, one unreachable
|
|
92
|
+
* font URL must not take the other nine fonts down with it. The error is
|
|
93
|
+
* still the typed `EditorError('E_FONT_LOAD_FAILED')`, never a swallow —
|
|
94
|
+
* omitting `onLoadError` rethrows.
|
|
95
|
+
*/
|
|
96
|
+
export declare function ensureCustomFontsLoaded(fonts: readonly CustomFont[], options?: LoadCustomFontOptions & {
|
|
97
|
+
onLoadError?: (error: EditorError, font: CustomFont) => void;
|
|
98
|
+
}): Promise<void>;
|
|
99
|
+
export {};
|