@oh-just-another/editor 0.59.0 → 0.61.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.
@@ -0,0 +1,41 @@
1
+ import type { Scene } from "@oh-just-another/scene";
2
+ import { type Action, type ActionRegistry, type Editor } from "@oh-just-another/state";
3
+ import { type PngExportBackground } from "./png-export.js";
4
+ /** Override the notifier used by the file actions (host toast, etc). */
5
+ export declare const setFileActionNotifier: (fn: (message: string) => void) => void;
6
+ /** "Save as JSON" — serialises the scene through `@serialization`. */
7
+ export declare const downloadScene: (scene: Scene) => void;
8
+ /**
9
+ * "Open…" — file picker that accepts `.diagram.json`, parses it, and
10
+ * replaces the editor's scene (history reset — the default `loadScene`
11
+ * behaviour). User cancellation = no-op; a parse failure shows a toast.
12
+ */
13
+ export declare const openSceneFile: (editor: Editor) => void;
14
+ /**
15
+ * "Export as PNG" — renders the full scene (not just the viewport) via
16
+ * {@link exportSceneToPng} and downloads it. `background` picks the
17
+ * transparent / solid / solid+grid variant.
18
+ */
19
+ export declare const downloadPng: (editor: Editor, background: PngExportBackground) => Promise<void>;
20
+ /** "Export as SVG" — vector export via `renderSceneToSvg`. */
21
+ export declare const downloadSvg: (scene: Scene) => void;
22
+ /**
23
+ * "Copy as image" — writes a PNG of the full scene to the system
24
+ * clipboard via the async Clipboard API. SVG-to-clipboard is a follow-up
25
+ * (no reliable cross-browser `image/svg+xml` clipboard support today, so
26
+ * we ship the PNG path that works everywhere the API exists).
27
+ */
28
+ export declare const copySceneAsImage: (editor: Editor) => Promise<void>;
29
+ /**
30
+ * File-ops actions. `save` / `export` / `copy-as-image` are flagged
31
+ * `viewMode` (non-mutating — fine in read-only); `open` replaces the
32
+ * document, so it stays gated in read-only.
33
+ */
34
+ export declare const fileActions: readonly Action[];
35
+ /**
36
+ * Register the file-ops actions on a registry (defaults to the shared
37
+ * {@link defaultActionRegistry}). Idempotent — safe to call on every
38
+ * `<Editor>` mount; re-registers in place via `replace`.
39
+ */
40
+ export declare const registerFileActions: (registry?: ActionRegistry) => void;
41
+ //# sourceMappingURL=file-actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-actions.d.ts","sourceRoot":"","sources":["../src/file-actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAGpD,OAAO,EACL,KAAK,MAAM,EACX,KAAK,cAAc,EACnB,KAAK,MAAM,EAEZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AA0B7E,wEAAwE;AACxE,eAAO,MAAM,qBAAqB,GAAI,IAAI,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,KAAG,IAErE,CAAC;AAoBF,sEAAsE;AACtE,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,IAG5C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,KAAG,IAmB9C,CAAC;AAaF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,EACd,YAAY,mBAAmB,KAC9B,OAAO,CAAC,IAAI,CAWd,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,KAAG,IAG1C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAwBnE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,SAAS,MAAM,EAyCxC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,WAAU,cAAsC,KAAG,IAEtF,CAAC"}
@@ -0,0 +1,201 @@
1
+ import { parseScene, stringifyScene } from "@oh-just-another/serialization";
2
+ import { renderSceneToSvg } from "@oh-just-another/renderer-svg";
3
+ import { defaultActionRegistry, } from "@oh-just-another/state";
4
+ import { exportSceneToPng } from "./png-export.js";
5
+ /**
6
+ * File operations for the editor — Save / Open / Export / Copy-as-image —
7
+ * wired as {@link Action}s so hosts binding the action registry (hotkeys,
8
+ * menus, command palette) get them for free. Each action just glues the
9
+ * existing serialization + exporter pipelines to the browser's file /
10
+ * clipboard APIs; nothing here re-implements serialization or rendering.
11
+ *
12
+ * Lives in `@oh-just-another/editor` (not the lower `state` / `react-ui`
13
+ * layers) because it needs `@oh-just-another/serialization` +
14
+ * {@link exportSceneToPng}, which are only available here.
15
+ */
16
+ /** Device-pixel scale for PNG export / copy. 2 = retina-quality. */
17
+ const PNG_EXPORT_SCALE = 2;
18
+ /**
19
+ * Host notifier for user-facing errors (bad file, empty canvas,
20
+ * clipboard unsupported). Defaults to `window.alert`; `<Editor>` swaps
21
+ * it for its toast via {@link setFileActionNotifier}.
22
+ */
23
+ let notify = (message) => {
24
+ if (typeof window !== "undefined")
25
+ window.alert(message);
26
+ };
27
+ /** Override the notifier used by the file actions (host toast, etc). */
28
+ export const setFileActionNotifier = (fn) => {
29
+ notify = fn;
30
+ };
31
+ /**
32
+ * Trigger a browser download of arbitrary bytes. Creates a temporary
33
+ * `<a>`, clicks it, and revokes the object URL on the next frame so the
34
+ * browser has time to start the download.
35
+ */
36
+ const downloadBlob = (blob, filename) => {
37
+ const url = URL.createObjectURL(blob);
38
+ const a = document.createElement("a");
39
+ a.href = url;
40
+ a.download = filename;
41
+ document.body.appendChild(a);
42
+ a.click();
43
+ document.body.removeChild(a);
44
+ requestAnimationFrame(() => {
45
+ URL.revokeObjectURL(url);
46
+ });
47
+ };
48
+ /** "Save as JSON" — serialises the scene through `@serialization`. */
49
+ export const downloadScene = (scene) => {
50
+ const json = stringifyScene(scene, 2);
51
+ downloadBlob(new Blob([json], { type: "application/json" }), "scene.diagram.json");
52
+ };
53
+ /**
54
+ * "Open…" — file picker that accepts `.diagram.json`, parses it, and
55
+ * replaces the editor's scene (history reset — the default `loadScene`
56
+ * behaviour). User cancellation = no-op; a parse failure shows a toast.
57
+ */
58
+ export const openSceneFile = (editor) => {
59
+ if (typeof document === "undefined")
60
+ return;
61
+ const input = document.createElement("input");
62
+ input.type = "file";
63
+ input.accept = "application/json,.json";
64
+ input.onchange = () => {
65
+ const file = input.files?.[0];
66
+ if (!file)
67
+ return;
68
+ void file.text().then((text) => {
69
+ try {
70
+ const scene = parseScene(text);
71
+ editor.loadScene(scene);
72
+ }
73
+ catch (err) {
74
+ console.error("[diagram] failed to parse scene file:", err);
75
+ notify("Failed to parse the file — make sure it was saved through this app's Save action.");
76
+ }
77
+ });
78
+ };
79
+ input.click();
80
+ };
81
+ /**
82
+ * Read the host's current `--du-canvas-bg` CSS variable (falls back to
83
+ * white). Matches what the user sees behind the shapes on the live canvas.
84
+ */
85
+ const readCanvasBackgroundColor = () => {
86
+ if (typeof document === "undefined")
87
+ return "#ffffff";
88
+ const probe = document.querySelector('canvas[data-layer="main"]') ?? document.body;
89
+ const value = getComputedStyle(probe).getPropertyValue("--du-canvas-bg").trim();
90
+ return value || "#ffffff";
91
+ };
92
+ /**
93
+ * "Export as PNG" — renders the full scene (not just the viewport) via
94
+ * {@link exportSceneToPng} and downloads it. `background` picks the
95
+ * transparent / solid / solid+grid variant.
96
+ */
97
+ export const downloadPng = async (editor, background) => {
98
+ const blob = await exportSceneToPng(editor.scene, {
99
+ background,
100
+ scale: PNG_EXPORT_SCALE,
101
+ backgroundColor: readCanvasBackgroundColor(),
102
+ });
103
+ if (!blob) {
104
+ notify("Nothing to export — the canvas is empty.");
105
+ return;
106
+ }
107
+ downloadBlob(blob, "scene.png");
108
+ };
109
+ /** "Export as SVG" — vector export via `renderSceneToSvg`. */
110
+ export const downloadSvg = (scene) => {
111
+ const svg = renderSceneToSvg(scene);
112
+ downloadBlob(new Blob([svg], { type: "image/svg+xml" }), "scene.svg");
113
+ };
114
+ /**
115
+ * "Copy as image" — writes a PNG of the full scene to the system
116
+ * clipboard via the async Clipboard API. SVG-to-clipboard is a follow-up
117
+ * (no reliable cross-browser `image/svg+xml` clipboard support today, so
118
+ * we ship the PNG path that works everywhere the API exists).
119
+ */
120
+ export const copySceneAsImage = async (editor) => {
121
+ // `navigator.clipboard` is typed as always-present but is absent in
122
+ // insecure contexts / older browsers, so probe it through an optional cast.
123
+ const clipboard = typeof navigator === "undefined" ? undefined : navigator.clipboard;
124
+ if (typeof clipboard?.write !== "function" || typeof ClipboardItem === "undefined") {
125
+ notify("Copy to clipboard isn't supported in this browser.");
126
+ return;
127
+ }
128
+ const blob = await exportSceneToPng(editor.scene, {
129
+ background: "color",
130
+ scale: PNG_EXPORT_SCALE,
131
+ backgroundColor: readCanvasBackgroundColor(),
132
+ });
133
+ if (!blob) {
134
+ notify("Nothing to copy — the canvas is empty.");
135
+ return;
136
+ }
137
+ try {
138
+ await clipboard.write([new ClipboardItem({ "image/png": blob })]);
139
+ }
140
+ catch (err) {
141
+ console.error("[diagram] copy-as-image failed:", err);
142
+ notify("Couldn't copy the image to the clipboard.");
143
+ }
144
+ };
145
+ /**
146
+ * File-ops actions. `save` / `export` / `copy-as-image` are flagged
147
+ * `viewMode` (non-mutating — fine in read-only); `open` replaces the
148
+ * document, so it stays gated in read-only.
149
+ */
150
+ export const fileActions = [
151
+ {
152
+ id: "save-scene",
153
+ label: "Save as JSON",
154
+ category: "other",
155
+ viewMode: true,
156
+ hotkey: { key: "s", meta: true },
157
+ perform: ({ editor }) => {
158
+ downloadScene(editor.scene);
159
+ },
160
+ },
161
+ {
162
+ id: "open-scene",
163
+ label: "Open…",
164
+ category: "other",
165
+ hotkey: { key: "o", meta: true },
166
+ perform: ({ editor }) => {
167
+ openSceneFile(editor);
168
+ },
169
+ },
170
+ {
171
+ id: "export-png",
172
+ label: "Export as PNG",
173
+ category: "other",
174
+ viewMode: true,
175
+ hotkey: { key: "e", meta: true, shift: true },
176
+ perform: ({ editor }) => {
177
+ void downloadPng(editor, "color");
178
+ },
179
+ },
180
+ {
181
+ id: "copy-as-image",
182
+ label: "Copy as image",
183
+ category: "other",
184
+ viewMode: true,
185
+ // ⇧⌥C — distinct from ⌘C (copy selection) and ⌥⌘C (copy style).
186
+ hotkey: { key: "c", shift: true, alt: true },
187
+ perform: ({ editor }) => {
188
+ void copySceneAsImage(editor);
189
+ },
190
+ },
191
+ ];
192
+ /**
193
+ * Register the file-ops actions on a registry (defaults to the shared
194
+ * {@link defaultActionRegistry}). Idempotent — safe to call on every
195
+ * `<Editor>` mount; re-registers in place via `replace`.
196
+ */
197
+ export const registerFileActions = (registry = defaultActionRegistry) => {
198
+ for (const action of fileActions)
199
+ registry.replace(action);
200
+ };
201
+ //# sourceMappingURL=file-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-actions.js","sourceRoot":"","sources":["../src/file-actions.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -22,13 +22,21 @@ export { detectCapabilities, logCapabilities, type CapabilityProfile, type Capab
22
22
  export { isEditableTarget } from "./dom-focus.js";
23
23
  export { bindEditorHotkeys, type HotkeyBindingOptions } from "@oh-just-another/state";
24
24
  export { exportSceneToPng, type PngExportBackground, type PngExportOptions } from "./png-export.js";
25
+ export { fileActions, registerFileActions, setFileActionNotifier, downloadScene, downloadSvg, downloadPng, openSceneFile, copySceneAsImage, } from "./file-actions.js";
25
26
  export { registerBounder, registerLayoutKind } from "@oh-just-another/scene";
26
27
  export { registerElementRenderer, registerAnimationAdapter } from "@oh-just-another/renderer-core";
28
+ export { registerInteractiveHitTester, registerRotateAnchor } from "@oh-just-another/state";
27
29
  export { registerMigration } from "@oh-just-another/serialization";
30
+ export { defineShape, type ShapeSpec, type ShapeRegistration } from "./define-shape.js";
28
31
  export { installGifAnimationAdapter } from "./gif-animation.js";
29
32
  export type { ElementId } from "@oh-just-another/types";
30
- export type { Editor as EditorInstance, Mode, FileDropHandler } from "@oh-just-another/state";
31
- export type { Scene, LayoutKindEntry } from "@oh-just-another/scene";
33
+ export type { ActiveTool, Editor as EditorInstance, Mode, FileDropHandler, } from "@oh-just-another/state";
34
+ export { clampCrop, computeConvertType, computeSetImageCrop, computeCommitImageCrop, computeSpawnConnectedNode, cropFullImageLocalRect, cropHandleWorldPoints, computeCropHandleDrag, computeCropBodyPan, CROP_HANDLES, FULL_CROP, pickColorAt, } from "@oh-just-another/state";
35
+ export type { ConvertTarget, CropDragResult, CropHandle, SpawnDirection, } from "@oh-just-another/state";
36
+ export type { ImageCrop } from "@oh-just-another/scene";
37
+ export type { Scene, LayoutKindEntry, ElementBase, ElementBounder, AnchorRef, } from "@oh-just-another/scene";
38
+ export type { ElementRenderer, RenderTarget } from "@oh-just-another/renderer-core";
39
+ export type { InteractiveHitTester } from "@oh-just-another/state";
32
40
  export type { Template } from "@oh-just-another/templates";
33
41
  export type { AnimatedSourceAdapter } from "@oh-just-another/renderer-core";
34
42
  export type { RendererBackend } from "@oh-just-another/renderer-canvas";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,OAAO,IAAI,MAAM,EACjB,OAAO,EACP,KAAK,UAAU,IAAI,SAAS,EAC5B,KAAK,UAAU,EACf,KAAK,YAAY,IAAI,WAAW,EAChC,KAAK,YAAY,EACjB,KAAK,YAAY,IAAI,WAAW,EAChC,KAAK,YAAY,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAKpG,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AACnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAOhE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,YAAY,EAAE,MAAM,IAAI,cAAc,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9F,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACrE,YAAY,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5E,YAAY,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,OAAO,IAAI,MAAM,EACjB,OAAO,EACP,KAAK,UAAU,IAAI,SAAS,EAC5B,KAAK,UAAU,EACf,KAAK,YAAY,IAAI,WAAW,EAChC,KAAK,YAAY,EACjB,KAAK,YAAY,IAAI,WAAW,EAChC,KAAK,YAAY,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAIpG,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,WAAW,EACX,WAAW,EACX,aAAa,EACb,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AACnG,OAAO,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGxF,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAOhE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,YAAY,EACV,UAAU,EACV,MAAM,IAAI,cAAc,EACxB,IAAI,EACJ,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,aAAa,EACb,cAAc,EACd,UAAU,EACV,cAAc,GACf,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,YAAY,EACV,KAAK,EACL,eAAe,EACf,WAAW,EACX,cAAc,EACd,SAAS,GACV,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACpF,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,YAAY,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5E,YAAY,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC"}
package/dist/index.js CHANGED
@@ -22,13 +22,23 @@ export { detectCapabilities, logCapabilities, } from "./capabilities.js";
22
22
  export { isEditableTarget } from "./dom-focus.js";
23
23
  export { bindEditorHotkeys } from "@oh-just-another/state";
24
24
  export { exportSceneToPng } from "./png-export.js";
25
+ // File operations (Save / Open / Export / Copy-as-image) — registered on
26
+ // the action registry by `<Editor>`; exported so hosts can wire them to
27
+ // their own chrome or a custom registry.
28
+ export { fileActions, registerFileActions, setFileActionNotifier, downloadScene, downloadSvg, downloadPng, openSceneFile, copySceneAsImage, } from "./file-actions.js";
25
29
  // Plug-in registries from the underlying packages, surfaced here so the
26
30
  // umbrella package is the single import for extending the editor without
27
31
  // reaching into the lower-level packages.
28
32
  export { registerBounder, registerLayoutKind } from "@oh-just-another/scene";
29
33
  export { registerElementRenderer, registerAnimationAdapter } from "@oh-just-another/renderer-core";
34
+ export { registerInteractiveHitTester, registerRotateAnchor } from "@oh-just-another/state";
30
35
  export { registerMigration } from "@oh-just-another/serialization";
36
+ // `defineShape` — one-call facade over the registries above for adding a
37
+ // custom shape type (bounds + render + optional interaction hooks).
38
+ export { defineShape } from "./define-shape.js";
31
39
  // Built-in GIF decoder — `<Editor>` installs it by default; exported so hosts
32
40
  // can install it explicitly or opt into it without the component.
33
41
  export { installGifAnimationAdapter } from "./gif-animation.js";
42
+ // Tool operations + types (eyedropper / convert-type / image-crop / spawn).
43
+ export { clampCrop, computeConvertType, computeSetImageCrop, computeCommitImageCrop, computeSpawnConnectedNode, cropFullImageLocalRect, cropHandleWorldPoints, computeCropHandleDrag, computeCropBodyPan, CROP_HANDLES, FULL_CROP, pickColorAt, } from "@oh-just-another/state";
34
44
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,OAAO,IAAI,MAAM,EACjB,OAAO,GAOR,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,eAAe,GAGhB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAA6B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAmD,MAAM,iBAAiB,CAAC;AAEpG,wEAAwE;AACxE,yEAAyE;AACzE,0CAA0C;AAC1C,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AACnG,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,8EAA8E;AAC9E,kEAAkE;AAClE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,OAAO,IAAI,MAAM,EACjB,OAAO,GAOR,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,eAAe,GAGhB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAA6B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAmD,MAAM,iBAAiB,CAAC;AACpG,yEAAyE;AACzE,wEAAwE;AACxE,yCAAyC;AACzC,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,WAAW,EACX,WAAW,EACX,aAAa,EACb,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,wEAAwE;AACxE,yEAAyE;AACzE,0CAA0C;AAC1C,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AACnG,OAAO,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC5F,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,yEAAyE;AACzE,oEAAoE;AACpE,OAAO,EAAE,WAAW,EAA0C,MAAM,mBAAmB,CAAC;AACxF,8EAA8E;AAC9E,kEAAkE;AAClE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAchE,4EAA4E;AAC5E,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,WAAW,GACZ,MAAM,wBAAwB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-just-another/editor",
3
- "version": "0.59.0",
3
+ "version": "0.61.0",
4
4
  "description": "Drop-in diagram editor as a single React component. Auto-detects renderer / WASM / worker capabilities and exposes a programmatic editor API.",
5
5
  "license": "MIT",
6
6
  "author": "Rustam Garifulin <rustam@n69.in>",
@@ -42,16 +42,16 @@
42
42
  "gifuct-js": "2.1.2",
43
43
  "lucide-react": "1.16.0",
44
44
  "@oh-just-another/fonts": "0.1.0",
45
- "@oh-just-another/raster-wasm": "0.57.2",
46
- "@oh-just-another/react-ui": "0.58.0",
47
- "@oh-just-another/renderer-canvas": "0.59.0",
48
- "@oh-just-another/renderer-core": "0.58.0",
49
- "@oh-just-another/renderer-svg": "0.57.2",
50
- "@oh-just-another/scene": "0.59.0",
51
- "@oh-just-another/serialization": "0.58.0",
52
- "@oh-just-another/state": "0.59.0",
53
- "@oh-just-another/templates": "0.57.2",
54
- "@oh-just-another/text-wasm": "0.57.2",
45
+ "@oh-just-another/raster-wasm": "0.57.4",
46
+ "@oh-just-another/react-ui": "0.60.0",
47
+ "@oh-just-another/renderer-canvas": "0.61.0",
48
+ "@oh-just-another/renderer-core": "0.60.0",
49
+ "@oh-just-another/renderer-svg": "0.57.4",
50
+ "@oh-just-another/scene": "0.61.0",
51
+ "@oh-just-another/serialization": "0.60.0",
52
+ "@oh-just-another/state": "0.61.0",
53
+ "@oh-just-another/templates": "0.57.4",
54
+ "@oh-just-another/text-wasm": "0.57.4",
55
55
  "@oh-just-another/types": "0.57.0"
56
56
  },
57
57
  "peerDependencies": {