ritext 1.0.28 → 1.2.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.
package/README.md CHANGED
@@ -1,16 +1,71 @@
1
- <picture>
2
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/logo/logo-white.png">
3
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/logo/logo-black.png">
4
- <img alt="Siam Ahnaf" src="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/logo/logo-black.png" height="auto" width="240">
5
- </picture>
6
- <br/> <br/>
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/logo/logo-white.png">
4
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/logo/logo-black.png">
5
+ <img alt="Ritext" src="https://raw.githubusercontent.com/siamahnaf/assets-kit/main/logo/logo-black.png" width="240">
6
+ </picture>
7
+ </p>
7
8
 
8
- # Ritext
9
- Ritext is a modern WYSIWYG rich text editor built with Tailwind CSS, powered by Tiptap. It offers a customizable UI and functional layer that lets you design your own editor controls and toolbars with clean, composable React components—no heavy UI, no extra dependencies beyond Tiptap.
9
+ <p align="center">
10
+ <b>Ritext</b> A modern, composable WYSIWYG rich text editor built with <b>Tailwind CSS</b>, powered by <b>Tiptap</b>.
11
+ <br />
12
+ Build your own toolbars & controls with clean React components — no heavy UI layer, no extra dependencies beyond Tiptap.
13
+ </p>
10
14
 
11
- <a href="https://www.buymeacoffee.com/siamahnaf" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
15
+ <p align="center">
16
+ <a href="https://www.npmjs.com/package/ritext"><img alt="npm" src="https://img.shields.io/npm/v/ritext?logo=npm"></a>
17
+ <a href="https://www.npmjs.com/package/ritext"><img alt="downloads" src="https://img.shields.io/npm/dm/ritext"></a>
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="https://www.buymeacoffee.com/siamahnaf" target="_blank">
22
+ <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="48">
23
+ </a>
24
+ </p>
25
+
26
+ ---
27
+
28
+ ## ✨ Why Ritext?
29
+ - **Composable UI**: bring your own toolbar/buttons/components
30
+ - **Tiptap-powered**: reliable ProseMirror foundation
31
+ - **Tailwind-friendly**: build modern UI fast
32
+ - **Package-first**: works great in Next.js apps & component libraries
33
+
34
+ ---
35
+
36
+ ## 📚 Docs help needed (Contributions welcome!)
37
+ Ritext is stable and production-ready — but the documentation is still growing.
38
+
39
+ If you like this project, please help by writing or improving docs:
40
+ - ✅ Installation & setup (Next.js / React)
41
+ - ✅ Basic editor example + toolbar patterns
42
+ - ✅ Extension usage & custom UI components
43
+ - ✅ Theming, styling, and Tailwind tips
44
+ - ✅ Recipes (tables, images, placeholders, slash menu, etc.)
45
+
46
+ ### Good first contribution ideas
47
+ - Add a “Getting Started” page
48
+ - Document one extension (Bold/Italic/Table/Image/etc.)
49
+ - Add small code examples + screenshots/GIFs
50
+
51
+ **Want to contribute?**
52
+ 1. Fork the repo
53
+ 2. Create a new branch: `docs/<topic>`
54
+ 3. Update or add docs inside `content/` (Markdown)
55
+ 4. Open a PR ✨
56
+
57
+ > If you’re not sure what to write, open an issue and I’ll assign you a docs task.
58
+
59
+ ---
60
+
61
+ ## 🤝 Contributing
62
+ All contributions are welcome — issues, PRs, bug reports, improvements, and docs.
63
+
64
+ - Create an issue for bugs/feature requests
65
+ - PRs should include a clear description and screenshots if UI-related
66
+
67
+ ---
12
68
 
13
- ### This is an testing phase will publish soon.
14
69
 
15
70
  ## Connect with me
16
71
  <div style="display: flex; align-items: center; gap: 3px;">
package/dist/index.d.mts CHANGED
@@ -1,15 +1,32 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { Extensions } from '@tiptap/react';
3
+ import { Extensions, JSONContent, Editor as Editor$1 } from '@tiptap/react';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
5
 
5
- interface Props$2 {
6
+ interface EditorRef {
7
+ editor: Editor$1 | null;
8
+ insert: (value: string) => void;
9
+ insertAtEnd: (value: string) => void;
10
+ replaceSelection: (value: string) => void;
11
+ focus: () => void;
12
+ getHTML: () => string;
13
+ setContent: (value: string) => void;
14
+ clear: () => void;
15
+ }
16
+ type OutputType = "html" | "json" | "text";
17
+ type ContentValue = string | JSONContent;
18
+ type EditorProps = {
6
19
  children?: ReactNode;
7
20
  extensions?: Extensions;
8
21
  className?: string;
9
22
  dragHandler?: boolean;
10
23
  showBubbleMenu?: boolean;
11
- }
12
- declare const Editor: ({ children, extensions, className, dragHandler, showBubbleMenu }: Props$2) => react_jsx_runtime.JSX.Element;
24
+ content?: ContentValue;
25
+ output?: OutputType;
26
+ onContentChange?: (value: string | JSONContent) => void;
27
+ };
28
+
29
+ declare const Editor: react.ForwardRefExoticComponent<EditorProps & react.RefAttributes<EditorRef>>;
13
30
 
14
31
  interface Props$1 {
15
32
  className?: string;
@@ -24,4 +41,4 @@ interface Props {
24
41
  }
25
42
  declare const Content: ({ className }: Props) => react_jsx_runtime.JSX.Element;
26
43
 
27
- export { Content, Editor, Toolbar };
44
+ export { Content, Editor, type EditorRef, Toolbar };
package/dist/index.d.ts CHANGED
@@ -1,15 +1,32 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { Extensions } from '@tiptap/react';
3
+ import { Extensions, JSONContent, Editor as Editor$1 } from '@tiptap/react';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
5
 
5
- interface Props$2 {
6
+ interface EditorRef {
7
+ editor: Editor$1 | null;
8
+ insert: (value: string) => void;
9
+ insertAtEnd: (value: string) => void;
10
+ replaceSelection: (value: string) => void;
11
+ focus: () => void;
12
+ getHTML: () => string;
13
+ setContent: (value: string) => void;
14
+ clear: () => void;
15
+ }
16
+ type OutputType = "html" | "json" | "text";
17
+ type ContentValue = string | JSONContent;
18
+ type EditorProps = {
6
19
  children?: ReactNode;
7
20
  extensions?: Extensions;
8
21
  className?: string;
9
22
  dragHandler?: boolean;
10
23
  showBubbleMenu?: boolean;
11
- }
12
- declare const Editor: ({ children, extensions, className, dragHandler, showBubbleMenu }: Props$2) => react_jsx_runtime.JSX.Element;
24
+ content?: ContentValue;
25
+ output?: OutputType;
26
+ onContentChange?: (value: string | JSONContent) => void;
27
+ };
28
+
29
+ declare const Editor: react.ForwardRefExoticComponent<EditorProps & react.RefAttributes<EditorRef>>;
13
30
 
14
31
  interface Props$1 {
15
32
  className?: string;
@@ -24,4 +41,4 @@ interface Props {
24
41
  }
25
42
  declare const Content: ({ className }: Props) => react_jsx_runtime.JSX.Element;
26
43
 
27
- export { Content, Editor, Toolbar };
44
+ export { Content, Editor, type EditorRef, Toolbar };
package/dist/index.js CHANGED
@@ -316,19 +316,66 @@ var EditorProvider = ({ children, value }) => {
316
316
 
317
317
  // src/lib/Editor.tsx
318
318
  var import_jsx_runtime6 = require("react/jsx-runtime");
319
- var Editor = ({ children, extensions = [], className, dragHandler = true, showBubbleMenu = true }) => {
319
+ var Editor = (0, import_react6.forwardRef)(({ children, extensions = [], className, dragHandler = true, showBubbleMenu = true, content, onContentChange, output }, ref) => {
320
320
  const stableExtensions = (0, import_react6.useMemo)(() => extensions, [extensions]);
321
321
  const editor = (0, import_react7.useEditor)({
322
322
  extensions: stableExtensions,
323
- immediatelyRender: false
323
+ immediatelyRender: false,
324
+ content,
325
+ onUpdate: ({ editor: editor2 }) => {
326
+ if (!onContentChange) return;
327
+ const out = output === "json" ? editor2.getJSON() : output === "text" ? editor2.getText() : editor2.getHTML();
328
+ onContentChange(out);
329
+ }
324
330
  }, [stableExtensions]);
325
331
  const value = (0, import_react6.useMemo)(() => ({ editor }), [editor]);
332
+ (0, import_react6.useImperativeHandle)(
333
+ ref,
334
+ () => ({
335
+ editor,
336
+ insert: (val) => {
337
+ if (!editor) return;
338
+ editor.chain().focus().insertContent(val).run();
339
+ },
340
+ insertAtEnd: (val) => {
341
+ if (!editor) return;
342
+ const end = editor.state.doc.content.size;
343
+ editor.commands.insertContentAt(end, val);
344
+ editor.commands.focus(end);
345
+ },
346
+ replaceSelection: (val) => {
347
+ if (!editor) return;
348
+ const { from, to } = editor.state.selection;
349
+ editor.commands.insertContentAt({ from, to }, val);
350
+ editor.chain().focus().run();
351
+ },
352
+ focus: () => {
353
+ if (!editor) return;
354
+ editor.chain().focus().run();
355
+ },
356
+ getHTML: () => {
357
+ var _a, _b;
358
+ return (_b = (_a = editor == null ? void 0 : editor.getHTML) == null ? void 0 : _a.call(editor)) != null ? _b : "";
359
+ },
360
+ setContent: (val) => {
361
+ if (!editor) return;
362
+ editor.commands.setContent(val);
363
+ },
364
+ clear: () => {
365
+ var _a, _b;
366
+ if (!editor) return;
367
+ (_b = (_a = editor.commands).clearContent) == null ? void 0 : _b.call(_a);
368
+ }
369
+ }),
370
+ [editor]
371
+ );
326
372
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(EditorProvider, { value: __spreadProps(__spreadValues({}, value), { dragHandler }), children: [
327
373
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, children }),
328
374
  value.editor && dragHandler && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RiDragHandler_default, { editor: value.editor }),
329
375
  value.editor && showBubbleMenu && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BubbleMenu_default, { editor: value.editor })
330
376
  ] });
331
- };
377
+ });
378
+ Editor.displayName = "Editor";
332
379
  var Editor_default = Editor;
333
380
 
334
381
  // src/lib/Toolbar.tsx
package/dist/index.mjs CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  import "@siamf/react-color-pick/dist/index.css";
17
17
 
18
18
  // src/lib/Editor.tsx
19
- import { useMemo } from "react";
19
+ import { forwardRef, useMemo, useImperativeHandle } from "react";
20
20
  import { useEditor as useEditor2 } from "@tiptap/react";
21
21
 
22
22
  // src/lib/internal_com/RiDragHandler.tsx
@@ -115,19 +115,66 @@ var BubbleMenu_default = BubbleMenu;
115
115
 
116
116
  // src/lib/Editor.tsx
117
117
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
118
- var Editor = ({ children, extensions = [], className, dragHandler = true, showBubbleMenu = true }) => {
118
+ var Editor = forwardRef(({ children, extensions = [], className, dragHandler = true, showBubbleMenu = true, content, onContentChange, output }, ref) => {
119
119
  const stableExtensions = useMemo(() => extensions, [extensions]);
120
120
  const editor = useEditor2({
121
121
  extensions: stableExtensions,
122
- immediatelyRender: false
122
+ immediatelyRender: false,
123
+ content,
124
+ onUpdate: ({ editor: editor2 }) => {
125
+ if (!onContentChange) return;
126
+ const out = output === "json" ? editor2.getJSON() : output === "text" ? editor2.getText() : editor2.getHTML();
127
+ onContentChange(out);
128
+ }
123
129
  }, [stableExtensions]);
124
130
  const value = useMemo(() => ({ editor }), [editor]);
131
+ useImperativeHandle(
132
+ ref,
133
+ () => ({
134
+ editor,
135
+ insert: (val) => {
136
+ if (!editor) return;
137
+ editor.chain().focus().insertContent(val).run();
138
+ },
139
+ insertAtEnd: (val) => {
140
+ if (!editor) return;
141
+ const end = editor.state.doc.content.size;
142
+ editor.commands.insertContentAt(end, val);
143
+ editor.commands.focus(end);
144
+ },
145
+ replaceSelection: (val) => {
146
+ if (!editor) return;
147
+ const { from, to } = editor.state.selection;
148
+ editor.commands.insertContentAt({ from, to }, val);
149
+ editor.chain().focus().run();
150
+ },
151
+ focus: () => {
152
+ if (!editor) return;
153
+ editor.chain().focus().run();
154
+ },
155
+ getHTML: () => {
156
+ var _a, _b;
157
+ return (_b = (_a = editor == null ? void 0 : editor.getHTML) == null ? void 0 : _a.call(editor)) != null ? _b : "";
158
+ },
159
+ setContent: (val) => {
160
+ if (!editor) return;
161
+ editor.commands.setContent(val);
162
+ },
163
+ clear: () => {
164
+ var _a, _b;
165
+ if (!editor) return;
166
+ (_b = (_a = editor.commands).clearContent) == null ? void 0 : _b.call(_a);
167
+ }
168
+ }),
169
+ [editor]
170
+ );
125
171
  return /* @__PURE__ */ jsxs2(EditorProvider, { value: __spreadProps(__spreadValues({}, value), { dragHandler }), children: [
126
172
  /* @__PURE__ */ jsx3("div", { className, children }),
127
173
  value.editor && dragHandler && /* @__PURE__ */ jsx3(RiDragHandler_default, { editor: value.editor }),
128
174
  value.editor && showBubbleMenu && /* @__PURE__ */ jsx3(BubbleMenu_default, { editor: value.editor })
129
175
  ] });
130
- };
176
+ });
177
+ Editor.displayName = "Editor";
131
178
  var Editor_default = Editor;
132
179
 
133
180
  // src/lib/Toolbar.tsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ritext",
3
- "version": "1.0.28",
3
+ "version": "1.2.0",
4
4
  "description": "Ritext is a modern WYSIWYG rich text editor built with Tailwind CSS, powered by Tiptap. It offers a customizable UI and functional layer that lets you design your own editor controls and toolbars with clean, composable React components—no heavy UI, no extra dependencies beyond Tiptap.",
5
5
  "homepage": "https://ritext.vercel.app/",
6
6
  "main": "dist/index.js",