Skip to content

Commit 06fa6f7

Browse files
committed
Refactored remaining uses of hooks with useEditorState where possible (excl. BlockTypeSelect)
1 parent 6a0150c commit 06fa6f7

File tree

7 files changed

+102
-101
lines changed

7 files changed

+102
-101
lines changed

packages/react/src/blocks/ToggleWrapper/ToggleWrapper.tsx

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import {
22
Block,
3+
blockHasType,
34
defaultToggledState,
45
UnreachableCaseError,
56
} from "@blocknote/core";
6-
import { ReactNode, useReducer, useState } from "react";
7+
import { ReactNode, useReducer } from "react";
78

89
import { ReactCustomBlockRenderProps } from "../../schema/ReactBlockSpec.js";
9-
import { useEditorChange } from "../../hooks/useEditorChange.js";
10+
import { useEditorState } from "../../hooks/useEditorState.js";
1011

1112
const showChildrenReducer = (
1213
showChildren: boolean,
@@ -51,7 +52,6 @@ export const ToggleWrapper = (
5152
showChildrenReducer,
5253
(toggledState || defaultToggledState).get(block),
5354
);
54-
const [childCount, setChildCount] = useState(block.children.length);
5555

5656
const handleToggle = (block: Block<any, any, any>) => {
5757
(toggledState || defaultToggledState).set(
@@ -77,28 +77,34 @@ export const ToggleWrapper = (
7777
});
7878
};
7979

80-
useEditorChange(() => {
81-
if ("isToggleable" in block.props && !block.props.isToggleable) {
82-
return;
83-
}
84-
85-
const newBlock = editor.getBlock(block)!;
86-
const newChildCount = newBlock.children.length ?? 0;
87-
88-
if (newChildCount > childCount) {
89-
// If a child block is added while children are hidden, show children.
90-
if (!showChildren) {
91-
handleChildAdded(newBlock);
80+
const childCount = useEditorState({
81+
editor,
82+
selector: ({ editor }) => {
83+
if (
84+
!blockHasType(block, editor, block.type, { isToggleable: "boolean" }) &&
85+
!block.props.isToggleable
86+
) {
87+
return 0;
9288
}
93-
} else if (newChildCount === 0 && newChildCount < childCount) {
94-
// If the last child block is removed while children are shown, hide
95-
// children.
96-
if (showChildren) {
97-
handleLastChildRemoved(newBlock);
89+
90+
const newBlock = editor.getBlock(block)!;
91+
const newChildCount = newBlock.children.length || 0;
92+
93+
if (newChildCount > childCount) {
94+
// If a child block is added while children are hidden, show children.
95+
if (!showChildren) {
96+
handleChildAdded(newBlock);
97+
}
98+
} else if (newChildCount === 0 && newChildCount < childCount) {
99+
// If the last child block is removed while children are shown, hide
100+
// children.
101+
if (showChildren) {
102+
handleLastChildRemoved(newBlock);
103+
}
98104
}
99-
}
100105

101-
setChildCount(newChildCount);
106+
return newChildCount;
107+
},
102108
});
103109

104110
if ("isToggleable" in block.props && !block.props.isToggleable) {

packages/react/src/components/FormattingToolbar/DefaultButtons/FileDeleteButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
InlineContentSchema,
55
StyleSchema,
66
} from "@blocknote/core";
7-
import { useCallback, useMemo } from "react";
7+
import { useCallback } from "react";
88
import { RiDeleteBin7Line } from "react-icons/ri";
99

1010
import { useComponentsContext } from "../../../editor/ComponentsContext.js";

packages/react/src/components/FormattingToolbar/DefaultButtons/FilePreviewButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
InlineContentSchema,
66
StyleSchema,
77
} from "@blocknote/core";
8-
import { useCallback, useMemo } from "react";
8+
import { useCallback } from "react";
99
import { RiImageAddFill } from "react-icons/ri";
1010

1111
import { useComponentsContext } from "../../../editor/ComponentsContext.js";

packages/react/src/components/FormattingToolbar/DefaultButtons/FileRenameButton.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@ import {
55
InlineContentSchema,
66
StyleSchema,
77
} from "@blocknote/core";
8-
import {
9-
ChangeEvent,
10-
KeyboardEvent,
11-
useCallback,
12-
useMemo,
13-
useState,
14-
} from "react";
8+
import { ChangeEvent, KeyboardEvent, useCallback, useState } from "react";
159
import { RiFontFamily } from "react-icons/ri";
1610

1711
import { useComponentsContext } from "../../../editor/ComponentsContext.js";

packages/react/src/components/FormattingToolbar/DefaultButtons/TextAlignButton.tsx

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
StyleSchema,
1010
TableContent,
1111
} from "@blocknote/core";
12-
import { useCallback, useMemo } from "react";
12+
import { useCallback } from "react";
1313
import { IconType } from "react-icons";
1414
import {
1515
RiAlignCenter,
@@ -20,7 +20,7 @@ import {
2020

2121
import { useComponentsContext } from "../../../editor/ComponentsContext.js";
2222
import { useBlockNoteEditor } from "../../../hooks/useBlockNoteEditor.js";
23-
import { useSelectedBlocks } from "../../../hooks/useSelectedBlocks.js";
23+
import { useEditorState } from "../../../hooks/useEditorState.js";
2424
import { useDictionary } from "../../../i18n/dictionary.js";
2525

2626
type TextAlignment = DefaultProps["textAlignment"];
@@ -42,44 +42,60 @@ export const TextAlignButton = (props: { textAlignment: TextAlignment }) => {
4242
StyleSchema
4343
>();
4444

45-
const selectedBlocks = useSelectedBlocks(editor);
46-
47-
const textAlignment = useMemo(() => {
48-
const block = selectedBlocks[0];
49-
50-
if (
51-
blockHasType(block, editor, block.type, {
52-
textAlignment: defaultProps.textAlignment,
53-
})
54-
) {
55-
return block.props.textAlignment;
56-
}
57-
if (block.type === "table") {
58-
const cellSelection = editor.tableHandles?.getCellSelection();
59-
if (!cellSelection) {
60-
return;
45+
const state = useEditorState({
46+
editor,
47+
selector: ({ editor }) => {
48+
if (!editor.isEditable) {
49+
return undefined;
6150
}
62-
const allCellsInTable = cellSelection.cells.map(
63-
({ row, col }) =>
64-
mapTableCell(
65-
(block.content as TableContent<any, any>).rows[row].cells[col],
66-
).props.textAlignment,
67-
);
68-
const firstAlignment = allCellsInTable[0];
6951

70-
if (allCellsInTable.every((alignment) => alignment === firstAlignment)) {
71-
return firstAlignment;
52+
const selectedBlocks = editor.getSelection()?.blocks || [
53+
editor.getTextCursorPosition().block,
54+
];
55+
56+
const firstBlock = selectedBlocks[0];
57+
58+
if (
59+
blockHasType(firstBlock, editor, firstBlock.type, {
60+
textAlignment: defaultProps.textAlignment,
61+
})
62+
) {
63+
return {
64+
textAlignment: firstBlock.props.textAlignment,
65+
blocks: selectedBlocks,
66+
};
67+
}
68+
69+
if (
70+
selectedBlocks.length === 1 &&
71+
blockHasType(firstBlock, editor, "table")
72+
) {
73+
const cellSelection = editor.tableHandles?.getCellSelection();
74+
if (!cellSelection) {
75+
return undefined;
76+
}
77+
78+
return {
79+
textAlignment: mapTableCell(
80+
(firstBlock.content as TableContent<any, any>).rows[0].cells[0],
81+
).props.textAlignment,
82+
blocks: [firstBlock],
83+
};
7284
}
73-
}
7485

75-
return;
76-
}, [editor, selectedBlocks]);
86+
return undefined;
87+
},
88+
});
7789

7890
const setTextAlignment = useCallback(
7991
(textAlignment: TextAlignment) => {
92+
if (state === undefined) {
93+
return;
94+
}
95+
8096
editor.focus();
8197

82-
for (const block of selectedBlocks) {
98+
for (const block of state.blocks) {
8399
if (
84100
blockHasType(block, editor, block.type, {
85101
textAlignment: defaultProps.textAlignment,
@@ -128,20 +144,10 @@ export const TextAlignButton = (props: { textAlignment: TextAlignment }) => {
128144
}
129145
}
130146
},
131-
[editor, selectedBlocks],
147+
[editor, state],
132148
);
133149

134-
const show = useMemo(() => {
135-
return !!selectedBlocks.find(
136-
(block) =>
137-
blockHasType(block, editor, block.type, {
138-
textAlignment: defaultProps.textAlignment,
139-
}) ||
140-
(block.type === "table" && block.children),
141-
);
142-
}, [editor, selectedBlocks]);
143-
144-
if (!show || !editor.isEditable) {
150+
if (state === undefined) {
145151
return null;
146152
}
147153

@@ -154,7 +160,7 @@ export const TextAlignButton = (props: { textAlignment: TextAlignment }) => {
154160
props.textAlignment.slice(1)
155161
}`}
156162
onClick={() => setTextAlignment(props.textAlignment)}
157-
isSelected={textAlignment === props.textAlignment}
163+
isSelected={state.textAlignment === props.textAlignment}
158164
label={dict.formatting_toolbar[`align_${props.textAlignment}`].tooltip}
159165
mainTooltip={
160166
dict.formatting_toolbar[`align_${props.textAlignment}`].tooltip

packages/react/src/components/FormattingToolbar/DefaultSelects/BlockTypeSelect.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
} from "../../../editor/ComponentsContext.js";
2929
import { useBlockNoteEditor } from "../../../hooks/useBlockNoteEditor.js";
3030
import { useEditorContentOrSelectionChange } from "../../../hooks/useEditorContentOrSelectionChange.js";
31-
import { useSelectedBlocks } from "../../../hooks/useSelectedBlocks.js";
31+
import { useEditorState } from "../../../hooks/useEditorState.js";
3232
import { useDictionary } from "../../../i18n/dictionary.js";
3333

3434
export type BlockTypeSelectItem = {
@@ -188,7 +188,11 @@ export const BlockTypeSelect = (props: { items?: BlockTypeSelectItem[] }) => {
188188
StyleSchema
189189
>();
190190

191-
const selectedBlocks = useSelectedBlocks(editor);
191+
const selectedBlocks = useEditorState({
192+
editor,
193+
selector: ({ editor }) =>
194+
editor.getSelection()?.blocks || [editor.getTextCursorPosition().block],
195+
});
192196

193197
const [block, setBlock] = useState(editor.getTextCursorPosition().block);
194198

packages/react/src/components/FormattingToolbar/FormattingToolbarController.tsx

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import {
2+
blockHasType,
23
BlockSchema,
4+
defaultProps,
35
DefaultProps,
46
InlineContentSchema,
57
StyleSchema,
68
} from "@blocknote/core";
79
import { UseFloatingOptions, flip, offset, shift } from "@floating-ui/react";
810
import { isEventTargetWithin } from "@floating-ui/react/utils";
9-
import { FC, useMemo, useRef, useState } from "react";
11+
import { FC, useMemo, useRef } from "react";
1012

1113
import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js";
12-
import { useEditorContentOrSelectionChange } from "../../hooks/useEditorContentOrSelectionChange.js";
14+
import { useEditorState } from "../../hooks/useEditorState.js";
1315
import { useUIElementPositioning } from "../../hooks/useUIElementPositioning.js";
1416
import { useUIPluginState } from "../../hooks/useUIPluginState.js";
1517
import { mergeRefs } from "../../util/mergeRefs.js";
@@ -43,33 +45,22 @@ export const FormattingToolbarController = (props: {
4345
StyleSchema
4446
>();
4547

46-
const [placement, setPlacement] = useState<"top-start" | "top" | "top-end">(
47-
() => {
48+
const placement = useEditorState({
49+
editor,
50+
selector: ({ editor }) => {
4851
const block = editor.getTextCursorPosition().block;
4952

50-
if (!("textAlignment" in block.props)) {
53+
if (
54+
!blockHasType(block, editor, block.type, {
55+
textAlignment: defaultProps.textAlignment,
56+
})
57+
) {
5158
return "top-start";
59+
} else {
60+
return textAlignmentToPlacement(block.props.textAlignment);
5261
}
53-
54-
return textAlignmentToPlacement(
55-
block.props.textAlignment as DefaultProps["textAlignment"],
56-
);
5762
},
58-
);
59-
60-
useEditorContentOrSelectionChange(() => {
61-
const block = editor.getTextCursorPosition().block;
62-
63-
if (!("textAlignment" in block.props)) {
64-
setPlacement("top-start");
65-
} else {
66-
setPlacement(
67-
textAlignmentToPlacement(
68-
block.props.textAlignment as DefaultProps["textAlignment"],
69-
),
70-
);
71-
}
72-
}, editor);
63+
});
7364

7465
// TODO refactor this to actually use the new extension & a hook for positioning to a selection
7566

0 commit comments

Comments
 (0)