Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: contentRef prop into useContent hook #789

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { defaultProps } from "@blocknote/core";
import { createReactBlockSpec } from "@blocknote/react";
import {
BlockConfig,
DefaultInlineContentSchema,
defaultProps,
DefaultStyleSchema,
} from "@blocknote/core";
import {
createReactBlockSpec,
ReactCustomBlockRenderProps,
useContent,
} from "@blocknote/react";
import { Menu } from "@mantine/core";
import { MdCancel, MdCheckCircle, MdError, MdInfo } from "react-icons/md";

Expand Down Expand Up @@ -49,72 +58,79 @@ export const alertTypes = [
},
] as const;

// The Alert block.
export const Alert = createReactBlockSpec(
{
type: "alert",
propSchema: {
textAlignment: defaultProps.textAlignment,
textColor: defaultProps.textColor,
type: {
default: "warning",
values: ["warning", "error", "info", "success"],
},
const alertBlockConfig = {
type: "alert",
propSchema: {
textAlignment: defaultProps.textAlignment,
textColor: defaultProps.textColor,
type: {
default: "warning",
values: ["warning", "error", "info", "success"],
},
content: "inline",
},
{
render: (props) => {
const alertType = alertTypes.find(
(a) => a.value === props.block.props.type
)!;
const Icon = alertType.icon;
content: "inline",
} satisfies BlockConfig;

return (
<div className={"alert"} data-alert-type={props.block.props.type}>
{/*Icon which opens a menu to choose the Alert type*/}
<Menu withinPortal={false} zIndex={999999}>
<Menu.Target>
<div className={"alert-icon-wrapper"} contentEditable={false}>
<Icon
className={"alert-icon"}
data-alert-icon-type={props.block.props.type}
size={32}
/>
</div>
</Menu.Target>
{/*Dropdown to change the Alert type*/}
<Menu.Dropdown>
<Menu.Label>Alert Type</Menu.Label>
<Menu.Divider />
{alertTypes.map((type) => {
const ItemIcon = type.icon;
const RenderAlert = (
props: ReactCustomBlockRenderProps<
typeof alertBlockConfig,
DefaultInlineContentSchema,
DefaultStyleSchema
>
) => {
const contentProps = useContent();

return (
<Menu.Item
key={type.value}
leftSection={
<ItemIcon
className={"alert-icon"}
data-alert-icon-type={type.value}
/>
}
onClick={() =>
props.editor.updateBlock(props.block, {
type: "alert",
props: { type: type.value },
})
}>
{type.title}
</Menu.Item>
);
})}
</Menu.Dropdown>
</Menu>
{/*Rich text field for user to type in*/}
<div className={"inline-content"} ref={props.contentRef} />
</div>
);
},
}
);
const alertType = alertTypes.find((a) => a.value === props.block.props.type)!;
const Icon = alertType.icon;

return (
<div className={"alert"} data-alert-type={props.block.props.type}>
{/*Icon which opens a menu to choose the Alert type*/}
<Menu withinPortal={false} zIndex={999999}>
<Menu.Target>
<div className={"alert-icon-wrapper"} contentEditable={false}>
<Icon
className={"alert-icon"}
data-alert-icon-type={props.block.props.type}
size={32}
/>
</div>
</Menu.Target>
{/*Dropdown to change the Alert type*/}
<Menu.Dropdown>
<Menu.Label>Alert Type</Menu.Label>
<Menu.Divider />
{alertTypes.map((type) => {
const ItemIcon = type.icon;

return (
<Menu.Item
key={type.value}
leftSection={
<ItemIcon
className={"alert-icon"}
data-alert-icon-type={type.value}
/>
}
onClick={() =>
props.editor.updateBlock(props.block, {
type: "alert",
props: { type: type.value },
})
}>
{type.title}
</Menu.Item>
);
})}
</Menu.Dropdown>
</Menu>
{/*Rich text field for user to type in*/}
<div className={"inline-content"} {...contentProps} />
</div>
);
};

// The Alert block.
export const Alert = createReactBlockSpec(alertBlockConfig, {
render: RenderAlert,
});
151 changes: 84 additions & 67 deletions examples/05-custom-schema/01-alert-block/Alert.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { defaultProps } from "@blocknote/core";
import { createReactBlockSpec } from "@blocknote/react";
import {
BlockConfig,
DefaultInlineContentSchema,
defaultProps,
DefaultStyleSchema,
} from "@blocknote/core";
import {
createReactBlockSpec,
ReactCustomBlockRenderProps,
useContent,
} from "@blocknote/react";
import { Menu } from "@mantine/core";
import { MdCancel, MdCheckCircle, MdError, MdInfo } from "react-icons/md";
import "./styles.css";
Expand Down Expand Up @@ -48,71 +57,79 @@ export const alertTypes = [
},
] as const;

// The Alert block.
export const Alert = createReactBlockSpec(
{
type: "alert",
propSchema: {
textAlignment: defaultProps.textAlignment,
textColor: defaultProps.textColor,
type: {
default: "warning",
values: ["warning", "error", "info", "success"],
},
const alertBlockConfig = {
type: "alert",
propSchema: {
textAlignment: defaultProps.textAlignment,
textColor: defaultProps.textColor,
type: {
default: "warning",
values: ["warning", "error", "info", "success"],
},
content: "inline",
},
{
render: (props) => {
const alertType = alertTypes.find(
(a) => a.value === props.block.props.type
)!;
const Icon = alertType.icon;
return (
<div className={"alert"} data-alert-type={props.block.props.type}>
{/*Icon which opens a menu to choose the Alert type*/}
<Menu withinPortal={false} zIndex={999999}>
<Menu.Target>
<div className={"alert-icon-wrapper"} contentEditable={false}>
<Icon
className={"alert-icon"}
data-alert-icon-type={props.block.props.type}
size={32}
/>
</div>
</Menu.Target>
{/*Dropdown to change the Alert type*/}
<Menu.Dropdown>
<Menu.Label>Alert Type</Menu.Label>
<Menu.Divider />
{alertTypes.map((type) => {
const ItemIcon = type.icon;
content: "inline",
} satisfies BlockConfig;

return (
<Menu.Item
key={type.value}
leftSection={
<ItemIcon
className={"alert-icon"}
data-alert-icon-type={type.value}
/>
}
onClick={() =>
props.editor.updateBlock(props.block, {
type: "alert",
props: { type: type.value },
})
}>
{type.title}
</Menu.Item>
);
})}
</Menu.Dropdown>
</Menu>
{/*Rich text field for user to type in*/}
<div className={"inline-content"} ref={props.contentRef} />
</div>
);
},
}
);
const RenderAlert = (
props: ReactCustomBlockRenderProps<
typeof alertBlockConfig,
DefaultInlineContentSchema,
DefaultStyleSchema
>
) => {
const contentProps = useContent();

const alertType = alertTypes.find((a) => a.value === props.block.props.type)!;
const Icon = alertType.icon;

return (
<div className={"alert"} data-alert-type={props.block.props.type}>
{/*Icon which opens a menu to choose the Alert type*/}
<Menu withinPortal={false} zIndex={999999}>
<Menu.Target>
<div className={"alert-icon-wrapper"} contentEditable={false}>
<Icon
className={"alert-icon"}
data-alert-icon-type={props.block.props.type}
size={32}
/>
</div>
</Menu.Target>
{/*Dropdown to change the Alert type*/}
<Menu.Dropdown>
<Menu.Label>Alert Type</Menu.Label>
<Menu.Divider />
{alertTypes.map((type) => {
const ItemIcon = type.icon;

return (
<Menu.Item
key={type.value}
leftSection={
<ItemIcon
className={"alert-icon"}
data-alert-icon-type={type.value}
/>
}
onClick={() =>
props.editor.updateBlock(props.block, {
type: "alert",
props: { type: type.value },
})
}>
{type.title}
</Menu.Item>
);
})}
</Menu.Dropdown>
</Menu>
{/*Rich text field for user to type in*/}
<div className={"inline-content"} {...contentProps} />
</div>
);
};

// The Alert block.
export const Alert = createReactBlockSpec(alertBlockConfig, {
render: RenderAlert,
});
12 changes: 8 additions & 4 deletions examples/05-custom-schema/03-font-style/Font.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { createReactStyleSpec } from "@blocknote/react";
import { createReactStyleSpec, useContent } from "@blocknote/react";

const RenderFont = (props: { value: string }) => {
const { style, ...rest } = useContent();

return <span style={{ fontFamily: props.value, ...style }} {...rest} />;
};

// The Font style.
export const Font = createReactStyleSpec(
Expand All @@ -7,8 +13,6 @@ export const Font = createReactStyleSpec(
propSchema: "string",
},
{
render: (props) => (
<span style={{ fontFamily: props.value }} ref={props.contentRef} />
),
render: RenderFont,
}
);
Loading
Loading