@docx-editor.dev/react 2.35.0-canary.20261104032723.sha-43c2012 → 2.35.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.
@@ -2,44 +2,37 @@
2
2
 
3
3
  # Accept or reject without scrolling
4
4
 
5
- When your own list drives the scroll, open an item with `useReview().setActive(key, { reveal: false })`. The caret moves to the item, and the page stays where it is. Then resolve the item with `accept(item)` or `reject(item)`. Review writes such as accept, reject, and comment never scroll the page.
5
+ Resolve a tracked change from your own list with `useReview().accept(item)` or `reject(item)`. Review writes such as accept, reject, and comment never scroll the page, and they need no prior activation.
6
+
7
+ ## Resolve a change without scrolling
8
+
9
+ The following row opens its item without scrolling and resolves it from two buttons:
6
10
 
7
11
  ```tsx
8
12
  import { useReview, type ReviewItemView } from '@docx-editor.dev/pro/react';
9
13
 
10
14
  export function ChangeRow({ item }: { item: ReviewItemView }) {
11
- const { setActive, accept, reject } = useReview();
15
+ const { setActive, accept, reject, lastRefusal } = useReview();
12
16
  return (
13
- <li onClick={() => setActive(item.key, { reveal: false })}>
14
- {item.text}
15
- <button
16
- disabled={item.readOnly}
17
- onClick={(event) => {
18
- event.stopPropagation();
19
- accept(item);
20
- }}
21
- >
17
+ <li>
18
+ <button onClick={() => setActive(item.key, { reveal: false })}>{item.text}</button>
19
+ <button disabled={item.readOnly} onClick={() => accept(item)}>
22
20
  Accept
23
21
  </button>
24
- <button
25
- disabled={item.readOnly}
26
- onClick={(event) => {
27
- event.stopPropagation();
28
- reject(item);
29
- }}
30
- >
22
+ <button disabled={item.readOnly} onClick={() => reject(item)}>
31
23
  Reject
32
24
  </button>
25
+ {lastRefusal?.key === item.key && <p role="alert">{lastRefusal.code}</p>}
33
26
  </li>
34
27
  );
35
28
  }
36
29
  ```
37
30
 
38
- `accept` and `reject` return `false` when the editor refuses the decision, for example in viewing mode. Read `useReview().lastRefusal` for the diagnostic code.
31
+ `accept` and `reject` return `false` when the editor refuses the decision, for example in viewing mode. `lastRefusal` holds the item key and the diagnostic code. In Vue it is a ref, so read `lastRefusal.value?.code` in script.
39
32
 
40
- The buttons stop the click from reaching the row, so a decision does not also activate the item.
33
+ ## Activate without scrolling
41
34
 
42
- `reveal` takes `false` or one of four placements:
35
+ `setActive(key, { reveal: false })` moves the caret to the item and keeps the scroll position. `reveal` takes `false` or one of four placements:
43
36
 
44
37
  | Value | Where the item lands |
45
38
  | --- | --- |
@@ -50,23 +43,14 @@ The buttons stop the click from reaching the row, so a decision does not also ac
50
43
 
51
44
  Add `announce: true` to open the packaged balloon or card for the item.
52
45
 
53
- ## Decide in a headless pipeline
46
+ ## Limits
54
47
 
55
- The editing API has no viewport. Load the revisions and call `Revision.accept()` or `Revision.reject()`.
48
+ - Disable the decision buttons for items where `item.readOnly` is `true`.
49
+ - If the whole row is clickable, stop button clicks from reaching it, so a decision does not also activate the item.
50
+ - Headless pipelines have no viewport. To decide changes on a server, call `Revision.accept()` or `Revision.reject()`. For more information, see [Tracked changes](https://www.docx-editor.dev/docs/2.x/editor-api/revisions).
56
51
 
57
- ```ts
58
- import { DocxEditor } from '@docx-editor.dev/editor-api';
52
+ ## See also
59
53
 
60
- const runtime = await DocxEditor.createServer(bytes, { author: 'Review bot' });
61
- await runtime.run(async (context) => {
62
- const revisions = context.document.body.revisions;
63
- revisions.load('items/author');
64
- await context.sync();
65
- for (const revision of revisions.items) {
66
- if (revision.author === 'Review bot') revision.accept();
67
- }
68
- await context.sync();
69
- });
70
- const saved = await runtime.save();
71
- runtime.dispose();
72
- ```
54
+ - [Tracked changes](https://www.docx-editor.dev/docs/2.x/pro/tracked-changes)
55
+ - [Diagnostics](https://www.docx-editor.dev/docs/2.x/guides/diagnostics)
56
+ - [Custom cards in the review rail](./custom-review-cards.md)
@@ -2,46 +2,65 @@
2
2
 
3
3
  # Comment on found text
4
4
 
5
- In a browser host, find the text with `editor.findMatches`, select the first match with `editor.selectMatch`, and then call `useReview().comment`. The comment is written as the editor's `author`, so set `author` on the editor and add `reviewModule()` to its modules. `selectMatch` opens the header, footer, or note that holds the match, so a match in any story works.
5
+ Find text with `editor.findMatches`, select a match with `editor.selectMatch`, and comment with `useReview().comment`. On a server, search with `body.search` and call `Range.insertComment`.
6
+
7
+ ## Comment on a search result
8
+
9
+ The following button comments on the first whole-word match of a term. The editor needs an `author` and `reviewModule()` in its modules.
6
10
 
7
11
  ```tsx
12
+ import { useState } from 'react';
8
13
  import { useDocxEditor } from '@docx-editor.dev/react';
9
14
  import { useReview } from '@docx-editor.dev/pro/react';
10
15
 
11
16
  export function CommentOnTerm({ term }: { term: string }) {
12
17
  const editor = useDocxEditor();
13
- const { comment } = useReview();
18
+ const { comment, lastRefusal } = useReview();
19
+ const [status, setStatus] = useState('');
14
20
  const run = () => {
15
21
  const [match] = editor?.findMatches(term, { wholeWord: true }) ?? [];
16
- if (match && editor?.selectMatch(match).ok) comment(`Define "${term}".`);
22
+ if (!match || !editor?.selectMatch(match).ok) return setStatus('No match');
23
+ setStatus(comment(`Define "${term}".`) ? '' : 'Refused');
17
24
  };
18
- return <button onClick={run}>Comment on {term}</button>;
25
+ return (
26
+ <>
27
+ <button onClick={run}>Comment on {term}</button>
28
+ {/* lastRefusal updates on the next render, so read it here. */}
29
+ <span role="status">{status === 'Refused' ? lastRefusal?.code : status}</span>
30
+ </>
31
+ );
19
32
  }
20
33
  ```
21
34
 
22
- `comment` returns `false` when the editor refuses the write. Read `useReview().lastRefusal` for the diagnostic code.
35
+ Comment only after `selectMatch(match).ok` is `true`. `selectMatch` opens the header, footer, or note that holds the match. `comment` returns `false` when the editor refuses the write, and `lastRefusal` holds the diagnostic code.
23
36
 
24
- ## Comment in a headless pipeline
37
+ ## Comment on a server
25
38
 
26
- On a server or in an agent pipeline, search the body and call `Range.insertComment`. The runtime writes the comment as its `author` option.
39
+ The following example searches the body, not every story, and saves the result:
27
40
 
28
41
  ```ts
29
42
  import { DocxEditor } from '@docx-editor.dev/editor-api';
30
43
 
31
44
  const runtime = await DocxEditor.createServer(bytes, { author: 'Review bot' });
32
- await runtime.run(async (context) => {
33
- const found = context.document.body.search(term, { matchWholeWord: true });
34
- found.load('items');
35
- await context.sync();
36
- found.items[0]?.insertComment(`Define "${term}".`);
37
- await context.sync();
38
- });
39
- const saved = await runtime.save();
40
- runtime.dispose();
45
+ try {
46
+ await runtime.run(async (context) => {
47
+ const found = context.document.body.search(term, { matchWholeWord: true });
48
+ found.load('items');
49
+ await context.sync();
50
+ if (found.items.length === 0) return;
51
+ found.items[0]!.insertComment(`Define "${term}".`);
52
+ await context.sync();
53
+ });
54
+ const saved = await runtime.save();
55
+ } finally {
56
+ runtime.dispose();
57
+ }
41
58
  ```
42
59
 
43
- Both paths save the same comment markup: the same `w:comment` attributes, the same date format, and the same range markers.
60
+ Load the search results before you read them, and end with `await context.sync()` to send the queued comment. The runtime writes the comment as its `author` option.
44
61
 
45
- ## Reply to a thread
62
+ ## See also
46
63
 
47
- To answer an existing comment, call `useReview().reply(item, text)` in a browser host, or `Comment.reply(text)` in the editing API.
64
+ - [Comments](https://www.docx-editor.dev/docs/2.x/pro/comments)
65
+ - [Diagnostics](https://www.docx-editor.dev/docs/2.x/guides/diagnostics)
66
+ - [Replace as a tracked change](./tracked-replacement.md)
@@ -2,9 +2,11 @@
2
2
 
3
3
  # Custom cards in the review rail
4
4
 
5
- To draw your own cards, render `DocxEditorReview` with `preset` set to `false` and put your card component inside it. Your component reads the items from `useReview()`, measures each card, stacks the cards with `useStackedReviewPositions`, and converts positions to pixels with `useReviewRailMetrics()`.
5
+ Render `DocxEditorReview` with `preset` set to `false` and put your card component inside it. The component reads items from `useReview()`, stacks measured cards with `useStackedReviewPositions`, and converts positions to pixels with `useReviewRailMetrics()`.
6
6
 
7
- Measure every card with a `ResizeObserver` and pass the heights in CSS pixels. Without measured heights, each card reserves only `defaultHeight`, and a taller card overlaps the next one.
7
+ ## Render custom cards
8
+
9
+ The following example measures each card with a `ResizeObserver`, stacks the cards, and shows a refused decision:
8
10
 
9
11
  ```tsx
10
12
  import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react';
@@ -17,17 +19,8 @@ import {
17
19
 
18
20
  type OnHeight = (key: string, height: number) => void;
19
21
 
20
- function MeasuredCard({
21
- id,
22
- top,
23
- onHeight,
24
- children,
25
- }: {
26
- id: string;
27
- top: number;
28
- onHeight: OnHeight;
29
- children: ReactNode;
30
- }) {
22
+ function MeasuredCard(props: { id: string; top: number; onHeight: OnHeight; children: ReactNode }) {
23
+ const { id, top, onHeight, children } = props;
31
24
  const ref = useRef<HTMLDivElement>(null);
32
25
  useEffect(() => {
33
26
  const node = ref.current!;
@@ -43,8 +36,9 @@ function MeasuredCard({
43
36
  }
44
37
 
45
38
  function MyCards() {
46
- const { items, selectionAnchorY, accept } = useReview();
39
+ const { items, selectionAnchorY, accept, lastRefusal } = useReview();
47
40
  const metrics = useReviewRailMetrics();
41
+ // A new map only when a height changes, so the stack recomputes only then.
48
42
  const [heights, setHeights] = useState<ReadonlyMap<string, number>>(() => new Map());
49
43
  const onHeight = useCallback<OnHeight>(
50
44
  (key, height) =>
@@ -67,6 +61,7 @@ function MyCards() {
67
61
  >
68
62
  {item.text}
69
63
  {item.kind === 'revision' && <button onClick={() => accept(item)}>Accept</button>}
64
+ {lastRefusal?.key === item.key && <p>{lastRefusal.code}</p>}
70
65
  </MeasuredCard>
71
66
  ))}
72
67
  <DocxEditorReview.Draft top={top(selectionAnchorY ?? 0)} />
@@ -84,22 +79,41 @@ export function MyRail() {
84
79
  }
85
80
  ```
86
81
 
87
- The heights map gets a new reference only when a height changes, so the stack recomputes only then. Keep that rule if you store heights another way.
82
+ `accept` returns `false` when the editor refuses, and `lastRefusal` names the item and the diagnostic code. `DocxEditorReview` already announces each refusal in a live region, so show it in the card as plain text. For a translated sentence, call `useReviewRefusalMessage()`.
83
+
84
+ ## Position cards and drafts
85
+
86
+ Convert a layout position to CSS pixels with `metrics.top + position * metrics.scale`.
87
+
88
+ | Input to `useStackedReviewPositions` | Description |
89
+ | --- | --- |
90
+ | `heights` | Measured card heights in CSS pixels, by item key. A card without a height reserves `defaultHeight`, and a taller card overlaps the next one. |
91
+ | `scale` | `metrics.scale`, CSS pixels per layout point. |
92
+ | `defaultHeight` | The height to reserve before a card is measured. |
93
+
94
+ `DocxEditorReview.Draft` renders only while a comment draft is open. Without `top`, it takes the packaged stack's position, so pass `top` from your own stack. To keep the box clear of your cards, add an entry at `selectionAnchorY` to the list that you stack, in document order.
88
95
 
89
- ## Root parts and card parts
96
+ ## Place review parts
90
97
 
91
- `DocxEditorReview` finds its parts among its own children by element type.
98
+ `DocxEditorReview` finds its parts among its own children by element type. Fragments are transparent in React and Vue.
92
99
 
93
- - **Root parts** are `List`, `Markers`, `AddComment`, `Draft`, and `Balloon`. Put them as direct children of `DocxEditorReview`. Fragments are transparent in React and in Vue. The rail gives these parts geometry that only it can compute, such as the comment button's `top`. A root part inside your own wrapper component is not a part. It renders as ordinary content, without that wiring.
94
- - **Card parts** are `Card`, `Empty`, and the parts inside a card, such as `Author`, `Summary`, `Accept`, and `Reply`. Put them inside `DocxEditorReview.List`.
100
+ | Part | Placement |
101
+ | --- | --- |
102
+ | `List`, `Markers`, `AddComment`, `Balloon` | Direct children of `DocxEditorReview`. Inside your own wrapper, a part renders as plain content without its geometry. |
103
+ | `Draft` | A direct child, or inside your own card component. Inside a custom stack, pass `top` explicitly. |
104
+ | `Card`, `Empty`, and card parts such as `Author`, `Summary`, `Accept`, and `Reply` | Inside `DocxEditorReview.List`. |
95
105
 
96
- With `preset` set to `false`, the rail adds no defaults. Root parts that you pass keep their wiring. Every other child renders as is inside the rail element, where `useReviewRailMetrics()` reads the rail's own measurement.
106
+ With `preset` set to `false`, the rail adds no defaults, but recognized parts keep their wiring. Other children render inside the rail element.
97
107
 
98
- ## Position the compose box
108
+ ## Limits
99
109
 
100
- `DocxEditorReview.Draft` renders only while a comment draft is open. A draft opens from `DocxEditorReview.AddComment` or from the `review.addComment` toolbar control. You can place `Draft` in either of these places:
110
+ - Disconnect each observer when its card unmounts or its item changes.
111
+ - In React, keep the heights map reference-stable. In Vue, keep it reactive.
112
+ - In the compact rail, `metrics.compact` is `true`. Place cards at `metrics.compactCardLeft`; `Draft` does this itself.
113
+ - Keep the column hidden while `metrics.left` is `null`.
101
114
 
102
- - As a direct child of `DocxEditorReview`.
103
- - Inside your own card component, as in the example. It still renders only while the draft is open.
115
+ ## See also
104
116
 
105
- Without `top`, the box sits where the packaged card stack puts it. That position comes from the packaged cards, not yours, so when you render your own cards, pass `top` from your own stack. In the narrow compact rail, the box takes the compact card's `left` in both cases, so it does not overflow the marker strip. The example places the box at the selection's anchor. To keep it clear of your cards, add an entry with the key of your choice and the anchor `selectionAnchorY` to the list that you pass to `useStackedReviewPositions`, in document order.
117
+ - [Review cards](https://www.docx-editor.dev/docs/2.x/customization/review-cards)
118
+ - [Tracked changes](https://www.docx-editor.dev/docs/2.x/pro/tracked-changes)
119
+ - [Accept or reject without scrolling](./accept-reject-without-scrolling.md)
@@ -2,13 +2,18 @@
2
2
 
3
3
  # Highlight ranges
4
4
 
5
- Use `useHighlights(name, source, options)` to mark text as a named set while a component is mounted. A function source runs again after document changes, so the marks follow the text. Highlights are view state. They do not change the document and are not saved.
5
+ Call `useHighlights(name, source, options)` to mark text as a named set while a component is mounted. Highlights are local view state. They do not change the document and are not saved.
6
+
7
+ ## Highlight matching text
8
+
9
+ The following component marks each whole-word match of a list of terms. Style the `glossary-term` class with your own CSS, or omit `className` for the default fill.
6
10
 
7
11
  ```tsx
8
12
  import { useCallback } from 'react';
9
13
  import { useHighlights, type Editor } from '@docx-editor.dev/react';
10
14
 
11
15
  export function GlossaryMarks({ terms }: { terms: readonly string[] }) {
16
+ // A stable function source, so the set refreshes only when `terms` changes.
12
17
  const findTerms = useCallback(
13
18
  (editor: Editor) => editor.findMatches(terms, { wholeWord: true }).flat(),
14
19
  [terms]
@@ -18,8 +23,24 @@ export function GlossaryMarks({ terms }: { terms: readonly string[] }) {
18
23
  }
19
24
  ```
20
25
 
21
- Keep a function source stable with `useCallback`.
26
+ A function source runs again after each document change, so the marks follow the text. The set is removed when the component unmounts.
27
+
28
+ ## Configure a highlight set
29
+
30
+ | Argument or field | Description |
31
+ | --- | --- |
32
+ | `name` | The set name. Two sets with the same name replace each other's ranges. |
33
+ | `source` | The ranges, or a function of the editor that returns them. |
34
+ | `options.className` | CSS classes added to every mark of the set. |
35
+ | `options.activeIndex` | The range to show in the active color, such as the current result of your own search list. |
36
+ | `applied` | The number of ranges that resolve and paint. |
37
+
38
+ ## Use highlights outside components
39
+
40
+ Call `watchHighlights(editor, name, source, options)` from `@docx-editor.dev/core/editor` to follow document changes. Call `stop()` on the returned watch to remove the set and stop watching. For a fixed set that does not refresh, call `editor.setHighlights`.
22
41
 
23
- Use a unique `name` for each set. Two calls with the same name replace each other's ranges. Set `activeIndex` in the options to show one range in the active color, for example the current result of your own search list.
42
+ ## See also
24
43
 
25
- Outside a component, call `watchHighlights(editor, name, source, options)` from `@docx-editor.dev/core/editor`, or `editor.setHighlights` for a fixed set.
44
+ - [Highlight text ranges](https://www.docx-editor.dev/docs/2.x/guides/navigation#highlight-text-ranges)
45
+ - [React hooks](https://www.docx-editor.dev/docs/2.x/react/hooks#usehighlights)
46
+ - [Vue composables](https://www.docx-editor.dev/docs/2.x/vue/composables#usehighlights)
package/docs/index.md CHANGED
@@ -1,36 +1,36 @@
1
1
  <!-- Generated from docs/site/content/recipes by scripts/sync-agent-docs.mjs. Edit the source and run `bun run docs:agent`. -->
2
2
 
3
- # Which API for which job
3
+ # Task recipes
4
4
 
5
- The library has two ways to change a document. Each one fits a different host. Choose the path first, then use the symbol for your task.
5
+ Each recipe solves one task with a complete code sample. Choose the API first, then find the symbol for your task.
6
6
 
7
- | Job | Use |
8
- | --- | --- |
9
- | Build a review UI in the browser | The React or Vue adapter hooks, plus the review hooks and `DocxEditorReview` from `@docx-editor.dev/pro/react` or `@docx-editor.dev/pro/vue`. |
10
- | Edit in a headless, server, or agent pipeline | The editing API in `@docx-editor.dev/editor-api`, which follows the Office.js object model. |
7
+ ## Which API for which job
11
8
 
12
- | Task | Browser host (React or Vue) | Headless, server, or agent |
9
+ Use the React or Vue adapter hooks, the review hooks, and `DocxEditorReview` from `@docx-editor.dev/pro/react` or `@docx-editor.dev/pro/vue` to build browser review controls. Use the editing API in `@docx-editor.dev/editor-api` for document automation. It follows the Office.js object model and runs in browser and server hosts.
10
+
11
+ | Task | Browser controls (React or Vue) | Document automation |
13
12
  | --- | --- | --- |
14
13
  | [Comment on found text](./comment-on-found-text.md) | `editor.findMatches`, `editor.selectMatch`, then `useReview().comment` | `body.search`, then `Range.insertComment` |
15
- | Reply to a thread | `useReview().reply(item, text)` | `Comment.reply(text)` |
14
+ | [Reply to a thread](https://www.docx-editor.dev/docs/2.x/pro/comments) | `useReview().reply(item, text)` | `Comment.reply(text)` |
16
15
  | [Record a tracked replacement](./tracked-replacement.md) | Suggesting mode, then `editor.exec({ type: 'replaceMatch', match, text })` | `document.changeTrackingMode = 'TrackMineOnly'`, then `Range.insertText(text, 'Replace')` |
17
- | [Propose an AI rewrite as tracked changes](./propose-rewrite.md) | The same code through `DocxEditor.createBrowser` from `@docx-editor.dev/editor-api/browser` | `prepareRewrite` from `@docx-editor.dev/editor-api/agent` |
16
+ | [Propose an AI rewrite as tracked changes](./propose-rewrite.md) | `prepareRewrite` through `DocxEditor.createBrowser` | `prepareRewrite` from `@docx-editor.dev/editor-api/agent` |
18
17
  | [Accept or reject a change](./accept-reject-without-scrolling.md) | `useReview().accept(item)` or `useReview().reject(item)` | `Revision.accept()` or `Revision.reject()` |
19
- | [Open or reveal a change without scrolling](./accept-reject-without-scrolling.md) | `useReview().setActive(key, { reveal: false })` | Not applicable: no viewport |
18
+ | [Open a change without scrolling](./accept-reject-without-scrolling.md) | `useReview().setActive(key, { reveal: false })` | Not applicable: no viewport |
20
19
  | [Highlight ranges](./highlight-ranges.md) | `useHighlights(name, source, options)` | Not applicable |
21
- | [Custom review rail cards](./custom-review-cards.md) | `DocxEditorReview` with `preset` set to `false`, `useReview().items`, `useStackedReviewPositions`, and `useReviewRailMetrics` | Not applicable |
20
+ | [Custom review rail cards](./custom-review-cards.md) | `DocxEditorReview` with `preset` set to `false`, `useStackedReviewPositions`, and `useReviewRailMetrics` | Not applicable |
22
21
  | Comment-on-selection button | `DocxEditorReview.AddComment` as a direct child of `DocxEditorReview`, or `useEditorCommand('review.addComment')` | Not applicable |
23
- | Page setup and paragraph dialogs from a custom toolbar | `DocxEditor.PageSetupDialog` or `DocxEditor.ParagraphDialog` with `open` and a close handler (`onClose` in React, `@close` in Vue); enable the button from `usePageSetup().isEnabled` or `useParagraphFormat().isEnabled` | `Section.pageSetup`, and `Paragraph` properties such as `alignment` |
22
+ | [Page setup and paragraph dialogs](https://www.docx-editor.dev/docs/2.x/customization/dialogs) | `DocxEditor.PageSetupDialog` or `DocxEditor.ParagraphDialog` | `Section.pageSetup`, and `Paragraph` properties such as `alignment` |
24
23
 
25
- The review hooks need `reviewModule()` from `@docx-editor.dev/pro` in the editor's modules, and an editor `author` for comments and tracked changes. The editing API takes its author from the `author` option of `DocxEditor.createServer`, imported from `@docx-editor.dev/editor-api`, or of `DocxEditor.createBrowser`, imported from `@docx-editor.dev/editor-api/browser`.
24
+ ## Check prerequisites
26
25
 
27
- ## Recipes
26
+ - The review hooks need `reviewModule()` from `@docx-editor.dev/pro` in the editor's modules.
27
+ - Comments and tracked changes need an author: the editor's `author` prop, or the runtime's `author` option.
28
+ - Create a server runtime with `DocxEditor.createServer` from `@docx-editor.dev/editor-api`. Create a browser runtime with `DocxEditor.createBrowser` from `@docx-editor.dev/editor-api/browser`.
29
+ - Review controls stay separate from the Office.js-shaped document model.
30
+ - `@docx-editor.dev/pro` and `@docx-editor.dev/editor-api` require the EigenPal Pro License. For more information, see [Pro features](https://www.docx-editor.dev/docs/2.x/pro).
28
31
 
29
- - [Comment on found text](./comment-on-found-text.md)
30
- - [Replace as a tracked change](./tracked-replacement.md)
31
- - [Propose an AI rewrite as tracked changes](./propose-rewrite.md)
32
- - [Custom cards in the review rail](./custom-review-cards.md)
33
- - [Highlight ranges](./highlight-ranges.md)
34
- - [Accept or reject without scrolling](./accept-reject-without-scrolling.md)
32
+ ## See also
35
33
 
36
- For the full hook reference, see [React hooks](https://www.docx-editor.dev/docs/2.x/react/hooks) and [Vue composables](https://www.docx-editor.dev/docs/2.x/vue/composables). For the editing API, see [Editing API](https://www.docx-editor.dev/docs/2.x/editor-api).
34
+ - [React hooks](https://www.docx-editor.dev/docs/2.x/react/hooks)
35
+ - [Vue composables](https://www.docx-editor.dev/docs/2.x/vue/composables)
36
+ - [Editing API](https://www.docx-editor.dev/docs/2.x/editor-api)