@orangecatai/adgen-canvas 0.0.6 → 0.0.8

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 (45) hide show
  1. package/dist/dev/{chunk-7QYIG5FZ.js → chunk-FAXV62EG.js} +2 -2
  2. package/dist/dev/{chunk-CEENA34D.js → chunk-LAGHQ2FH.js} +32 -3
  3. package/dist/dev/chunk-LAGHQ2FH.js.map +7 -0
  4. package/dist/dev/data/{image-YK44DYB7.js → image-FJMUJMRD.js} +3 -3
  5. package/dist/dev/index.css +390 -0
  6. package/dist/dev/index.css.map +3 -3
  7. package/dist/dev/index.js +5127 -2278
  8. package/dist/dev/index.js.map +4 -4
  9. package/dist/dev/subset-shared.chunk.js +1 -1
  10. package/dist/dev/subset-worker.chunk.js +1 -1
  11. package/dist/prod/{chunk-GCPOY3UH.js → chunk-7LYXIGC7.js} +3 -3
  12. package/dist/prod/{chunk-R5LMMFAL.js → chunk-B427J75A.js} +1 -1
  13. package/dist/prod/data/image-RPDJGGN2.js +1 -0
  14. package/dist/prod/index.css +1 -1
  15. package/dist/prod/index.js +335 -78
  16. package/dist/prod/subset-shared.chunk.js +1 -1
  17. package/dist/prod/subset-worker.chunk.js +1 -1
  18. package/dist/types/excalidraw/components/AIChatPanel.d.ts +10 -1
  19. package/dist/types/excalidraw/components/DarkModeToggle.d.ts +1 -1
  20. package/dist/types/excalidraw/components/ElementCanvasButtons.d.ts +1 -1
  21. package/dist/types/excalidraw/components/FrameToolbar.d.ts +1 -1
  22. package/dist/types/excalidraw/components/HintViewer.d.ts +1 -1
  23. package/dist/types/excalidraw/components/Stats/DragInput.d.ts +1 -1
  24. package/dist/types/excalidraw/components/Stats/index.d.ts +1 -1
  25. package/dist/types/excalidraw/components/TTDDialog/utils/TTDStreamFetch.d.ts +1 -0
  26. package/dist/types/excalidraw/components/ToolButton.d.ts +1 -1
  27. package/dist/types/excalidraw/components/ai-chat/agentLoop.d.ts +14 -1
  28. package/dist/types/excalidraw/components/ai-chat/canvasTools.d.ts +193 -1
  29. package/dist/types/excalidraw/components/ai-chat/htmlToExcalidraw.d.ts +53 -0
  30. package/dist/types/excalidraw/components/ai-chat/openRouterStream.d.ts +50 -0
  31. package/dist/types/excalidraw/components/auto-resize/AutoResizePanel.d.ts +16 -0
  32. package/dist/types/excalidraw/components/auto-resize/AutoResizeShimmerLayer.d.ts +7 -0
  33. package/dist/types/excalidraw/components/auto-resize/autoResizeEngine.d.ts +89 -0
  34. package/dist/types/excalidraw/components/auto-resize/autoResizeStore.d.ts +16 -0
  35. package/dist/types/excalidraw/components/hyperlink/Hyperlink.d.ts +1 -1
  36. package/dist/types/excalidraw/components/main-menu/DefaultItems.d.ts +1 -1
  37. package/dist/types/excalidraw/components/ui/button.d.ts +1 -1
  38. package/dist/types/excalidraw/fonts/Fonts.d.ts +11 -0
  39. package/dist/types/excalidraw/index.d.ts +1 -0
  40. package/dist/types/excalidraw/types.d.ts +96 -0
  41. package/package.json +1 -1
  42. package/dist/dev/chunk-CEENA34D.js.map +0 -7
  43. package/dist/prod/data/image-XZPNP25M.js +0 -1
  44. /package/dist/dev/{chunk-7QYIG5FZ.js.map → chunk-FAXV62EG.js.map} +0 -0
  45. /package/dist/dev/data/{image-YK44DYB7.js.map → image-FJMUJMRD.js.map} +0 -0
@@ -1 +1 @@
1
- import{a,b,c,d}from"./chunk-Z5NKEFVG.js";import"./chunk-R5LMMFAL.js";import"./chunk-SRAX5OIU.js";export{a as Commands,b as subsetToBase64,c as subsetToBinary,d as toBase64};
1
+ import{a,b,c,d}from"./chunk-Z5NKEFVG.js";import"./chunk-B427J75A.js";import"./chunk-SRAX5OIU.js";export{a as Commands,b as subsetToBase64,c as subsetToBinary,d as toBase64};
@@ -1 +1 @@
1
- import{a as r,c as t}from"./chunk-Z5NKEFVG.js";import"./chunk-R5LMMFAL.js";import"./chunk-SRAX5OIU.js";var s=import.meta.url?new URL(import.meta.url):void 0;typeof window>"u"&&typeof self<"u"&&(self.onmessage=async e=>{switch(e.data.command){case r.Subset:let a=await t(e.data.arrayBuffer,e.data.codePoints);self.postMessage(a,{transfer:[a]});break}});export{s as WorkerUrl};
1
+ import{a as r,c as t}from"./chunk-Z5NKEFVG.js";import"./chunk-B427J75A.js";import"./chunk-SRAX5OIU.js";var s=import.meta.url?new URL(import.meta.url):void 0;typeof window>"u"&&typeof self<"u"&&(self.onmessage=async e=>{switch(e.data.command){case r.Subset:let a=await t(e.data.arrayBuffer,e.data.codePoints);self.postMessage(a,{transfer:[a]});break}});export{s as WorkerUrl};
@@ -54,7 +54,7 @@ export type AIChatPanelProps = {
54
54
  onAfterImageGen?: () => void;
55
55
  /**
56
56
  * OpenRouter model tag for the chat system (both plain chat and agent loop).
57
- * @default "openai/gpt-4.1-mini"
57
+ * @default "google/gemini-2.0-flash-001"
58
58
  * @example "openai/gpt-4o" or "anthropic/claude-sonnet-4"
59
59
  */
60
60
  chatModel?: string;
@@ -69,5 +69,14 @@ export type AIChatPanelProps = {
69
69
  * @example "gemini-2.0-flash-preview-image-generation"
70
70
  */
71
71
  agentImageModel?: string;
72
+ /**
73
+ * Optional brand identity context. When provided, the AI agent receives
74
+ * the brand's colors, typography, tone of voice, and imagery direction as
75
+ * a system-level context message so it can create on-brand ads.
76
+ *
77
+ * Pair this with `customFonts` on `<Excalidraw>` so that any uploaded
78
+ * brand font files are also registered in the canvas.
79
+ */
80
+ brandContext?: import("../types").BrandContext;
72
81
  };
73
82
  export declare const AIChatPanel: React.ForwardRefExoticComponent<AIChatPanelProps & React.RefAttributes<AIChatPanelRef>>;
@@ -1,5 +1,5 @@
1
- import type { Theme } from "@orangecatai/element/types";
2
1
  import "./ToolIcon.scss";
2
+ import type { Theme } from "@orangecatai/element/types";
3
3
  export declare const DarkModeToggle: (props: {
4
4
  value: Theme;
5
5
  onChange: (value: Theme) => void;
@@ -1,5 +1,5 @@
1
- import type { ElementsMap, NonDeletedExcalidrawElement } from "@orangecatai/element/types";
2
1
  import "./ElementCanvasButtons.scss";
2
+ import type { ElementsMap, NonDeletedExcalidrawElement } from "@orangecatai/element/types";
3
3
  export declare const ElementCanvasButtons: ({ children, element, elementsMap, }: {
4
4
  children: React.ReactNode;
5
5
  element: NonDeletedExcalidrawElement;
@@ -1,5 +1,5 @@
1
- import type { ExcalidrawFrameLikeElement, NonDeletedExcalidrawElement } from "@orangecatai/element/types";
2
1
  import "./FrameToolbar.scss";
2
+ import type { ExcalidrawFrameLikeElement, NonDeletedExcalidrawElement } from "@orangecatai/element/types";
3
3
  import type { AppClassProperties } from "../types";
4
4
  export declare const FrameToolbar: ({ element, app, }: {
5
5
  element: NonDeletedExcalidrawElement & ExcalidrawFrameLikeElement;
@@ -1,5 +1,5 @@
1
- import type { EditorInterface } from "@orangecatai/common";
2
1
  import "./HintViewer.scss";
2
+ import type { EditorInterface } from "@orangecatai/common";
3
3
  import type { AppClassProperties, UIAppState } from "../types";
4
4
  interface HintViewerProps {
5
5
  appState: UIAppState;
@@ -1,6 +1,6 @@
1
- import type { Scene } from "@orangecatai/element";
2
1
  import { useApp, useExcalidrawSetAppState } from "../App";
3
2
  import "./DragInput.scss";
3
+ import type { Scene } from "@orangecatai/element";
4
4
  import type { ElementsMap, ExcalidrawElement } from "@orangecatai/element/types";
5
5
  import type { StatsInputProperty } from "./utils";
6
6
  import type { AppState } from "../../types";
@@ -1,5 +1,5 @@
1
- import type { NonDeletedExcalidrawElement } from "@orangecatai/element/types";
2
1
  import "./Stats.scss";
2
+ import type { NonDeletedExcalidrawElement } from "@orangecatai/element/types";
3
3
  import type { AppClassProperties, AppState, ExcalidrawProps } from "../../types";
4
4
  interface StatsProps {
5
5
  app: AppClassProperties;
@@ -20,5 +20,6 @@ export type StreamChunk = {
20
20
  status?: number;
21
21
  };
22
22
  };
23
+ export declare function parseSSEStream(reader: ReadableStreamDefaultReader<Uint8Array>): AsyncGenerator<string, void, unknown>;
23
24
  export declare function TTDStreamFetch(options: StreamingOptions): Promise<TTTDDialog.OnTextSubmitRetValue>;
24
25
  export {};
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
- import type { PointerType } from "@orangecatai/element/types";
3
2
  import "./ToolIcon.scss";
3
+ import type { PointerType } from "@orangecatai/element/types";
4
4
  import type { CSSProperties } from "react";
5
5
  export type ToolButtonSize = "small" | "medium";
6
6
  type ToolButtonBaseProps = {
@@ -1,4 +1,5 @@
1
1
  import { type ToolExecutionContext, type ToolResult } from "./canvasTools";
2
+ import type { BrandContext } from "../../types";
2
3
  type ContentPart = {
3
4
  type: "text";
4
5
  text: string;
@@ -37,7 +38,7 @@ export type ToolAction = {
37
38
  result: ToolResult;
38
39
  };
39
40
  export type AgentUpdate = {
40
- type: "status" | "tool_start" | "tool_done" | "final";
41
+ type: "status" | "tool_start" | "tool_done" | "final" | "content_delta";
41
42
  message: string;
42
43
  toolAction?: ToolAction;
43
44
  };
@@ -55,6 +56,11 @@ export declare function runAgentLoop(opts: {
55
56
  userMessages: Array<{
56
57
  role: "user" | "assistant";
57
58
  content: string;
59
+ /** Images attached to THIS specific message (from the user's upload history) */
60
+ imageAttachments?: Array<{
61
+ name: string;
62
+ dataUrl: string;
63
+ }>;
58
64
  }>;
59
65
  elementContext?: string;
60
66
  frameScreenshot?: string;
@@ -71,5 +77,12 @@ export declare function runAgentLoop(opts: {
71
77
  error?: string;
72
78
  }>;
73
79
  onAfterImageGen?: () => void;
80
+ /** Optional brand identity context — injected as a system message before user messages. */
81
+ brandContext?: BrandContext;
82
+ /**
83
+ * @deprecated Font IDs are now derived from brandContext.typography.fontFamilyId.
84
+ * Kept for API compatibility but no longer used internally.
85
+ */
86
+ customFontIds?: number[];
74
87
  }): Promise<AgentResult>;
75
88
  export {};
@@ -110,7 +110,7 @@ export declare const CANVAS_TOOLS: readonly [{
110
110
  readonly fontFamily: {
111
111
  readonly type: "number";
112
112
  readonly enum: readonly [1, 2, 3, 4, 5];
113
- readonly description: "Font family: 1=Excalifont(hand), 2=Nunito(sans), 3=Comic Shanns(code), 4=Liberation Sans(clean sans), 5=cascadia(code). Default 2.";
113
+ readonly description: "Font family: 1=Excalifont(hand), 2=Nunito(sans), 3=Comic Shanns(code), 4=Liberation Sans(clean sans), 5=Cascadia(code). Default 2.";
114
114
  };
115
115
  readonly strokeColor: {
116
116
  readonly type: "string";
@@ -260,6 +260,183 @@ export declare const CANVAS_TOOLS: readonly [{
260
260
  };
261
261
  };
262
262
  }];
263
+ /**
264
+ * Returns the canvas tool definitions for the agent, optionally extending
265
+ * the `add_text` fontFamily enum with custom font IDs.
266
+ *
267
+ * Pass the family IDs registered via `Fonts.registerCustomFont` so the
268
+ * agent knows it can use those numbers in `add_text` calls.
269
+ */
270
+ export declare function getCanvasTools(extraFontIds?: number[]): typeof CANVAS_TOOLS;
271
+ export declare const BANNER_TOOLS: readonly [{
272
+ readonly type: "function";
273
+ readonly function: {
274
+ readonly name: "create_frame";
275
+ readonly description: "Create a new frame on the canvas to act as the root container for your banner. Default size is 512x512. ALWAYS call this FIRST before generating images or HTML.";
276
+ readonly parameters: {
277
+ readonly type: "object";
278
+ readonly properties: {
279
+ readonly width: {
280
+ readonly type: "number";
281
+ readonly description: "Frame width in pixels (default 512)";
282
+ };
283
+ readonly height: {
284
+ readonly type: "number";
285
+ readonly description: "Frame height in pixels (default 512)";
286
+ };
287
+ readonly name: {
288
+ readonly type: "string";
289
+ readonly description: "Optional display name for the frame";
290
+ };
291
+ };
292
+ readonly required: readonly [];
293
+ readonly additionalProperties: false;
294
+ };
295
+ };
296
+ }, {
297
+ readonly type: "function";
298
+ readonly function: {
299
+ readonly name: "generate_image";
300
+ readonly description: "Generate an image using AI (Gemini) and place it onto the canvas. Always call this for any photo or image content — even when the user has attached a reference image. The attached image is passed to Gemini as visual reference; Gemini generates the final output. Use referenceImageIndex to tell Gemini which user attachment to reference. IMPORTANT: your prompt must describe a purely visual scene — NO text, NO typography, NO words, NO captions, NO watermarks. All copy is handled by the HTML layer. A 'no text' safety suffix will be auto-appended, but you must also describe composition clearly (e.g. which side should be left open/empty for the HTML text).";
301
+ readonly parameters: {
302
+ readonly type: "object";
303
+ readonly properties: {
304
+ readonly frameId: {
305
+ readonly type: "string";
306
+ readonly description: "ID of the parent frame to insert the image into";
307
+ };
308
+ readonly prompt: {
309
+ readonly type: "string";
310
+ readonly description: "Detailed generation prompt. When using a reference image, describe what you want Gemini to produce — e.g. 'use this building as the subject, wide cinematic crop with open sky on the left for text overlay'.";
311
+ };
312
+ readonly x: {
313
+ readonly type: "number";
314
+ readonly description: "X position relative to the frame's top-left corner";
315
+ };
316
+ readonly y: {
317
+ readonly type: "number";
318
+ readonly description: "Y position relative to the frame's top-left corner";
319
+ };
320
+ readonly width: {
321
+ readonly type: "number";
322
+ readonly description: "Image width in pixels";
323
+ };
324
+ readonly height: {
325
+ readonly type: "number";
326
+ readonly description: "Image height in pixels";
327
+ };
328
+ readonly referenceImageIndex: {
329
+ readonly type: "number";
330
+ readonly description: "0-based index of the user's attached image to pass to Gemini as reference. Always use 0 when the user has attached an image.";
331
+ };
332
+ };
333
+ readonly required: readonly ["frameId", "prompt", "x", "y", "width", "height"];
334
+ readonly additionalProperties: false;
335
+ };
336
+ };
337
+ }, {
338
+ readonly type: "function";
339
+ readonly function: {
340
+ readonly name: "generate_html_banner";
341
+ readonly description: "Place HTML/CSS text and shape elements into an EXISTING frame on the canvas. Always call create_frame first to get a frameId, then generate_image, then call this with that frameId. frameId is required — this tool does NOT create frames.";
342
+ readonly parameters: {
343
+ readonly type: "object";
344
+ readonly properties: {
345
+ readonly html: {
346
+ readonly type: "string";
347
+ readonly description: "Complete self-contained HTML with inline <style>. All layer elements must use position:absolute with explicit left/top/width/height in px. Root div must have class='canvas'.";
348
+ };
349
+ readonly frameId: {
350
+ readonly type: "string";
351
+ readonly description: "Required. The ID of the frame created by create_frame. Adds HTML elements into this existing frame, preserving existing children like images.";
352
+ };
353
+ };
354
+ readonly required: readonly ["html", "frameId"];
355
+ readonly additionalProperties: false;
356
+ };
357
+ };
358
+ }, {
359
+ readonly type: "function";
360
+ readonly function: {
361
+ readonly name: "get_frame_elements";
362
+ readonly description: "Get all child elements inside a frame. Use when editing an existing banner to understand its current state before replacing.";
363
+ readonly parameters: {
364
+ readonly type: "object";
365
+ readonly properties: {
366
+ readonly frameId: {
367
+ readonly type: "string";
368
+ readonly description: "ID of the frame to inspect";
369
+ };
370
+ };
371
+ readonly required: readonly ["frameId"];
372
+ readonly additionalProperties: false;
373
+ };
374
+ };
375
+ }, {
376
+ readonly type: "function";
377
+ readonly function: {
378
+ readonly name: "update_element";
379
+ readonly description: "Update properties of an existing element. Use for minor targeted fixes after the banner is placed.";
380
+ readonly parameters: {
381
+ readonly type: "object";
382
+ readonly properties: {
383
+ readonly elementId: {
384
+ readonly type: "string";
385
+ };
386
+ readonly x: {
387
+ readonly type: "number";
388
+ };
389
+ readonly y: {
390
+ readonly type: "number";
391
+ };
392
+ readonly width: {
393
+ readonly type: "number";
394
+ };
395
+ readonly height: {
396
+ readonly type: "number";
397
+ };
398
+ readonly backgroundColor: {
399
+ readonly type: "string";
400
+ };
401
+ readonly strokeColor: {
402
+ readonly type: "string";
403
+ };
404
+ readonly opacity: {
405
+ readonly type: "number";
406
+ };
407
+ readonly fontSize: {
408
+ readonly type: "number";
409
+ };
410
+ readonly text: {
411
+ readonly type: "string";
412
+ };
413
+ readonly fillStyle: {
414
+ readonly type: "string";
415
+ readonly enum: readonly ["solid", "hachure", "cross-hatch"];
416
+ };
417
+ };
418
+ readonly required: readonly ["elementId"];
419
+ readonly additionalProperties: false;
420
+ };
421
+ };
422
+ }, {
423
+ readonly type: "function";
424
+ readonly function: {
425
+ readonly name: "delete_element";
426
+ readonly description: "Delete an element from the canvas.";
427
+ readonly parameters: {
428
+ readonly type: "object";
429
+ readonly properties: {
430
+ readonly elementId: {
431
+ readonly type: "string";
432
+ readonly description: "ID of the element to delete";
433
+ };
434
+ };
435
+ readonly required: readonly ["elementId"];
436
+ readonly additionalProperties: false;
437
+ };
438
+ };
439
+ }];
263
440
  export declare function serializeElements(elements: readonly ExcalidrawElement[]): Record<string, unknown>[];
264
441
  export type FrameInfo = {
265
442
  id: string;
@@ -280,6 +457,21 @@ export type ToolExecutionContext = {
280
457
  signal?: AbortSignal;
281
458
  /** Override Gemini model ID for the agent's generate_image tool. */
282
459
  agentImageModel?: string;
460
+ /**
461
+ * Maps lowercase brand font-family names to their registered Excalidraw
462
+ * fontFamilyIds. Built from BrandContext.typography in runAgentLoop and
463
+ * used by the HTML parser to preserve brand fonts in text elements.
464
+ */
465
+ customFontMap?: Record<string, number>;
466
+ /**
467
+ * Image file attachments the user uploaded in the current chat turn.
468
+ * Indexed 0-based in the order they were attached.
469
+ * Used by place_attachment (direct placement) and generate_image (as Gemini reference).
470
+ */
471
+ fileAttachments?: Array<{
472
+ name: string;
473
+ dataUrl?: string;
474
+ }>;
283
475
  };
284
476
  export type ToolResult = {
285
477
  success: boolean;
@@ -0,0 +1,53 @@
1
+ export type ParsedRectangle = {
2
+ kind: "rectangle";
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ backgroundColor: string;
8
+ backgroundGradient?: string;
9
+ strokeColor: string;
10
+ strokeWidth: number;
11
+ opacity: number;
12
+ borderRadius: number;
13
+ };
14
+ export type ParsedEllipse = {
15
+ kind: "ellipse";
16
+ x: number;
17
+ y: number;
18
+ width: number;
19
+ height: number;
20
+ backgroundColor: string;
21
+ backgroundGradient?: string;
22
+ strokeColor: string;
23
+ strokeWidth: number;
24
+ opacity: number;
25
+ };
26
+ export type ParsedText = {
27
+ kind: "text";
28
+ x: number;
29
+ y: number;
30
+ width: number;
31
+ height: number;
32
+ text: string;
33
+ fontSize: number;
34
+ fontFamily: number;
35
+ color: string;
36
+ textAlign: "left" | "center" | "right";
37
+ opacity: number;
38
+ };
39
+ export type ParsedImage = {
40
+ kind: "image";
41
+ x: number;
42
+ y: number;
43
+ width: number;
44
+ height: number;
45
+ dataUrl: string;
46
+ };
47
+ export type ParsedElement = ParsedRectangle | ParsedEllipse | ParsedText | ParsedImage;
48
+ /**
49
+ * Render `html` in an off-screen iframe and walk the DOM to produce an
50
+ * array of ParsedElement objects, translated so the root .canvas div sits
51
+ * at (frameX, frameY) in Excalidraw canvas coordinates.
52
+ */
53
+ export declare function htmlToExcalidrawElements(html: string, frameX: number, frameY: number, frameWidth: number, frameHeight: number, customFontMap?: Record<string, number>): Promise<ParsedElement[]>;
@@ -0,0 +1,50 @@
1
+ import type { ToolCall } from "./agentLoop";
2
+ export type OpenRouterDelta = {
3
+ content: string | null;
4
+ toolCalls: Array<{
5
+ index: number;
6
+ id?: string;
7
+ type?: string;
8
+ function?: {
9
+ name?: string;
10
+ arguments?: string;
11
+ };
12
+ }> | null;
13
+ finishReason: string | null;
14
+ };
15
+ export type ToolCallAccumulator = {
16
+ id: string;
17
+ type: "function";
18
+ function: {
19
+ name: string;
20
+ arguments: string;
21
+ };
22
+ };
23
+ /**
24
+ * Parse a single OpenAI-compatible SSE chunk JSON string into a typed delta.
25
+ * Returns null if the JSON is invalid or missing expected structure.
26
+ */
27
+ export declare function parseOpenRouterChunk(jsonStr: string): OpenRouterDelta | null;
28
+ /**
29
+ * Async generator that yields parsed deltas from an OpenRouter streaming
30
+ * response. Reuses `parseSSEStream` for SSE line parsing.
31
+ */
32
+ export declare function streamOpenRouter(response: Response): AsyncGenerator<OpenRouterDelta>;
33
+ /**
34
+ * Accumulate streaming tool call deltas into complete ToolCall objects.
35
+ * OpenRouter sends tool calls in chunks:
36
+ * - First chunk for a tool: has `id`, `type`, `function.name`, empty `function.arguments`
37
+ * - Subsequent chunks: has `function.arguments` fragment to append
38
+ */
39
+ export declare function accumulateToolCalls(accumulated: ToolCallAccumulator[], delta: OpenRouterDelta): ToolCallAccumulator[];
40
+ /**
41
+ * Convert accumulators to the ToolCall type used by the agent loop.
42
+ */
43
+ export declare function finalizeToolCalls(accumulated: ToolCallAccumulator[]): ToolCall[];
44
+ /**
45
+ * Check if a response is a streaming SSE response.
46
+ * Returns true only when the response has a body AND the content-type
47
+ * indicates an SSE stream (`text/event-stream`). Any other content-type
48
+ * (including `application/json` or `text/plain`) falls back to non-streaming.
49
+ */
50
+ export declare function isStreamingResponse(response: Response): boolean;
@@ -0,0 +1,16 @@
1
+ import "./AutoResizePanel.scss";
2
+ import type { ExcalidrawFrameLikeElement, NonDeletedExcalidrawElement } from "@orangecatai/element/types";
3
+ import type { AppClassProperties } from "../../types";
4
+ export declare const AutoResizePanel: ({ element, app, onClose, onBeforeAutoResize, onAfterAutoResize, openRouterApiKey, chatModel, agentImageModel, }: {
5
+ element: NonDeletedExcalidrawElement & ExcalidrawFrameLikeElement;
6
+ app: AppClassProperties;
7
+ onClose: () => void;
8
+ onBeforeAutoResize?: () => Promise<{
9
+ allowed: boolean;
10
+ error?: string;
11
+ }>;
12
+ onAfterAutoResize?: () => void;
13
+ openRouterApiKey: string;
14
+ chatModel: string;
15
+ agentImageModel?: string;
16
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Renders shimmer overlays on top of in-progress auto-resize frames.
3
+ * Rendered unconditionally from App.tsx — same React tree as FrameToolbar
4
+ * and ElementCanvasButtons. Uses useExcalidrawAppState() for reactive
5
+ * viewport state (scroll, zoom, offset) so it repositions on every change.
6
+ */
7
+ export declare const AutoResizeShimmerLayer: () => import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,89 @@
1
+ import type { ExcalidrawElement, ExcalidrawFrameLikeElement } from "@orangecatai/element/types";
2
+ import type { AppClassProperties } from "../../types";
3
+ import type { BinaryFiles } from "../../types";
4
+ export type TargetDimension = {
5
+ width: number;
6
+ height: number;
7
+ label?: string;
8
+ };
9
+ export type DimensionResult = {
10
+ status: "ok";
11
+ frameId: string;
12
+ } | {
13
+ status: "error";
14
+ error: string;
15
+ };
16
+ export type ProgressCallback = (dimensionIndex: number, total: number, phase: "bg-regen" | "layout" | "inserting" | "done" | "error", label: string) => void;
17
+ type ForegroundEl = {
18
+ kind: "text";
19
+ relX: number;
20
+ relY: number;
21
+ width: number;
22
+ height: number;
23
+ text: string;
24
+ fontSize: number;
25
+ color: string;
26
+ textAlign: string;
27
+ fontWeight: string;
28
+ opacity: number;
29
+ } | {
30
+ kind: "image";
31
+ relX: number;
32
+ relY: number;
33
+ width: number;
34
+ height: number;
35
+ dataUrl: string;
36
+ opacity: number;
37
+ } | {
38
+ kind: "rect";
39
+ relX: number;
40
+ relY: number;
41
+ width: number;
42
+ height: number;
43
+ backgroundColor: string;
44
+ borderRadius: number;
45
+ opacity: number;
46
+ };
47
+ type SourceFrameInfo = {
48
+ frame: ExcalidrawFrameLikeElement;
49
+ background: {
50
+ type: "solid";
51
+ color: string;
52
+ } | {
53
+ type: "image";
54
+ dataUrl: string;
55
+ } | {
56
+ type: "none";
57
+ };
58
+ foreground: ForegroundEl[];
59
+ };
60
+ export declare function extractFrameInfo(elements: readonly ExcalidrawElement[], frame: ExcalidrawFrameLikeElement, files: BinaryFiles): SourceFrameInfo;
61
+ export declare function needsBackgroundRegeneration(srcW: number, srcH: number, tgtW: number, tgtH: number): boolean;
62
+ export type PreCreatedFrameInfo = {
63
+ frameId: string;
64
+ x: number;
65
+ y: number;
66
+ width: number;
67
+ height: number;
68
+ };
69
+ export declare function preCreateAllFrames(targetDimensions: TargetDimension[], sourceFrame: ExcalidrawFrameLikeElement, app: AppClassProperties): PreCreatedFrameInfo[];
70
+ export declare function runAutoResize(opts: {
71
+ sourceFrameId: string;
72
+ targetDimensions: TargetDimension[];
73
+ app: AppClassProperties;
74
+ geminiApiKey: string;
75
+ openRouterApiKey: string;
76
+ chatModel?: string;
77
+ agentImageModel?: string;
78
+ customFontMap?: Record<string, number>;
79
+ onBeforeAutoResize?: () => Promise<{
80
+ allowed: boolean;
81
+ error?: string;
82
+ }>;
83
+ onAfterAutoResize?: () => void;
84
+ onProgress?: ProgressCallback;
85
+ signal?: AbortSignal;
86
+ /** Pass the result of preCreateAllFrames() to skip redundant frame creation */
87
+ preCreatedFrameInfos?: PreCreatedFrameInfo[];
88
+ }): Promise<DimensionResult[]>;
89
+ export {};
@@ -0,0 +1,16 @@
1
+ export type LoadingFrameInfo = {
2
+ frameId: string;
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ };
8
+ type Listener = () => void;
9
+ export declare const autoResizeStore: {
10
+ setLoadingFrames(frames: LoadingFrameInfo[]): void;
11
+ markComplete(frameId: string): void;
12
+ clear(): void;
13
+ getLoadingFrames(): LoadingFrameInfo[];
14
+ subscribe(fn: Listener): () => void;
15
+ };
16
+ export {};
@@ -1,6 +1,6 @@
1
+ import "./Hyperlink.scss";
1
2
  import type { Scene } from "@orangecatai/element";
2
3
  import type { ElementsMap, ExcalidrawEmbeddableElement, NonDeletedExcalidrawElement } from "@orangecatai/element/types";
3
- import "./Hyperlink.scss";
4
4
  import type { AppState, ExcalidrawProps, UIAppState } from "../../types";
5
5
  export declare const Hyperlink: ({ element, scene, setAppState, onLinkOpen, setToast, updateEmbedValidationStatus, }: {
6
6
  element: NonDeletedExcalidrawElement;
@@ -1,5 +1,5 @@
1
- import type { Theme } from "@orangecatai/element/types";
2
1
  import "./DefaultItems.scss";
2
+ import type { Theme } from "@orangecatai/element/types";
3
3
  export declare const LoadScene: {
4
4
  (): import("react/jsx-runtime").JSX.Element | null;
5
5
  displayName: string;
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { type VariantProps } from "class-variance-authority";
3
3
  declare const buttonVariants: (props?: ({
4
- variant?: "link" | "default" | "outline" | "destructive" | "secondary" | "ghost" | null | undefined;
4
+ variant?: "link" | "default" | "outline" | "secondary" | "destructive" | "ghost" | null | undefined;
5
5
  size?: "icon" | "default" | "sm" | "lg" | null | undefined;
6
6
  } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
7
7
  export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
@@ -14,6 +14,17 @@ export declare class Fonts {
14
14
  metadata: FontMetadata;
15
15
  fontFaces: ExcalidrawFontFace[];
16
16
  }>;
17
+ /**
18
+ * Register a custom font from a URL into the canvas font system.
19
+ *
20
+ * Use family IDs >= 1000 to avoid collisions with built-in fonts.
21
+ *
22
+ * Note: custom fonts are registered without a weight/style descriptor
23
+ * because getFontString generates "${size}px ${familyName}" (no weight),
24
+ * so the browser always requests the normal-weight variant. Pass the font
25
+ * file that should render by default for this family ID.
26
+ */
27
+ static registerCustomFont(spec: import("../types").CustomFontSpec): void;
17
28
  private readonly scene;
18
29
  constructor(scene: Scene);
19
30
  /**
@@ -52,3 +52,4 @@ export type { ExcalidrawImperativeAPI } from "./types";
52
52
  export type { AppState, BinaryFiles, BinaryFileData, ExcalidrawProps, ExcalidrawInitialDataState, LibraryItem, LibraryItems, SceneData, UnsubscribeCallback, } from "./types";
53
53
  export type { ExcalidrawElement, NonDeletedExcalidrawElement, NonDeleted, OrderedExcalidrawElement, ExcalidrawElementType, } from "@orangecatai/element/types";
54
54
  export type { ImageEditToolbarCallbacks } from "./components/ImageEditToolbar";
55
+ export type { CustomFontSpec, BrandContext } from "./types";