@melv1c/rich-text-editor 0.0.0 → 1.0.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/dist/index.d.mts CHANGED
@@ -1 +1,253 @@
1
- export { };
1
+ import { Editor, EditorContent, useEditor } from "@tiptap/react";
2
+ import { Button, ButtonGroup, Select, SelectContent, SelectTrigger, ToggleGroup, ToggleGroupItem } from "@melv1c/ui-core";
3
+ import * as react from "react";
4
+ import { ComponentProps, HTMLAttributes } from "react";
5
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
6
+ import StarterKit from "@tiptap/starter-kit";
7
+
8
+ //#region src/content.d.ts
9
+ type RichTextEditorContentProps = Omit<ComponentProps<typeof EditorContent>, 'editor'> & {
10
+ /**
11
+ * Minimum height of the editor content area.
12
+ * Accepts a number (treated as pixels) or any valid CSS size string.
13
+ * @default 180
14
+ */
15
+ minHeight?: number | string;
16
+ /**
17
+ * Maximum height of the editor content area. When set, the content area becomes
18
+ * scrollable once the content exceeds this height.
19
+ * Accepts a number (treated as pixels) or any valid CSS size string.
20
+ */
21
+ maxHeight?: number | string;
22
+ };
23
+ declare function RichTextEditorContent({
24
+ className,
25
+ minHeight,
26
+ maxHeight,
27
+ style,
28
+ ...props
29
+ }: RichTextEditorContentProps): react_jsx_runtime0.JSX.Element;
30
+ //#endregion
31
+ //#region src/context.d.ts
32
+ type RichTextEditorContextValue = {
33
+ editor: Editor | null;
34
+ };
35
+ declare const RichTextEditorContext: react.Context<RichTextEditorContextValue | null>;
36
+ declare function useRichTextEditor(): RichTextEditorContextValue;
37
+ //#endregion
38
+ //#region src/editor.d.ts
39
+ type RichTextEditorProps = HTMLAttributes<HTMLDivElement> & {
40
+ value?: string;
41
+ defaultValue?: string;
42
+ onValueChange?: (value: string, editor: Editor) => void;
43
+ editable?: boolean;
44
+ extensions?: Parameters<typeof useEditor>[0]['extensions'];
45
+ starterKit?: Parameters<typeof StarterKit.configure>[0];
46
+ };
47
+ declare function RichTextEditor({
48
+ children,
49
+ className,
50
+ value,
51
+ defaultValue,
52
+ onValueChange,
53
+ editable,
54
+ extensions,
55
+ starterKit,
56
+ ...props
57
+ }: RichTextEditorProps): react_jsx_runtime0.JSX.Element;
58
+ //#endregion
59
+ //#region src/groups/formatting-group.d.ts
60
+ type RichTextEditorToggleButtonProps$2 = Omit<ComponentProps<typeof ToggleGroupItem>, 'value'>;
61
+ type RichTextEditorFormattingItem = 'bold' | 'italic' | 'strike' | 'code';
62
+ type RichTextEditorFormattingValue = RichTextEditorFormattingItem[];
63
+ declare function BoldButton({
64
+ className,
65
+ ...props
66
+ }: RichTextEditorToggleButtonProps$2): react_jsx_runtime0.JSX.Element;
67
+ declare function ItalicButton({
68
+ className,
69
+ ...props
70
+ }: RichTextEditorToggleButtonProps$2): react_jsx_runtime0.JSX.Element;
71
+ declare function StrikethroughButton({
72
+ className,
73
+ ...props
74
+ }: RichTextEditorToggleButtonProps$2): react_jsx_runtime0.JSX.Element;
75
+ declare function CodeButton({
76
+ className,
77
+ ...props
78
+ }: RichTextEditorToggleButtonProps$2): react_jsx_runtime0.JSX.Element;
79
+ type RichTextEditorToggleGroupProps$2 = Omit<ComponentProps<typeof ToggleGroup>, 'type' | 'value' | 'onValueChange'>;
80
+ type RichTextEditorFormattingGroupProps = RichTextEditorToggleGroupProps$2 & {
81
+ boldProps?: ComponentProps<typeof BoldButton>;
82
+ italicProps?: ComponentProps<typeof ItalicButton>;
83
+ strikethroughProps?: ComponentProps<typeof StrikethroughButton>;
84
+ codeProps?: ComponentProps<typeof CodeButton>;
85
+ items?: RichTextEditorFormattingItem[];
86
+ defaultValue?: RichTextEditorFormattingValue;
87
+ };
88
+ declare function RichTextEditorFormattingGroup({
89
+ boldProps,
90
+ italicProps,
91
+ strikethroughProps,
92
+ codeProps,
93
+ items,
94
+ variant,
95
+ size,
96
+ ...props
97
+ }: RichTextEditorFormattingGroupProps): react_jsx_runtime0.JSX.Element;
98
+ //#endregion
99
+ //#region src/groups/heading-group.d.ts
100
+ type RichTextEditorToggleButtonProps$1 = Omit<ComponentProps<typeof ToggleGroupItem>, 'value'>;
101
+ type RichTextEditorHeadingLevel = 1 | 2 | 3;
102
+ type RichTextEditorHeadingMode = 'toggle' | 'select';
103
+ type RichTextEditorHeadingValue = `heading-${RichTextEditorHeadingLevel}` | '';
104
+ declare function Heading1Button({
105
+ className,
106
+ ...props
107
+ }: RichTextEditorToggleButtonProps$1): react_jsx_runtime0.JSX.Element;
108
+ declare function Heading2Button({
109
+ className,
110
+ ...props
111
+ }: RichTextEditorToggleButtonProps$1): react_jsx_runtime0.JSX.Element;
112
+ declare function Heading3Button({
113
+ className,
114
+ ...props
115
+ }: RichTextEditorToggleButtonProps$1): react_jsx_runtime0.JSX.Element;
116
+ type RichTextEditorToggleGroupProps$1 = Omit<ComponentProps<typeof ToggleGroup>, 'type' | 'value' | 'onValueChange'>;
117
+ type RichTextEditorHeadingSelectProps = Omit<ComponentProps<typeof Select>, 'value' | 'onValueChange'>;
118
+ type RichTextEditorHeadingGroupProps = RichTextEditorToggleGroupProps$1 & {
119
+ mode?: RichTextEditorHeadingMode;
120
+ levels?: RichTextEditorHeadingLevel[];
121
+ heading1Props?: ComponentProps<typeof Heading1Button>;
122
+ heading2Props?: ComponentProps<typeof Heading2Button>;
123
+ heading3Props?: ComponentProps<typeof Heading3Button>;
124
+ includeParagraphOption?: boolean;
125
+ paragraphLabel?: string;
126
+ selectPlaceholder?: string;
127
+ selectProps?: RichTextEditorHeadingSelectProps;
128
+ selectTriggerProps?: Omit<ComponentProps<typeof SelectTrigger>, 'children'>;
129
+ selectContentProps?: ComponentProps<typeof SelectContent>;
130
+ defaultValue?: RichTextEditorHeadingValue;
131
+ };
132
+ declare function RichTextEditorHeadingGroup({
133
+ mode,
134
+ levels,
135
+ heading1Props,
136
+ heading2Props,
137
+ heading3Props,
138
+ includeParagraphOption,
139
+ paragraphLabel,
140
+ selectPlaceholder,
141
+ selectProps,
142
+ selectTriggerProps,
143
+ selectContentProps,
144
+ variant,
145
+ size,
146
+ ...props
147
+ }: RichTextEditorHeadingGroupProps): react_jsx_runtime0.JSX.Element;
148
+ //#endregion
149
+ //#region src/groups/history-group.d.ts
150
+ type RichTextEditorActionButtonProps = ComponentProps<typeof Button>;
151
+ type RichTextEditorHistoryItem = 'undo' | 'redo';
152
+ declare function UndoButton({
153
+ className,
154
+ ...props
155
+ }: RichTextEditorActionButtonProps): react_jsx_runtime0.JSX.Element;
156
+ declare function RedoButton({
157
+ className,
158
+ ...props
159
+ }: RichTextEditorActionButtonProps): react_jsx_runtime0.JSX.Element;
160
+ type RichTextEditorHistoryGroupProps = ComponentProps<typeof ButtonGroup> & {
161
+ undoProps?: ComponentProps<typeof UndoButton>;
162
+ redoProps?: ComponentProps<typeof RedoButton>;
163
+ items?: RichTextEditorHistoryItem[];
164
+ };
165
+ declare function RichTextEditorHistoryGroup({
166
+ undoProps,
167
+ redoProps,
168
+ items,
169
+ ...props
170
+ }: RichTextEditorHistoryGroupProps): react_jsx_runtime0.JSX.Element;
171
+ //#endregion
172
+ //#region src/groups/list-group.d.ts
173
+ type RichTextEditorToggleButtonProps = Omit<ComponentProps<typeof ToggleGroupItem>, 'value'>;
174
+ type RichTextEditorListValue = 'bullet-list' | 'ordered-list' | '';
175
+ type RichTextEditorListItem = Exclude<RichTextEditorListValue, ''>;
176
+ declare function BulletListButton({
177
+ className,
178
+ ...props
179
+ }: RichTextEditorToggleButtonProps): react_jsx_runtime0.JSX.Element;
180
+ declare function OrderedListButton({
181
+ className,
182
+ ...props
183
+ }: RichTextEditorToggleButtonProps): react_jsx_runtime0.JSX.Element;
184
+ type RichTextEditorToggleGroupProps = Omit<ComponentProps<typeof ToggleGroup>, 'type' | 'value' | 'onValueChange'>;
185
+ type RichTextEditorListGroupProps = RichTextEditorToggleGroupProps & {
186
+ bulletListProps?: ComponentProps<typeof BulletListButton>;
187
+ orderedListProps?: ComponentProps<typeof OrderedListButton>;
188
+ items?: RichTextEditorListItem[];
189
+ defaultValue?: RichTextEditorListValue;
190
+ };
191
+ declare function RichTextEditorListGroup({
192
+ bulletListProps,
193
+ orderedListProps,
194
+ items,
195
+ variant,
196
+ size,
197
+ ...props
198
+ }: RichTextEditorListGroupProps): react_jsx_runtime0.JSX.Element;
199
+ //#endregion
200
+ //#region src/built-in.d.ts
201
+ /**
202
+ * Built-in editor presets:
203
+ * - `"minimal"`: Formatting controls (bold, italic, strike, code) + undo/redo
204
+ * - `"simple"` (default): Heading select + formatting + undo/redo
205
+ * - `"complete"`: Heading toggles + formatting + lists + undo/redo
206
+ * - `"oneline"`: No toolbar, single-line (Enter is blocked)
207
+ */
208
+ type RichTextEditorPreset = 'minimal' | 'simple' | 'complete' | 'oneline';
209
+ type RichTextEditorBuiltInProps = Omit<RichTextEditorProps, 'children'> & {
210
+ contentClassName?: string;
211
+ toolbarClassName?: string;
212
+ /**
213
+ * Selects a built-in toolbar / behaviour configuration.
214
+ * @default "complete"
215
+ */
216
+ preset?: RichTextEditorPreset;
217
+ /**
218
+ * Minimum height of the editor content area.
219
+ * Accepts a number (px) or any valid CSS size string.
220
+ * Forwarded to `RichTextEditorContent`.
221
+ */
222
+ minHeight?: RichTextEditorContentProps['minHeight'];
223
+ /**
224
+ * Maximum height of the editor content area. When set the content area becomes
225
+ * scrollable once the content exceeds this height.
226
+ * Accepts a number (px) or any valid CSS size string.
227
+ * Forwarded to `RichTextEditorContent`.
228
+ */
229
+ maxHeight?: RichTextEditorContentProps['maxHeight'];
230
+ };
231
+ declare function RichTextEditorBuiltIn({
232
+ className,
233
+ contentClassName,
234
+ toolbarClassName,
235
+ preset,
236
+ minHeight,
237
+ maxHeight,
238
+ extensions,
239
+ ...props
240
+ }: RichTextEditorBuiltInProps): react_jsx_runtime0.JSX.Element;
241
+ /** @deprecated Use `RichTextEditorBuiltIn` instead. */
242
+ declare const RichTextEditorSimple: typeof RichTextEditorBuiltIn;
243
+ /** @deprecated Use `RichTextEditorBuiltInProps` instead. */
244
+ type RichTextEditorSimpleProps = RichTextEditorBuiltInProps;
245
+ //#endregion
246
+ //#region src/toolbar.d.ts
247
+ type RichTextEditorToolbarProps = HTMLAttributes<HTMLDivElement>;
248
+ declare function RichTextEditorToolbar({
249
+ className,
250
+ ...props
251
+ }: RichTextEditorToolbarProps): react_jsx_runtime0.JSX.Element;
252
+ //#endregion
253
+ export { RichTextEditor, RichTextEditorBuiltIn, RichTextEditorBuiltInProps, RichTextEditorContent, RichTextEditorContentProps, RichTextEditorContext, RichTextEditorContextValue, RichTextEditorFormattingGroup, RichTextEditorFormattingGroupProps, RichTextEditorHeadingGroup, RichTextEditorHeadingGroupProps, RichTextEditorHistoryGroup, RichTextEditorHistoryGroupProps, RichTextEditorListGroup, RichTextEditorListGroupProps, RichTextEditorPreset, RichTextEditorProps, RichTextEditorSimple, RichTextEditorSimpleProps, RichTextEditorToolbar, RichTextEditorToolbarProps, useRichTextEditor };
package/dist/index.mjs CHANGED
@@ -1 +1,388 @@
1
- export { };
1
+ import { EditorContent, useEditor, useEditorState } from "@tiptap/react";
2
+ import { Button, ButtonGroup, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, ToggleGroup, ToggleGroupItem, cn } from "@melv1c/ui-core";
3
+ import { createContext, useContext, useEffect, useMemo } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import StarterKit from "@tiptap/starter-kit";
6
+ import { Bold, Code, Heading1, Heading2, Heading3, Italic, List, ListOrdered, Redo2, Strikethrough, Undo2 } from "lucide-react";
7
+ import { Extension } from "@tiptap/core";
8
+
9
+ //#region src/context.tsx
10
+ const RichTextEditorContext = createContext(null);
11
+ function useRichTextEditor() {
12
+ const context = useContext(RichTextEditorContext);
13
+ if (!context) throw new Error("useRichTextEditor must be used within RichTextEditor.");
14
+ return context;
15
+ }
16
+
17
+ //#endregion
18
+ //#region src/content.tsx
19
+ function toSize(value) {
20
+ if (value === void 0) return void 0;
21
+ return typeof value === "number" ? `${value}px` : value;
22
+ }
23
+ function RichTextEditorContent({ className, minHeight = 180, maxHeight, style, ...props }) {
24
+ const { editor } = useRichTextEditor();
25
+ const heightStyles = {
26
+ minHeight: toSize(minHeight),
27
+ maxHeight: toSize(maxHeight),
28
+ overflowY: maxHeight !== void 0 ? "auto" : void 0
29
+ };
30
+ return /* @__PURE__ */ jsx(EditorContent, {
31
+ "data-slot": "rich-text-editor-content",
32
+ editor,
33
+ className: cn("text-foreground [&_.ProseMirror]:px-2 [&_.ProseMirror]:py-1 [&_.ProseMirror]:outline-none [&_.ProseMirror_p.is-editor-empty:first-child::before]:text-muted-foreground [&_.ProseMirror_p.is-editor-empty:first-child::before]:pointer-events-none [&_.ProseMirror_p.is-editor-empty:first-child::before]:float-left [&_.ProseMirror_p.is-editor-empty:first-child::before]:h-0 [&_.ProseMirror_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]", className),
34
+ style: {
35
+ ...heightStyles,
36
+ ...style
37
+ },
38
+ ...props
39
+ });
40
+ }
41
+
42
+ //#endregion
43
+ //#region src/editor.tsx
44
+ function RichTextEditor({ children, className, value, defaultValue, onValueChange, editable = true, extensions, starterKit, ...props }) {
45
+ const mergedExtensions = useMemo(() => [StarterKit.configure(starterKit ?? {}), ...extensions ?? []], [extensions, starterKit]);
46
+ const editor = useEditor({
47
+ extensions: mergedExtensions,
48
+ editable,
49
+ content: value ?? defaultValue ?? "",
50
+ onUpdate({ editor: currentEditor }) {
51
+ onValueChange?.(currentEditor.getHTML(), currentEditor);
52
+ }
53
+ }, [mergedExtensions, editable]);
54
+ useEffect(() => {
55
+ if (!editor || value === void 0) return;
56
+ if (editor.getHTML() === value) return;
57
+ editor.commands.setContent(value, { emitUpdate: false });
58
+ }, [editor, value]);
59
+ const contextValue = useMemo(() => ({ editor }), [editor]);
60
+ return /* @__PURE__ */ jsx(RichTextEditorContext.Provider, {
61
+ value: contextValue,
62
+ children: /* @__PURE__ */ jsx("div", {
63
+ "data-slot": "rich-text-editor",
64
+ className: cn("bg-background border-border rounded-lg border", className),
65
+ ...props,
66
+ children
67
+ })
68
+ });
69
+ }
70
+
71
+ //#endregion
72
+ //#region src/groups/formatting-group.tsx
73
+ const ALL_FORMATTING_ITEMS = [
74
+ "bold",
75
+ "italic",
76
+ "strike",
77
+ "code"
78
+ ];
79
+ function BoldButton({ className, ...props }) {
80
+ const { editor } = useRichTextEditor();
81
+ return /* @__PURE__ */ jsx(ToggleGroupItem, {
82
+ "data-slot": "rich-text-editor-toggle-button",
83
+ value: "bold",
84
+ "aria-label": "Bold",
85
+ disabled: editor ? !editor.can().chain().focus().toggleBold().run() : true,
86
+ onClick: () => editor?.chain().focus().toggleBold().run(),
87
+ className: cn("shadow-none", className),
88
+ ...props,
89
+ children: props.children ?? /* @__PURE__ */ jsx(Bold, {})
90
+ });
91
+ }
92
+ function ItalicButton({ className, ...props }) {
93
+ const { editor } = useRichTextEditor();
94
+ return /* @__PURE__ */ jsx(ToggleGroupItem, {
95
+ "data-slot": "rich-text-editor-toggle-button",
96
+ value: "italic",
97
+ "aria-label": "Italic",
98
+ disabled: editor ? !editor.can().chain().focus().toggleItalic().run() : true,
99
+ onClick: () => editor?.chain().focus().toggleItalic().run(),
100
+ className: cn("shadow-none", className),
101
+ ...props,
102
+ children: props.children ?? /* @__PURE__ */ jsx(Italic, {})
103
+ });
104
+ }
105
+ function StrikethroughButton({ className, ...props }) {
106
+ const { editor } = useRichTextEditor();
107
+ return /* @__PURE__ */ jsx(ToggleGroupItem, {
108
+ "data-slot": "rich-text-editor-toggle-button",
109
+ value: "strike",
110
+ "aria-label": "Strikethrough",
111
+ disabled: editor ? !editor.can().chain().focus().toggleStrike().run() : true,
112
+ onClick: () => editor?.chain().focus().toggleStrike().run(),
113
+ className: cn("shadow-none", className),
114
+ ...props,
115
+ children: props.children ?? /* @__PURE__ */ jsx(Strikethrough, {})
116
+ });
117
+ }
118
+ function CodeButton({ className, ...props }) {
119
+ const { editor } = useRichTextEditor();
120
+ return /* @__PURE__ */ jsx(ToggleGroupItem, {
121
+ "data-slot": "rich-text-editor-toggle-button",
122
+ value: "code",
123
+ "aria-label": "Inline code",
124
+ disabled: editor ? !editor.can().chain().focus().toggleCode().run() : true,
125
+ onClick: () => editor?.chain().focus().toggleCode().run(),
126
+ className: cn("shadow-none", className),
127
+ ...props,
128
+ children: props.children ?? /* @__PURE__ */ jsx(Code, {})
129
+ });
130
+ }
131
+ function RichTextEditorFormattingGroup({ boldProps, italicProps, strikethroughProps, codeProps, items = ALL_FORMATTING_ITEMS, variant = "outline", size = "sm", ...props }) {
132
+ const { editor } = useRichTextEditor();
133
+ const visibleItems = new Set(items);
134
+ const activeValue = useEditorState({
135
+ editor,
136
+ selector: ({ editor: currentEditor }) => {
137
+ if (!currentEditor) return [];
138
+ return ALL_FORMATTING_ITEMS.filter((format) => visibleItems.has(format) && currentEditor.isActive(format));
139
+ }
140
+ });
141
+ return /* @__PURE__ */ jsxs(ToggleGroup, {
142
+ type: "multiple",
143
+ variant,
144
+ size,
145
+ "aria-label": "Inline formatting",
146
+ value: activeValue ?? [],
147
+ ...props,
148
+ children: [
149
+ visibleItems.has("bold") && /* @__PURE__ */ jsx(BoldButton, { ...boldProps }),
150
+ visibleItems.has("italic") && /* @__PURE__ */ jsx(ItalicButton, { ...italicProps }),
151
+ visibleItems.has("strike") && /* @__PURE__ */ jsx(StrikethroughButton, { ...strikethroughProps }),
152
+ visibleItems.has("code") && /* @__PURE__ */ jsx(CodeButton, { ...codeProps })
153
+ ]
154
+ });
155
+ }
156
+
157
+ //#endregion
158
+ //#region src/groups/heading-group.tsx
159
+ const ALL_HEADING_LEVELS = [
160
+ 1,
161
+ 2,
162
+ 3
163
+ ];
164
+ const HEADING_ICONS = {
165
+ 1: Heading1,
166
+ 2: Heading2,
167
+ 3: Heading3
168
+ };
169
+ function HeadingButton({ className, level, ...props }) {
170
+ const { editor } = useRichTextEditor();
171
+ const Icon = HEADING_ICONS[level];
172
+ return /* @__PURE__ */ jsx(ToggleGroupItem, {
173
+ "data-slot": "rich-text-editor-toggle-button",
174
+ value: `heading-${level}`,
175
+ "aria-label": `Heading ${level}`,
176
+ disabled: editor ? !editor.can().chain().focus().toggleHeading({ level }).run() : true,
177
+ onClick: () => editor?.chain().focus().toggleHeading({ level }).run(),
178
+ className: cn("shadow-none", className),
179
+ ...props,
180
+ children: props.children ?? /* @__PURE__ */ jsx(Icon, {})
181
+ });
182
+ }
183
+ const headingItemLabelMap = {
184
+ 1: "Heading 1",
185
+ 2: "Heading 2",
186
+ 3: "Heading 3"
187
+ };
188
+ function RichTextEditorHeadingGroup({ mode = "select", levels, heading1Props, heading2Props, heading3Props, includeParagraphOption = true, paragraphLabel = "Paragraph", selectPlaceholder = "Select heading", selectProps, selectTriggerProps, selectContentProps, variant = "outline", size = "sm", ...props }) {
189
+ const { editor } = useRichTextEditor();
190
+ const resolvedLevels = levels ?? ALL_HEADING_LEVELS;
191
+ const visibleLevels = new Set(resolvedLevels);
192
+ const headingPropsByLevel = {
193
+ 1: heading1Props,
194
+ 2: heading2Props,
195
+ 3: heading3Props
196
+ };
197
+ const activeValue = useEditorState({
198
+ editor,
199
+ selector: ({ editor: currentEditor }) => {
200
+ if (!currentEditor) return "";
201
+ for (const level of ALL_HEADING_LEVELS) if (currentEditor.isActive("heading", { level })) return `heading-${level}`;
202
+ return "";
203
+ }
204
+ });
205
+ if (mode === "select") return /* @__PURE__ */ jsxs(Select, {
206
+ value: activeValue || (includeParagraphOption ? "paragraph" : void 0),
207
+ onValueChange: (value) => {
208
+ if (!editor) return;
209
+ if (value === "paragraph") {
210
+ editor.chain().focus().setParagraph().run();
211
+ return;
212
+ }
213
+ const level = Number(value.replace("heading-", ""));
214
+ editor.chain().focus().setHeading({ level }).run();
215
+ },
216
+ ...selectProps,
217
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
218
+ "aria-label": "Heading levels",
219
+ size: "sm",
220
+ disabled: !editor,
221
+ className: "shadow-none",
222
+ ...selectTriggerProps,
223
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: selectPlaceholder })
224
+ }), /* @__PURE__ */ jsxs(SelectContent, {
225
+ ...selectContentProps,
226
+ children: [includeParagraphOption && /* @__PURE__ */ jsx(SelectItem, {
227
+ value: "paragraph",
228
+ disabled: editor ? !editor.can().chain().focus().setParagraph().run() : true,
229
+ children: paragraphLabel
230
+ }), ALL_HEADING_LEVELS.filter((level) => visibleLevels.has(level)).map((level) => /* @__PURE__ */ jsx(SelectItem, {
231
+ value: `heading-${level}`,
232
+ disabled: editor ? !editor.can().chain().focus().setHeading({ level }).run() : true,
233
+ children: headingItemLabelMap[level]
234
+ }, level))]
235
+ })]
236
+ });
237
+ return /* @__PURE__ */ jsx(ToggleGroup, {
238
+ type: "single",
239
+ variant,
240
+ size,
241
+ "aria-label": "Heading levels",
242
+ value: activeValue ?? "",
243
+ ...props,
244
+ children: ALL_HEADING_LEVELS.filter((level) => visibleLevels.has(level)).map((level) => /* @__PURE__ */ jsx(HeadingButton, {
245
+ level,
246
+ ...headingPropsByLevel[level]
247
+ }, level))
248
+ });
249
+ }
250
+
251
+ //#endregion
252
+ //#region src/groups/history-group.tsx
253
+ function UndoButton({ className, ...props }) {
254
+ const { editor } = useRichTextEditor();
255
+ return /* @__PURE__ */ jsx(Button, {
256
+ "data-slot": "rich-text-editor-action-button",
257
+ "aria-label": "Undo",
258
+ variant: "outline",
259
+ size: "icon-sm",
260
+ disabled: editor ? !editor.can().chain().focus().undo().run() : true,
261
+ onClick: () => editor?.chain().focus().undo().run(),
262
+ className: cn("shadow-none", className),
263
+ ...props,
264
+ children: props.children ?? /* @__PURE__ */ jsx(Undo2, {})
265
+ });
266
+ }
267
+ function RedoButton({ className, ...props }) {
268
+ const { editor } = useRichTextEditor();
269
+ return /* @__PURE__ */ jsx(Button, {
270
+ "data-slot": "rich-text-editor-action-button",
271
+ "aria-label": "Redo",
272
+ variant: "outline",
273
+ size: "icon-sm",
274
+ disabled: editor ? !editor.can().chain().focus().redo().run() : true,
275
+ onClick: () => editor?.chain().focus().redo().run(),
276
+ className: cn("shadow-none", className),
277
+ ...props,
278
+ children: props.children ?? /* @__PURE__ */ jsx(Redo2, {})
279
+ });
280
+ }
281
+ function RichTextEditorHistoryGroup({ undoProps, redoProps, items = ["undo", "redo"], ...props }) {
282
+ const visibleItems = new Set(items);
283
+ return /* @__PURE__ */ jsxs(ButtonGroup, {
284
+ ...props,
285
+ children: [visibleItems.has("undo") && /* @__PURE__ */ jsx(UndoButton, { ...undoProps }), visibleItems.has("redo") && /* @__PURE__ */ jsx(RedoButton, { ...redoProps })]
286
+ });
287
+ }
288
+
289
+ //#endregion
290
+ //#region src/groups/list-group.tsx
291
+ function BulletListButton({ className, ...props }) {
292
+ const { editor } = useRichTextEditor();
293
+ return /* @__PURE__ */ jsx(ToggleGroupItem, {
294
+ "data-slot": "rich-text-editor-toggle-button",
295
+ value: "bullet-list",
296
+ "aria-label": "Bullet list",
297
+ disabled: editor ? !editor.can().chain().focus().toggleBulletList().run() : true,
298
+ onClick: () => editor?.chain().focus().toggleBulletList().run(),
299
+ className: cn("shadow-none", className),
300
+ ...props,
301
+ children: props.children ?? /* @__PURE__ */ jsx(List, {})
302
+ });
303
+ }
304
+ function OrderedListButton({ className, ...props }) {
305
+ const { editor } = useRichTextEditor();
306
+ return /* @__PURE__ */ jsx(ToggleGroupItem, {
307
+ "data-slot": "rich-text-editor-toggle-button",
308
+ value: "ordered-list",
309
+ "aria-label": "Ordered list",
310
+ disabled: editor ? !editor.can().chain().focus().toggleOrderedList().run() : true,
311
+ onClick: () => editor?.chain().focus().toggleOrderedList().run(),
312
+ className: cn("shadow-none", className),
313
+ ...props,
314
+ children: props.children ?? /* @__PURE__ */ jsx(ListOrdered, {})
315
+ });
316
+ }
317
+ function RichTextEditorListGroup({ bulletListProps, orderedListProps, items = ["bullet-list", "ordered-list"], variant = "outline", size = "sm", ...props }) {
318
+ const { editor } = useRichTextEditor();
319
+ const visibleItems = new Set(items);
320
+ const activeValue = useEditorState({
321
+ editor,
322
+ selector: ({ editor: currentEditor }) => {
323
+ if (!currentEditor) return "";
324
+ if (currentEditor.isActive("bulletList")) return "bullet-list";
325
+ if (currentEditor.isActive("orderedList")) return "ordered-list";
326
+ return "";
327
+ }
328
+ });
329
+ return /* @__PURE__ */ jsxs(ToggleGroup, {
330
+ type: "single",
331
+ variant,
332
+ size,
333
+ "aria-label": "List type",
334
+ value: activeValue ?? "",
335
+ ...props,
336
+ children: [visibleItems.has("bullet-list") && /* @__PURE__ */ jsx(BulletListButton, { ...bulletListProps }), visibleItems.has("ordered-list") && /* @__PURE__ */ jsx(OrderedListButton, { ...orderedListProps })]
337
+ });
338
+ }
339
+
340
+ //#endregion
341
+ //#region src/toolbar.tsx
342
+ function RichTextEditorToolbar({ className, ...props }) {
343
+ return /* @__PURE__ */ jsx("div", {
344
+ "data-slot": "rich-text-editor-toolbar",
345
+ className: cn("border-border flex flex-wrap items-center gap-2 border-b p-2", className),
346
+ ...props
347
+ });
348
+ }
349
+
350
+ //#endregion
351
+ //#region src/built-in.tsx
352
+ /** Blocks Enter / Shift-Enter so the editor stays on a single line. */
353
+ const OneLinerExtension = Extension.create({
354
+ name: "oneLiner",
355
+ addKeyboardShortcuts() {
356
+ return {
357
+ Enter: () => true,
358
+ "Shift-Enter": () => true
359
+ };
360
+ }
361
+ });
362
+ function RichTextEditorBuiltIn({ className, contentClassName, toolbarClassName, preset = "complete", minHeight, maxHeight, extensions, ...props }) {
363
+ const isOneline = preset === "oneline";
364
+ const resolvedMinHeight = minHeight ?? (isOneline ? 0 : 180);
365
+ return /* @__PURE__ */ jsxs(RichTextEditor, {
366
+ className,
367
+ extensions: useMemo(() => isOneline ? [OneLinerExtension, ...extensions ?? []] : extensions, [isOneline, extensions]),
368
+ ...props,
369
+ children: [/* @__PURE__ */ jsxs(RichTextEditorToolbar, {
370
+ className: toolbarClassName,
371
+ children: [
372
+ (preset === "complete" || preset === "simple") && /* @__PURE__ */ jsx(RichTextEditorHistoryGroup, {}),
373
+ preset !== "oneline" && /* @__PURE__ */ jsx(RichTextEditorHeadingGroup, { mode: "select" }),
374
+ /* @__PURE__ */ jsx(RichTextEditorFormattingGroup, {}),
375
+ preset === "complete" && /* @__PURE__ */ jsx(RichTextEditorListGroup, {})
376
+ ]
377
+ }), /* @__PURE__ */ jsx(RichTextEditorContent, {
378
+ className: contentClassName,
379
+ minHeight: resolvedMinHeight,
380
+ maxHeight
381
+ })]
382
+ });
383
+ }
384
+ /** @deprecated Use `RichTextEditorBuiltIn` instead. */
385
+ const RichTextEditorSimple = RichTextEditorBuiltIn;
386
+
387
+ //#endregion
388
+ export { RichTextEditor, RichTextEditorBuiltIn, RichTextEditorContent, RichTextEditorContext, RichTextEditorFormattingGroup, RichTextEditorHeadingGroup, RichTextEditorHistoryGroup, RichTextEditorListGroup, RichTextEditorSimple, RichTextEditorToolbar, useRichTextEditor };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melv1c/rich-text-editor",
3
- "version": "0.0.0",
3
+ "version": "1.0.0",
4
4
  "description": "A rich text editor component for React, built with TipTap and styled with Tailwind CSS.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,10 +11,10 @@
11
11
  ],
12
12
  "type": "module",
13
13
  "main": "./dist/index.mjs",
14
- "types": "./src/index.ts",
14
+ "types": "./dist/index.d.mts",
15
15
  "exports": {
16
16
  ".": {
17
- "types": "./src/index.ts",
17
+ "types": "./dist/index.d.mts",
18
18
  "import": "./dist/index.mjs",
19
19
  "default": "./dist/index.mjs"
20
20
  }
@@ -26,7 +26,12 @@
26
26
  "build": "tsdown",
27
27
  "dev": "tsdown --watch --no-clean"
28
28
  },
29
- "dependencies": {},
29
+ "dependencies": {
30
+ "@tiptap/core": "^3.20.0",
31
+ "@tiptap/react": "^3.7.2",
32
+ "@tiptap/starter-kit": "^3.7.2",
33
+ "lucide-react": "^0.513.0"
34
+ },
30
35
  "devDependencies": {
31
36
  "@types/node": "^25.2.3",
32
37
  "@types/react": "^19.2.14",
@@ -37,7 +42,7 @@
37
42
  "typescript": "~5.9.3"
38
43
  },
39
44
  "peerDependencies": {
40
- "@melv1c/ui-core": ">=1.1.0",
45
+ "@melv1c/ui-core": ">=1.1.2",
41
46
  "react": ">=19",
42
47
  "react-dom": ">=19",
43
48
  "tailwindcss": "^4.1.17",