@uxf/wysiwyg 11.122.3 → 11.122.5
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 +191 -7
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,17 +1,201 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @uxf/wysiwyg
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Rich-text / WYSIWYG editor for React, built on [Plate](https://plate.udecode.io) / [Slate](https://docs.slatejs.org). It ships a ready-made `WysiwygEditor` component, a toolbar, and a set of UXF-styled plugins (headings, marks, lists, links, images, videos, buttons, blockquote, highlight).
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
Reach for `@uxf/wysiwyg` when you need a structured rich-text editor whose value is a JSON document (a Slate/Plate node tree), not an HTML string. The editor is uncontrolled: it is seeded once from `initialValue` and reports every edit through `onChange` as a `WysiwygContent` array.
|
|
8
|
+
|
|
9
|
+
It is a **client component only** and depends on `@uxf/ui` for its visual primitives. For a higher-level CMS content-builder wrapper, see `@uxf/cms`; use this package directly when you want the standalone editor.
|
|
4
10
|
|
|
5
11
|
## Installation
|
|
6
12
|
|
|
7
|
-
```
|
|
8
|
-
yarn add @uxf/
|
|
13
|
+
```
|
|
14
|
+
yarn add @uxf/wysiwyg
|
|
9
15
|
```
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
All Plate/Slate packages and the UXF packages are **peer dependencies** with pinned versions — install them at the versions declared in [`package.json`](./package.json):
|
|
18
|
+
|
|
19
|
+
- UXF: `@uxf/core`, `@uxf/core-react`, `@uxf/ui`
|
|
20
|
+
- Plate (`20.7.2`): `@udecode/plate-basic-marks`, `@udecode/plate-block-quote`, `@udecode/plate-break`, `@udecode/plate-code-block`, `@udecode/plate-common`, `@udecode/plate-core`, `@udecode/plate-floating`, `@udecode/plate-link`, `@udecode/plate-list`, `@udecode/plate-media`, `@udecode/plate-node-id`, `@udecode/plate-paragraph`, `@udecode/plate-reset-node`, `@udecode/plate-select`, `@udecode/plate-trailing-block`
|
|
21
|
+
- Slate wrappers: `@udecode/slate` (`19.8.0`), `@udecode/slate-react` (`19.7.1`), `@udecode/slate-utils` (`19.7.1`)
|
|
22
|
+
- Slate core: `slate` (`0.90.0`), `slate-history` (`0.86.0`), `slate-hyperscript` (`0.77.0`), `slate-react` (`0.91.11`)
|
|
23
|
+
- `react` / `react-dom` (`>=18.2.0`)
|
|
24
|
+
|
|
25
|
+
### Required CSS
|
|
26
|
+
|
|
27
|
+
Import the published stylesheet once (e.g. in your global CSS):
|
|
12
28
|
|
|
13
29
|
```css
|
|
14
|
-
|
|
15
|
-
|
|
30
|
+
@import url("@uxf/wysiwyg/styles/styles.css");
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This stylesheet uses Tailwind's `theme()`, `@apply` (including `uxf-typo-*` utilities from `@uxf/ui`) and CSS nesting, so it must be processed by your app's Tailwind/PostCSS pipeline alongside the `@uxf/ui` Tailwind config.
|
|
34
|
+
|
|
35
|
+
### Required translations
|
|
36
|
+
|
|
37
|
+
The editor renders its toolbar/labels through `useUxfTranslation` (`@uxf/core-react/translations`). Register this package's translations, or you will see raw translation keys instead of text. Merge the default export of `@uxf/wysiwyg/translations/translations` (locales: `cs`, `en`, `sk`, `de`) into the translation function you pass to your app's provider:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import wysiwygTranslations from "@uxf/wysiwyg/translations/translations";
|
|
41
|
+
import uiTranslations from "@uxf/ui/translations/translations";
|
|
42
|
+
import { createDevT } from "@uxf/core-react/translations/create-dev-t";
|
|
43
|
+
|
|
44
|
+
export const tFunction = createDevT("cs", {
|
|
45
|
+
...uiTranslations,
|
|
46
|
+
...wysiwygTranslations,
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Wire `tFunction` through the standard UXF setup (`translationFn` on `UiContextProvider` from `@uxf/ui/context`, or `TranslationsProvider` from `@uxf/core-react/translations`).
|
|
51
|
+
|
|
52
|
+
## Quick start
|
|
53
|
+
|
|
54
|
+
Build the plugin set once, then render `WysiwygEditor`. `createAllPluginsWithUi` enables every plugin; its only required option is `image` (image insertion needs `uploadImage` + `getImageUrl`).
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
"use client";
|
|
58
|
+
|
|
59
|
+
import { createAllPluginsWithUi, WysiwygContent, WysiwygEditor } from "@uxf/wysiwyg";
|
|
60
|
+
import { useState } from "react";
|
|
61
|
+
|
|
62
|
+
const plugins = createAllPluginsWithUi({
|
|
63
|
+
image: {
|
|
64
|
+
uploadImage: async (file) => uploadToS3(file), // returns FileResponse
|
|
65
|
+
getImageUrl: (file) => resolveUrl(file),
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const INITIAL_VALUE: WysiwygContent = [{ type: "paragraph", id: "p1", children: [{ text: "Hello" }] }];
|
|
70
|
+
|
|
71
|
+
export function MyEditor() {
|
|
72
|
+
const [value, setValue] = useState<WysiwygContent>(INITIAL_VALUE);
|
|
73
|
+
|
|
74
|
+
return <WysiwygEditor id="my-editor" initialValue={value} onChange={setValue} plugins={plugins} />;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
To enable only some plugins, compose them yourself with `createPluginsWithUi`:
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { createBoldPluginWithUi, createHeadingsPluginWithUi, createPluginsWithUi } from "@uxf/wysiwyg";
|
|
82
|
+
|
|
83
|
+
const plugins = createPluginsWithUi([
|
|
84
|
+
createHeadingsPluginWithUi({ disabledLevels: [1] }),
|
|
85
|
+
createBoldPluginWithUi(),
|
|
86
|
+
]);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Content model
|
|
90
|
+
|
|
91
|
+
`WysiwygContent` is a `WysiwygRootBlock[]` — a Plate/Slate document, not HTML. Each block carries a `type`, an optional `id`, and `children`:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
type WysiwygRootBlock =
|
|
95
|
+
| UxfParagraphElement // type: "paragraph"
|
|
96
|
+
| UxfHeadingElement // type: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"
|
|
97
|
+
| UxfBlockQuoteElement // type: "blockquote"
|
|
98
|
+
| UxfUnorderedListElement // type: "ul" (li > lic)
|
|
99
|
+
| UxfOrderedListElement // type: "ol" (li > lic)
|
|
100
|
+
| UxfLinkElement // type: "link" (inline)
|
|
101
|
+
| UxfImageElement // type: "image" (void)
|
|
102
|
+
| UxfVideoElement // type: "video" (void)
|
|
103
|
+
| UxfButtonElement; // type: "button" (void)
|
|
16
104
|
```
|
|
17
105
|
|
|
106
|
+
Inline text (`RichText`) carries the mark flags `bold`, `italic`, `underline`, `code`, `highlight`. `onChange` always receives the full, current document.
|
|
107
|
+
|
|
108
|
+
## API
|
|
109
|
+
|
|
110
|
+
Everything below is exported from the package root (`@uxf/wysiwyg`) unless a deep path is shown. There is no `exports` map, so deep imports resolve by filesystem.
|
|
111
|
+
|
|
112
|
+
### `WysiwygEditor`
|
|
113
|
+
|
|
114
|
+
`import { WysiwygEditor } from "@uxf/wysiwyg";`
|
|
115
|
+
|
|
116
|
+
| Prop | Type | Required | Description |
|
|
117
|
+
| --- | --- | --- | --- |
|
|
118
|
+
| `id` | `string` | yes | Unique Plate instance id. Must be unique per editor on the page. |
|
|
119
|
+
| `initialValue` | `WysiwygContent \| undefined` | yes | Document the editor is seeded with on mount. |
|
|
120
|
+
| `onChange` | `(value: WysiwygContent) => void` | yes | Called on every edit with the full document. |
|
|
121
|
+
| `plugins` | `UxfPlatePlugin[]` | yes | Build with `createAllPluginsWithUi` / `createPluginsWithUi`. |
|
|
122
|
+
| `className` | `string` | no | Class on the editor root wrapper. |
|
|
123
|
+
| `editableProps` | `TEditableProps<WysiwygContent>` | no | Passed to Plate's editable area (`placeholder`, `readOnly`, `autoFocus`, `spellCheck`, `className`, …). Defaults: `autoFocus: false`, `readOnly: false`, `spellCheck: false`, localized placeholder. |
|
|
124
|
+
| `customPluginsToolbarButtons` | `ReactNode` | no | Extra toolbar buttons appended to the built-in ones. |
|
|
125
|
+
| `toolbarLeftElement` | `ReactNode` | no | Node rendered at the toolbar's left edge. |
|
|
126
|
+
| `toolbarRightElement` | `ReactNode` | no | Node rendered at the toolbar's right edge. |
|
|
127
|
+
|
|
128
|
+
### Plugin builders
|
|
129
|
+
|
|
130
|
+
`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
|
+
|
|
132
|
+
| Export | Signature | Notes |
|
|
133
|
+
| --- | --- | --- |
|
|
134
|
+
| `createPluginsWithUi` | `(plugins: Array<WysiwygPlugin \| WysiwygRecursivePlugin<string>>, options?: { overrideByKey?: MyOverrideByKey }) => UxfPlatePlugin[]` | Compose a custom subset. |
|
|
135
|
+
| `createAllPluginsWithUi` | `(options: CreateAllPluginsOptions) => UxfPlatePlugin[]` | Enable every plugin. |
|
|
136
|
+
| `createHeadingsPluginWithUi` | `(options?: HeadingsPluginOptions) => WysiwygRecursivePlugin` | `disabledLevels?: (1..6)[]`. |
|
|
137
|
+
| `createBoldPluginWithUi` | `() => WysiwygPlugin` | |
|
|
138
|
+
| `createItalicPluginWithUi` | `() => WysiwygPlugin` | |
|
|
139
|
+
| `createUnderlinePluginWithUi` | `() => WysiwygPlugin` | |
|
|
140
|
+
| `createCodePluginWithUi` | `() => WysiwygPlugin` | |
|
|
141
|
+
| `createHighlightPluginWithUi` | `(color?: CSSProperties["color"]) => WysiwygPlugin` | Defaults to `twColors.yellow[300]`. |
|
|
142
|
+
| `createBlockquotePluginWithUi` | `() => WysiwygPlugin` | |
|
|
143
|
+
| `createListPluginWithUi` | `() => WysiwygRecursivePlugin` | Renders `ul` / `ol` / `li`. |
|
|
144
|
+
| `createLinkPluginWithUi` | `() => WysiwygPlugin` | |
|
|
145
|
+
| `createImagePluginWithUi` | `(options: UxfImagePluginOptions) => WysiwygPlugin` | See options below. |
|
|
146
|
+
| `createVideoPluginWithUi` | `() => WysiwygPlugin` | |
|
|
147
|
+
| `createButtonPluginWithUi` | `() => WysiwygPlugin` | |
|
|
148
|
+
|
|
149
|
+
`CreateAllPluginsOptions`:
|
|
150
|
+
|
|
151
|
+
| Key | Type | Required | Description |
|
|
152
|
+
| --- | --- | --- | --- |
|
|
153
|
+
| `image` | `UxfImagePluginOptions` | yes | Image plugin options (pass `{}` to enable without upload handlers). |
|
|
154
|
+
| `headings` | `HeadingsPluginOptions` | no | e.g. `{ disabledLevels: [1] }`. |
|
|
155
|
+
| `highlightColor` | `CSSProperties["color"]` | no | Highlight mark color. |
|
|
156
|
+
|
|
157
|
+
`UxfImagePluginOptions` (extends Plate's `MediaPlugin`):
|
|
158
|
+
|
|
159
|
+
| Key | Type | Description |
|
|
160
|
+
| --- | --- | --- |
|
|
161
|
+
| `uploadImage` | `(file: File) => Promise<FileResponse>` | Upload handler; returns a `FileResponse` (`@uxf/core/types`). |
|
|
162
|
+
| `getImageUrl` | `(file: FileResponse) => string` | Resolves the display URL for an uploaded file. |
|
|
163
|
+
| `disableUploadOnPasteImageUrl` | `boolean` | Disable auto-upload when an image URL is pasted. |
|
|
164
|
+
| `disableUploadOnPasteImage` | `boolean` | Disable auto-upload when an image blob is pasted. |
|
|
165
|
+
|
|
166
|
+
### Hooks
|
|
167
|
+
|
|
168
|
+
`import { ... } from "@uxf/wysiwyg";` — thin, typed wrappers over Plate's editor hooks, bound to `WysiwygContent` / `UxfEditor`:
|
|
169
|
+
|
|
170
|
+
`useUxfPlateEditorRef`, `useUxfEditorRef`, `useUxfEditorState`, `useUxfPlateEditorState`, `useUxfPlateSelectors`, `useUxfPlateActions`, `useUxfPlateStates`, and a re-export of `useSelected` (from `slate-react`).
|
|
171
|
+
|
|
172
|
+
### Utilities
|
|
173
|
+
|
|
174
|
+
Editor helpers for building custom plugins/toolbar buttons: `getUxfEditor`, `getPluginOptions`, `getPluginType`, `someNode`, `toggleNodeType`, `focusEditor`, `isRangeInSingleText`, `isMarkActive`, `toggleMark`, `isPluginEnabled`, `isSomeOfPluginsEnabled`, `getSelectedNode`, `getActiveElement`, `removeElement`, `insertVoid`, `removeSelectedNode`.
|
|
175
|
+
|
|
176
|
+
Serialize a document to plain text (deep import, not in the root barrel):
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import { serializeToPlaintext } from "@uxf/wysiwyg/serializers/serialize-to-plaintext";
|
|
180
|
+
|
|
181
|
+
serializeToPlaintext(value); // keepIndentation defaults to true (joins blocks with "\n")
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Types
|
|
185
|
+
|
|
186
|
+
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
|
+
|
|
188
|
+
## Gotchas
|
|
189
|
+
|
|
190
|
+
- **Client component only.** `WysiwygEditor` is marked `"use client"` and renders a `Loader` until it has mounted on the client; it cannot render on the server.
|
|
191
|
+
- **Uncontrolled value.** `initialValue` seeds the document once on mount. Changing `initialValue` later does not reset the editor — remount it (e.g. via a changed React `key`) to load a different document. Read the live value from `onChange`.
|
|
192
|
+
- **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
|
+
- **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
|
+
- **Translations are required.** Register `@uxf/wysiwyg/translations/translations`, otherwise labels/tooltips render as raw keys.
|
|
195
|
+
- **Pinned peers.** Plate/Slate and `@uxf/*` peer versions are pinned exactly (see `package.json`); mismatched versions will not work.
|
|
196
|
+
|
|
197
|
+
## Links
|
|
198
|
+
|
|
199
|
+
- [Plate documentation](https://plate.udecode.io) — the underlying editor framework.
|
|
200
|
+
- [Slate documentation](https://docs.slatejs.org) — the underlying document model.
|
|
201
|
+
- Package homepage: [gitlab.com/uxf-npm/wysiwyg](https://gitlab.com/uxf-npm/wysiwyg)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uxf/wysiwyg",
|
|
3
|
-
"version": "11.122.
|
|
3
|
+
"version": "11.122.5",
|
|
4
4
|
"description": "UXF Wysiwyg editor",
|
|
5
5
|
"author": "Robin Dvorak <dvorak@uxf.cz>",
|
|
6
6
|
"homepage": "https://gitlab.com/uxf-npm/wysiwyg",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@udecode/slate-utils": "19.7.1",
|
|
34
34
|
"@uxf/core": "11.114.0",
|
|
35
35
|
"@uxf/core-react": "11.122.2",
|
|
36
|
-
"@uxf/ui": "11.122.
|
|
36
|
+
"@uxf/ui": "11.122.5",
|
|
37
37
|
"react": ">=18.2.0",
|
|
38
38
|
"react-dom": ">=18.2.0",
|
|
39
39
|
"slate": "0.90.0",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"@udecode/slate-utils": "19.7.1",
|
|
65
65
|
"@uxf/core": "11.114.0",
|
|
66
66
|
"@uxf/core-react": "11.122.2",
|
|
67
|
-
"@uxf/ui": "11.122.
|
|
67
|
+
"@uxf/ui": "11.122.5",
|
|
68
68
|
"react": "18.3.1",
|
|
69
69
|
"react-dom": "18.3.1",
|
|
70
70
|
"slate": "0.90.0",
|