@uxf/wysiwyg 11.126.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 CHANGED
@@ -110,17 +110,18 @@ Everything below is exported from the package root (`@uxf/wysiwyg`) unless a dee
110
110
 
111
111
  `import { WysiwygEditor } from "@uxf/wysiwyg";`
112
112
 
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
- | `customPluginsToolbarButtons` | `ReactNode` | no | Extra toolbar buttons appended to the built-in ones. |
122
- | `toolbarLeftElement` | `ReactNode` | no | Node rendered at the toolbar's left edge. |
123
- | `toolbarRightElement` | `ReactNode` | no | Node rendered at the toolbar's right edge. |
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. |
124
125
 
125
126
  ### Plugin builders
126
127
 
@@ -180,6 +181,21 @@ serializeToPlaintext(value); // keepIndentation defaults to true (joins blocks w
180
181
 
181
182
  ### Types
182
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
+
183
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`).
184
200
 
185
201
  ## Gotchas
@@ -189,6 +205,7 @@ The full node model and editor types are re-exported, including: `WysiwygContent
189
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.
190
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.
191
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.
192
209
  - **Pinned peers.** Plate/Slate and `@uxf/*` peer versions are pinned exactly (see `package.json`); mismatched versions will not work.
193
210
 
194
211
  ## Links
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxf/wysiwyg",
3
- "version": "11.126.0",
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.126.0",
35
- "@uxf/core-react": "11.126.0",
36
- "@uxf/ui": "11.126.0",
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.126.0",
66
- "@uxf/core-react": "11.126.0",
67
- "@uxf/ui": "11.126.0",
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",
@@ -1,10 +1,15 @@
1
1
  import { TEditableProps } from "@udecode/plate-core";
2
- import { FC, ReactNode } from "react";
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 __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
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 = __importDefault(require("react"));
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;