Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/core/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,15 +325,19 @@ export const en = {
},
align_left: {
tooltip: "Align text left",
label: "Left"
},
align_center: {
tooltip: "Align text center",
label: "Center"
},
align_right: {
tooltip: "Align text right",
label: "Right"
},
align_justify: {
tooltip: "Justify text",
label: "Justify"
},
table_cell_merge: {
tooltip: "Merge cells",
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/i18n/locales/pt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,15 +317,19 @@ export const pt: Dictionary = {
},
align_left: {
tooltip: "Alinhar à esquerda",
label: "Esquerda"
},
align_center: {
tooltip: "Alinhar ao centro",
label: "Centro"
},
align_right: {
tooltip: "Alinhar à direita",
label: "Direita"
},
align_justify: {
tooltip: "Justificar texto",
label: "Justificar"
},
Comment thread
GuiLeme marked this conversation as resolved.
table_cell_merge: {
tooltip: "Juntar células",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import {
blockHasType,
BlockSchema,
defaultProps,
DefaultProps,
editorHasBlockWithType,
InlineContentSchema,
mapTableCell,
StyleSchema,
TableContent,
} from "@blocknote/core";
import { TableHandlesExtension } from "@blocknote/core/extensions";
import { useCallback, useMemo } from "react";
import { IconType } from "react-icons";
import {
RiAlignCenter,
RiAlignJustify,
RiAlignLeft,
RiAlignRight,
} from "react-icons/ri";

import {
ComponentProps,
useComponentsContext,
} from "../../../editor/ComponentsContext.js";
import { useBlockNoteEditor } from "../../../hooks/useBlockNoteEditor.js";
import { useEditorState } from "../../../hooks/useEditorState.js";
import { useDictionary } from "../../../i18n/dictionary.js";

type TextAlignment = DefaultProps["textAlignment"];

const icons: Record<TextAlignment, IconType> = {
left: RiAlignLeft,
center: RiAlignCenter,
right: RiAlignRight,
justify: RiAlignJustify,
};

const alignments: TextAlignment[] = ["left", "center", "right", "justify"];

export const TextAlignSelect = () => {
const Components = useComponentsContext()!;
const dict = useDictionary();

const editor = useBlockNoteEditor<
BlockSchema,
InlineContentSchema,
StyleSchema
>();

const state = useEditorState({
editor,
selector: ({ editor }) => {
if (!editor.isEditable) {
return undefined;
}

const selectedBlocks = editor.getSelection()?.blocks || [
editor.getTextCursorPosition().block,
];

const firstBlock = selectedBlocks[0];

if (
blockHasType(firstBlock, editor, firstBlock.type, {
textAlignment: defaultProps.textAlignment,
})
) {
return {
textAlignment: firstBlock.props.textAlignment,
blocks: selectedBlocks,
};
}

if (
selectedBlocks.length === 1 &&
blockHasType(firstBlock, editor, "table")
) {
const cellSelection = editor
.getExtension(TableHandlesExtension)
?.getCellSelection();

if (!cellSelection) {
return undefined;
}

return {
textAlignment: mapTableCell(
(firstBlock.content as TableContent<any, any>).rows[0].cells[0],
).props.textAlignment,
blocks: [firstBlock],
};
}
Comment thread
GuiLeme marked this conversation as resolved.

return undefined;
},
});

const setTextAlignment = useCallback(
(textAlignment: TextAlignment) => {
if (state === undefined) {
return;
}

editor.focus();

for (const block of state.blocks) {
if (
blockHasType(block, editor, block.type, {
textAlignment: defaultProps.textAlignment,
}) &&
editorHasBlockWithType(editor, block.type, {
textAlignment: defaultProps.textAlignment,
})
) {
editor.updateBlock(block, {
props: { textAlignment },
});
} else if (block.type === "table") {
const cellSelection = editor
.getExtension(TableHandlesExtension)
?.getCellSelection();
if (!cellSelection) {
continue;
}

const newTable = (block.content as TableContent<any, any>).rows.map(
(row) => ({
...row,
cells: row.cells.map((cell) => mapTableCell(cell)),
}),
);

cellSelection.cells.forEach(({ row, col }) => {
newTable[row].cells[col].props.textAlignment = textAlignment;
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

editor.updateBlock(block, {
type: "table",
content: {
...(block.content as TableContent<any, any>),
type: "tableContent",
rows: newTable,
} as any,
});

editor.setTextCursorPosition(block);
}
}
},
[editor, state],
);

const selectItems: ComponentProps["FormattingToolbar"]["Select"]["items"] =
useMemo(
() =>
alignments.map((alignment) => {
const Icon = icons[alignment];
return {
text: dict.formatting_toolbar[`align_${alignment}`].label,
icon: <Icon size={16} />,
isSelected: state?.textAlignment === alignment,
onClick: () => setTextAlignment(alignment),
};
}),
[dict, setTextAlignment, state?.textAlignment],
);

if (state === undefined) {
return null;
}

return (
<Components.FormattingToolbar.Select
className={"bn-select"}
items={selectItems}
/>
);
};
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export * from "./components/FormattingToolbar/DefaultButtons/NestBlockButtons.js
export * from "./components/FormattingToolbar/DefaultButtons/TableCellMergeButton.js";
export * from "./components/FormattingToolbar/DefaultButtons/TextAlignButton.js";
export * from "./components/FormattingToolbar/DefaultSelects/BlockTypeSelect.js";
export * from "./components/FormattingToolbar/DefaultSelects/TextAlignSelect.js";
export * from "./components/FormattingToolbar/FormattingToolbar.js";
export * from "./components/FormattingToolbar/FormattingToolbarController.js";
export * from "./components/FormattingToolbar/ExperimentalMobileFormattingToolbarController.js";
Expand Down