@grida/svg-editor 1.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.mjs ADDED
@@ -0,0 +1,92 @@
1
+ "use client";
2
+ import { t as createSvgEditor } from "./editor-B5z-gTML.mjs";
3
+ import { t as attach_dom_surface } from "./dom-kA8NDuVh.mjs";
4
+ import { createContext, useContext, useEffect, useMemo, useRef, useSyncExternalStore } from "react";
5
+ import { jsx } from "react/jsx-runtime";
6
+ //#region src/react.tsx
7
+ const SvgEditorContext = createContext(null);
8
+ /**
9
+ * Owns the headless editor and exposes it via context. The editor is created
10
+ * once on first render; subsequent prop changes to `svg` call `editor.load()`.
11
+ */
12
+ function SvgEditorProvider({ svg, providers, style, children }) {
13
+ const editor_ref = useRef(null);
14
+ if (editor_ref.current === null) editor_ref.current = createSvgEditor({
15
+ svg,
16
+ providers,
17
+ style
18
+ });
19
+ const editor = editor_ref.current;
20
+ const last_svg = useRef(svg);
21
+ useEffect(() => {
22
+ if (last_svg.current !== svg) {
23
+ editor.load(svg);
24
+ last_svg.current = svg;
25
+ }
26
+ }, [svg, editor]);
27
+ useEffect(() => {
28
+ return () => {
29
+ editor.dispose();
30
+ };
31
+ }, [editor]);
32
+ return /* @__PURE__ */ jsx(SvgEditorContext.Provider, {
33
+ value: editor,
34
+ children
35
+ });
36
+ }
37
+ /**
38
+ * Renders the editor's SVG into a `div` and wires it to the DOM surface.
39
+ *
40
+ * Internally calls `attach_dom_surface(editor, { container })` on mount and
41
+ * `handle.detach()` on unmount. This is the only UI component the package
42
+ * ships; everything else (toolbar, property panel, etc.) is consumer-built.
43
+ */
44
+ function SvgEditorCanvas({ className, style }) {
45
+ const editor = useSvgEditor();
46
+ const ref = useRef(null);
47
+ useEffect(() => {
48
+ const container = ref.current;
49
+ if (!container) return;
50
+ const handle = attach_dom_surface(editor, { container });
51
+ return () => handle.detach();
52
+ }, [editor]);
53
+ return /* @__PURE__ */ jsx("div", {
54
+ ref,
55
+ className,
56
+ style
57
+ });
58
+ }
59
+ function useSvgEditor() {
60
+ const editor = useContext(SvgEditorContext);
61
+ if (editor === null) throw new Error("useSvgEditor must be used inside a <SvgEditorProvider>.");
62
+ return editor;
63
+ }
64
+ /**
65
+ * Subscribe to a slice of `editor.state`. Re-renders when the selected slice
66
+ * changes by reference (or by the supplied `equals` function).
67
+ */
68
+ function useEditorState(selector, equals = Object.is) {
69
+ const editor = useSvgEditor();
70
+ const last_ref = useRef({
71
+ has: false,
72
+ value: void 0
73
+ });
74
+ return useSyncExternalStore((cb) => editor.subscribe(cb), () => {
75
+ const next = selector(editor.state);
76
+ if (!last_ref.current.has || !equals(last_ref.current.value, next)) last_ref.current = {
77
+ has: true,
78
+ value: next
79
+ };
80
+ return last_ref.current.value;
81
+ }, () => selector(editor.state));
82
+ }
83
+ /**
84
+ * Sugar for `useSvgEditor().commands`. The returned object is stable across
85
+ * re-renders (commands themselves don't change identity).
86
+ */
87
+ function useCommands() {
88
+ const editor = useSvgEditor();
89
+ return useMemo(() => editor.commands, [editor]);
90
+ }
91
+ //#endregion
92
+ export { SvgEditorCanvas, SvgEditorProvider, useCommands, useEditorState, useSvgEditor };
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@grida/svg-editor",
3
+ "version": "1.0.0-alpha.1",
4
+ "description": "Headless SVG editor (experimental).",
5
+ "license": "MIT",
6
+ "author": "Grida",
7
+ "repository": "https://github.com/gridaco/grida",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "main": "./dist/index.js",
12
+ "module": "./dist/index.mjs",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.mjs",
18
+ "require": "./dist/index.js"
19
+ },
20
+ "./dom": {
21
+ "types": "./dist/dom.d.ts",
22
+ "import": "./dist/dom.mjs",
23
+ "require": "./dist/dom.js"
24
+ },
25
+ "./react": {
26
+ "types": "./dist/react.d.ts",
27
+ "import": "./dist/react.mjs",
28
+ "require": "./dist/react.js"
29
+ }
30
+ },
31
+ "publishConfig": {
32
+ "access": "public",
33
+ "tag": "alpha"
34
+ },
35
+ "dependencies": {
36
+ "svg-pathdata": "^7.2.0",
37
+ "@grida/hud": "0.1.0",
38
+ "@grida/history": "0.1.0",
39
+ "@grida/cmath": "0.1.0",
40
+ "@grida/keybinding": "0.1.0",
41
+ "@grida/text-editor": "0.1.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/react": "^19",
45
+ "react": "^19",
46
+ "tsdown": "^0.21.9",
47
+ "typescript": "^6",
48
+ "vitest": "^4"
49
+ },
50
+ "peerDependencies": {
51
+ "react": ">=18"
52
+ },
53
+ "peerDependenciesMeta": {
54
+ "react": {
55
+ "optional": true
56
+ }
57
+ },
58
+ "scripts": {
59
+ "bench": "vitest bench --run",
60
+ "build": "tsdown",
61
+ "dev": "tsdown --watch",
62
+ "test": "vitest run",
63
+ "test:watch": "vitest",
64
+ "typecheck": "tsc --noEmit"
65
+ }
66
+ }