@uxf/wysiwyg 11.125.0 → 11.127.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 +56 -42
- package/package.json +7 -7
- package/wysiwyg-editor.d.ts +6 -1
- package/wysiwyg-editor.js +58 -6
package/README.md
CHANGED
|
@@ -80,10 +80,7 @@ To enable only some plugins, compose them yourself with `createPluginsWithUi`:
|
|
|
80
80
|
```tsx
|
|
81
81
|
import { createBoldPluginWithUi, createHeadingsPluginWithUi, createPluginsWithUi } from "@uxf/wysiwyg";
|
|
82
82
|
|
|
83
|
-
const plugins = createPluginsWithUi([
|
|
84
|
-
createHeadingsPluginWithUi({ disabledLevels: [1] }),
|
|
85
|
-
createBoldPluginWithUi(),
|
|
86
|
-
]);
|
|
83
|
+
const plugins = createPluginsWithUi([createHeadingsPluginWithUi({ disabledLevels: [1] }), createBoldPluginWithUi()]);
|
|
87
84
|
```
|
|
88
85
|
|
|
89
86
|
## Content model
|
|
@@ -113,55 +110,56 @@ Everything below is exported from the package root (`@uxf/wysiwyg`) unless a dee
|
|
|
113
110
|
|
|
114
111
|
`import { WysiwygEditor } from "@uxf/wysiwyg";`
|
|
115
112
|
|
|
116
|
-
| Prop
|
|
117
|
-
|
|
|
118
|
-
| `id`
|
|
119
|
-
| `initialValue`
|
|
120
|
-
| `onChange`
|
|
121
|
-
| `plugins`
|
|
122
|
-
| `className`
|
|
123
|
-
| `editableProps`
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
113
|
+
| Prop | Type | Required | Description |
|
|
114
|
+
| ----------------------------- | ----------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
115
|
+
| `id` | `string` | yes | Unique Plate instance id. Must be unique per editor on the page. |
|
|
116
|
+
| `initialValue` | `WysiwygContent \| undefined` | yes | Document the editor is seeded with on mount. |
|
|
117
|
+
| `onChange` | `(value: WysiwygContent) => void` | yes | Called on every edit with the full document. |
|
|
118
|
+
| `plugins` | `UxfPlatePlugin[]` | yes | Build with `createAllPluginsWithUi` / `createPluginsWithUi`. |
|
|
119
|
+
| `className` | `string` | no | Class on the editor root wrapper. |
|
|
120
|
+
| `editableProps` | `TEditableProps<WysiwygContent>` | no | Passed to Plate's editable area (`placeholder`, `readOnly`, `autoFocus`, `spellCheck`, `className`, …). Defaults: `autoFocus: false`, `readOnly: false`, `spellCheck: false`, localized placeholder. |
|
|
121
|
+
| `editorRef` | `ForwardedRef<WysiwygEditorHandle>` | no | Imperative handle exposing `focus()`, which selects the end of the document and then focuses the editable area. |
|
|
122
|
+
| `customPluginsToolbarButtons` | `ReactNode` | no | Extra toolbar buttons appended to the built-in ones. |
|
|
123
|
+
| `toolbarLeftElement` | `ReactNode` | no | Node rendered at the toolbar's left edge. |
|
|
124
|
+
| `toolbarRightElement` | `ReactNode` | no | Node rendered at the toolbar's right edge. |
|
|
127
125
|
|
|
128
126
|
### Plugin builders
|
|
129
127
|
|
|
130
128
|
`createPluginsWithUi` / `createAllPluginsWithUi` return the `UxfPlatePlugin[]` you pass to `WysiwygEditor`. Both inject the base plugins automatically (paragraph, exit-break, reset-node, soft-break, node-id, select-on-backspace, trailing-block), so pass only the feature builders below — not raw Plate plugins.
|
|
131
129
|
|
|
132
|
-
| Export
|
|
133
|
-
|
|
|
134
|
-
| `createPluginsWithUi`
|
|
135
|
-
| `createAllPluginsWithUi`
|
|
136
|
-
| `createHeadingsPluginWithUi`
|
|
137
|
-
| `createBoldPluginWithUi`
|
|
138
|
-
| `createItalicPluginWithUi`
|
|
139
|
-
| `createUnderlinePluginWithUi`
|
|
140
|
-
| `createCodePluginWithUi`
|
|
141
|
-
| `createHighlightPluginWithUi`
|
|
142
|
-
| `createBlockquotePluginWithUi` | `() => WysiwygPlugin`
|
|
143
|
-
| `createListPluginWithUi`
|
|
144
|
-
| `createLinkPluginWithUi`
|
|
145
|
-
| `createImagePluginWithUi`
|
|
146
|
-
| `createVideoPluginWithUi`
|
|
147
|
-
| `createButtonPluginWithUi`
|
|
130
|
+
| Export | Signature | Notes |
|
|
131
|
+
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
|
|
132
|
+
| `createPluginsWithUi` | `(plugins: Array<WysiwygPlugin \| WysiwygRecursivePlugin<string>>, options?: { overrideByKey?: MyOverrideByKey }) => UxfPlatePlugin[]` | Compose a custom subset. |
|
|
133
|
+
| `createAllPluginsWithUi` | `(options: CreateAllPluginsOptions) => UxfPlatePlugin[]` | Enable every plugin. |
|
|
134
|
+
| `createHeadingsPluginWithUi` | `(options?: HeadingsPluginOptions) => WysiwygRecursivePlugin` | `disabledLevels?: (1..6)[]`. |
|
|
135
|
+
| `createBoldPluginWithUi` | `() => WysiwygPlugin` | |
|
|
136
|
+
| `createItalicPluginWithUi` | `() => WysiwygPlugin` | |
|
|
137
|
+
| `createUnderlinePluginWithUi` | `() => WysiwygPlugin` | |
|
|
138
|
+
| `createCodePluginWithUi` | `() => WysiwygPlugin` | |
|
|
139
|
+
| `createHighlightPluginWithUi` | `(color?: CSSProperties["color"]) => WysiwygPlugin` | Defaults to `twColors.yellow[300]`. |
|
|
140
|
+
| `createBlockquotePluginWithUi` | `() => WysiwygPlugin` | |
|
|
141
|
+
| `createListPluginWithUi` | `() => WysiwygRecursivePlugin` | Renders `ul` / `ol` / `li`. |
|
|
142
|
+
| `createLinkPluginWithUi` | `() => WysiwygPlugin` | |
|
|
143
|
+
| `createImagePluginWithUi` | `(options: UxfImagePluginOptions) => WysiwygPlugin` | See options below. |
|
|
144
|
+
| `createVideoPluginWithUi` | `() => WysiwygPlugin` | |
|
|
145
|
+
| `createButtonPluginWithUi` | `() => WysiwygPlugin` | |
|
|
148
146
|
|
|
149
147
|
`CreateAllPluginsOptions`:
|
|
150
148
|
|
|
151
|
-
| Key
|
|
152
|
-
|
|
|
153
|
-
| `image`
|
|
154
|
-
| `headings`
|
|
155
|
-
| `highlightColor` | `CSSProperties["color"]` | no
|
|
149
|
+
| Key | Type | Required | Description |
|
|
150
|
+
| ---------------- | ------------------------ | -------- | ------------------------------------------------------------------- |
|
|
151
|
+
| `image` | `UxfImagePluginOptions` | yes | Image plugin options (pass `{}` to enable without upload handlers). |
|
|
152
|
+
| `headings` | `HeadingsPluginOptions` | no | e.g. `{ disabledLevels: [1] }`. |
|
|
153
|
+
| `highlightColor` | `CSSProperties["color"]` | no | Highlight mark color. |
|
|
156
154
|
|
|
157
155
|
`UxfImagePluginOptions` (extends Plate's `MediaPlugin`):
|
|
158
156
|
|
|
159
|
-
| Key
|
|
160
|
-
|
|
|
161
|
-
| `uploadImage`
|
|
162
|
-
| `getImageUrl`
|
|
163
|
-
| `disableUploadOnPasteImageUrl` | `boolean`
|
|
164
|
-
| `disableUploadOnPasteImage`
|
|
157
|
+
| Key | Type | Description |
|
|
158
|
+
| ------------------------------ | --------------------------------------- | ------------------------------------------------------------- |
|
|
159
|
+
| `uploadImage` | `(file: File) => Promise<FileResponse>` | Upload handler; returns a `FileResponse` (`@uxf/core/types`). |
|
|
160
|
+
| `getImageUrl` | `(file: FileResponse) => string` | Resolves the display URL for an uploaded file. |
|
|
161
|
+
| `disableUploadOnPasteImageUrl` | `boolean` | Disable auto-upload when an image URL is pasted. |
|
|
162
|
+
| `disableUploadOnPasteImage` | `boolean` | Disable auto-upload when an image blob is pasted. |
|
|
165
163
|
|
|
166
164
|
### Hooks
|
|
167
165
|
|
|
@@ -183,6 +181,21 @@ serializeToPlaintext(value); // keepIndentation defaults to true (joins blocks w
|
|
|
183
181
|
|
|
184
182
|
### Types
|
|
185
183
|
|
|
184
|
+
`WysiwygEditorHandle` — the shape behind `editorRef`:
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
import { WysiwygEditor } from "@uxf/wysiwyg";
|
|
188
|
+
// deep import: this type is not re-exported from the package index
|
|
189
|
+
import { WysiwygEditorHandle } from "@uxf/wysiwyg/wysiwyg-editor";
|
|
190
|
+
import { useRef } from "react";
|
|
191
|
+
|
|
192
|
+
const editorRef = useRef<WysiwygEditorHandle>(null);
|
|
193
|
+
|
|
194
|
+
<WysiwygEditor editorRef={editorRef} id="body" initialValue={value} onChange={setValue} plugins={plugins} />;
|
|
195
|
+
|
|
196
|
+
editorRef.current?.focus(); // caret goes to the end of the document
|
|
197
|
+
```
|
|
198
|
+
|
|
186
199
|
The full node model and editor types are re-exported, including: `WysiwygContent`, `WysiwygRootBlock`, `RichText`, the element interfaces (`UxfParagraphElement`, `UxfHeadingElement`, `UxfBlockQuoteElement`, `UxfLinkElement`, `UxfImageElement`, `UxfVideoElement`, `UxfButtonElement`, `UxfUnorderedListElement`, `UxfOrderedListElement`, `LiElement`, `LicElement`), plus `UxfEditor`, `UxfPlatePlugin`, `WysiwygPlugin`, `WysiwygRecursivePlugin`, and the render prop/component types (`RenderElementProps`, `ElementUiComponent`, `RenderLeafProps`, `LeafUiComponent`, `RenderAfterEditable`, `MyOverrideByKey`, `UiComponents`).
|
|
187
200
|
|
|
188
201
|
## Gotchas
|
|
@@ -192,6 +205,7 @@ The full node model and editor types are re-exported, including: `WysiwygContent
|
|
|
192
205
|
- **Build plugins with the provided factories.** Pass only the results of `createPluginsWithUi` / `createAllPluginsWithUi` to `plugins`; they inject the required base plugins. Do not hand-assemble raw Plate plugin arrays.
|
|
193
206
|
- **CSS is required and Tailwind-dependent.** Without `@uxf/wysiwyg/styles/styles.css` the editor is unstyled; the file relies on your Tailwind/PostCSS setup and `@uxf/ui`'s `uxf-typo-*` utilities.
|
|
194
207
|
- **Translations are required.** Register `@uxf/wysiwyg/translations/translations`, otherwise labels/tooltips render as raw keys.
|
|
208
|
+
- **`WysiwygEditorHandle` is not on the package index.** `index.ts` exports only the `WysiwygEditor` component, so the ref type has to come from the deep import `@uxf/wysiwyg/wysiwyg-editor` — which is what `@uxf/cms`'s own `WysiwygInput` does.
|
|
195
209
|
- **Pinned peers.** Plate/Slate and `@uxf/*` peer versions are pinned exactly (see `package.json`); mismatched versions will not work.
|
|
196
210
|
|
|
197
211
|
## Links
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uxf/wysiwyg",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.127.0",
|
|
4
4
|
"description": "UXF Wysiwyg editor",
|
|
5
5
|
"author": "Robin Dvorak <dvorak@uxf.cz>",
|
|
6
6
|
"homepage": "https://gitlab.com/uxf-npm/wysiwyg",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"@udecode/slate": "19.8.0",
|
|
32
32
|
"@udecode/slate-react": "19.7.1",
|
|
33
33
|
"@udecode/slate-utils": "19.7.1",
|
|
34
|
-
"@uxf/core": "11.
|
|
35
|
-
"@uxf/core-react": "11.
|
|
36
|
-
"@uxf/ui": "11.
|
|
34
|
+
"@uxf/core": "11.127.0",
|
|
35
|
+
"@uxf/core-react": "11.127.0",
|
|
36
|
+
"@uxf/ui": "11.127.0",
|
|
37
37
|
"react": ">=18.2.0",
|
|
38
38
|
"react-dom": ">=18.2.0",
|
|
39
39
|
"slate": "0.90.0",
|
|
@@ -62,9 +62,9 @@
|
|
|
62
62
|
"@udecode/slate": "19.8.0",
|
|
63
63
|
"@udecode/slate-react": "19.7.1",
|
|
64
64
|
"@udecode/slate-utils": "19.7.1",
|
|
65
|
-
"@uxf/core": "11.
|
|
66
|
-
"@uxf/core-react": "11.
|
|
67
|
-
"@uxf/ui": "11.
|
|
65
|
+
"@uxf/core": "11.127.0",
|
|
66
|
+
"@uxf/core-react": "11.127.0",
|
|
67
|
+
"@uxf/ui": "11.127.0",
|
|
68
68
|
"react": "18.3.1",
|
|
69
69
|
"react-dom": "18.3.1",
|
|
70
70
|
"slate": "0.90.0",
|
package/wysiwyg-editor.d.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { TEditableProps } from "@udecode/plate-core";
|
|
2
|
-
import {
|
|
2
|
+
import { Noop } from "@uxf/core/types";
|
|
3
|
+
import { FC, ForwardedRef, ReactNode } from "react";
|
|
3
4
|
import { UxfPlatePlugin, WysiwygContent } from "./types";
|
|
5
|
+
export interface WysiwygEditorHandle {
|
|
6
|
+
focus: Noop;
|
|
7
|
+
}
|
|
4
8
|
export interface WysiwygEditorProps {
|
|
5
9
|
className?: string;
|
|
6
10
|
customPluginsToolbarButtons?: ReactNode;
|
|
7
11
|
editableProps?: TEditableProps<WysiwygContent>;
|
|
12
|
+
editorRef?: ForwardedRef<WysiwygEditorHandle>;
|
|
8
13
|
id: string;
|
|
9
14
|
initialValue: WysiwygContent | undefined;
|
|
10
15
|
onChange: (value: WysiwygContent) => void;
|
package/wysiwyg-editor.js
CHANGED
|
@@ -1,8 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
"use client";
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
6
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
37
|
exports.WysiwygEditor = void 0;
|
|
8
38
|
const plate_core_1 = require("@udecode/plate-core");
|
|
@@ -10,9 +40,30 @@ const classes_1 = require("@uxf/core/constants/classes");
|
|
|
10
40
|
const use_is_mounted_1 = require("@uxf/core-react/hooks/use-is-mounted");
|
|
11
41
|
const translations_1 = require("@uxf/core-react/translations");
|
|
12
42
|
const loader_1 = require("@uxf/ui/loader");
|
|
13
|
-
const react_1 =
|
|
43
|
+
const react_1 = __importStar(require("react"));
|
|
44
|
+
const slate_1 = require("slate");
|
|
45
|
+
const hooks_1 = require("./hooks");
|
|
14
46
|
const toolbar_1 = require("./ui/toolbar/toolbar");
|
|
47
|
+
const utils_1 = require("./utils");
|
|
15
48
|
const CLASS_NAME = "uxf-wysiwyg";
|
|
49
|
+
/**
|
|
50
|
+
* Component that accesses the editor from Slate context and exposes focus method via ref
|
|
51
|
+
* Must be rendered inside Plate component
|
|
52
|
+
*/
|
|
53
|
+
const EditorRefHandler = (0, react_1.forwardRef)((props, ref) => {
|
|
54
|
+
const editor = (0, hooks_1.useUxfEditorRef)();
|
|
55
|
+
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
56
|
+
focus: () => {
|
|
57
|
+
// Select the end of the document first
|
|
58
|
+
const end = slate_1.Editor.end(editor, []);
|
|
59
|
+
slate_1.Transforms.select(editor, end);
|
|
60
|
+
// Then focus the editor
|
|
61
|
+
(0, utils_1.focusEditor)(editor);
|
|
62
|
+
},
|
|
63
|
+
}));
|
|
64
|
+
return null;
|
|
65
|
+
});
|
|
66
|
+
EditorRefHandler.displayName = "EditorRefHandler";
|
|
16
67
|
const Editor = (props) => {
|
|
17
68
|
var _a, _b;
|
|
18
69
|
const t = (0, translations_1.useUxfTranslation)();
|
|
@@ -26,7 +77,8 @@ const Editor = (props) => {
|
|
|
26
77
|
spellCheck: false,
|
|
27
78
|
...props.editableProps,
|
|
28
79
|
className: `${CLASS_NAME}__editable ${(_b = (_a = props.editableProps) === null || _a === void 0 ? void 0 : _a.className) !== null && _b !== void 0 ? _b : ""}`,
|
|
29
|
-
}, id: props.plateId, normalizeInitialValue: true })
|
|
80
|
+
}, id: props.plateId, normalizeInitialValue: true }),
|
|
81
|
+
props.editorRef && react_1.default.createElement(EditorRefHandler, { ref: props.editorRef }))));
|
|
30
82
|
};
|
|
31
83
|
const WysiwygEditor = (props) => {
|
|
32
84
|
var _a, _b;
|
|
@@ -37,6 +89,6 @@ const WysiwygEditor = (props) => {
|
|
|
37
89
|
}
|
|
38
90
|
return (react_1.default.createElement("div", { className: `${CLASS_NAME} ${(_b = props.className) !== null && _b !== void 0 ? _b : ""}` },
|
|
39
91
|
react_1.default.createElement(plate_core_1.PlateProvider, { id: props.id, initialValue: props.initialValue, onChange: props.onChange, plugins: props.plugins },
|
|
40
|
-
react_1.default.createElement(Editor, { customPluginsToolbarButtons: props.customPluginsToolbarButtons, editableProps: props.editableProps, plateId: props.id, toolbarLeftElement: props.toolbarLeftElement, toolbarRightElement: props.toolbarRightElement }))));
|
|
92
|
+
react_1.default.createElement(Editor, { customPluginsToolbarButtons: props.customPluginsToolbarButtons, editableProps: props.editableProps, editorRef: props.editorRef, plateId: props.id, toolbarLeftElement: props.toolbarLeftElement, toolbarRightElement: props.toolbarRightElement }))));
|
|
41
93
|
};
|
|
42
94
|
exports.WysiwygEditor = WysiwygEditor;
|