@matrajs/react 0.0.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/README.md ADDED
@@ -0,0 +1,12 @@
1
+ # @matrajs/react
2
+
3
+ React bindings: `useEditor`, `useEditorState`, `useEditorFocus` and `EditorContent`.
4
+
5
+ ```bash
6
+ npm i matra @matrajs/react
7
+ ```
8
+
9
+ - Docs: https://matrajs.com
10
+ - Source: https://github.com/amrelaco/matra
11
+
12
+ MIT.
package/dist/index.cjs ADDED
@@ -0,0 +1,65 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var core = require('@matrajs/core');
6
+
7
+ // src/editor-content.tsx
8
+ function EditorContent({
9
+ editor,
10
+ ...rest
11
+ }) {
12
+ const ref = react.useRef(null);
13
+ react.useEffect(() => {
14
+ const element = ref.current;
15
+ if (!element || editor.unsafe.view) return;
16
+ editor.mount(element);
17
+ }, [editor]);
18
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, ...rest });
19
+ }
20
+ function useEditor(options) {
21
+ const ref = react.useRef(null);
22
+ if (ref.current === null) ref.current = core.createEditor(options);
23
+ const editor = ref.current;
24
+ react.useEffect(() => {
25
+ return () => {
26
+ editor.destroy();
27
+ ref.current = null;
28
+ };
29
+ }, [editor]);
30
+ return editor;
31
+ }
32
+ function useEditorState(editor, select) {
33
+ const subscribe = react.useRef((onChange) => {
34
+ const offChange = editor.on("change", onChange);
35
+ const offSelection = editor.on("selectionChange", onChange);
36
+ return () => {
37
+ offChange();
38
+ offSelection();
39
+ };
40
+ }).current;
41
+ return react.useSyncExternalStore(
42
+ subscribe,
43
+ () => select(editor),
44
+ () => select(editor)
45
+ );
46
+ }
47
+ function useEditorFocus(editor) {
48
+ const [focused, setFocused] = react.useState(false);
49
+ react.useEffect(() => {
50
+ const onFocus = editor.on("focus", () => setFocused(true));
51
+ const onBlur = editor.on("blur", () => setFocused(false));
52
+ return () => {
53
+ onFocus();
54
+ onBlur();
55
+ };
56
+ }, [editor]);
57
+ return focused;
58
+ }
59
+
60
+ exports.EditorContent = EditorContent;
61
+ exports.useEditor = useEditor;
62
+ exports.useEditorFocus = useEditorFocus;
63
+ exports.useEditorState = useEditorState;
64
+ //# sourceMappingURL=index.cjs.map
65
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/editor-content.tsx","../src/use-editor.ts"],"names":["useRef","useEffect","jsx","createEditor","useSyncExternalStore","useState"],"mappings":";;;;;;;AAcO,SAAS,aAAA,CAA2C;AAAA,EACzD,MAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA0B;AACxB,EAAA,MAAM,GAAA,GAAMA,aAA8B,IAAI,CAAA;AAE9C,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAU,GAAA,CAAI,OAAA;AACpB,IAAA,IAAI,CAAC,OAAA,IAAW,MAAA,CAAO,MAAA,CAAO,IAAA,EAAM;AACpC,IAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AAAA,EACtB,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,uBAAOC,cAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAW,GAAG,IAAA,EAAM,CAAA;AAClC;ACfO,SAAS,UACd,OAAA,EACW;AACX,EAAA,MAAM,GAAA,GAAMF,aAAyB,IAAI,CAAA;AACzC,EAAA,IAAI,IAAI,OAAA,KAAY,IAAA,EAAM,GAAA,CAAI,OAAA,GAAUG,kBAAa,OAAO,CAAA;AAC5D,EAAA,MAAM,SAAS,GAAA,CAAI,OAAA;AAEnB,EAAAF,gBAAU,MAAM;AACd,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,CAAO,OAAA,EAAQ;AACf,MAAA,GAAA,CAAI,OAAA,GAAU,IAAA;AAAA,IAChB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,OAAO,MAAA;AACT;AAQO,SAAS,cAAA,CACd,QACA,MAAA,EACG;AACH,EAAA,MAAM,SAAA,GAAYD,YAAAA,CAAO,CAAC,QAAA,KAAyB;AACjD,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,EAAA,CAAG,QAAA,EAAU,QAAQ,CAAA;AAC9C,IAAA,MAAM,YAAA,GAAe,MAAA,CAAO,EAAA,CAAG,iBAAA,EAAmB,QAAQ,CAAA;AAC1D,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,EAAU;AACV,MAAA,YAAA,EAAa;AAAA,IACf,CAAA;AAAA,EACF,CAAC,CAAA,CAAE,OAAA;AAEH,EAAA,OAAOI,0BAAA;AAAA,IACL,SAAA;AAAA,IACA,MAAM,OAAO,MAAM,CAAA;AAAA,IACnB,MAAM,OAAO,MAAM;AAAA,GACrB;AACF;AAGO,SAAS,eAA4C,MAAA,EAA4B;AACtF,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIC,eAAS,KAAK,CAAA;AAC5C,EAAAJ,gBAAU,MAAM;AACd,IAAA,MAAM,UAAU,MAAA,CAAO,EAAA,CAAG,SAAS,MAAM,UAAA,CAAW,IAAI,CAAC,CAAA;AACzD,IAAA,MAAM,SAAS,MAAA,CAAO,EAAA,CAAG,QAAQ,MAAM,UAAA,CAAW,KAAK,CAAC,CAAA;AACxD,IAAA,OAAO,MAAM;AACX,MAAA,OAAA,EAAQ;AACR,MAAA,MAAA,EAAO;AAAA,IACT,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AACX,EAAA,OAAO,OAAA;AACT","file":"index.cjs","sourcesContent":["import type { AnyDef, Editor } from '@matrajs/core'\nimport { useEffect, useRef } from 'react'\n\nexport interface EditorContentProps<T extends readonly AnyDef[] = readonly AnyDef[]>\n extends React.HTMLAttributes<HTMLDivElement> {\n editor: Editor<T>\n}\n\n/**\n * The element the editor mounts into.\n *\n * The mount is guarded on `unsafe.view` so StrictMode's double-invoke in\n * development cannot leave two views attached to one element.\n */\nexport function EditorContent<T extends readonly AnyDef[]>({\n editor,\n ...rest\n}: EditorContentProps<T>) {\n const ref = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n const element = ref.current\n if (!element || editor.unsafe.view) return\n editor.mount(element)\n }, [editor])\n\n return <div ref={ref} {...rest} />\n}\n","import { createEditor } from '@matrajs/core'\nimport type { AnyDef, Editor, EditorOptions } from '@matrajs/core'\nimport { useEffect, useRef, useState, useSyncExternalStore } from 'react'\n\n/**\n * Create an editor that lives for the lifetime of the component.\n *\n * The editor is created lazily on first render and destroyed on unmount.\n * Options are read once — changing them later will not recreate the editor,\n * because tearing down a live document on a prop change loses the user's work.\n * Use the returned editor's commands to change things instead.\n */\nexport function useEditor<const T extends readonly AnyDef[]>(\n options: EditorOptions<T>,\n): Editor<T> {\n const ref = useRef<Editor<T> | null>(null)\n if (ref.current === null) ref.current = createEditor(options)\n const editor = ref.current\n\n useEffect(() => {\n return () => {\n editor.destroy()\n ref.current = null\n }\n }, [editor])\n\n return editor\n}\n\n/**\n * Re-render when the editor changes.\n *\n * Toolbars need this: without it, `editor.commands` mutate the document but\n * React never hears about it, so active states go stale.\n */\nexport function useEditorState<T extends readonly AnyDef[], S>(\n editor: Editor<T>,\n select: (editor: Editor<T>) => S,\n): S {\n const subscribe = useRef((onChange: () => void) => {\n const offChange = editor.on('change', onChange)\n const offSelection = editor.on('selectionChange', onChange)\n return () => {\n offChange()\n offSelection()\n }\n }).current\n\n return useSyncExternalStore(\n subscribe,\n () => select(editor),\n () => select(editor),\n )\n}\n\n/** True while the editor has DOM focus. */\nexport function useEditorFocus<T extends readonly AnyDef[]>(editor: Editor<T>): boolean {\n const [focused, setFocused] = useState(false)\n useEffect(() => {\n const onFocus = editor.on('focus', () => setFocused(true))\n const onBlur = editor.on('blur', () => setFocused(false))\n return () => {\n onFocus()\n onBlur()\n }\n }, [editor])\n return focused\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import * as react from 'react';
2
+ import { AnyDef, Editor, EditorOptions } from '@matrajs/core';
3
+
4
+ interface EditorContentProps<T extends readonly AnyDef[] = readonly AnyDef[]> extends React.HTMLAttributes<HTMLDivElement> {
5
+ editor: Editor<T>;
6
+ }
7
+ /**
8
+ * The element the editor mounts into.
9
+ *
10
+ * The mount is guarded on `unsafe.view` so StrictMode's double-invoke in
11
+ * development cannot leave two views attached to one element.
12
+ */
13
+ declare function EditorContent<T extends readonly AnyDef[]>({ editor, ...rest }: EditorContentProps<T>): react.JSX.Element;
14
+
15
+ /**
16
+ * Create an editor that lives for the lifetime of the component.
17
+ *
18
+ * The editor is created lazily on first render and destroyed on unmount.
19
+ * Options are read once — changing them later will not recreate the editor,
20
+ * because tearing down a live document on a prop change loses the user's work.
21
+ * Use the returned editor's commands to change things instead.
22
+ */
23
+ declare function useEditor<const T extends readonly AnyDef[]>(options: EditorOptions<T>): Editor<T>;
24
+ /**
25
+ * Re-render when the editor changes.
26
+ *
27
+ * Toolbars need this: without it, `editor.commands` mutate the document but
28
+ * React never hears about it, so active states go stale.
29
+ */
30
+ declare function useEditorState<T extends readonly AnyDef[], S>(editor: Editor<T>, select: (editor: Editor<T>) => S): S;
31
+ /** True while the editor has DOM focus. */
32
+ declare function useEditorFocus<T extends readonly AnyDef[]>(editor: Editor<T>): boolean;
33
+
34
+ export { EditorContent, type EditorContentProps, useEditor, useEditorFocus, useEditorState };
@@ -0,0 +1,34 @@
1
+ import * as react from 'react';
2
+ import { AnyDef, Editor, EditorOptions } from '@matrajs/core';
3
+
4
+ interface EditorContentProps<T extends readonly AnyDef[] = readonly AnyDef[]> extends React.HTMLAttributes<HTMLDivElement> {
5
+ editor: Editor<T>;
6
+ }
7
+ /**
8
+ * The element the editor mounts into.
9
+ *
10
+ * The mount is guarded on `unsafe.view` so StrictMode's double-invoke in
11
+ * development cannot leave two views attached to one element.
12
+ */
13
+ declare function EditorContent<T extends readonly AnyDef[]>({ editor, ...rest }: EditorContentProps<T>): react.JSX.Element;
14
+
15
+ /**
16
+ * Create an editor that lives for the lifetime of the component.
17
+ *
18
+ * The editor is created lazily on first render and destroyed on unmount.
19
+ * Options are read once — changing them later will not recreate the editor,
20
+ * because tearing down a live document on a prop change loses the user's work.
21
+ * Use the returned editor's commands to change things instead.
22
+ */
23
+ declare function useEditor<const T extends readonly AnyDef[]>(options: EditorOptions<T>): Editor<T>;
24
+ /**
25
+ * Re-render when the editor changes.
26
+ *
27
+ * Toolbars need this: without it, `editor.commands` mutate the document but
28
+ * React never hears about it, so active states go stale.
29
+ */
30
+ declare function useEditorState<T extends readonly AnyDef[], S>(editor: Editor<T>, select: (editor: Editor<T>) => S): S;
31
+ /** True while the editor has DOM focus. */
32
+ declare function useEditorFocus<T extends readonly AnyDef[]>(editor: Editor<T>): boolean;
33
+
34
+ export { EditorContent, type EditorContentProps, useEditor, useEditorFocus, useEditorState };
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ import { useRef, useEffect, useSyncExternalStore, useState } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { createEditor } from '@matrajs/core';
4
+
5
+ // src/editor-content.tsx
6
+ function EditorContent({
7
+ editor,
8
+ ...rest
9
+ }) {
10
+ const ref = useRef(null);
11
+ useEffect(() => {
12
+ const element = ref.current;
13
+ if (!element || editor.unsafe.view) return;
14
+ editor.mount(element);
15
+ }, [editor]);
16
+ return /* @__PURE__ */ jsx("div", { ref, ...rest });
17
+ }
18
+ function useEditor(options) {
19
+ const ref = useRef(null);
20
+ if (ref.current === null) ref.current = createEditor(options);
21
+ const editor = ref.current;
22
+ useEffect(() => {
23
+ return () => {
24
+ editor.destroy();
25
+ ref.current = null;
26
+ };
27
+ }, [editor]);
28
+ return editor;
29
+ }
30
+ function useEditorState(editor, select) {
31
+ const subscribe = useRef((onChange) => {
32
+ const offChange = editor.on("change", onChange);
33
+ const offSelection = editor.on("selectionChange", onChange);
34
+ return () => {
35
+ offChange();
36
+ offSelection();
37
+ };
38
+ }).current;
39
+ return useSyncExternalStore(
40
+ subscribe,
41
+ () => select(editor),
42
+ () => select(editor)
43
+ );
44
+ }
45
+ function useEditorFocus(editor) {
46
+ const [focused, setFocused] = useState(false);
47
+ useEffect(() => {
48
+ const onFocus = editor.on("focus", () => setFocused(true));
49
+ const onBlur = editor.on("blur", () => setFocused(false));
50
+ return () => {
51
+ onFocus();
52
+ onBlur();
53
+ };
54
+ }, [editor]);
55
+ return focused;
56
+ }
57
+
58
+ export { EditorContent, useEditor, useEditorFocus, useEditorState };
59
+ //# sourceMappingURL=index.js.map
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/editor-content.tsx","../src/use-editor.ts"],"names":["useRef","useEffect"],"mappings":";;;;;AAcO,SAAS,aAAA,CAA2C;AAAA,EACzD,MAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA0B;AACxB,EAAA,MAAM,GAAA,GAAM,OAA8B,IAAI,CAAA;AAE9C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,UAAU,GAAA,CAAI,OAAA;AACpB,IAAA,IAAI,CAAC,OAAA,IAAW,MAAA,CAAO,MAAA,CAAO,IAAA,EAAM;AACpC,IAAA,MAAA,CAAO,MAAM,OAAO,CAAA;AAAA,EACtB,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAW,GAAG,IAAA,EAAM,CAAA;AAClC;ACfO,SAAS,UACd,OAAA,EACW;AACX,EAAA,MAAM,GAAA,GAAMA,OAAyB,IAAI,CAAA;AACzC,EAAA,IAAI,IAAI,OAAA,KAAY,IAAA,EAAM,GAAA,CAAI,OAAA,GAAU,aAAa,OAAO,CAAA;AAC5D,EAAA,MAAM,SAAS,GAAA,CAAI,OAAA;AAEnB,EAAAC,UAAU,MAAM;AACd,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,CAAO,OAAA,EAAQ;AACf,MAAA,GAAA,CAAI,OAAA,GAAU,IAAA;AAAA,IAChB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,OAAO,MAAA;AACT;AAQO,SAAS,cAAA,CACd,QACA,MAAA,EACG;AACH,EAAA,MAAM,SAAA,GAAYD,MAAAA,CAAO,CAAC,QAAA,KAAyB;AACjD,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,EAAA,CAAG,QAAA,EAAU,QAAQ,CAAA;AAC9C,IAAA,MAAM,YAAA,GAAe,MAAA,CAAO,EAAA,CAAG,iBAAA,EAAmB,QAAQ,CAAA;AAC1D,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,EAAU;AACV,MAAA,YAAA,EAAa;AAAA,IACf,CAAA;AAAA,EACF,CAAC,CAAA,CAAE,OAAA;AAEH,EAAA,OAAO,oBAAA;AAAA,IACL,SAAA;AAAA,IACA,MAAM,OAAO,MAAM,CAAA;AAAA,IACnB,MAAM,OAAO,MAAM;AAAA,GACrB;AACF;AAGO,SAAS,eAA4C,MAAA,EAA4B;AACtF,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAAC,UAAU,MAAM;AACd,IAAA,MAAM,UAAU,MAAA,CAAO,EAAA,CAAG,SAAS,MAAM,UAAA,CAAW,IAAI,CAAC,CAAA;AACzD,IAAA,MAAM,SAAS,MAAA,CAAO,EAAA,CAAG,QAAQ,MAAM,UAAA,CAAW,KAAK,CAAC,CAAA;AACxD,IAAA,OAAO,MAAM;AACX,MAAA,OAAA,EAAQ;AACR,MAAA,MAAA,EAAO;AAAA,IACT,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AACX,EAAA,OAAO,OAAA;AACT","file":"index.js","sourcesContent":["import type { AnyDef, Editor } from '@matrajs/core'\nimport { useEffect, useRef } from 'react'\n\nexport interface EditorContentProps<T extends readonly AnyDef[] = readonly AnyDef[]>\n extends React.HTMLAttributes<HTMLDivElement> {\n editor: Editor<T>\n}\n\n/**\n * The element the editor mounts into.\n *\n * The mount is guarded on `unsafe.view` so StrictMode's double-invoke in\n * development cannot leave two views attached to one element.\n */\nexport function EditorContent<T extends readonly AnyDef[]>({\n editor,\n ...rest\n}: EditorContentProps<T>) {\n const ref = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n const element = ref.current\n if (!element || editor.unsafe.view) return\n editor.mount(element)\n }, [editor])\n\n return <div ref={ref} {...rest} />\n}\n","import { createEditor } from '@matrajs/core'\nimport type { AnyDef, Editor, EditorOptions } from '@matrajs/core'\nimport { useEffect, useRef, useState, useSyncExternalStore } from 'react'\n\n/**\n * Create an editor that lives for the lifetime of the component.\n *\n * The editor is created lazily on first render and destroyed on unmount.\n * Options are read once — changing them later will not recreate the editor,\n * because tearing down a live document on a prop change loses the user's work.\n * Use the returned editor's commands to change things instead.\n */\nexport function useEditor<const T extends readonly AnyDef[]>(\n options: EditorOptions<T>,\n): Editor<T> {\n const ref = useRef<Editor<T> | null>(null)\n if (ref.current === null) ref.current = createEditor(options)\n const editor = ref.current\n\n useEffect(() => {\n return () => {\n editor.destroy()\n ref.current = null\n }\n }, [editor])\n\n return editor\n}\n\n/**\n * Re-render when the editor changes.\n *\n * Toolbars need this: without it, `editor.commands` mutate the document but\n * React never hears about it, so active states go stale.\n */\nexport function useEditorState<T extends readonly AnyDef[], S>(\n editor: Editor<T>,\n select: (editor: Editor<T>) => S,\n): S {\n const subscribe = useRef((onChange: () => void) => {\n const offChange = editor.on('change', onChange)\n const offSelection = editor.on('selectionChange', onChange)\n return () => {\n offChange()\n offSelection()\n }\n }).current\n\n return useSyncExternalStore(\n subscribe,\n () => select(editor),\n () => select(editor),\n )\n}\n\n/** True while the editor has DOM focus. */\nexport function useEditorFocus<T extends readonly AnyDef[]>(editor: Editor<T>): boolean {\n const [focused, setFocused] = useState(false)\n useEffect(() => {\n const onFocus = editor.on('focus', () => setFocused(true))\n const onBlur = editor.on('blur', () => setFocused(false))\n return () => {\n onFocus()\n onBlur()\n }\n }, [editor])\n return focused\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@matrajs/react",
3
+ "version": "0.0.1",
4
+ "description": "React bindings for Matra \u2014 useEditor and EditorContent.",
5
+ "license": "MIT",
6
+ "author": "Nahim Hossain Shohan",
7
+ "homepage": "https://matrajs.com",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/amrelaco/matra.git",
11
+ "directory": "packages/react"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/amrelaco/matra/issues"
15
+ },
16
+ "keywords": [
17
+ "editor",
18
+ "rich-text",
19
+ "react",
20
+ "matra",
21
+ "prosemirror"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "type": "module",
27
+ "sideEffects": false,
28
+ "main": "./dist/index.cjs",
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.js",
35
+ "require": "./dist/index.cjs"
36
+ }
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md"
41
+ ],
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "clean": "rm -rf dist"
45
+ },
46
+ "dependencies": {
47
+ "@matrajs/core": "workspace:*"
48
+ },
49
+ "peerDependencies": {
50
+ "react": "^18 || ^19"
51
+ },
52
+ "devDependencies": {
53
+ "@types/react": "^18.3.12",
54
+ "react": "^18.3.1",
55
+ "react-dom": "^18.3.1"
56
+ }
57
+ }