Skip to content

Commit 34bbf49

Browse files
committed
implement tests + first example
1 parent 5a685a1 commit 34bbf49

File tree

4 files changed

+63
-5
lines changed

4 files changed

+63
-5
lines changed

examples/06-custom-schema/react-custom-blocks/src/App.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,36 @@ export const alertBlock = createReactBlockSpec(
8383
},
8484
);
8585

86+
// TODO
87+
export const advancedBlock = createReactBlockSpec(
88+
{
89+
type: "advanced",
90+
propSchema: createPropSchemaFromZod(
91+
z.object({
92+
nested: z.object({
93+
type: z.enum(["warning", "error", "info", "success"]),
94+
message: z.string(),
95+
}),
96+
}),
97+
),
98+
content: "inline",
99+
},
100+
{
101+
render: (props) => (
102+
<div
103+
className={"alert"}
104+
style={{
105+
backgroundColor:
106+
alertTypes[props.block.props.nested.type].backgroundColor,
107+
}}
108+
>
109+
<span>{props.block.props.nested.message}</span>
110+
<div className={"inline-content"} ref={props.contentRef} />
111+
</div>
112+
),
113+
},
114+
);
115+
86116
const simpleImageBlock = createReactBlockSpec(
87117
{
88118
type: "simpleImage",
@@ -133,20 +163,32 @@ const schema = BlockNoteSchema.create({
133163
alert: alertBlock(),
134164
simpleImage: simpleImageBlock(),
135165
bracketsParagraph: bracketsParagraphBlock(),
166+
advanced: advancedBlock(),
136167
},
137168
});
138169

139170
export default function App() {
140171
const editor = useCreateBlockNote({
141172
schema,
142173
initialContent: [
174+
{
175+
type: "advanced",
176+
props: {
177+
nested: {
178+
type: "warning",
179+
message: "Warning",
180+
},
181+
},
182+
content: "Advanced",
183+
},
143184
{
144185
type: "alert",
145186
props: {
146187
type: "success",
147188
},
148189
content: "Alert",
149190
},
191+
150192
{
151193
type: "simpleImage",
152194
props: {

packages/core/src/schema/blocks/internal.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export function propsToAttributes(propSchema: PropSchema): Attributes {
3333
// Props are displayed in kebab-case as HTML attributes. If a prop's
3434
// value is the same as its default, we don't display an HTML
3535
// attribute for it.
36+
// TODO: needed? (seems tiptap specific)
3637
parseHTML: (element) => {
3738
const value = element.getAttribute(camelToDataKebab(name));
3839

@@ -50,13 +51,20 @@ export function propsToAttributes(propSchema: PropSchema): Attributes {
5051
return z.parse(spec, value);
5152
}
5253
},
54+
// TODO: needed? (seems tiptap specific)
5355
renderHTML: (attributes) => {
5456
// don't render to html if the value is the same as the default
55-
return attributes[name] !== def
56-
? {
57-
[camelToDataKebab(name)]: attributes[name],
58-
}
59-
: {};
57+
if (attributes[name] === def) {
58+
return {};
59+
}
60+
if (typeof attributes[name] === "object") {
61+
return {
62+
[camelToDataKebab(name)]: JSON.stringify(attributes[name]),
63+
};
64+
}
65+
return {
66+
[camelToDataKebab(name)]: attributes[name],
67+
};
6068
},
6169
};
6270
},

packages/react/src/schema/ReactBlockSpec.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export function BlockContentWrapper<
9292
// props which are already added as HTML attributes to the parent
9393
// `blockContent` element (inheritedProps) and props set to their default
9494
// values
95+
// TODO: reuse same code from core
9596
{...Object.fromEntries(
9697
Object.entries(props.blockProps)
9798
.filter(([prop, value]) => {
@@ -103,6 +104,9 @@ export function BlockContentWrapper<
103104
return value !== defaultValue;
104105
})
105106
.map(([prop, value]) => {
107+
if (typeof value === "object") {
108+
return [camelToDataKebab(prop), JSON.stringify(value)];
109+
}
106110
return [camelToDataKebab(prop), value];
107111
}),
108112
)}

packages/react/src/schema/ReactInlineContentSpec.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export function InlineContentWrapper<
8080
data-inline-content-type={props.inlineContentType}
8181
// Adds props as HTML attributes in kebab-case with "data-" prefix. Skips
8282
// props set to their default values.
83+
// TODO: reuse same code from core
8384
{...Object.fromEntries(
8485
Object.entries(props.inlineContentProps)
8586
.filter(([prop, value]) => {
@@ -91,6 +92,9 @@ export function InlineContentWrapper<
9192
return value !== defaultValue;
9293
})
9394
.map(([prop, value]) => {
95+
if (typeof value === "object") {
96+
return [camelToDataKebab(prop), JSON.stringify(value)];
97+
}
9498
return [camelToDataKebab(prop), value];
9599
}),
96100
)}

0 commit comments

Comments
 (0)