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