@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.
Files changed (2) hide show
  1. package/README.md +191 -7
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,17 +1,201 @@
1
- # Wysiwyg
1
+ # @uxf/wysiwyg
2
2
 
3
- > **Note:** This package contains translations. For proper functionality, you must use the `TranslationsProvider` from `@uxf/core-react/translations`. See the [core-react documentation](https://fe.uxf.dev/docs/core-react) for more information.
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
- ```bash
8
- yarn add @uxf/core @uxf/ui @uxf/wysiwyg
13
+ ```
14
+ yarn add @uxf/wysiwyg
9
15
  ```
10
16
 
11
- ## CSS Dependencies
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
- /** link plugin css */
15
- @import url("@uxf/wysiwyg/styles/base.css");
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",
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.3",
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.3",
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",