@portabletext/editor 7.10.19 → 7.12.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.
Files changed (40) hide show
  1. package/README.md +57 -64
  2. package/lib/{behavior.types.action-CYtiRDck.d.ts → behavior.types.action-DH6ujvaH.d.ts} +409 -109
  3. package/lib/behavior.types.action-DH6ujvaH.d.ts.map +1 -0
  4. package/lib/{behavior.types.behavior-B_77VtQR.js → behavior.types.behavior-BxSLb73I.js} +5 -5
  5. package/lib/behavior.types.behavior-BxSLb73I.js.map +1 -0
  6. package/lib/behaviors/index.d.ts +1 -1
  7. package/lib/behaviors/index.js +1 -1
  8. package/lib/{get-container-BeXYKpoi.js → get-container-D1nM_ww9.js} +14 -14
  9. package/lib/get-container-D1nM_ww9.js.map +1 -0
  10. package/lib/{get-parent-51Kzgaf9.js → get-parent-Ci5241qs.js} +3 -3
  11. package/lib/get-parent-Ci5241qs.js.map +1 -0
  12. package/lib/{get-path-sub-schema--2I4NJbG.js → get-path-sub-schema-CZd9VcVM.js} +10 -10
  13. package/lib/get-path-sub-schema-CZd9VcVM.js.map +1 -0
  14. package/lib/index.d.ts +2 -2
  15. package/lib/index.js +294 -101
  16. package/lib/index.js.map +1 -1
  17. package/lib/plugins/index.d.ts +6 -6
  18. package/lib/plugins/index.js +5 -5
  19. package/lib/plugins/index.js.map +1 -1
  20. package/lib/{selector.is-at-the-start-of-block-gJIMWRpU.js → selector.is-at-the-start-of-block-D0boZbDu.js} +4 -4
  21. package/lib/selector.is-at-the-start-of-block-D0boZbDu.js.map +1 -0
  22. package/lib/selectors/index.d.ts +6 -6
  23. package/lib/selectors/index.js +6 -6
  24. package/lib/selectors/index.js.map +1 -1
  25. package/lib/traversal/index.d.ts +31 -31
  26. package/lib/traversal/index.js +4 -4
  27. package/lib/traversal/index.js.map +1 -1
  28. package/lib/{util.is-equal-selections-BF4WJtz5.js → util.is-equal-selections-N1hxVUbE.js} +2 -2
  29. package/lib/{util.is-equal-selections-BF4WJtz5.js.map → util.is-equal-selections-N1hxVUbE.js.map} +1 -1
  30. package/lib/{util.slice-blocks-DQnr9X2s.js → util.slice-blocks-B2fZcNok.js} +2 -2
  31. package/lib/{util.slice-blocks-DQnr9X2s.js.map → util.slice-blocks-B2fZcNok.js.map} +1 -1
  32. package/lib/utils/index.d.ts +1 -1
  33. package/lib/utils/index.js +3 -3
  34. package/package.json +3 -3
  35. package/lib/behavior.types.action-CYtiRDck.d.ts.map +0 -1
  36. package/lib/behavior.types.behavior-B_77VtQR.js.map +0 -1
  37. package/lib/get-container-BeXYKpoi.js.map +0 -1
  38. package/lib/get-parent-51Kzgaf9.js.map +0 -1
  39. package/lib/get-path-sub-schema--2I4NJbG.js.map +0 -1
  40. package/lib/selector.is-at-the-start-of-block-gJIMWRpU.js.map +0 -1
package/README.md CHANGED
@@ -17,7 +17,7 @@ In order to set up an editor you'll need to:
17
17
 
18
18
  - Create a schema that defines the rich text and block content elements.
19
19
  - Create a toolbar to toggle and insert these elements.
20
- - Write render functions to style and display each element type in the editor.
20
+ - Set up rendering for each element type in the editor, including text blocks and inline formatting.
21
21
  - Render the editor.
22
22
 
23
23
  Check out the [Portable Text Playground](../../apps/playground/) for a comprehensive example of the editor in action.
@@ -41,16 +41,14 @@ Next, in your app or the component you're building, import `EditorProvider`, `Po
41
41
  ```tsx
42
42
  // App.tsx
43
43
  import {
44
+ defineDecorator,
44
45
  defineSchema,
46
+ defineTextBlock,
45
47
  EditorProvider,
46
48
  PortableTextEditable,
47
49
  } from '@portabletext/editor'
48
- import type {
49
- PortableTextBlock,
50
- RenderDecoratorFunction,
51
- RenderStyleFunction,
52
- } from '@portabletext/editor'
53
- import {EventListenerPlugin} from '@portabletext/editor/plugins'
50
+ import type {PortableTextBlock} from '@portabletext/editor'
51
+ import {EventListenerPlugin, NodePlugin} from '@portabletext/editor/plugins'
54
52
  ```
55
53
 
56
54
  ### Define the schema
@@ -103,16 +101,14 @@ Add `useState` from React, then scaffold out a basic application component. For
103
101
  ```tsx
104
102
  // app.tsx
105
103
  import {
104
+ defineDecorator,
106
105
  defineSchema,
106
+ defineTextBlock,
107
107
  EditorProvider,
108
108
  PortableTextEditable,
109
109
  } from '@portabletext/editor'
110
- import type {
111
- PortableTextBlock,
112
- RenderDecoratorFunction,
113
- RenderStyleFunction,
114
- } from '@portabletext/editor'
115
- import {EventListenerPlugin} from '@portabletext/editor/plugins'
110
+ import type {PortableTextBlock} from '@portabletext/editor'
111
+ import {EventListenerPlugin, NodePlugin} from '@portabletext/editor/plugins'
116
112
  import {useState} from 'react'
117
113
 
118
114
  const schemaDefinition = defineSchema({
@@ -154,77 +150,77 @@ export default App
154
150
 
155
151
  Include the `App` component in your application and run it. You should see an outlined editor that accepts text, but doesn't do much else.
156
152
 
157
- ### Create render functions for schema elements
153
+ ### Set up rendering for schema elements
158
154
 
159
- At this point the PTE only has a schema, but it doesn't know how to render anything. Fix that by creating render functions for each property in the schema.
155
+ At this point the editor renders every text block as plain text, whatever its style. Fix that by registering a `defineTextBlock` node for the text blocks and `defineDecorator`/`defineAnnotation` nodes for the marks. If your editor still renders through the deprecated `renderStyle`, `renderBlock`, `renderListItem`, `renderChild`, `renderDecorator`, and `renderAnnotation` props, see the [migration guide](https://www.portabletext.org/editor/guides/migrate-render-props/) to move to node registrations instead.
160
156
 
161
- Start by creating a render function for styles.
157
+ Start by registering the text block render with `defineTextBlock`. The editor dispatches every text block to this callback. Your callback owns the block's wrapper element, so spread `props.attributes` on the outermost element you return, and use the block's `style` to pick the element.
162
158
 
163
159
  ```tsx
164
- const renderStyle: RenderStyleFunction = (props) => {
165
- if (props.schemaType.value === 'h1') {
166
- return <h1>{props.children}</h1>
167
- }
168
- if (props.schemaType.value === 'h2') {
169
- return <h2>{props.children}</h2>
170
- }
171
- if (props.schemaType.value === 'h3') {
172
- return <h3>{props.children}</h3>
173
- }
174
- if (props.schemaType.value === 'blockquote') {
175
- return <blockquote>{props.children}</blockquote>
176
- }
177
- return <>{props.children}</>
178
- }
160
+ const textBlock = defineTextBlock({
161
+ type: 'block',
162
+ render: (props) => {
163
+ if (props.node.style === 'h1') {
164
+ return <h1 {...props.attributes}>{props.children}</h1>
165
+ }
166
+ if (props.node.style === 'h2') {
167
+ return <h2 {...props.attributes}>{props.children}</h2>
168
+ }
169
+ if (props.node.style === 'h3') {
170
+ return <h3 {...props.attributes}>{props.children}</h3>
171
+ }
172
+ if (props.node.style === 'blockquote') {
173
+ return <blockquote {...props.attributes}>{props.children}</blockquote>
174
+ }
175
+ return <div {...props.attributes}>{props.children}</div>
176
+ },
177
+ })
179
178
  ```
180
179
 
181
- Render functions all follow the same format.
180
+ Marks (decorators and annotations) join the same `nodes` array. Registrations all follow the same shape.
182
181
 
183
182
  - They take in props and return JSX elements.
184
- - They use the schema to make decisions.
185
- - They return JSX and pass `children` as a fallback.
183
+ - They decide what to render from the registration's `type` and the node itself, not a separate schema-type argument.
184
+ - They return JSX that renders `children` somewhere inside it, the editable content the registration wraps.
186
185
 
187
186
  With this in mind, continue for the remaining schema types.
188
187
 
189
- Create a render function for decorators.
188
+ Register a decorator with `defineDecorator`, one per decorator name.
190
189
 
191
190
  ```tsx
192
- const renderDecorator: RenderDecoratorFunction = (props) => {
193
- if (props.value === 'strong') {
194
- return <strong>{props.children}</strong>
195
- }
196
- if (props.value === 'em') {
197
- return <em>{props.children}</em>
198
- }
199
- if (props.value === 'underline') {
200
- return <u>{props.children}</u>
201
- }
202
- return <>{props.children}</>
203
- }
191
+ const strong = defineDecorator({
192
+ type: 'strong',
193
+ render: ({children}) => <strong>{children}</strong>,
194
+ })
195
+ const em = defineDecorator({
196
+ type: 'em',
197
+ render: ({children}) => <em>{children}</em>,
198
+ })
199
+ const underline = defineDecorator({
200
+ type: 'underline',
201
+ render: ({children}) => <u>{children}</u>,
202
+ })
203
+
204
+ const nodes = [textBlock, strong, em, underline]
204
205
  ```
205
206
 
206
207
  > [!NOTE]
207
- > By default, text is rendered as an inline `span` element in the editor. While most render functions return a fragment (`<>`) as the fallback, make sure block level elements return blocks, like `<div>` elements.
208
-
209
- Update the `PortableTextEditable` with each corresponding function to attach them to the editor.
208
+ > By default, text is rendered as an inline `span` element in the editor. A decorator's render can pass `children` through unwrapped, but the registered text block render must return a block-level element, like a `<div>`.
210
209
 
211
- You may notice that we skipped a few types from the schema. Declare these inline in the configuration, like in the code below. You can learn more about [customizing the render functions](https://www.portabletext.org/editor/guides/custom-rendering/) in the documentation.
210
+ Mount every registration through one `NodePlugin`, inside the `EditorProvider`. Keep the `nodes` array itself at module scope, as above: a fresh array on every render would make `NodePlugin` unregister and re-register on every keystroke. You can learn more about [customizing the rendering](https://www.portabletext.org/editor/guides/custom-rendering/) in the documentation.
212
211
 
213
212
  ```tsx
214
- <PortableTextEditable
215
- style={{border: '1px solid black', padding: '0.5em'}}
216
- renderStyle={renderStyle}
217
- renderDecorator={renderDecorator}
218
- renderBlock={(props) => <div>{props.children}</div>}
219
- renderListItem={(props) => <>{props.children}</>}
220
- />
213
+ <>
214
+ <NodePlugin nodes={nodes} />
215
+ <PortableTextEditable style={{border: '1px solid black', padding: '0.5em'}} />
216
+ </>
221
217
  ```
222
218
 
223
219
  Before you can see if anything changed, you need a way to interact with the editor.
224
220
 
225
221
  ### Create a toolbar
226
222
 
227
- A toolbar is a collection of UI elements for interacting with the editor. The PTE library gives you the necessary hooks to create a toolbar however you like. Learn more about [creating your own toolbar](https://www.portabletext.org/editor/guides/customize-toolbar/) in the documentation.
223
+ A toolbar is a collection of UI elements for interacting with the editor. [`@portabletext/toolbar`](../toolbar/) provides ready-made hooks (`useStyleSelector`, `useDecoratorButton`, and more) for common toolbar UI; see the [toolbar customization guide](https://www.portabletext.org/editor/guides/customize-toolbar/) to use them. What follows here is the lower-level approach: sending events to the editor directly.
228
224
 
229
225
  1. Create a `Toolbar` component in the same file.
230
226
  2. Import the `useEditor` hook, and declare an `editor` constant in the component.
@@ -293,7 +289,7 @@ The `useEditor` hook gives you access to the active editor. `send` lets you send
293
289
 
294
290
  ### Bring it all together
295
291
 
296
- With render functions created and a toolbar in place, you can fully render the editor. Add the `Toolbar` inside the `EditorProvider`.
292
+ With the registrations created and a toolbar in place, you can fully render the editor. Add the `Toolbar` inside the `EditorProvider`.
297
293
 
298
294
  ```tsx
299
295
  // App.tsx
@@ -319,12 +315,9 @@ function App() {
319
315
  }}
320
316
  />
321
317
  <Toolbar />
318
+ <NodePlugin nodes={nodes} />
322
319
  <PortableTextEditable
323
320
  style={{border: '1px solid black', padding: '0.5em'}}
324
- renderStyle={renderStyle}
325
- renderDecorator={renderDecorator}
326
- renderBlock={(props) => <div>{props.children}</div>}
327
- renderListItem={(props) => <>{props.children}</>}
328
321
  />
329
322
  </EditorProvider>
330
323
  </>