Skip to content

Commit bb149cd

Browse files
committed
migrate buttons to useEditorState selectors
1 parent 0479373 commit bb149cd

8 files changed

Lines changed: 76 additions & 175 deletions

File tree

packages/ra-input-rich-text/src/RichTextInput.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Highlight from '@tiptap/extension-highlight';
77
import Image from '@tiptap/extension-image';
88
import Link from '@tiptap/extension-link';
99
import TextAlign from '@tiptap/extension-text-align';
10-
import TextStyle from '@tiptap/extension-text-style';
10+
import { TextStyle } from '@tiptap/extension-text-style';
1111
import Underline from '@tiptap/extension-underline';
1212
import { Editor, EditorContent, EditorOptions, useEditor } from '@tiptap/react';
1313
import StarterKit from '@tiptap/starter-kit';
@@ -120,8 +120,9 @@ export const RichTextInput = (props: RichTextInputProps) => {
120120

121121
const { from, to } = editor.state.selection;
122122

123-
editor.commands.setContent(field.value, false, {
124-
preserveWhitespace: true,
123+
editor.commands.setContent(field.value, {
124+
emitUpdate: false,
125+
parseOptions: { preserveWhitespace: true },
125126
});
126127
editor.commands.setTextSelection({ from, to });
127128
}, [editor, field.value]);

packages/ra-input-rich-text/src/buttons/AlignmentButtons.tsx

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
2-
import { MouseEvent, useEffect, useState } from 'react';
2+
import { MouseEvent } from 'react';
33

4-
import { Editor } from '@tiptap/react';
4+
import { Editor, useEditorState } from '@tiptap/react';
55
import {
66
ToggleButton,
77
ToggleButtonGroup,
@@ -18,38 +18,23 @@ import { useTiptapEditor } from '../useTiptapEditor';
1818
export const AlignmentButtons = (props: ToggleButtonGroupProps) => {
1919
const editor = useTiptapEditor();
2020
const translate = useTranslate();
21-
const [value, setValue] = useState<string>('left');
21+
22+
const value = useEditorState({
23+
editor,
24+
selector: ({ editor }) => {
25+
if (!editor) return 'left';
26+
return (
27+
AlignmentValues.find(v => editor.isActive({ textAlign: v })) ??
28+
'left'
29+
);
30+
},
31+
});
2232

2333
const leftLabel = translate('ra.tiptap.align_left', { _: 'Align left' });
2434
const rightLabel = translate('ra.tiptap.align_right', { _: 'Align right' });
2535
const centerLabel = translate('ra.tiptap.align_center', { _: 'Center' });
2636
const justifyLabel = translate('ra.tiptap.align_justify', { _: 'Justify' });
2737

28-
useEffect(() => {
29-
const handleUpdate = () => {
30-
setValue(currentValue =>
31-
AlignmentValues.reduce((acc, value) => {
32-
if (editor && editor.isActive({ textAlign: value })) {
33-
return value;
34-
}
35-
return acc;
36-
}, currentValue)
37-
);
38-
};
39-
40-
if (editor) {
41-
editor.on('update', handleUpdate);
42-
editor.on('selectionUpdate', handleUpdate);
43-
}
44-
45-
return () => {
46-
if (editor) {
47-
editor.off('update', handleUpdate);
48-
editor.off('selectionUpdate', handleUpdate);
49-
}
50-
};
51-
}, [editor]);
52-
5338
const handleChange = (
5439
event: MouseEvent<HTMLElement>,
5540
newFormat: string

packages/ra-input-rich-text/src/buttons/FormatButtons.tsx

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
2-
import { MouseEvent, useEffect, useState } from 'react';
2+
import { MouseEvent } from 'react';
33

4-
import { Editor } from '@tiptap/react';
4+
import { Editor, useEditorState } from '@tiptap/react';
55
import {
66
ToggleButton,
77
ToggleButtonGroup,
@@ -18,7 +18,12 @@ import { useTiptapEditor } from '../useTiptapEditor';
1818
export const FormatButtons = (props: ToggleButtonGroupProps) => {
1919
const editor = useTiptapEditor();
2020
const translate = useTranslate();
21-
const [values, setValues] = useState<string[]>([]);
21+
22+
const values = useEditorState({
23+
editor,
24+
selector: ({ editor }) =>
25+
editor ? FormatValues.filter(value => editor.isActive(value)) : [],
26+
});
2227

2328
const boldLabel = translate('ra.tiptap.bold', {
2429
_: 'Bold',
@@ -40,31 +45,6 @@ export const FormatButtons = (props: ToggleButtonGroupProps) => {
4045
_: 'Code',
4146
});
4247

43-
useEffect(() => {
44-
const handleUpdate = () => {
45-
setValues(() =>
46-
FormatValues.reduce((acc, value) => {
47-
if (editor && editor.isActive(value)) {
48-
acc.push(value);
49-
}
50-
return acc;
51-
}, [])
52-
);
53-
};
54-
55-
if (editor) {
56-
editor.on('update', handleUpdate);
57-
editor.on('selectionUpdate', handleUpdate);
58-
}
59-
60-
return () => {
61-
if (editor) {
62-
editor.off('update', handleUpdate);
63-
editor.off('selectionUpdate', handleUpdate);
64-
}
65-
};
66-
}, [editor]);
67-
6848
const handleChange = (
6949
event: MouseEvent<HTMLElement>,
7050
newFormats: string[]

packages/ra-input-rich-text/src/buttons/LevelSelect.tsx

Lines changed: 19 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import { useEffect, useState } from 'react';
2+
import { useState } from 'react';
33
import {
44
List,
55
ListItem,
@@ -10,6 +10,7 @@ import {
1010
} from '@mui/material';
1111
import { styled } from '@mui/material/styles';
1212
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
13+
import { useEditorState } from '@tiptap/react';
1314
import { useTranslate } from 'ra-core';
1415
import clsx from 'clsx';
1516
import { useTiptapEditor } from '../useTiptapEditor';
@@ -21,7 +22,23 @@ export const LevelSelect = (props: LevelSelectProps) => {
2122
null
2223
);
2324
const { size } = props;
24-
const [selectedOption, setSelectedOption] = useState(options[0]);
25+
26+
const selectedOption = useEditorState({
27+
editor,
28+
selector: ({ editor }) => {
29+
if (!editor) return options[0];
30+
return (
31+
options.find(option => {
32+
if (option.value === 'paragraph') {
33+
return editor.isActive('paragraph');
34+
}
35+
return editor.isActive('heading', {
36+
level: (option as HeadingLevelOption).level,
37+
});
38+
}) ?? options[0]
39+
);
40+
},
41+
});
2542

2643
const handleMenuItemClick = (
2744
event: React.MouseEvent<HTMLLIElement, MouseEvent>,
@@ -50,44 +67,6 @@ export const LevelSelect = (props: LevelSelectProps) => {
5067
setAnchorElement(null);
5168
};
5269

53-
useEffect(() => {
54-
const handleUpdate = () => {
55-
setSelectedOption(currentOption =>
56-
options.reduce((acc, option) => {
57-
if (editor) {
58-
if (
59-
option.value === 'paragraph' &&
60-
editor.isActive('paragraph')
61-
) {
62-
return option;
63-
}
64-
65-
if (
66-
editor.isActive('heading', {
67-
level: (option as HeadingLevelOption).level,
68-
})
69-
) {
70-
return option;
71-
}
72-
}
73-
return acc;
74-
}, currentOption)
75-
);
76-
};
77-
78-
if (editor) {
79-
editor.on('update', handleUpdate);
80-
editor.on('selectionUpdate', handleUpdate);
81-
}
82-
83-
return () => {
84-
if (editor) {
85-
editor.off('update', handleUpdate);
86-
editor.off('selectionUpdate', handleUpdate);
87-
}
88-
};
89-
}, [editor]);
90-
9170
return (
9271
<Root>
9372
<List

packages/ra-input-rich-text/src/buttons/LinkButtons.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as React from 'react';
22
import { ToggleButton, ToggleButtonProps } from '@mui/material';
33
import InsertLink from '@mui/icons-material/InsertLink';
4+
import { useEditorState } from '@tiptap/react';
45

56
import { useTranslate } from 'ra-core';
67
import { useTiptapEditor } from '../useTiptapEditor';
@@ -11,6 +12,11 @@ export const LinkButtons = (props: Omit<ToggleButtonProps, 'value'>) => {
1112
const translate = useTranslate();
1213
const currentTextSelection = useEditorSelection();
1314

15+
const isActive = useEditorState({
16+
editor,
17+
selector: ({ editor }) => (editor ? editor.isActive('link') : false),
18+
});
19+
1420
const label = translate('ra.tiptap.link', {
1521
_: 'Add a link',
1622
});
@@ -38,7 +44,7 @@ export const LinkButtons = (props: Omit<ToggleButtonProps, 'value'>) => {
3844
disabled={!editor?.isEditable || !currentTextSelection}
3945
value="link"
4046
onClick={handleClick}
41-
selected={editor && editor.isActive('link')}
47+
selected={isActive}
4248
>
4349
<InsertLink fontSize="inherit" />
4450
</ToggleButton>

packages/ra-input-rich-text/src/buttons/ListButtons.tsx

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as React from 'react';
2-
import { MouseEvent, useEffect, useState } from 'react';
2+
import { MouseEvent } from 'react';
33

44
import { findParentNode } from '@tiptap/core';
5-
import { Editor } from '@tiptap/react';
5+
import { Editor, useEditorState } from '@tiptap/react';
66
import {
77
ToggleButton,
88
ToggleButtonGroup,
@@ -25,7 +25,11 @@ export const ListButtons = (props: ToggleButtonGroupProps) => {
2525
_: 'Numbered list',
2626
});
2727

28-
const [value, setValue] = useState<string>();
28+
const value = useEditorState({
29+
editor,
30+
selector: ({ editor }) =>
31+
editor ? getInnermostListType(editor) : undefined,
32+
});
2933

3034
const handleChange = (
3135
event: MouseEvent<HTMLElement>,
@@ -45,24 +49,6 @@ export const ListButtons = (props: ToggleButtonGroupProps) => {
4549
}
4650
};
4751

48-
useEffect(() => {
49-
const handleUpdate = () => {
50-
setValue(editor ? getInnermostListType(editor) : undefined);
51-
};
52-
53-
if (editor) {
54-
editor.on('update', handleUpdate);
55-
editor.on('selectionUpdate', handleUpdate);
56-
}
57-
58-
return () => {
59-
if (editor) {
60-
editor.off('update', handleUpdate);
61-
editor.off('selectionUpdate', handleUpdate);
62-
}
63-
};
64-
}, [editor]);
65-
6652
return (
6753
<ToggleButtonGroup
6854
{...props}

packages/ra-input-rich-text/src/buttons/QuoteButtons.tsx

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,24 @@
11
import * as React from 'react';
2-
import { useEffect, useState } from 'react';
32
import { ToggleButton, ToggleButtonProps } from '@mui/material';
43
import FormatQuote from '@mui/icons-material/FormatQuote';
4+
import { useEditorState } from '@tiptap/react';
55
import { useTranslate } from 'ra-core';
66
import { useTiptapEditor } from '../useTiptapEditor';
77

88
export const QuoteButtons = (props: Omit<ToggleButtonProps, 'value'>) => {
99
const editor = useTiptapEditor();
1010
const translate = useTranslate();
11-
const [isActive, setIsActive] = useState(false);
11+
12+
const isActive = useEditorState({
13+
editor,
14+
selector: ({ editor }) =>
15+
editor ? editor.isActive('blockquote') : false,
16+
});
1217

1318
const label = translate('ra.tiptap.blockquote', {
1419
_: 'Blockquote',
1520
});
1621

17-
useEffect(() => {
18-
const handleUpdate = () => {
19-
setIsActive(editor && editor.isActive('blockquote'));
20-
};
21-
22-
if (editor) {
23-
editor.on('update', handleUpdate);
24-
editor.on('selectionUpdate', handleUpdate);
25-
}
26-
27-
return () => {
28-
if (editor) {
29-
editor.off('update', handleUpdate);
30-
editor.off('selectionUpdate', handleUpdate);
31-
}
32-
};
33-
}, [editor]);
34-
3522
return (
3623
<ToggleButton
3724
aria-label={label}
Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState } from 'react';
1+
import { useEditorState } from '@tiptap/react';
22
import { useTiptapEditor } from '../useTiptapEditor';
33

44
/**
@@ -8,37 +8,14 @@ import { useTiptapEditor } from '../useTiptapEditor';
88
export const useEditorSelection = () => {
99
const editor = useTiptapEditor();
1010

11-
const [selection, setSelection] = useState<string | null>(
12-
editor
13-
? editor.state.doc.textBetween(
14-
editor.state.selection.from,
15-
editor.state.selection.to
16-
)
17-
: null
18-
);
19-
20-
useEffect(() => {
21-
const handleSelectionChange = () => {
22-
setSelection(
23-
editor
24-
? editor.state.doc.textBetween(
25-
editor.state.selection.from,
26-
editor.state.selection.to
27-
)
28-
: null
29-
);
30-
};
31-
32-
if (editor) {
33-
editor.on('selectionUpdate', handleSelectionChange);
34-
}
35-
36-
return () => {
37-
if (editor) {
38-
editor.off('selectionUpdate', handleSelectionChange);
39-
}
40-
};
41-
}, [editor]);
42-
43-
return selection;
11+
return useEditorState({
12+
editor,
13+
selector: ({ editor }) =>
14+
editor
15+
? editor.state.doc.textBetween(
16+
editor.state.selection.from,
17+
editor.state.selection.to
18+
)
19+
: null,
20+
});
4421
};

0 commit comments

Comments
 (0)