Skip to content

Commit dca5d67

Browse files
author
Zaydek Michels-Gualtieri
committed
Prototypes ::before and ::after implementation of display markdown mode. This one seems to work less well because we forfeit control of how elements render and we can’t render a selection background color on highlight -- which may be ideal for communicating ‘copy as markdown’. It also makes it harder to conditionally style select elements as font-mono.
1 parent a2ef79a commit dca5d67

5 files changed

Lines changed: 93 additions & 48 deletions

File tree

src/RichTextEditor/RichTextEditor.css

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,29 @@
11
[data-root] {
2+
--font-sans:
3+
"-apple-system",
4+
"BlinkMacSystemFont",
5+
"Inter",
6+
"system-ui",
7+
"-apple-system",
8+
"BlinkMacSystemFont",
9+
"Segoe UI",
10+
"Roboto",
11+
"Helvetica Neue",
12+
"Arial",
13+
"Noto Sans",
14+
"sans-serif",
15+
"Apple Color Emoji",
16+
"Segoe UI Emoji",
17+
"Segoe UI Symbol",
18+
"Noto Color Emoji";
19+
--font-mono:
20+
"Menlo",
21+
"Monaco",
22+
"Consolas",
23+
"Liberation Mono",
24+
"Courier New",
25+
"monospace";
26+
227
-webkit-font-smoothing: auto;
328
-moz-osx-font-smoothing: auto;
429

@@ -8,13 +33,31 @@
833
caret-color: var(--black);
934
}
1035

11-
/* Obscures markdown syntax. */
12-
[data-display-markdown-mode="false"] [data-type="markdown"] {
13-
display: none;
36+
/* Displays markdown syntax as pseudo elements (1 of 2). */
37+
[data-display-markdown-mode="true"] [data-type="em"]::before,
38+
[data-display-markdown-mode="true"] [data-type="strong"]::before,
39+
[data-display-markdown-mode="true"] [data-type="code"]::before,
40+
[data-display-markdown-mode="true"] [data-type="strike"]::before,
41+
[data-display-markdown-mode="true"] [data-type="a"]::before {
42+
content: attr(data-markdown-start);
43+
--text-opacity: 1;
44+
color: #1c64f2;
45+
color: rgba(28, 100, 242, var(--text-opacity));
46+
}
47+
/* Displays markdown syntax as pseudo elements (2 of 2). */
48+
[data-display-markdown-mode="true"] [data-type="em"]::after,
49+
[data-display-markdown-mode="true"] [data-type="strong"]::after,
50+
[data-display-markdown-mode="true"] [data-type="code"]::after,
51+
[data-display-markdown-mode="true"] [data-type="strike"]::after,
52+
[data-display-markdown-mode="true"] [data-type="a"]::after {
53+
content: attr(data-markdown-end);
54+
--text-opacity: 1;
55+
color: #1c64f2;
56+
color: rgba(28, 100, 242, var(--text-opacity));
1457
}
1558

16-
/* Masks markdown syntax as text-blue-600. */
17-
[data-display-markdown-mode="true"] [data-type="strike"] [data-type="markdown"] {
59+
/* <strike> .text-blue-600 -> <strike> .text-gray-400 */
60+
[data-display-markdown-mode="true"] [data-type="strike"] .text-blue-600 {
1861
--text-opacity: 1;
1962
color: #9fa6b2;
2063
color: rgba(159, 166, 178, var(--text-opacity));
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from "react"
2+
import toArray from "lib/Array/toArray"
3+
4+
const Syntax = ({ children }) => (
5+
<span className="text-sm font-mono text-blue-600" data-type="markdown" contentEditable={false}>
6+
{children}
7+
</span>
8+
)
9+
10+
const Markdown = ({ syntax, children }) => (
11+
<React.Fragment>
12+
<Syntax>
13+
{toArray(syntax)[0]}
14+
</Syntax>
15+
{children}
16+
<Syntax>
17+
{toArray(syntax).slice(-1)[0]}
18+
</Syntax>
19+
</React.Fragment>
20+
)
21+
22+
export default Markdown

src/RichTextEditor/components/T.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import React from "react"
2+
import toArray from "lib/Array/toArray"
23

3-
// Adds [data-type] and [data-props] to props.children
4-
const T = ({ type, props, children }) => (
4+
// Adds [data-type], [data-props], and [data-markdown].
5+
const T = ({ type, props, markdown, children }) => (
56
React.cloneElement(children, {
67
"data-type": type,
7-
"data-props": props && JSON.stringify(props, null, " ")
8-
.replace(/\s*\n\s*/g, " "),
8+
"data-props": props && JSON.stringify(props, null, " ").replace(/\s*\n\s*/g, " "),
9+
"data-markdown-start": toArray(markdown)[0],
10+
"data-markdown-end": toArray(markdown).slice(-1)[0],
911
})
1012
)
1113

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,49 @@
1+
// import Markdown from "./Markdown"
12
import attrs from "./attrs"
23
import React from "react"
34
import T from "./T"
4-
import toArray from "lib/Array/toArray"
5-
6-
const Syntax = ({ children }) => (
7-
<span className="text-sm font-mono text-blue-600" data-type="markdown">
8-
{children}
9-
</span>
10-
)
11-
12-
const Markdown = ({ syntax, children }) => (
13-
<React.Fragment>
14-
<Syntax>
15-
{toArray(syntax)[0]}
16-
</Syntax>
17-
{children}
18-
<Syntax>
19-
{toArray(syntax).slice(-1)[0]}
20-
</Syntax>
21-
</React.Fragment>
22-
)
235

246
// Renders <em>.
257
export const Em = ({ children }) => (
26-
<T type="em">
8+
<T type="em" markdown="_">
279
<span className="italic">
28-
<Markdown syntax="_">
29-
{children}
30-
</Markdown>
10+
{children}
3111
</span>
3212
</T>
3313
)
3414

3515
// Renders <strong>.
3616
export const Strong = ({ children }) => (
37-
<T type="strong">
17+
<T type="strong" markdown="**">
3818
<span className="font-semibold">
39-
<Markdown syntax="**">
40-
{children}
41-
</Markdown>
19+
{children}
4220
</span>
4321
</T>
4422
)
4523

4624
// Renders <code>.
4725
export const Code = ({ children }) => (
48-
<T type="code">
26+
<T type="code" markdown="`">
4927
<span className="mx-px py-1 text-sm font-mono text-blue-600 border border-cool-gray-300" {...attrs.code}>
50-
<Markdown syntax="`">
51-
{children}
52-
</Markdown>
28+
{children}
5329
</span>
5430
</T>
5531
)
5632

5733
// Renders <strike>.
5834
export const Strike = ({ children }) => (
59-
<T type="strike">
35+
<T type="strike" markdown="~~">
6036
<span className="line-through text-gray-400">
61-
<Markdown syntax="~~">
62-
{children}
63-
</Markdown>
37+
{children}
6438
</span>
6539
</T>
6640
)
6741

6842
// Renders <a href="...">.
6943
export const A = ({ href, children }) => (
70-
<T type="a" props={{ href }}>
44+
<T type="a" props={{ href }} markdown={["[", "](" + href + ")"]}>
7145
<span className="mx-px underline text-blue-600" {...attrs.a}>
72-
{/* <Markdown syntax="TODO"> */}
7346
{children}
74-
{/* </Markdown> */}
7547
</span>
7648
</T>
7749
)

src/RichTextEditor/parsers/parsers.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,14 @@ function parseChildren(element, parser) {
1818
return
1919
}
2020
for (const each of on.childNodes) {
21+
// Guard <br> and <... contenteditable="false">:
22+
if (helpers.isElement(each) && (helpers.isBrElement(each) ||
23+
each.getAttribute("contenteditable") === "false")) {
24+
// No-op
25+
continue
26+
}
2127
const nextTypes = JSONClone(types)
22-
if (helpers.isElement(each) && !helpers.isBrElement(each)) {
28+
if (helpers.isElement(each)) {
2329
const { type, props } = parser(each)
2430
nextTypes.push({ type, props })
2531
}

0 commit comments

Comments
 (0)