@snowcone-app/canvas 0.28.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.
Files changed (84) hide show
  1. package/ERROR_CONTRACT.md +13 -0
  2. package/dist/{CanvasRenderer-B_3GISlW.js → CanvasRenderer-BEf0hXeF.js} +1083 -1071
  3. package/dist/CanvasRenderer-BEf0hXeF.js.map +1 -0
  4. package/dist/{CanvasStateV1-kL09wsAn.js → CanvasStateV1-BDSyYo4A.js} +872 -844
  5. package/dist/{CanvasStateV1-kL09wsAn.js.map → CanvasStateV1-BDSyYo4A.js.map} +1 -1
  6. package/dist/ContextualToolbars-C3D_6sep.js +5960 -0
  7. package/dist/ContextualToolbars-C3D_6sep.js.map +1 -0
  8. package/dist/{EditorCanvasImpl-CrI9C_xM.js → EditorCanvasImpl-DXeBz2CX.js} +8 -8
  9. package/dist/{EditorCanvasImpl-CrI9C_xM.js.map → EditorCanvasImpl-DXeBz2CX.js.map} +1 -1
  10. package/dist/{ExportManager-J2xK86uq.js → ExportManager-DUdis6se.js} +1307 -970
  11. package/dist/ExportManager-DUdis6se.js.map +1 -0
  12. package/dist/{FontAnalyzer-PE6nysqE.js → FontAnalyzer-DKG5JK0x.js} +1419 -1342
  13. package/dist/FontAnalyzer-DKG5JK0x.js.map +1 -0
  14. package/dist/{ImagePanel-CmQCxBGm.js → ImagePanel-CBgGqmVV.js} +53 -53
  15. package/dist/{ImagePanel-CmQCxBGm.js.map → ImagePanel-CBgGqmVV.js.map} +1 -1
  16. package/dist/SnowconeCanvas-BWPBngvI.js +1192 -0
  17. package/dist/SnowconeCanvas-BWPBngvI.js.map +1 -0
  18. package/dist/{UnifiedFontService-BJzoqfBF.js → UnifiedFontService-Co9tQ59z.js} +869 -826
  19. package/dist/UnifiedFontService-Co9tQ59z.js.map +1 -0
  20. package/dist/advanced.mjs +14 -14
  21. package/dist/api/embed.d.ts +2 -0
  22. package/dist/api/stable.d.ts +2 -0
  23. package/dist/components/CanvasContextMenu.d.ts +15 -0
  24. package/dist/components/CanvasEditor/hooks/useCanvasInteraction.d.ts +27 -0
  25. package/dist/components/CanvasEditor.d.ts +8 -0
  26. package/dist/components/embed/SnowconeCanvas.d.ts +13 -0
  27. package/dist/components/embed/kernel.d.ts +8 -0
  28. package/dist/components/toolbars/SecondaryPanels.d.ts +11 -0
  29. package/dist/components/ui/icons.d.ts +2 -0
  30. package/dist/contexts/CanvasServicesContext.d.ts +17 -0
  31. package/dist/contexts/EditorContext.d.ts +7 -0
  32. package/dist/core/TextElement.d.ts +13 -0
  33. package/dist/core/TextMetrics.d.ts +17 -3
  34. package/dist/core/rich-text-layout.d.ts +2 -0
  35. package/dist/core/text-spacing.d.ts +74 -0
  36. package/dist/{custom-icons-BWiUGqD6.js → custom-icons-BIaRovwG.js} +2 -2
  37. package/dist/{custom-icons-BWiUGqD6.js.map → custom-icons-BIaRovwG.js.map} +1 -1
  38. package/dist/{design-builder-bquxIHct.js → design-builder-JYLO_Hyi.js} +2 -2
  39. package/dist/{design-builder-bquxIHct.js.map → design-builder-JYLO_Hyi.js.map} +1 -1
  40. package/dist/{editorErrors-8uDRMhow.js → editorErrors-WzaNxU1Y.js} +181 -194
  41. package/dist/editorErrors-WzaNxU1Y.js.map +1 -0
  42. package/dist/{embed-L3oRIgsj.js → embed-Csez1hui.js} +113 -112
  43. package/dist/{embed-L3oRIgsj.js.map → embed-Csez1hui.js.map} +1 -1
  44. package/dist/embed.mjs +51 -45
  45. package/dist/embed.mjs.map +1 -1
  46. package/dist/errors/editorError.d.ts +8 -0
  47. package/dist/{guards-BlbhM5MX.js → guards-BSoX73yg.js} +2 -2
  48. package/dist/{guards-BlbhM5MX.js.map → guards-BSoX73yg.js.map} +1 -1
  49. package/dist/hooks/useKeyboardShortcuts.d.ts +15 -2
  50. package/dist/hooks/useLayers.d.ts +2 -0
  51. package/dist/hooks/useTextToolbar.d.ts +8 -0
  52. package/dist/index.mjs +42 -37
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/internals.mjs +47 -47
  55. package/dist/rendering/renderer-types.d.ts +4 -0
  56. package/dist/rendering/rich-text-renderer.d.ts +4 -0
  57. package/dist/rendering/text-renderer.d.ts +4 -1
  58. package/dist/state/CanvasStateV1.d.ts +34 -3
  59. package/dist/state/index.d.ts +2 -2
  60. package/dist/{template-fields-ai7vnW8g.js → template-fields-DYPW7bVU.js} +40 -40
  61. package/dist/{template-fields-ai7vnW8g.js.map → template-fields-DYPW7bVU.js.map} +1 -1
  62. package/dist/testing.mjs +13 -13
  63. package/dist/types/index.d.ts +26 -0
  64. package/dist/{usePieceGuideBundle-CMe5br2a.js → usePieceGuideBundle-CRLY2iQa.js} +2 -2
  65. package/dist/{usePieceGuideBundle-CMe5br2a.js.map → usePieceGuideBundle-CRLY2iQa.js.map} +1 -1
  66. package/dist/utils/custom-fonts.d.ts +99 -0
  67. package/dist/utils/featureApplied.d.ts +6 -0
  68. package/dist/validation-BGEl9rrE.js +8686 -0
  69. package/dist/validation-BGEl9rrE.js.map +1 -0
  70. package/dist/workers/export-protocol.d.ts +13 -0
  71. package/dist/workers/export-worker.bundle.string.d.ts +1 -1
  72. package/example/package.json +1 -1
  73. package/package.json +1 -1
  74. package/dist/CanvasRenderer-B_3GISlW.js.map +0 -1
  75. package/dist/ContextualToolbars-C69oYLdw.js +0 -5771
  76. package/dist/ContextualToolbars-C69oYLdw.js.map +0 -1
  77. package/dist/ExportManager-J2xK86uq.js.map +0 -1
  78. package/dist/FontAnalyzer-PE6nysqE.js.map +0 -1
  79. package/dist/SnowconeCanvas-CQiFVR0X.js +0 -1173
  80. package/dist/SnowconeCanvas-CQiFVR0X.js.map +0 -1
  81. package/dist/UnifiedFontService-BJzoqfBF.js.map +0 -1
  82. package/dist/editorErrors-8uDRMhow.js.map +0 -1
  83. package/dist/validation-B8kIYutI.js +0 -8397
  84. package/dist/validation-B8kIYutI.js.map +0 -1
package/dist/advanced.mjs CHANGED
@@ -1,21 +1,21 @@
1
- import { D as te, T as M, h as D, B as re, I as q, i as I, j as ne, e as se } from "./UnifiedFontService-BJzoqfBF.js";
2
- import { k as at, L as it, M as ct, l as lt, S as dt, m as ut, s as mt, n as ft } from "./UnifiedFontService-BJzoqfBF.js";
3
- import { r as oe, v as ae } from "./validation-B8kIYutI.js";
4
- import { a as pt, b as xt, c as gt, d as bt, D as yt, e as vt, f as wt, G as St, K as Ct, g as Tt, L as Et, S as $t, T as kt, Z as At, h as Ft, i as Pt, j as Nt, k as Rt, l as Bt, m as Mt, n as Dt, u as It, o as zt, p as Ot } from "./validation-B8kIYutI.js";
5
- import { ImagePanel as Wt } from "./ImagePanel-CmQCxBGm.js";
6
- import { P as ie, a as ce, b as le } from "./ContextualToolbars-C69oYLdw.js";
7
- import { A as Gt, B as _t, c as Ut, C as jt, d as Jt, e as qt, F as Zt, f as Vt, I as Xt, g as Yt, M as Ht, h as Qt, S as er, T as tr, i as rr, j as nr, k as sr, U as or, l as ar, u as ir, m as cr } from "./ContextualToolbars-C69oYLdw.js";
8
- import { u as Z } from "./editorErrors-8uDRMhow.js";
9
- import { E as dr, P as ur, p as mr, s as fr, b as hr, c as pr, d as xr, e as gr, f as br, a as yr } from "./editorErrors-8uDRMhow.js";
1
+ import { D as te, T as M, h as D, B as re, I as q, i as I, j as ne, e as se } from "./UnifiedFontService-Co9tQ59z.js";
2
+ import { k as at, L as it, M as ct, l as lt, S as dt, m as ut, s as mt, n as ft } from "./UnifiedFontService-Co9tQ59z.js";
3
+ import { r as oe, v as ae } from "./validation-BGEl9rrE.js";
4
+ import { a as pt, b as xt, c as gt, d as bt, D as yt, e as vt, f as wt, G as St, K as Ct, g as Tt, L as Et, S as $t, T as kt, Z as At, h as Ft, i as Pt, j as Nt, k as Rt, l as Bt, m as Mt, n as Dt, u as It, o as zt, p as Ot } from "./validation-BGEl9rrE.js";
5
+ import { ImagePanel as Wt } from "./ImagePanel-CBgGqmVV.js";
6
+ import { P as ie, a as ce, b as le } from "./ContextualToolbars-C3D_6sep.js";
7
+ import { A as Gt, B as _t, c as Ut, C as jt, d as Jt, e as qt, F as Zt, f as Vt, I as Xt, g as Yt, M as Ht, h as Qt, S as er, T as tr, i as rr, j as nr, k as sr, U as or, l as ar, u as ir, m as cr } from "./ContextualToolbars-C3D_6sep.js";
8
+ import { u as Z } from "./editorErrors-WzaNxU1Y.js";
9
+ import { E as dr, P as ur, p as mr, s as fr, b as hr, c as pr, d as xr, e as gr, f as br, a as yr } from "./editorErrors-WzaNxU1Y.js";
10
10
  import { T as wr, u as Sr } from "./ThemeContext-Rjz25x9X.js";
11
- import { c as de, G as ue, F as me, g as fe, r as he, u as pe } from "./FontAnalyzer-PE6nysqE.js";
12
- import { A as Tr, B as Er, I as $r, P as kr, R as Ar, S as Fr, T as Pr, h as Nr, a as Rr, b as Br, i as Mr, d as Dr, e as Ir, f as zr, j as Or, k as Lr, l as Wr, m as Kr, n as Gr, o as _r, p as Ur, q as jr, s as Jr, t as qr, v as Zr, w as Vr, x as Xr } from "./FontAnalyzer-PE6nysqE.js";
13
- import { i as Hr, a as Qr, b as en, c as tn, d as rn } from "./guards-BlbhM5MX.js";
11
+ import { c as de, G as ue, F as me, g as fe, r as he, u as pe } from "./FontAnalyzer-DKG5JK0x.js";
12
+ import { A as Tr, B as Er, I as $r, P as kr, R as Ar, S as Fr, T as Pr, h as Nr, a as Rr, b as Br, i as Mr, d as Dr, e as Ir, f as zr, j as Or, k as Lr, l as Wr, m as Kr, n as Gr, o as _r, p as Ur, q as jr, s as Jr, t as qr, v as Zr, w as Vr, x as Xr } from "./FontAnalyzer-DKG5JK0x.js";
13
+ import { i as Hr, a as Qr, b as en, c as tn, d as rn } from "./guards-BSoX73yg.js";
14
14
  import { useState as A, useCallback as y, useEffect as V, useMemo as X, useRef as B, memo as xe } from "react";
15
- import { I as ge } from "./ExportManager-J2xK86uq.js";
15
+ import { I as ge } from "./ExportManager-DUdis6se.js";
16
16
  import { e as be, c as ye } from "./compose-DtQL_oit.js";
17
17
  import { jsxs as b, jsx as a, Fragment as ve } from "react/jsx-runtime";
18
- import { P as sn, p as on, u as an } from "./usePieceGuideBundle-CMe5br2a.js";
18
+ import { P as sn, p as on, u as an } from "./usePieceGuideBundle-CRLY2iQa.js";
19
19
  const ze = ({
20
20
  title: e,
21
21
  icon: t,
@@ -70,6 +70,8 @@ export type { ExportProgress, ContinuousExportOptions, UseExportReturn } from '.
70
70
  export { useSelectedElement } from '../hooks/useSelectedElement.js';
71
71
  export { serializeState } from '../state/index.js';
72
72
  export type { CanvasStateV1, SerializedArtboard, SerializedElement, } from '../state/index.js';
73
+ export { loadCustomFont, registerCustomFonts, ensureCustomFontsLoaded, customFontRegistry, } from '../utils/custom-fonts.js';
74
+ export type { CustomFont, LoadCustomFontOptions } from '../utils/custom-fonts.js';
73
75
  export { useTextBinding } from '../hooks/useTextBinding.js';
74
76
  export { useImageBinding } from '../hooks/useImageBinding.js';
75
77
  export { useColorBinding } from '../hooks/useColorBinding.js';
@@ -48,6 +48,8 @@ export type { ArtboardConfig as ArtboardElementConfig, ArtboardRole, TransformTy
48
48
  export { ErrorBoundary } from '../components/embed/ErrorBoundary.js';
49
49
  export type { ErrorBoundaryProps } from '../components/embed/ErrorBoundary.js';
50
50
  export { serializeState, deserializeState, validateState, migrateState, } from '../state/index.js';
51
+ export { loadCustomFont, registerCustomFonts, ensureCustomFontsLoaded, customFontRegistry, } from '../utils/custom-fonts.js';
52
+ export type { CustomFont, LoadCustomFontOptions } from '../utils/custom-fonts.js';
51
53
  export { serializeStateForServer, CANVAS_STATE_SCHEMA_VERSION, } from '../rendering/serialize-for-server.js';
52
54
  export type { ServerRenderRequest } from '../rendering/serialize-for-server.js';
53
55
  export { design, DesignBuilder } from '../design/design-builder.js';
@@ -0,0 +1,15 @@
1
+ import { default as React } from 'react';
2
+ /** Where (viewport px) and on what the menu was requested. */
3
+ export interface CanvasContextMenuState {
4
+ /** Viewport coords of the right-click — the menu's top-left corner. */
5
+ x: number;
6
+ y: number;
7
+ /** Topmost hit element id, or null for the empty-canvas menu. */
8
+ targetId: string | null;
9
+ }
10
+ export interface CanvasContextMenuProps {
11
+ menu: CanvasContextMenuState;
12
+ onClose: () => void;
13
+ }
14
+ export declare const CanvasContextMenu: React.FC<CanvasContextMenuProps>;
15
+ export default CanvasContextMenu;
@@ -256,6 +256,14 @@ export interface UseCanvasInteractionParams {
256
256
  onMultiSelectionChange: (ids: string[]) => void;
257
257
  onRotationStateChange?: (isRotating: boolean) => void;
258
258
  onCropModeEnter?: () => void;
259
+ /**
260
+ * Fired by {@link CanvasInteractionResult.handleContextMenu} after the
261
+ * right-click target has been hit-tested and selected. The host renders
262
+ * the actual menu UI (see `CanvasContextMenu`). When omitted, right-click
263
+ * still never enters the select/drag pipeline (the button-2 interception
264
+ * below), and the browser's native menu is left alone.
265
+ */
266
+ onContextMenuRequest?: (request: CanvasContextMenuRequest) => void;
259
267
  updateActiveChild: (child: ChildElement | null) => void;
260
268
  getActiveArtboardElements: () => CanvasElement[];
261
269
  startMarqueeSelection: (x: number, y: number) => void;
@@ -274,11 +282,30 @@ export interface UseCanvasInteractionParams {
274
282
  setCurrentFormattingStyle: React.Dispatch<React.SetStateAction<CharacterStyle | null>>;
275
283
  getWrappedTextForEditing: (element: TextElement) => string;
276
284
  }
285
+ /**
286
+ * Payload handed to {@link UseCanvasInteractionParams.onContextMenuRequest}
287
+ * when the user right-clicks (or long-presses, where the platform
288
+ * synthesizes a `contextmenu` event) on the canvas. By the time this fires,
289
+ * selection has already been updated Figma-style: the element under the
290
+ * cursor is selected (an existing multi-selection is preserved when the
291
+ * target is part of it), or the selection is left untouched on empty canvas.
292
+ */
293
+ export interface CanvasContextMenuRequest {
294
+ /** Viewport coords of the gesture — position the menu here. */
295
+ clientX: number;
296
+ clientY: number;
297
+ /** World/artboard coords of the gesture. */
298
+ worldX: number;
299
+ worldY: number;
300
+ /** Topmost hit element id, or null when the gesture landed on empty canvas. */
301
+ elementId: string | null;
302
+ }
277
303
  export interface CanvasInteractionResult {
278
304
  handlePointerDown: (e: React.PointerEvent<HTMLCanvasElement>) => void;
279
305
  handlePointerMove: (e: React.PointerEvent<HTMLCanvasElement>) => void;
280
306
  handlePointerUp: (e: React.PointerEvent<HTMLCanvasElement>) => void;
281
307
  handleDoubleClick: (e: React.MouseEvent<HTMLCanvasElement>) => void;
308
+ handleContextMenu: (e: React.MouseEvent<HTMLCanvasElement>) => void;
282
309
  }
283
310
  export declare function useCanvasInteraction(params: UseCanvasInteractionParams): CanvasInteractionResult;
284
311
  export {};
@@ -25,6 +25,14 @@ interface CanvasEditorProps {
25
25
  onHoverChange?: (elementId: string | null) => void;
26
26
  onRotationStateChange?: (isRotating: boolean) => void;
27
27
  onCropModeEnter?: () => void;
28
+ /**
29
+ * Right-click (contextmenu) on the canvas: fired AFTER the target under
30
+ * the cursor has been hit-tested and selected (existing multi-selection
31
+ * preserved when the target is part of it). The host renders the menu —
32
+ * see `CanvasContextMenu`. When omitted, the browser's native menu is
33
+ * left alone; either way right-click never starts a drag/marquee.
34
+ */
35
+ onContextMenuRequest?: (request: import('./CanvasEditor/hooks/useCanvasInteraction.js').CanvasContextMenuRequest) => void;
28
36
  hideHandles?: boolean;
29
37
  canvasRef?: React.RefObject<HTMLCanvasElement | null>;
30
38
  width?: number;
@@ -2,6 +2,7 @@ import { default as React } from 'react';
2
2
  import { CanvasServices } from '../../contexts/CanvasServicesContext.js';
3
3
  import { CanvasError, ArtboardRole, ClipShape, AnyElementConfig } from '../../types/index.js';
4
4
  import { KitPresetId, KitDefinition } from '../../kits/types.js';
5
+ import { CustomFont } from '../../utils/custom-fonts.js';
5
6
  import { PieceGuide, PieceGuideRendererPiece, PieceGuideRendererStyle, PieceGuideVisibility } from '../../rendering/PieceGuideRenderer.js';
6
7
  export type { ClipShape, ArtboardRole } from '../../types/index.js';
7
8
  /** 9-point alignment grid values */
@@ -501,6 +502,18 @@ export interface SnowconeCanvasProps {
501
502
  * the first artboard, so pre-existing saved states keep working.
502
503
  */
503
504
  initialElements?: AnyElementConfig[];
505
+ /**
506
+ * Custom (brand) fonts the restored design depends on — pass the saved
507
+ * state's `customFonts` (`CanvasStateV1.customFonts`) alongside
508
+ * `initialElements`. Each `{ family, url }` is registered before the
509
+ * design-open font preload runs and its binary is loaded bytes-first from
510
+ * `url`; a custom family deterministically shadows any same-named Google
511
+ * family (see `utils/custom-fonts.ts`). A font that fails to load surfaces
512
+ * the typed `E_FONT_LOAD_FAILED` through `onError` — never a silent serif
513
+ * fallback. (Designs loaded via `deserializeState` register their custom
514
+ * fonts automatically; this prop covers hosts that thread raw elements.)
515
+ */
516
+ customFonts?: CustomFont[];
504
517
  /**
505
518
  * Called when canvas content changes (elements added, modified, or removed).
506
519
  * Use this to persist the design state.
@@ -1,4 +1,5 @@
1
1
  import { default as React } from 'react';
2
+ import { CustomFont } from '../../utils/custom-fonts.js';
2
3
  import { CanvasError, AnyElementConfig } from '../../types/index.js';
3
4
  import { AlignmentPoint, ArtboardConfig, CanvasState, ExportStatusEvent, PieceGuidesConfig, SnowconeCanvasHandle } from './SnowconeCanvas.js';
4
5
  export type ImageLoadingState = 'idle' | 'loading' | 'success' | 'error';
@@ -45,6 +46,13 @@ export declare function useArtboardKernel(opts: ArtboardKernelOptions): void;
45
46
  export interface InitialElementsKernelOptions {
46
47
  initialElements: AnyElementConfig[] | undefined;
47
48
  emitError: (error: CanvasError) => void;
49
+ /**
50
+ * Custom (brand) fonts the design depends on (`CanvasStateV1.customFonts`).
51
+ * Registered with `customFontRegistry` BEFORE the font preload below runs,
52
+ * so a custom family never gets a Google `<link>` injected for it — the
53
+ * deterministic-shadowing contract (see `utils/custom-fonts.ts`).
54
+ */
55
+ customFonts?: CustomFont[];
48
56
  }
49
57
  /**
50
58
  * Restore saved state (`initialElements`) onto the named artboards, then
@@ -20,6 +20,17 @@ export interface FontSizePanelProps {
20
20
  widthValue?: number | null;
21
21
  /** Called when the width slider moves. */
22
22
  onWidthChange?: (value: number) => void;
23
+ /** Letter-spacing in px (extra advance per character). When
24
+ * null/undefined the slider is hidden (curved transforms — they lay
25
+ * glyphs along a path and intentionally ignore letter-spacing). */
26
+ letterSpacingValue?: number | null;
27
+ /** Called when the letter-spacing slider moves. */
28
+ onLetterSpacingChange?: (value: number) => void;
29
+ /** Line-height multiplier (lineSpacing = fontSize × value). When
30
+ * null/undefined the slider is hidden (curved transforms). */
31
+ lineHeightValue?: number | null;
32
+ /** Called when the line-height slider moves. */
33
+ onLineHeightChange?: (value: number) => void;
23
34
  }
24
35
  export declare const FontSizePanel: React.FC<FontSizePanelProps>;
25
36
  export interface OpacityPanelProps {
@@ -22,6 +22,8 @@ export declare const icons: {
22
22
  readonly shapes: "lucide:shapes";
23
23
  readonly trash: "lucide:trash-2";
24
24
  readonly copy: "lucide:copy";
25
+ readonly paste: "lucide:clipboard-paste";
26
+ readonly selectAll: "lucide:box-select";
25
27
  readonly pencil: "lucide:pencil";
26
28
  readonly scissors: "lucide:scissors";
27
29
  readonly save: "lucide:save";
@@ -69,6 +69,22 @@ export interface CanvasServices {
69
69
  * `bgRemoveUrl`.
70
70
  */
71
71
  removeBackground?: (imageUrl: string) => Promise<string>;
72
+ /**
73
+ * Host-owned brand-font upload. The canvas never owns storage: the host
74
+ * receives the font `File` (woff2/woff/ttf/otf), stores it in its own
75
+ * (shop-scoped) asset storage, and resolves with the hosted font's
76
+ * `{ family, url }` — `url` must serve the binary over a plain
77
+ * cross-origin GET (the export worker fetches it too). On resolve the
78
+ * canvas loads + registers the font, selects it, and persists it in the
79
+ * design's `customFonts`. When absent, the font picker renders NO upload
80
+ * affordance at all (capability opt-in — no broken button to click).
81
+ */
82
+ onFontUpload?: (file: File) => Promise<{
83
+ family: string;
84
+ url: string;
85
+ weight?: number;
86
+ style?: 'normal' | 'italic';
87
+ }>;
72
88
  }
73
89
  /** The resolved providers consumers actually use. */
74
90
  export interface ResolvedCanvasServices {
@@ -76,6 +92,7 @@ export interface ResolvedCanvasServices {
76
92
  generate?: GenerateProvider;
77
93
  vectors?: VectorSearchProvider;
78
94
  removeBackground?: (imageUrl: string) => Promise<string>;
95
+ onFontUpload?: CanvasServices['onFontUpload'];
79
96
  }
80
97
  export interface CanvasServicesProviderProps {
81
98
  services?: CanvasServices;
@@ -110,6 +110,13 @@ export interface EditorContextValue {
110
110
  handleLoadWorkspace: (loadedArtboards: ArtboardElement[], loadedElements: EditorElement[], activeArtboardId: string | null) => void;
111
111
  handleCopyElements: () => void;
112
112
  handlePasteElements: () => void;
113
+ /**
114
+ * Whether the editor's internal copy/paste clipboard holds anything.
115
+ * `handlePasteElements` is a silent no-op when this is false — surfaces
116
+ * offering a Paste affordance (canvas context menu) use this to disable
117
+ * the entry instead of presenting an action that does nothing.
118
+ */
119
+ hasClipboardContent: boolean;
113
120
  historyManager: ReturnType<typeof useCommandHistory>['historyManager'];
114
121
  executeElementUpdate: ReturnType<typeof useCommandHistory>['executeElementUpdate'];
115
122
  executeAddElement: ReturnType<typeof useCommandHistory>['executeAddElement'];
@@ -11,6 +11,19 @@ export declare class TextElement extends BaseElement {
11
11
  italic: boolean;
12
12
  underline: boolean;
13
13
  strikethrough: boolean;
14
+ /**
15
+ * Element-level letter-spacing in world-space px (extra advance after each
16
+ * character, CSS model). Per-character override via
17
+ * `CharacterStyle.letterSpacing`. undefined = 0. Custom transform only —
18
+ * curved transforms intentionally ignore it.
19
+ */
20
+ letterSpacing?: number;
21
+ /**
22
+ * Line-height multiplier (lineSpacing = fontSize × lineHeight).
23
+ * undefined = LINE_HEIGHT_MULTIPLIER (1.2), the historical layout.
24
+ * Custom transform only.
25
+ */
26
+ lineHeight?: number;
14
27
  glyphOverrides?: GlyphOverride[];
15
28
  openTypeFeatures?: OpenTypeFeatures;
16
29
  constructor(config?: Partial<BaseTextElementConfig>);
@@ -2,6 +2,17 @@
2
2
  * TextMetrics - Shared utilities for text measurement and layout
3
3
  * Reduces duplication across transform types
4
4
  */
5
+ /**
6
+ * Optional typography knobs threaded through layout/measurement.
7
+ * Omitting them (or passing {}) reproduces the historical layout EXACTLY:
8
+ * letterSpacing 0, lineHeight LINE_HEIGHT_MULTIPLIER (1.2).
9
+ */
10
+ export interface TextLayoutOptions {
11
+ /** Extra advance per character in px (CSS letter-spacing model). */
12
+ letterSpacing?: number;
13
+ /** Line-height multiplier (lineSpacing = fontSize × lineHeight). */
14
+ lineHeight?: number;
15
+ }
5
16
  /**
6
17
  * Build font string with optional bold and italic
7
18
  * @param {number} fontSize - Font size
@@ -21,9 +32,10 @@ export declare function buildFontString(fontSize: number, fontFamily: string, bo
21
32
  * @param {boolean} italic - Whether text is italic
22
33
  * @param {number} lockedLineCount - Optional locked line count (forces exact number of lines during corner resize)
23
34
  * @param {boolean} strict - If true, disable tolerance (wrap exactly at maxWidth, matching richText behavior)
35
+ * @param {TextLayoutOptions} opts - Optional letterSpacing (affects wrap points); omitting = legacy layout
24
36
  * @returns {string[]} Array of lines
25
37
  */
26
- export declare function wrapText(text: string, maxWidth: number, fontSize: number, fontFamily: string, bold?: boolean, italic?: boolean, lockedLineCount?: number, strict?: boolean): string[];
38
+ export declare function wrapText(text: string, maxWidth: number, fontSize: number, fontFamily: string, bold?: boolean, italic?: boolean, lockedLineCount?: number, strict?: boolean, opts?: TextLayoutOptions): string[];
27
39
  /**
28
40
  * Measure width of text
29
41
  * @param {string} text - Text to measure
@@ -31,9 +43,10 @@ export declare function wrapText(text: string, maxWidth: number, fontSize: numbe
31
43
  * @param {string} fontFamily - Font family name
32
44
  * @param {boolean} bold - Whether text is bold
33
45
  * @param {boolean} italic - Whether text is italic
46
+ * @param {number} letterSpacing - Extra advance per character in px (default 0 — legacy width)
34
47
  * @returns {number} Width in pixels
35
48
  */
36
- export declare function measureTextWidth(text: string, fontSize: number, fontFamily: string, bold?: boolean, italic?: boolean): number;
49
+ export declare function measureTextWidth(text: string, fontSize: number, fontFamily: string, bold?: boolean, italic?: boolean, letterSpacing?: number): number;
37
50
  /**
38
51
  * Get font metrics for accurate text positioning
39
52
  * @param {number} fontSize - Font size
@@ -98,9 +111,10 @@ export declare function calculateContainerHeight(lineCount: number, fontSize: nu
98
111
  * @param {boolean} italic - Whether text is italic
99
112
  * @param {number} lockedLineCount - Optional locked line count (forces exact number of lines during corner resize)
100
113
  * @param {boolean} strict - If true, disable tolerance (wrap exactly at maxWidth)
114
+ * @param {TextLayoutOptions} opts - Optional letterSpacing/lineHeight; omitting = legacy layout
101
115
  * @returns {Object} {width, height, lines} - Adjusted dimensions and line array
102
116
  */
103
- export declare function calculateVisualBoundsWithSpaceCollapsing(text: string, maxWidth: number, fontSize: number, fontFamily: string, bold?: boolean, italic?: boolean, lockedLineCount?: number, strict?: boolean): {
117
+ export declare function calculateVisualBoundsWithSpaceCollapsing(text: string, maxWidth: number, fontSize: number, fontFamily: string, bold?: boolean, italic?: boolean, lockedLineCount?: number, strict?: boolean, opts?: TextLayoutOptions): {
104
118
  width: number;
105
119
  height: number;
106
120
  lines: string[];
@@ -15,6 +15,8 @@ export declare function wrapRichTextSpans(spans: Array<{
15
15
  fontFamily: string;
16
16
  bold?: boolean;
17
17
  italic?: boolean;
18
+ /** Element-level letter-spacing default (px per character). */
19
+ letterSpacing?: number;
18
20
  }): Array<{
19
21
  text: string;
20
22
  style: CharacterStyle;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * text-spacing — the ONE advance computation for letter-spaced text.
3
+ *
4
+ * Letter-spacing model (CSS `letter-spacing` / canvas `ctx.letterSpacing`
5
+ * semantics): every character's advance grows by `letterSpacing` world-space
6
+ * pixels, INCLUDING the last character of a run. So:
7
+ *
8
+ * spacedWidth(text) = ctx.measureText(text).width + spacing × charCount
9
+ * advance(char at index i) = ctx.measureText(prefix(i+1)).width − measureText(prefix(i)).width + spacing
10
+ * cursor x after N chars = ctx.measureText(prefix(N)).width + spacing × N
11
+ *
12
+ * The uniform per-character `+spacing` is what keeps cursor math, selection
13
+ * rects, hover chrome, stroke outlines, and painted glyphs in lockstep — every
14
+ * site sums the SAME advances. Do not invent a second model (e.g. "between
15
+ * characters only", spacing × (n−1)); a mixed model drifts the caret.
16
+ *
17
+ * Painting is done per-character at kerning-preserving offsets (each glyph is
18
+ * positioned by the measured width of its prefix, so kerning pairs inside the
19
+ * run stay intact) rather than via the native `ctx.letterSpacing` property,
20
+ * which is not implemented across all engines we ship to. When spacing is 0
21
+ * the fast path is a single fillText/strokeText — byte-identical to the
22
+ * pre-letter-spacing renderer, which is what the "default unchanged" tests pin.
23
+ *
24
+ * Worker-compatible: no DOM access; operates on whatever 2D context (canvas or
25
+ * OffscreenCanvas) the caller already configured (`ctx.font` must be set).
26
+ *
27
+ * SCOPE: straight ('custom') text transform only. Curved transforms (circle,
28
+ * arch, wave, lean, ascend, flag) place glyphs along their own path math and
29
+ * intentionally ignore letter-spacing (pinned in transform-renderer.test.ts).
30
+ */
31
+ type AnyRenderContext = CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;
32
+ /** Minimal context shape needed for measurement-only callers (tests, layout). */
33
+ export interface MeasureOnlyContext {
34
+ measureText(text: string): {
35
+ width: number;
36
+ };
37
+ }
38
+ /**
39
+ * Count user-perceived characters (code points, not UTF-16 units) so
40
+ * surrogate pairs (emoji, PUA glyphs) get ONE spacing slot, matching the
41
+ * per-character paint loop which iterates with Array.from.
42
+ */
43
+ export declare function countSpacedChars(text: string): number;
44
+ /**
45
+ * Add letter-spacing to a raw measured width.
46
+ * `spacedTextWidth(ctx.measureText(t).width, t, s)` — every char gets +s.
47
+ */
48
+ export declare function spacedTextWidth(rawWidth: number, text: string, letterSpacing: number | undefined): number;
49
+ /**
50
+ * Measure text with letter-spacing using an already-configured context
51
+ * (ctx.font must be set by the caller).
52
+ */
53
+ export declare function measureTextWithSpacing(ctx: MeasureOnlyContext, text: string, letterSpacing: number | undefined): number;
54
+ /**
55
+ * Per-character x offsets (relative to the run's left edge) for a
56
+ * letter-spaced run. offsets[i] is where character i is painted; a trailing
57
+ * entry offsets[n] is the total advance (== spacedTextWidth). Kerning inside
58
+ * the run is preserved because each offset is the measured width of the full
59
+ * prefix, not a sum of isolated char widths.
60
+ */
61
+ export declare function getSpacedCharOffsets(ctx: MeasureOnlyContext, text: string, letterSpacing: number): number[];
62
+ /**
63
+ * Drop-in replacement for `ctx.fillText(text, x, y)` that honors
64
+ * letter-spacing. Respects the ctx's current `textAlign` (the spaced total
65
+ * width — trailing spacing included — is what gets centered/right-aligned,
66
+ * matching CSS). Zero/undefined spacing calls fillText once, unchanged.
67
+ */
68
+ export declare function fillTextWithSpacing(ctx: AnyRenderContext, text: string, x: number, y: number, letterSpacing: number | undefined): void;
69
+ /**
70
+ * Drop-in replacement for `ctx.strokeText(text, x, y)` that honors
71
+ * letter-spacing. Same alignment semantics as fillTextWithSpacing.
72
+ */
73
+ export declare function strokeTextWithSpacing(ctx: AnyRenderContext, text: string, x: number, y: number, letterSpacing: number | undefined): void;
74
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { jsx as i, jsxs as h } from "react/jsx-runtime";
2
2
  import * as c from "react";
3
- import { n as T, z as y, O as w } from "./UnifiedFontService-BJzoqfBF.js";
3
+ import { n as T, z as y, O as w } from "./UnifiedFontService-Co9tQ59z.js";
4
4
  import * as R from "@radix-ui/react-label";
5
5
  import { cva as S } from "class-variance-authority";
6
6
  import * as g from "@radix-ui/react-tabs";
@@ -233,4 +233,4 @@ export {
233
233
  z as T,
234
234
  A as a
235
235
  };
236
- //# sourceMappingURL=custom-icons-BWiUGqD6.js.map
236
+ //# sourceMappingURL=custom-icons-BIaRovwG.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"custom-icons-BWiUGqD6.js","sources":["../src/vendor/ui/primitives/input.tsx","../src/vendor/ui/primitives/label.tsx","../src/vendor/ui/primitives/tabs.tsx","../src/vendor/ui/primitives/text-field.tsx","../src/components/ui/custom-icons.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { cn } from '../lib/utils';\nimport { useSurface } from './surface';\n\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n /** Whether the input is in an invalid state */\n isInvalid?: boolean;\n /** Content to display at the start of the input */\n startContent?: React.ReactNode;\n /** Content to display at the end of the input */\n endContent?: React.ReactNode;\n /**\n * Visual variant - auto-detected from Surface context, or can be set explicitly\n * - `default`: Standard field styling for forms (bg-field)\n * - `filled`: Field on elevated surface (bg-field-on-surface)\n * - `subtle`: Blends with buttons/tabs in toolbars (bg-default)\n */\n variant?: 'default' | 'filled' | 'subtle';\n}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n (\n {\n className,\n type,\n isInvalid,\n startContent,\n endContent,\n disabled,\n readOnly,\n required,\n variant,\n ...props\n },\n ref\n ) => {\n // Auto-detect variant from Surface context\n const surface = useSurface();\n const isOnSurface = surface.variant === 'default' || surface.variant === 'secondary';\n const effectiveVariant = variant ?? (isOnSurface ? 'filled' : 'default');\n\n const inputElement = (\n <input\n type={type}\n className={cn(\n 'sc:flex sc:h-10 sc:w-full sc:rounded-input sc:px-2.5 sc:py-1.5 sc:text-sm sc:appearance-none',\n 'sc:text-foreground sc:border-none',\n 'sc:file:border-0 sc:file:bg-transparent sc:file:text-sm sc:file:font-medium sc:file:text-foreground',\n 'sc:placeholder:text-foreground/50',\n 'sc:transition-shadow sc:duration-200 sc:ease-out sc:focus-visible:outline-none sc:focus:ring-2 sc:focus:ring-focus sc:focus:ring-offset-1 sc:focus:ring-offset-background',\n 'sc:disabled:cursor-not-allowed sc:disabled:opacity-50',\n // Variant styles - semantic: field on page vs field on surface vs toolbar\n effectiveVariant === 'default' && 'sc:bg-field sc:shadow-soft sc:dark:shadow-none',\n effectiveVariant === 'filled' && 'sc:bg-[var(--color-field-on-surface)]',\n effectiveVariant === 'subtle' && 'sc:bg-default sc:dark:bg-[var(--color-default-on-surface)]',\n isInvalid && 'sc:ring-2 sc:ring-danger sc:focus-visible:ring-danger',\n startContent && 'sc:pl-10',\n endContent && 'sc:pr-10',\n className\n )}\n ref={ref}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n aria-invalid={isInvalid}\n {...props}\n />\n );\n\n if (startContent || endContent) {\n return (\n <div className=\"sc:relative\">\n {startContent && (\n <div className=\"sc:absolute sc:left-3 sc:top-1/2 sc:-translate-y-1/2 sc:text-foreground sc:opacity-40\">{startContent}</div>\n )}\n {inputElement}\n {endContent && (\n <div className=\"sc:absolute sc:right-3 sc:top-1/2 sc:-translate-y-1/2 sc:text-foreground sc:opacity-40\">{endContent}</div>\n )}\n </div>\n );\n }\n\n return inputElement;\n }\n);\nInput.displayName = 'Input';\n\nexport { Input };\n","'use client';\n\nimport * as React from 'react';\nimport * as LabelPrimitive from '@radix-ui/react-label';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/utils';\n\nconst labelVariants = cva(\n 'sc:block sc:text-sm sc:leading-none sc:text-foreground sc:peer-disabled:cursor-not-allowed sc:peer-disabled:opacity-70 sc:font-label'\n);\n\nconst Label = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>\n>(({ className, ...props }, ref) => (\n <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />\n));\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n","\"use client\";\n\n'use client';\n\nimport * as React from 'react';\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport { cn } from '../lib/utils';\nimport { useSurface } from './surface';\n\ninterface TabsProps\n extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>, 'value' | 'onValueChange'> {\n value?: string;\n onValueChange?: (value: string) => void;\n}\n\nconst TabsRoot = React.forwardRef<React.ElementRef<typeof TabsPrimitive.Root>, TabsProps>(\n ({ value, onValueChange, ...props }, ref) => (\n <TabsPrimitive.Root ref={ref} value={value} onValueChange={onValueChange} {...props} />\n )\n);\nTabsRoot.displayName = 'Tabs';\n\nconst TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, children, ...props }, ref) => {\n const listRef = React.useRef<HTMLDivElement>(null);\n const [indicatorStyle, setIndicatorStyle] = React.useState<React.CSSProperties>({\n opacity: 0,\n });\n\n // Update indicator position when active tab changes\n React.useEffect(() => {\n const listElement = listRef.current;\n if (!listElement) return;\n\n const updateIndicator = () => {\n const activeTab = listElement.querySelector('[data-state=\"active\"]') as HTMLElement;\n if (activeTab) {\n const listRect = listElement.getBoundingClientRect();\n const tabRect = activeTab.getBoundingClientRect();\n\n setIndicatorStyle({\n width: tabRect.width,\n height: tabRect.height,\n left: tabRect.left - listRect.left,\n opacity: 1,\n });\n }\n };\n\n // Initial position\n updateIndicator();\n\n // Use MutationObserver to detect when active tab changes\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'attributes' && mutation.attributeName === 'data-state') {\n updateIndicator();\n break;\n }\n }\n });\n\n // Observe all trigger elements for data-state changes\n const triggers = listElement.querySelectorAll('[role=\"tab\"]');\n triggers.forEach((trigger) => {\n observer.observe(trigger, { attributes: true, attributeFilter: ['data-state'] });\n });\n\n // Also update on resize\n const resizeObserver = new ResizeObserver(updateIndicator);\n resizeObserver.observe(listElement);\n\n return () => {\n observer.disconnect();\n resizeObserver.disconnect();\n };\n }, [children]);\n\n return (\n <TabsPrimitive.List\n ref={(node) => {\n // Handle both refs\n (listRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n }}\n className={cn(\n 'sc:relative sc:inline-flex sc:h-10 sc:items-center sc:justify-center sc:rounded-full sc:px-1 sc:text-muted-foreground',\n // Consistent bg-default matches Button secondary variant for toolbar harmony\n 'sc:bg-default sc:dark:bg-[var(--color-default-on-surface)]',\n className\n )}\n {...props}\n >\n {/* Animated sliding indicator. In dark mode the previous `bg-muted`\n value resolved to the same color as `bg-default` on the container,\n so the active tab was invisible without relying purely on\n shadow-md. `bg-popover` lands ~0.08 lightness above `bg-default`\n in dark mode for a clearly visible elevation. */}\n <span\n className=\"sc:absolute sc:top-1/2 sc:-translate-y-1/2 sc:rounded-full sc:bg-surface sc:dark:bg-popover sc:shadow-md sc:transition-[left,width,opacity]\"\n style={{\n ...indicatorStyle,\n transitionDuration: '350ms',\n transitionTimingFunction: 'cubic-bezier(0.22, 1, 0.36, 1)',\n }}\n aria-hidden=\"true\"\n />\n {children}\n </TabsPrimitive.List>\n );\n});\nTabsList.displayName = TabsPrimitive.List.displayName;\n\ninterface TabsTriggerProps extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>, 'value'> {\n // HeroUI uses 'id' for tab identification, Radix uses 'value'\n // At least one must be provided\n id?: string;\n value?: string;\n}\n\nconst TabsTrigger = React.forwardRef<React.ElementRef<typeof TabsPrimitive.Trigger>, TabsTriggerProps>(\n ({ className, id, value, ...props }, ref) => {\n const { variant: surfaceVariant } = useSurface();\n const isOnSurface = surfaceVariant === 'default' || surfaceVariant === 'secondary';\n\n return (\n <TabsPrimitive.Trigger\n ref={ref}\n value={id ?? value ?? ''}\n className={cn(\n 'sc:relative sc:z-10 sc:inline-flex sc:h-8 sc:items-center sc:justify-center sc:gap-2 sc:whitespace-nowrap sc:rounded-full sc:px-4 sc:text-sm sc:font-label',\n 'sc:transition-[color,opacity]',\n 'sc:focus-visible:outline-none sc:focus-visible:ring-2 sc:focus-visible:ring-focus sc:focus-visible:ring-offset-2',\n 'sc:disabled:pointer-events-none sc:disabled:opacity-50',\n 'sc:data-[state=active]:text-foreground sc:data-[state=active]:opacity-100',\n // Inactive tabs use element opacity (not color opacity) to avoid SVG path overlap issues\n isOnSurface\n ? 'sc:data-[state=inactive]:text-foreground sc:data-[state=inactive]:opacity-30 sc:data-[state=inactive]:hover:opacity-50'\n : 'sc:data-[state=inactive]:text-foreground sc:data-[state=inactive]:opacity-50 sc:data-[state=inactive]:hover:opacity-70',\n className\n )}\n {...props}\n />\n );\n }\n);\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName;\n\ninterface TabsContentProps extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>, 'value'> {\n // HeroUI uses 'id' for panel identification, Radix uses 'value'\n // At least one must be provided\n id?: string;\n value?: string;\n}\n\nconst TabsContent = React.forwardRef<React.ElementRef<typeof TabsPrimitive.Content>, TabsContentProps>(\n ({ className, id, value, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n value={id ?? value ?? ''}\n className={cn(\n 'sc:mt-2 sc:ring-offset-background sc:focus-visible:outline-none sc:focus-visible:ring-2 sc:focus-visible:ring-focus sc:focus-visible:ring-offset-2',\n className\n )}\n {...props}\n />\n )\n);\nTabsContent.displayName = TabsPrimitive.Content.displayName;\n\n// HeroUI ListContainer - wrapper for the tabs list (passthrough div)\nconst TabsListContainer = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => <div ref={ref} className={className} {...props} />\n);\nTabsListContainer.displayName = 'TabsListContainer';\n\n// HeroUI Tab - alias for TabsTrigger\nconst TabsTab = TabsTrigger;\n\n// HeroUI Panel - alias for TabsContent\nconst TabsPanel = TabsContent;\n\n// HeroUI Indicator - now rendered automatically by TabsList, this is a no-op\nconst TabsIndicator = () => null;\n\n// Create compound component with all aliases\nconst TabsBase = TabsRoot;\n\n// HeroUI-compatible compound component\nconst Tabs = Object.assign(TabsBase, {\n List: TabsList,\n ListContainer: TabsListContainer,\n Tab: TabsTab,\n Trigger: TabsTrigger,\n Panel: TabsPanel,\n Content: TabsContent,\n Indicator: TabsIndicator,\n});\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent, TabsRoot };\n","'use client';\n\nimport * as React from 'react';\nimport { cn } from '../lib/utils';\n\nexport interface TextFieldProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Accessible label for the input.\n * If not provided via children, use aria-label on the div.\n */\n 'aria-label'?: string;\n /**\n * Error state - applies error styling to children inputs\n */\n isInvalid?: boolean;\n /**\n * Disabled state - disables all children inputs\n */\n disabled?: boolean;\n /**\n * Required state - marks all children inputs as required\n */\n required?: boolean;\n}\n\n/**\n * TextField - A wrapper component that groups Label and Input together.\n *\n * Groups Label and Input with a convenient wrapper that can propagate\n * disabled, required, and invalid states to child inputs.\n *\n * @example\n * ```tsx\n * <TextField>\n * <Label>Email</Label>\n * <Input type=\"email\" placeholder=\"Enter email...\" />\n * </TextField>\n * ```\n */\nconst TextField = React.forwardRef<HTMLDivElement, TextFieldProps>(\n ({ className, children, isInvalid, disabled, required, ...props }, ref) => {\n // Clone children to pass through state props to Input/Textarea children\n const enhancedChildren = React.Children.map(children, (child) => {\n if (!React.isValidElement(child)) return child;\n\n // Get the display name or type name to check if it's an input component\n const childType = child.type;\n const displayName =\n typeof childType === 'function'\n ? (childType as React.ComponentType).displayName || childType.name\n : typeof childType === 'string'\n ? childType\n : '';\n\n // Check if this is an input-like element that should receive state props\n const isInputElement =\n displayName === 'Input' ||\n displayName === 'Textarea' ||\n displayName === 'TextArea' ||\n displayName === 'input' ||\n displayName === 'textarea';\n\n if (isInputElement) {\n const childProps = child.props as Record<string, unknown>;\n return React.cloneElement(child as React.ReactElement<Record<string, unknown>>, {\n isInvalid: (childProps.isInvalid as boolean) ?? isInvalid,\n disabled: (childProps.disabled as boolean) ?? disabled,\n required: (childProps.required as boolean) ?? required,\n });\n }\n\n return child;\n });\n\n return (\n <div ref={ref} className={cn('sc:flex sc:flex-col sc:gap-1.5', className)} {...props}>\n {enhancedChildren}\n </div>\n );\n }\n);\nTextField.displayName = 'TextField';\n\nexport { TextField };\n","/**\n * Custom Icons - Centered versions of icons from various sets\n *\n * These are copies of icons with adjusted viewBox to center properly.\n * Use these instead of the original iconify versions for consistent alignment.\n */\n\nimport React from 'react';\nimport { cn } from '../../lib/utils';\n\ninterface IconProps {\n className?: string;\n size?: number | string;\n}\n\n/**\n * Rotate Left icon (lucide-style stroked version)\n */\nexport const RotateLeftIcon: React.FC<IconProps> = ({ className, size = 24 }) => (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n width={size}\n height={size}\n className={cn('sc:inline-block iconify', className)}\n >\n <path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\" />\n <path d=\"M3 3v5h5\" />\n </svg>\n);\n\n/**\n * Rotate Right icon (lucide-style stroked version)\n */\nexport const RotateRightIcon: React.FC<IconProps> = ({ className, size = 24 }) => (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n width={size}\n height={size}\n className={cn('sc:inline-block iconify', className)}\n >\n <path d=\"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8\" />\n <path d=\"M21 3v5h-5\" />\n </svg>\n);\n\n/**\n * Sparkles icon (based on gravity-ui:sparkles)\n * Two sparkle shapes - main 4-point star and smaller accent\n */\nexport const SparklesIcon: React.FC<IconProps> = ({ className, size = 24 }) => (\n <svg\n viewBox=\"0 0 28 28\"\n fill=\"currentColor\"\n width={size}\n height={size}\n className={cn('sc:inline-block', className)}\n >\n <path d=\"M10.06 18.701a1.628 1.628 0 0 0 2.43-.676l.77-2.34a3.82 3.82 0 0 1 2.416-2.418l2.238-.727a1.6 1.6 0 0 0 .786-.595a1.62 1.62 0 0 0-.849-2.489l-2.215-.72a3.82 3.82 0 0 1-2.42-2.414l-.727-2.237a1.62 1.62 0 0 0-.594-.785a1.655 1.655 0 0 0-1.879 0a1.63 1.63 0 0 0-.6.8L8.68 6.365a3.82 3.82 0 0 1-2.359 2.37l-2.24.726a1.626 1.626 0 0 0 .02 3.073l2.216.72a3.86 3.86 0 0 1 1.816 1.286c.266.343.471.728.606 1.14l.728 2.234c.112.318.32.593.595.787m-3.273-6.873l-2.22-.72s-.085-.038-.085-.108a.14.14 0 0 1 .084-.115L6.8 10.16a5.34 5.34 0 0 0 3.32-3.375l.721-2.219s.043-.084.114-.084s.113.084.113.084l.723 2.223a5.32 5.32 0 0 0 3.377 3.372l2.27.735a.13.13 0 0 1 .078.11a.15.15 0 0 1-.083.113l-2.225.722a5.32 5.32 0 0 0-3.374 3.374l-.715 2.2a.11.11 0 0 1-.115.093c-.104 0-.118-.075-.118-.075l-.723-2.22a5.32 5.32 0 0 0-3.376-3.385m13.017 12.954A1.2 1.2 0 0 0 20.5 25a1.2 1.2 0 0 0 .692-.216a1.2 1.2 0 0 0 .446-.6l.372-1.143a1.61 1.61 0 0 1 1.017-1.02l1.166-.378A1.21 1.21 0 0 0 25 20.505a1.2 1.2 0 0 0-.844-1.146l-1.144-.37a1.61 1.61 0 0 1-1.02-1.018l-.38-1.163a1.2 1.2 0 0 0-2.274.016l-.374 1.146a1.61 1.61 0 0 1-.993 1.017l-1.166.378a1.21 1.21 0 0 0-.807 1.139a1.2 1.2 0 0 0 .823 1.138l1.144.372a1.6 1.6 0 0 1 1.02 1.023l.379 1.163a1.2 1.2 0 0 0 .44.582m-1.371-4.194l-.27-.088l.283-.096a3.12 3.12 0 0 0 1.943-1.974l.088-.27l.089.272a3.11 3.11 0 0 0 1.974 1.975l.293.1l-.271.087a3.12 3.12 0 0 0-1.974 1.977l-.088.27l-.088-.272a3.12 3.12 0 0 0-1.98-1.98\" />\n </svg>\n);\n\n// Map of icon names to components for easy lookup\nexport const CustomIcons = {\n 'rotate-left': RotateLeftIcon,\n 'rotate-right': RotateRightIcon,\n 'sparkles': SparklesIcon,\n} as const;\n\nexport type CustomIconName = keyof typeof CustomIcons;\n"],"names":["Input","React","className","type","isInvalid","startContent","endContent","disabled","readOnly","required","variant","props","ref","surface","useSurface","isOnSurface","effectiveVariant","inputElement","jsx","cn","jsxs","labelVariants","cva","Label","LabelPrimitive","TabsRoot","value","onValueChange","TabsPrimitive","TabsList","children","listRef","indicatorStyle","setIndicatorStyle","listElement","updateIndicator","activeTab","listRect","tabRect","observer","mutations","mutation","trigger","resizeObserver","node","TabsTrigger","id","surfaceVariant","TabsContent","TabsListContainer","TabsTab","TabsPanel","TabsIndicator","TabsBase","Tabs","TextField","enhancedChildren","child","childType","displayName","childProps","RotateLeftIcon","size","SparklesIcon"],"mappings":"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"}
1
+ {"version":3,"file":"custom-icons-BIaRovwG.js","sources":["../src/vendor/ui/primitives/input.tsx","../src/vendor/ui/primitives/label.tsx","../src/vendor/ui/primitives/tabs.tsx","../src/vendor/ui/primitives/text-field.tsx","../src/components/ui/custom-icons.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { cn } from '../lib/utils';\nimport { useSurface } from './surface';\n\nexport interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {\n /** Whether the input is in an invalid state */\n isInvalid?: boolean;\n /** Content to display at the start of the input */\n startContent?: React.ReactNode;\n /** Content to display at the end of the input */\n endContent?: React.ReactNode;\n /**\n * Visual variant - auto-detected from Surface context, or can be set explicitly\n * - `default`: Standard field styling for forms (bg-field)\n * - `filled`: Field on elevated surface (bg-field-on-surface)\n * - `subtle`: Blends with buttons/tabs in toolbars (bg-default)\n */\n variant?: 'default' | 'filled' | 'subtle';\n}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n (\n {\n className,\n type,\n isInvalid,\n startContent,\n endContent,\n disabled,\n readOnly,\n required,\n variant,\n ...props\n },\n ref\n ) => {\n // Auto-detect variant from Surface context\n const surface = useSurface();\n const isOnSurface = surface.variant === 'default' || surface.variant === 'secondary';\n const effectiveVariant = variant ?? (isOnSurface ? 'filled' : 'default');\n\n const inputElement = (\n <input\n type={type}\n className={cn(\n 'sc:flex sc:h-10 sc:w-full sc:rounded-input sc:px-2.5 sc:py-1.5 sc:text-sm sc:appearance-none',\n 'sc:text-foreground sc:border-none',\n 'sc:file:border-0 sc:file:bg-transparent sc:file:text-sm sc:file:font-medium sc:file:text-foreground',\n 'sc:placeholder:text-foreground/50',\n 'sc:transition-shadow sc:duration-200 sc:ease-out sc:focus-visible:outline-none sc:focus:ring-2 sc:focus:ring-focus sc:focus:ring-offset-1 sc:focus:ring-offset-background',\n 'sc:disabled:cursor-not-allowed sc:disabled:opacity-50',\n // Variant styles - semantic: field on page vs field on surface vs toolbar\n effectiveVariant === 'default' && 'sc:bg-field sc:shadow-soft sc:dark:shadow-none',\n effectiveVariant === 'filled' && 'sc:bg-[var(--color-field-on-surface)]',\n effectiveVariant === 'subtle' && 'sc:bg-default sc:dark:bg-[var(--color-default-on-surface)]',\n isInvalid && 'sc:ring-2 sc:ring-danger sc:focus-visible:ring-danger',\n startContent && 'sc:pl-10',\n endContent && 'sc:pr-10',\n className\n )}\n ref={ref}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n aria-invalid={isInvalid}\n {...props}\n />\n );\n\n if (startContent || endContent) {\n return (\n <div className=\"sc:relative\">\n {startContent && (\n <div className=\"sc:absolute sc:left-3 sc:top-1/2 sc:-translate-y-1/2 sc:text-foreground sc:opacity-40\">{startContent}</div>\n )}\n {inputElement}\n {endContent && (\n <div className=\"sc:absolute sc:right-3 sc:top-1/2 sc:-translate-y-1/2 sc:text-foreground sc:opacity-40\">{endContent}</div>\n )}\n </div>\n );\n }\n\n return inputElement;\n }\n);\nInput.displayName = 'Input';\n\nexport { Input };\n","'use client';\n\nimport * as React from 'react';\nimport * as LabelPrimitive from '@radix-ui/react-label';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../lib/utils';\n\nconst labelVariants = cva(\n 'sc:block sc:text-sm sc:leading-none sc:text-foreground sc:peer-disabled:cursor-not-allowed sc:peer-disabled:opacity-70 sc:font-label'\n);\n\nconst Label = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>\n>(({ className, ...props }, ref) => (\n <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />\n));\nLabel.displayName = LabelPrimitive.Root.displayName;\n\nexport { Label };\n","\"use client\";\n\n'use client';\n\nimport * as React from 'react';\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport { cn } from '../lib/utils';\nimport { useSurface } from './surface';\n\ninterface TabsProps\n extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>, 'value' | 'onValueChange'> {\n value?: string;\n onValueChange?: (value: string) => void;\n}\n\nconst TabsRoot = React.forwardRef<React.ElementRef<typeof TabsPrimitive.Root>, TabsProps>(\n ({ value, onValueChange, ...props }, ref) => (\n <TabsPrimitive.Root ref={ref} value={value} onValueChange={onValueChange} {...props} />\n )\n);\nTabsRoot.displayName = 'Tabs';\n\nconst TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, children, ...props }, ref) => {\n const listRef = React.useRef<HTMLDivElement>(null);\n const [indicatorStyle, setIndicatorStyle] = React.useState<React.CSSProperties>({\n opacity: 0,\n });\n\n // Update indicator position when active tab changes\n React.useEffect(() => {\n const listElement = listRef.current;\n if (!listElement) return;\n\n const updateIndicator = () => {\n const activeTab = listElement.querySelector('[data-state=\"active\"]') as HTMLElement;\n if (activeTab) {\n const listRect = listElement.getBoundingClientRect();\n const tabRect = activeTab.getBoundingClientRect();\n\n setIndicatorStyle({\n width: tabRect.width,\n height: tabRect.height,\n left: tabRect.left - listRect.left,\n opacity: 1,\n });\n }\n };\n\n // Initial position\n updateIndicator();\n\n // Use MutationObserver to detect when active tab changes\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'attributes' && mutation.attributeName === 'data-state') {\n updateIndicator();\n break;\n }\n }\n });\n\n // Observe all trigger elements for data-state changes\n const triggers = listElement.querySelectorAll('[role=\"tab\"]');\n triggers.forEach((trigger) => {\n observer.observe(trigger, { attributes: true, attributeFilter: ['data-state'] });\n });\n\n // Also update on resize\n const resizeObserver = new ResizeObserver(updateIndicator);\n resizeObserver.observe(listElement);\n\n return () => {\n observer.disconnect();\n resizeObserver.disconnect();\n };\n }, [children]);\n\n return (\n <TabsPrimitive.List\n ref={(node) => {\n // Handle both refs\n (listRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n }}\n className={cn(\n 'sc:relative sc:inline-flex sc:h-10 sc:items-center sc:justify-center sc:rounded-full sc:px-1 sc:text-muted-foreground',\n // Consistent bg-default matches Button secondary variant for toolbar harmony\n 'sc:bg-default sc:dark:bg-[var(--color-default-on-surface)]',\n className\n )}\n {...props}\n >\n {/* Animated sliding indicator. In dark mode the previous `bg-muted`\n value resolved to the same color as `bg-default` on the container,\n so the active tab was invisible without relying purely on\n shadow-md. `bg-popover` lands ~0.08 lightness above `bg-default`\n in dark mode for a clearly visible elevation. */}\n <span\n className=\"sc:absolute sc:top-1/2 sc:-translate-y-1/2 sc:rounded-full sc:bg-surface sc:dark:bg-popover sc:shadow-md sc:transition-[left,width,opacity]\"\n style={{\n ...indicatorStyle,\n transitionDuration: '350ms',\n transitionTimingFunction: 'cubic-bezier(0.22, 1, 0.36, 1)',\n }}\n aria-hidden=\"true\"\n />\n {children}\n </TabsPrimitive.List>\n );\n});\nTabsList.displayName = TabsPrimitive.List.displayName;\n\ninterface TabsTriggerProps extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>, 'value'> {\n // HeroUI uses 'id' for tab identification, Radix uses 'value'\n // At least one must be provided\n id?: string;\n value?: string;\n}\n\nconst TabsTrigger = React.forwardRef<React.ElementRef<typeof TabsPrimitive.Trigger>, TabsTriggerProps>(\n ({ className, id, value, ...props }, ref) => {\n const { variant: surfaceVariant } = useSurface();\n const isOnSurface = surfaceVariant === 'default' || surfaceVariant === 'secondary';\n\n return (\n <TabsPrimitive.Trigger\n ref={ref}\n value={id ?? value ?? ''}\n className={cn(\n 'sc:relative sc:z-10 sc:inline-flex sc:h-8 sc:items-center sc:justify-center sc:gap-2 sc:whitespace-nowrap sc:rounded-full sc:px-4 sc:text-sm sc:font-label',\n 'sc:transition-[color,opacity]',\n 'sc:focus-visible:outline-none sc:focus-visible:ring-2 sc:focus-visible:ring-focus sc:focus-visible:ring-offset-2',\n 'sc:disabled:pointer-events-none sc:disabled:opacity-50',\n 'sc:data-[state=active]:text-foreground sc:data-[state=active]:opacity-100',\n // Inactive tabs use element opacity (not color opacity) to avoid SVG path overlap issues\n isOnSurface\n ? 'sc:data-[state=inactive]:text-foreground sc:data-[state=inactive]:opacity-30 sc:data-[state=inactive]:hover:opacity-50'\n : 'sc:data-[state=inactive]:text-foreground sc:data-[state=inactive]:opacity-50 sc:data-[state=inactive]:hover:opacity-70',\n className\n )}\n {...props}\n />\n );\n }\n);\nTabsTrigger.displayName = TabsPrimitive.Trigger.displayName;\n\ninterface TabsContentProps extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>, 'value'> {\n // HeroUI uses 'id' for panel identification, Radix uses 'value'\n // At least one must be provided\n id?: string;\n value?: string;\n}\n\nconst TabsContent = React.forwardRef<React.ElementRef<typeof TabsPrimitive.Content>, TabsContentProps>(\n ({ className, id, value, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n value={id ?? value ?? ''}\n className={cn(\n 'sc:mt-2 sc:ring-offset-background sc:focus-visible:outline-none sc:focus-visible:ring-2 sc:focus-visible:ring-focus sc:focus-visible:ring-offset-2',\n className\n )}\n {...props}\n />\n )\n);\nTabsContent.displayName = TabsPrimitive.Content.displayName;\n\n// HeroUI ListContainer - wrapper for the tabs list (passthrough div)\nconst TabsListContainer = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => <div ref={ref} className={className} {...props} />\n);\nTabsListContainer.displayName = 'TabsListContainer';\n\n// HeroUI Tab - alias for TabsTrigger\nconst TabsTab = TabsTrigger;\n\n// HeroUI Panel - alias for TabsContent\nconst TabsPanel = TabsContent;\n\n// HeroUI Indicator - now rendered automatically by TabsList, this is a no-op\nconst TabsIndicator = () => null;\n\n// Create compound component with all aliases\nconst TabsBase = TabsRoot;\n\n// HeroUI-compatible compound component\nconst Tabs = Object.assign(TabsBase, {\n List: TabsList,\n ListContainer: TabsListContainer,\n Tab: TabsTab,\n Trigger: TabsTrigger,\n Panel: TabsPanel,\n Content: TabsContent,\n Indicator: TabsIndicator,\n});\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent, TabsRoot };\n","'use client';\n\nimport * as React from 'react';\nimport { cn } from '../lib/utils';\n\nexport interface TextFieldProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Accessible label for the input.\n * If not provided via children, use aria-label on the div.\n */\n 'aria-label'?: string;\n /**\n * Error state - applies error styling to children inputs\n */\n isInvalid?: boolean;\n /**\n * Disabled state - disables all children inputs\n */\n disabled?: boolean;\n /**\n * Required state - marks all children inputs as required\n */\n required?: boolean;\n}\n\n/**\n * TextField - A wrapper component that groups Label and Input together.\n *\n * Groups Label and Input with a convenient wrapper that can propagate\n * disabled, required, and invalid states to child inputs.\n *\n * @example\n * ```tsx\n * <TextField>\n * <Label>Email</Label>\n * <Input type=\"email\" placeholder=\"Enter email...\" />\n * </TextField>\n * ```\n */\nconst TextField = React.forwardRef<HTMLDivElement, TextFieldProps>(\n ({ className, children, isInvalid, disabled, required, ...props }, ref) => {\n // Clone children to pass through state props to Input/Textarea children\n const enhancedChildren = React.Children.map(children, (child) => {\n if (!React.isValidElement(child)) return child;\n\n // Get the display name or type name to check if it's an input component\n const childType = child.type;\n const displayName =\n typeof childType === 'function'\n ? (childType as React.ComponentType).displayName || childType.name\n : typeof childType === 'string'\n ? childType\n : '';\n\n // Check if this is an input-like element that should receive state props\n const isInputElement =\n displayName === 'Input' ||\n displayName === 'Textarea' ||\n displayName === 'TextArea' ||\n displayName === 'input' ||\n displayName === 'textarea';\n\n if (isInputElement) {\n const childProps = child.props as Record<string, unknown>;\n return React.cloneElement(child as React.ReactElement<Record<string, unknown>>, {\n isInvalid: (childProps.isInvalid as boolean) ?? isInvalid,\n disabled: (childProps.disabled as boolean) ?? disabled,\n required: (childProps.required as boolean) ?? required,\n });\n }\n\n return child;\n });\n\n return (\n <div ref={ref} className={cn('sc:flex sc:flex-col sc:gap-1.5', className)} {...props}>\n {enhancedChildren}\n </div>\n );\n }\n);\nTextField.displayName = 'TextField';\n\nexport { TextField };\n","/**\n * Custom Icons - Centered versions of icons from various sets\n *\n * These are copies of icons with adjusted viewBox to center properly.\n * Use these instead of the original iconify versions for consistent alignment.\n */\n\nimport React from 'react';\nimport { cn } from '../../lib/utils';\n\ninterface IconProps {\n className?: string;\n size?: number | string;\n}\n\n/**\n * Rotate Left icon (lucide-style stroked version)\n */\nexport const RotateLeftIcon: React.FC<IconProps> = ({ className, size = 24 }) => (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n width={size}\n height={size}\n className={cn('sc:inline-block iconify', className)}\n >\n <path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\" />\n <path d=\"M3 3v5h5\" />\n </svg>\n);\n\n/**\n * Rotate Right icon (lucide-style stroked version)\n */\nexport const RotateRightIcon: React.FC<IconProps> = ({ className, size = 24 }) => (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n width={size}\n height={size}\n className={cn('sc:inline-block iconify', className)}\n >\n <path d=\"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8\" />\n <path d=\"M21 3v5h-5\" />\n </svg>\n);\n\n/**\n * Sparkles icon (based on gravity-ui:sparkles)\n * Two sparkle shapes - main 4-point star and smaller accent\n */\nexport const SparklesIcon: React.FC<IconProps> = ({ className, size = 24 }) => (\n <svg\n viewBox=\"0 0 28 28\"\n fill=\"currentColor\"\n width={size}\n height={size}\n className={cn('sc:inline-block', className)}\n >\n <path d=\"M10.06 18.701a1.628 1.628 0 0 0 2.43-.676l.77-2.34a3.82 3.82 0 0 1 2.416-2.418l2.238-.727a1.6 1.6 0 0 0 .786-.595a1.62 1.62 0 0 0-.849-2.489l-2.215-.72a3.82 3.82 0 0 1-2.42-2.414l-.727-2.237a1.62 1.62 0 0 0-.594-.785a1.655 1.655 0 0 0-1.879 0a1.63 1.63 0 0 0-.6.8L8.68 6.365a3.82 3.82 0 0 1-2.359 2.37l-2.24.726a1.626 1.626 0 0 0 .02 3.073l2.216.72a3.86 3.86 0 0 1 1.816 1.286c.266.343.471.728.606 1.14l.728 2.234c.112.318.32.593.595.787m-3.273-6.873l-2.22-.72s-.085-.038-.085-.108a.14.14 0 0 1 .084-.115L6.8 10.16a5.34 5.34 0 0 0 3.32-3.375l.721-2.219s.043-.084.114-.084s.113.084.113.084l.723 2.223a5.32 5.32 0 0 0 3.377 3.372l2.27.735a.13.13 0 0 1 .078.11a.15.15 0 0 1-.083.113l-2.225.722a5.32 5.32 0 0 0-3.374 3.374l-.715 2.2a.11.11 0 0 1-.115.093c-.104 0-.118-.075-.118-.075l-.723-2.22a5.32 5.32 0 0 0-3.376-3.385m13.017 12.954A1.2 1.2 0 0 0 20.5 25a1.2 1.2 0 0 0 .692-.216a1.2 1.2 0 0 0 .446-.6l.372-1.143a1.61 1.61 0 0 1 1.017-1.02l1.166-.378A1.21 1.21 0 0 0 25 20.505a1.2 1.2 0 0 0-.844-1.146l-1.144-.37a1.61 1.61 0 0 1-1.02-1.018l-.38-1.163a1.2 1.2 0 0 0-2.274.016l-.374 1.146a1.61 1.61 0 0 1-.993 1.017l-1.166.378a1.21 1.21 0 0 0-.807 1.139a1.2 1.2 0 0 0 .823 1.138l1.144.372a1.6 1.6 0 0 1 1.02 1.023l.379 1.163a1.2 1.2 0 0 0 .44.582m-1.371-4.194l-.27-.088l.283-.096a3.12 3.12 0 0 0 1.943-1.974l.088-.27l.089.272a3.11 3.11 0 0 0 1.974 1.975l.293.1l-.271.087a3.12 3.12 0 0 0-1.974 1.977l-.088.27l-.088-.272a3.12 3.12 0 0 0-1.98-1.98\" />\n </svg>\n);\n\n// Map of icon names to components for easy lookup\nexport const CustomIcons = {\n 'rotate-left': RotateLeftIcon,\n 'rotate-right': RotateRightIcon,\n 'sparkles': SparklesIcon,\n} as const;\n\nexport type CustomIconName = keyof typeof CustomIcons;\n"],"names":["Input","React","className","type","isInvalid","startContent","endContent","disabled","readOnly","required","variant","props","ref","surface","useSurface","isOnSurface","effectiveVariant","inputElement","jsx","cn","jsxs","labelVariants","cva","Label","LabelPrimitive","TabsRoot","value","onValueChange","TabsPrimitive","TabsList","children","listRef","indicatorStyle","setIndicatorStyle","listElement","updateIndicator","activeTab","listRect","tabRect","observer","mutations","mutation","trigger","resizeObserver","node","TabsTrigger","id","surfaceVariant","TabsContent","TabsListContainer","TabsTab","TabsPanel","TabsIndicator","TabsBase","Tabs","TextField","enhancedChildren","child","childType","displayName","childProps","RotateLeftIcon","size","SparklesIcon"],"mappings":";;;;;;AAsBA,MAAMA,IAAQC,EAAM;AAAA,EAClB,CACE;AAAA,IACE,WAAAC;AAAA,IACA,MAAAC;AAAA,IACA,WAAAC;AAAA,IACA,cAAAC;AAAA,IACA,YAAAC;AAAA,IACA,UAAAC;AAAA,IACA,UAAAC;AAAA,IACA,UAAAC;AAAA,IACA,SAAAC;AAAA,IACA,GAAGC;AAAA,EAAA,GAELC,MACG;AAEH,UAAMC,IAAUC,EAAA,GACVC,IAAcF,EAAQ,YAAY,aAAaA,EAAQ,YAAY,aACnEG,IAAmBN,MAAYK,IAAc,WAAW,YAExDE,IACJ,gBAAAC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAAf;AAAA,QACA,WAAWgB;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,UAEAH,MAAqB,aAAa;AAAA,UAClCA,MAAqB,YAAY;AAAA,UACjCA,MAAqB,YAAY;AAAA,UACjCZ,KAAa;AAAA,UACbC,KAAgB;AAAA,UAChBC,KAAc;AAAA,UACdJ;AAAA,QAAA;AAAA,QAEF,KAAAU;AAAA,QACA,UAAAL;AAAA,QACA,UAAAC;AAAA,QACA,UAAAC;AAAA,QACA,gBAAcL;AAAA,QACb,GAAGO;AAAA,MAAA;AAAA,IAAA;AAIR,WAAIN,KAAgBC,IAEhB,gBAAAc,EAAC,OAAA,EAAI,WAAU,eACZ,UAAA;AAAA,MAAAf,KACC,gBAAAa,EAAC,OAAA,EAAI,WAAU,yFAAyF,UAAAb,GAAa;AAAA,MAEtHY;AAAA,MACAX,KACC,gBAAAY,EAAC,OAAA,EAAI,WAAU,0FAA0F,UAAAZ,EAAA,CAAW;AAAA,IAAA,GAExH,IAIGW;AAAA,EACT;AACF;AACAjB,EAAM,cAAc;ACjFpB,MAAMqB,IAAgBC;AAAA,EACpB;AACF,GAEMC,IAAQtB,EAAM,WAGlB,CAAC,EAAE,WAAAC,GAAW,GAAGS,EAAA,GAASC,MAC1B,gBAAAM,EAACM,EAAe,MAAf,EAAoB,KAAAZ,GAAU,WAAWO,EAAGE,EAAA,GAAiBnB,CAAS,GAAI,GAAGS,GAAO,CACtF;AACDY,EAAM,cAAcC,EAAe,KAAK;ACFxC,MAAMC,IAAWxB,EAAM;AAAA,EACrB,CAAC,EAAE,OAAAyB,GAAO,eAAAC,GAAe,GAAGhB,KAASC,MACnC,gBAAAM,EAACU,EAAc,MAAd,EAAmB,KAAAhB,GAAU,OAAAc,GAAc,eAAAC,GAA+B,GAAGhB,EAAA,CAAO;AAEzF;AACAc,EAAS,cAAc;AAEvB,MAAMI,IAAW5B,EAAM,WAGrB,CAAC,EAAE,WAAAC,GAAW,UAAA4B,GAAU,GAAGnB,EAAA,GAASC,MAAQ;AAC5C,QAAMmB,IAAU9B,EAAM,OAAuB,IAAI,GAC3C,CAAC+B,GAAgBC,CAAiB,IAAIhC,EAAM,SAA8B;AAAA,IAC9E,SAAS;AAAA,EAAA,CACV;AAGD,SAAAA,EAAM,UAAU,MAAM;AACpB,UAAMiC,IAAcH,EAAQ;AAC5B,QAAI,CAACG,EAAa;AAElB,UAAMC,IAAkB,MAAM;AAC5B,YAAMC,IAAYF,EAAY,cAAc,uBAAuB;AACnE,UAAIE,GAAW;AACb,cAAMC,IAAWH,EAAY,sBAAA,GACvBI,IAAUF,EAAU,sBAAA;AAE1B,QAAAH,EAAkB;AAAA,UAChB,OAAOK,EAAQ;AAAA,UACf,QAAQA,EAAQ;AAAA,UAChB,MAAMA,EAAQ,OAAOD,EAAS;AAAA,UAC9B,SAAS;AAAA,QAAA,CACV;AAAA,MACH;AAAA,IACF;AAGA,IAAAF,EAAA;AAGA,UAAMI,IAAW,IAAI,iBAAiB,CAACC,MAAc;AACnD,iBAAWC,KAAYD;AACrB,YAAIC,EAAS,SAAS,gBAAgBA,EAAS,kBAAkB,cAAc;AAC7E,UAAAN,EAAA;AACA;AAAA,QACF;AAAA,IAEJ,CAAC;AAID,IADiBD,EAAY,iBAAiB,cAAc,EACnD,QAAQ,CAACQ,MAAY;AAC5B,MAAAH,EAAS,QAAQG,GAAS,EAAE,YAAY,IAAM,iBAAiB,CAAC,YAAY,GAAG;AAAA,IACjF,CAAC;AAGD,UAAMC,IAAiB,IAAI,eAAeR,CAAe;AACzD,WAAAQ,EAAe,QAAQT,CAAW,GAE3B,MAAM;AACX,MAAAK,EAAS,WAAA,GACTI,EAAe,WAAA;AAAA,IACjB;AAAA,EACF,GAAG,CAACb,CAAQ,CAAC,GAGX,gBAAAV;AAAA,IAACQ,EAAc;AAAA,IAAd;AAAA,MACC,KAAK,CAACgB,MAAS;AAEZ,QAAAb,EAA0D,UAAUa,GACjE,OAAOhC,KAAQ,aACjBA,EAAIgC,CAAI,IACChC,MACTA,EAAI,UAAUgC;AAAA,MAElB;AAAA,MACA,WAAWzB;AAAA,QACT;AAAA;AAAA,QAEA;AAAA,QACAjB;AAAA,MAAA;AAAA,MAED,GAAGS;AAAA,MAOJ,UAAA;AAAA,QAAA,gBAAAO;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,GAAGc;AAAA,cACH,oBAAoB;AAAA,cACpB,0BAA0B;AAAA,YAAA;AAAA,YAE5B,eAAY;AAAA,UAAA;AAAA,QAAA;AAAA,QAEbF;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;AACDD,EAAS,cAAcD,EAAc,KAAK;AAS1C,MAAMiB,IAAc5C,EAAM;AAAA,EACxB,CAAC,EAAE,WAAAC,GAAW,IAAA4C,GAAI,OAAApB,GAAO,GAAGf,EAAA,GAASC,MAAQ;AAC3C,UAAM,EAAE,SAASmC,EAAA,IAAmBjC,EAAA,GAC9BC,IAAcgC,MAAmB,aAAaA,MAAmB;AAEvE,WACE,gBAAA7B;AAAA,MAACU,EAAc;AAAA,MAAd;AAAA,QACC,KAAAhB;AAAA,QACA,OAAOkC,KAAMpB,KAAS;AAAA,QACtB,WAAWP;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,UAEAJ,IACI,2HACA;AAAA,UACJb;AAAA,QAAA;AAAA,QAED,GAAGS;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV;AACF;AACAkC,EAAY,cAAcjB,EAAc,QAAQ;AAShD,MAAMoB,IAAc/C,EAAM;AAAA,EACxB,CAAC,EAAE,WAAAC,GAAW,IAAA4C,GAAI,OAAApB,GAAO,GAAGf,EAAA,GAASC,MACnC,gBAAAM;AAAA,IAACU,EAAc;AAAA,IAAd;AAAA,MACC,KAAAhB;AAAA,MACA,OAAOkC,KAAMpB,KAAS;AAAA,MACtB,WAAWP;AAAA,QACT;AAAA,QACAjB;AAAA,MAAA;AAAA,MAED,GAAGS;AAAA,IAAA;AAAA,EAAA;AAGV;AACAqC,EAAY,cAAcpB,EAAc,QAAQ;AAGhD,MAAMqB,IAAoBhD,EAAM;AAAA,EAC9B,CAAC,EAAE,WAAAC,GAAW,GAAGS,EAAA,GAASC,MAAQ,gBAAAM,EAAC,OAAA,EAAI,KAAAN,GAAU,WAAAV,GAAuB,GAAGS,EAAA,CAAO;AACpF;AACAsC,EAAkB,cAAc;AAGhC,MAAMC,IAAUL,GAGVM,IAAYH,GAGZI,IAAgB,MAAM,MAGtBC,IAAW5B,GAGX6B,IAAO,OAAO,OAAOD,GAAU;AAAA,EACnC,MAAMxB;AAAA,EACN,eAAeoB;AAAA,EACf,KAAKC;AAAA,EACL,SAASL;AAAA,EACT,OAAOM;AAAA,EACP,SAASH;AAAA,EACT,WAAWI;AACb,CAAC,GCpKKG,IAAYtD,EAAM;AAAA,EACtB,CAAC,EAAE,WAAAC,GAAW,UAAA4B,GAAU,WAAA1B,GAAW,UAAAG,GAAU,UAAAE,GAAU,GAAGE,EAAA,GAASC,MAAQ;AAEzE,UAAM4C,IAAmBvD,EAAM,SAAS,IAAI6B,GAAU,CAAC2B,MAAU;AAC/D,UAAI,CAACxD,EAAM,eAAewD,CAAK,EAAG,QAAOA;AAGzC,YAAMC,IAAYD,EAAM,MAClBE,IACJ,OAAOD,KAAc,aAChBA,EAAkC,eAAeA,EAAU,OAC5D,OAAOA,KAAc,WACnBA,IACA;AAUR,UANEC,MAAgB,WAChBA,MAAgB,cAChBA,MAAgB,cAChBA,MAAgB,WAChBA,MAAgB,YAEE;AAClB,cAAMC,IAAaH,EAAM;AACzB,eAAOxD,EAAM,aAAawD,GAAsD;AAAA,UAC9E,WAAYG,EAAW,aAAyBxD;AAAA,UAChD,UAAWwD,EAAW,YAAwBrD;AAAA,UAC9C,UAAWqD,EAAW,YAAwBnD;AAAA,QAAA,CAC/C;AAAA,MACH;AAEA,aAAOgD;AAAA,IACT,CAAC;AAED,WACE,gBAAAvC,EAAC,OAAA,EAAI,KAAAN,GAAU,WAAWO,EAAG,kCAAkCjB,CAAS,GAAI,GAAGS,GAC5E,UAAA6C,EAAA,CACH;AAAA,EAEJ;AACF;AACAD,EAAU,cAAc;AC/DjB,MAAMM,IAAsC,CAAC,EAAE,WAAA3D,GAAW,MAAA4D,IAAO,SACtE,gBAAA1C;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,QAAO;AAAA,IACP,aAAY;AAAA,IACZ,eAAc;AAAA,IACd,gBAAe;AAAA,IACf,OAAO0C;AAAA,IACP,QAAQA;AAAA,IACR,WAAW3C,EAAG,2BAA2BjB,CAAS;AAAA,IAElD,UAAA;AAAA,MAAA,gBAAAgB,EAAC,QAAA,EAAK,GAAE,oDAAA,CAAoD;AAAA,MAC5D,gBAAAA,EAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,IAAA;AAAA,EAAA;AACrB,GA2BW6C,IAAoC,CAAC,EAAE,WAAA7D,GAAW,MAAA4D,IAAO,SACpE,gBAAA5C;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,OAAO4C;AAAA,IACP,QAAQA;AAAA,IACR,WAAW3C,EAAG,mBAAmBjB,CAAS;AAAA,IAE1C,UAAA,gBAAAgB,EAAC,QAAA,EAAK,GAAE,m6CAAA,CAAm6C;AAAA,EAAA;AAC76C;"}
@@ -1,4 +1,4 @@
1
- import { g as l } from "./editorErrors-8uDRMhow.js";
1
+ import { E as l } from "./FontAnalyzer-DKG5JK0x.js";
2
2
  const x = 1;
3
3
  function d(e) {
4
4
  return typeof e == "number" && Number.isFinite(e) ? Math.round(e * 100) / 100 : e;
@@ -467,4 +467,4 @@ export {
467
467
  F as l,
468
468
  O as s
469
469
  };
470
- //# sourceMappingURL=design-builder-bquxIHct.js.map
470
+ //# sourceMappingURL=design-builder-JYLO_Hyi.js.map