tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
27
pulls
pipelines
make copying buttons and alignment work
awarm.space
1 year ago
2a326ec9
fa1aca31
+64
-16
3 changed files
expand all
collapse all
unified
split
components
Blocks
TextBlock
RenderYJSFragment.tsx
useHandlePaste.ts
src
utils
getBlocksAsHTML.tsx
+9
-6
components/Blocks/TextBlock/RenderYJSFragment.tsx
···
6
export function RenderYJSFragment({
7
node,
8
wrapper,
0
9
}: {
10
node: XmlElement | XmlText | XmlHook;
11
wrapper?: "h1" | "h2" | "h3" | null;
0
12
}) {
13
if (node.constructor === XmlElement) {
14
switch (node.nodeName as keyof typeof nodes) {
15
case "paragraph": {
16
let children = node.toArray();
17
return (
18
-
<BlockWrapper wrapper={wrapper}>
19
{children.length === 0 ? (
20
<br />
21
) : (
···
49
</a>
50
);
51
return (
52
-
<span key={index} {...attributesToStyle(d)}>
53
{d.insert}
54
</span>
55
);
···
63
const BlockWrapper = (props: {
64
wrapper?: "h1" | "h2" | "h3" | null;
65
children: React.ReactNode;
0
66
}) => {
67
if (props.wrapper === null) return <>{props.children}</>;
68
-
if (!props.wrapper) return <p>{props.children}</p>;
69
switch (props.wrapper) {
70
case "h1":
71
-
return <h1>{props.children}</h1>;
72
case "h2":
73
-
return <h2>{props.children}</h2>;
74
case "h3":
75
-
return <h3>{props.children}</h3>;
76
}
77
};
78
···
6
export function RenderYJSFragment({
7
node,
8
wrapper,
9
+
attrs,
10
}: {
11
node: XmlElement | XmlText | XmlHook;
12
wrapper?: "h1" | "h2" | "h3" | null;
13
+
attrs?: { [k: string]: any };
14
}) {
15
if (node.constructor === XmlElement) {
16
switch (node.nodeName as keyof typeof nodes) {
17
case "paragraph": {
18
let children = node.toArray();
19
return (
20
+
<BlockWrapper wrapper={wrapper} attrs={attrs}>
21
{children.length === 0 ? (
22
<br />
23
) : (
···
51
</a>
52
);
53
return (
54
+
<span key={index} {...attributesToStyle(d)} {...attrs}>
55
{d.insert}
56
</span>
57
);
···
65
const BlockWrapper = (props: {
66
wrapper?: "h1" | "h2" | "h3" | null;
67
children: React.ReactNode;
68
+
attrs?: { [k: string]: any };
69
}) => {
70
if (props.wrapper === null) return <>{props.children}</>;
71
+
if (!props.wrapper) return <p {...props.attrs}>{props.children}</p>;
72
switch (props.wrapper) {
73
case "h1":
74
+
return <h1 {...props.attrs}>{props.children}</h1>;
75
case "h2":
76
+
return <h2 {...props.attrs}>{props.children}</h2>;
77
case "h3":
78
+
return <h3 {...props.attrs}>{props.children}</h3>;
79
}
80
};
81
+34
-9
components/Blocks/TextBlock/useHandlePaste.ts
···
54
let xml = new DOMParser().parseFromString(textHTML, "text/html");
55
let currentPosition = propsRef.current.position;
56
let children = flattenHTMLToTextBlocks(xml.body);
57
-
if (
58
-
children.find((c) =>
59
-
["P", "H1", "H2", "H3", "UL", "DIV", "SPAN", "IMG"].includes(
60
-
c.tagName,
61
-
),
62
-
) &&
63
-
!(children.length === 1 && children[0].tagName === "IMG")
64
-
) {
65
children.forEach((child, index) => {
66
createBlockFromHTML(child, {
67
parentType: propsRef.current.pageType,
···
243
});
244
}
245
}
0
0
0
0
0
0
0
0
0
0
0
246
if (child.tagName === "A") {
247
let href = child.getAttribute("href");
0
248
if (href) {
249
-
addLinkBlock(href, entityID, rep);
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
250
}
251
}
252
if (child.tagName === "IMG") {
···
54
let xml = new DOMParser().parseFromString(textHTML, "text/html");
55
let currentPosition = propsRef.current.position;
56
let children = flattenHTMLToTextBlocks(xml.body);
57
+
if (!(children.length === 1 && children[0].tagName === "IMG")) {
0
0
0
0
0
0
0
58
children.forEach((child, index) => {
59
createBlockFromHTML(child, {
60
parentType: propsRef.current.pageType,
···
236
});
237
}
238
}
239
+
let alignment = child.getAttribute("data-alignment");
240
+
if (alignment && ["right", "left", "center"].includes(alignment)) {
241
+
rep.mutate.assertFact({
242
+
entity: entityID,
243
+
attribute: "block/text-alignment",
244
+
data: {
245
+
type: "text-alignment-type-union",
246
+
value: alignment as "right" | "left" | "center",
247
+
},
248
+
});
249
+
}
250
if (child.tagName === "A") {
251
let href = child.getAttribute("href");
252
+
let dataType = child.getAttribute("data-type");
253
if (href) {
254
+
if (dataType === "button") {
255
+
rep.mutate.assertFact([
256
+
{
257
+
entity: entityID,
258
+
attribute: "block/type",
259
+
data: { type: "block-type-union", value: "button" },
260
+
},
261
+
{
262
+
entity: entityID,
263
+
attribute: "button/text",
264
+
data: { type: "string", value: child.textContent || "" },
265
+
},
266
+
{
267
+
entity: entityID,
268
+
attribute: "button/url",
269
+
data: { type: "string", value: href },
270
+
},
271
+
]);
272
+
} else {
273
+
addLinkBlock(href, entityID, rep);
274
+
}
275
}
276
}
277
if (child.tagName === "IMG") {
+21
-1
src/utils/getBlocksAsHTML.tsx
···
74
ignoreWrapper?: boolean,
75
) {
76
let wrapper: undefined | "h1" | "h2" | "h3";
0
77
if (b.type === "image") {
78
let [src] = await scanIndex(tx).eav(b.value, "block/image");
79
if (!src) return "";
80
-
return renderToStaticMarkup(<img src={src.data.src} />);
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
81
}
82
if (b.type === "heading") {
83
let headingLevel =
···
125
let nodes = doc.getXmlElement("prosemirror").toArray();
126
return renderToStaticMarkup(
127
<RenderYJSFragment
0
0
0
128
node={nodes[0]}
129
wrapper={ignoreWrapper ? null : wrapper}
130
/>,
···
74
ignoreWrapper?: boolean,
75
) {
76
let wrapper: undefined | "h1" | "h2" | "h3";
77
+
let [alignment] = await scanIndex(tx).eav(b.value, "block/text-alignment");
78
if (b.type === "image") {
79
let [src] = await scanIndex(tx).eav(b.value, "block/image");
80
if (!src) return "";
81
+
return renderToStaticMarkup(
82
+
<img src={src.data.src} data-alignment={alignment?.data.value} />,
83
+
);
84
+
}
85
+
if (b.type === "button") {
86
+
let [text] = await scanIndex(tx).eav(b.value, "button/text");
87
+
let [url] = await scanIndex(tx).eav(b.value, "button/url");
88
+
if (!text || !url) return "";
89
+
return renderToStaticMarkup(
90
+
<a
91
+
href={url.data.value}
92
+
data-type="button"
93
+
data-alignment={alignment?.data.value}
94
+
>
95
+
{text.data.value}
96
+
</a>,
97
+
);
98
}
99
if (b.type === "heading") {
100
let headingLevel =
···
142
let nodes = doc.getXmlElement("prosemirror").toArray();
143
return renderToStaticMarkup(
144
<RenderYJSFragment
145
+
attrs={{
146
+
"data-alignment": alignment?.data.value,
147
+
}}
148
node={nodes[0]}
149
wrapper={ignoreWrapper ? null : wrapper}
150
/>,