Skip to content

Commit 68784d2

Browse files
author
Zaydek Michels-Gualtieri
committed
Prototyped basic dependencies
1 parent f9e0059 commit 68784d2

108 files changed

Lines changed: 551 additions & 338 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

EditorApp/EditorApp.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import React from "react"
2+
3+
const EditorApp = () => (
4+
"Hello"
5+
)
6+
7+
export default EditorApp

EditorApp/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default from "./EditorApp"

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"uuidv4": "latest"
1111
},
1212
"scripts": {
13-
"tailwind-start": "tailwind build -c src/tailwind-css/js/tailwind.config.js -o src/tailwind-css/css/tailwind.generated.css",
13+
"tailwind-start": "tailwind build -o src/tailwind-css/css/tailwind.generated.css",
1414
"start": "react-scripts start",
1515
"tailwind-build": "NODE_ENV=production yarn tailwind-start",
1616
"build": "yarn tailwind-build && yarn react-scripts build && osascript -e 'display notification \"Production build ready\" with title \"yarn build\"' && yarn tailwind-start && osascript -e 'display notification \"Development build ready\" with title \"yarn start\"'",

src/Editor/Editor.js

Lines changed: 6 additions & 328 deletions
Original file line numberDiff line numberDiff line change
@@ -1,336 +1,14 @@
1-
import componentMap from "./components/componentMap"
2-
import keyDownTypeFor from "./keyDownTypeFor"
31
import React from "react"
4-
import ReactDOM from "react-dom"
5-
import testForSelection from "./useEditor/testForSelection"
62

7-
import {
8-
initElementsFromChildren,
9-
parseRenderedChildren,
10-
} from "./parsers"
11-
12-
import {
13-
convRangeToUserLiteral,
14-
getCurrentRange,
15-
} from "./Range"
16-
17-
import "./Editor.css"
18-
19-
const MemoElements = React.memo(({ elements }) => (
20-
elements.map(each => (
21-
React.createElement(componentMap[each.type], {
22-
...each.props,
23-
key: each.key, // For React
24-
id: each.key, // For the DOM
25-
})
26-
))
27-
))
28-
29-
// Renders a read-write editor.
30-
const Editor = ({ id, className, style, state, dispatch, children }) => {
31-
const ref = React.useRef(null)
32-
const pointerdownRef = React.useRef(false)
33-
34-
// Mounts elements from props.children (once).
35-
//
36-
// eslint-disable-next-line react-hooks/exhaustive-deps
37-
React.useLayoutEffect(
38-
React.useCallback(() => {
39-
const elements = initElementsFromChildren(children)
40-
dispatch({
41-
type: "MOUNT_ELEMENTS",
42-
elements,
43-
})
44-
}, [dispatch, children]),
45-
[],
46-
)
47-
48-
// Rerenders on state.shouldRerender.
49-
//
50-
// eslint-disable-next-line react-hooks/exhaustive-deps
51-
React.useLayoutEffect(
52-
React.useCallback(() => {
53-
// https://bugs.chromium.org/p/chromium/issues/detail?id=138439#c10
54-
const selection = document.getSelection()
55-
if (selection.rangeCount) {
56-
selection.removeAllRanges()
57-
}
58-
ReactDOM.render(
59-
<MemoElements elements={state.elements} />,
60-
ref.current,
61-
() => {
62-
if (!state.focused) {
63-
// No-op
64-
return
65-
}
66-
try {
67-
const userRange = convRangeToUserLiteral(state.range)
68-
selection.addRange(userRange)
69-
} catch (error) {
70-
console.error(error)
71-
}
72-
},
73-
)
74-
}, [state]),
75-
[state.shouldRerender],
76-
)
3+
const Editor = ({
4+
state,
5+
dispatch,
6+
}) => {
7+
// ...
778

789
return (
79-
<article
80-
ref={ref}
81-
82-
id={id}
83-
className={`em-context ${className}`.trim()}
84-
style={style}
85-
86-
onFocus={e => {
87-
dispatch({
88-
type: "FOCUS",
89-
})
90-
}}
91-
92-
onBlur={e => {
93-
dispatch({
94-
type: "BLUR",
95-
})
96-
}}
97-
98-
onPointerDown={e => {
99-
pointerdownRef.current = true
100-
}}
101-
102-
onPointerMove={e => {
103-
if (!state.focused || !pointerdownRef.current) {
104-
if (!state.focused && pointerdownRef.current) {
105-
pointerdownRef.current = false
106-
}
107-
return
108-
}
109-
const range = getCurrentRange(ref.current)
110-
if (!range) {
111-
// No-op
112-
return
113-
}
114-
dispatch({
115-
type: "SELECT",
116-
range,
117-
})
118-
}}
119-
120-
onPointerUp={e => {
121-
pointerdownRef.current = false
122-
}}
123-
124-
// TODO: Add COMPAT guard for select-all or prevent
125-
// default?
126-
onSelect={e => {
127-
try {
128-
const range = getCurrentRange(ref.current)
129-
if (!range) {
130-
// No-op
131-
return
132-
}
133-
dispatch({
134-
type: "SELECT",
135-
range,
136-
})
137-
} catch (error) {
138-
console.error(error)
139-
}
140-
}}
141-
142-
// TODO: e.nativeEvent.isComposing or
143-
// "insert-text-composed" needs to negate
144-
// state.rangeTypes because the insertion point is
145-
// advanced during composition.
146-
onKeyDown={e => {
147-
let formatType = ""
148-
let text = ""
149-
let deleteType = ""
150-
151-
const keyDownType = keyDownTypeFor(e)
152-
if (keyDownType) {
153-
console.log(keyDownType)
154-
}
155-
156-
switch (keyDownType) {
157-
case "apply-format-plaintext":
158-
case "apply-format-em":
159-
case "apply-format-strong":
160-
case "apply-format-code":
161-
case "apply-format-strike":
162-
case "apply-format-a":
163-
// NOTE: Formatting events must always be
164-
// prevented.
165-
e.preventDefault()
166-
if (testForSelection(state)) {
167-
formatType = keyDownType.slice("apply-format-".length)
168-
const types = {}
169-
if (formatType !== "plaintext") {
170-
types[formatType] = {} // TODO
171-
}
172-
dispatch({
173-
type: "APPLY_TYPES",
174-
types,
175-
})
176-
}
177-
break
178-
case "apply-format-markdown-em":
179-
case "apply-format-markdown-strong":
180-
case "apply-format-markdown-code":
181-
case "apply-format-markdown-strike":
182-
case "apply-format-markdown-a":
183-
184-
// // NOTE: Formatting events must always be
185-
// // prevented.
186-
// e.preventDefault()
187-
188-
if (testForSelection(state)) {
189-
e.preventDefault()
190-
formatType = keyDownType.slice("apply-format-markdown-".length)
191-
const types = {}
192-
if (formatType !== "plaintext") {
193-
// types[formatType] = {}
194-
types[formatType] = formatType !== "a" ? {} : {
195-
href: "TODO",
196-
}
197-
}
198-
dispatch({
199-
type: "APPLY_TYPES",
200-
types,
201-
})
202-
}
203-
break
204-
case "insert-text":
205-
if (testForSelection(state)) {
206-
e.preventDefault()
207-
text = e.key
208-
dispatch({
209-
type: "INSERT_TEXT",
210-
text,
211-
})
212-
}
213-
break
214-
case "insert-composed-text-unidentified":
215-
case "insert-composed-text-identified":
216-
if (testForSelection(state) && state.range.start.key !== state.range.end.key) {
217-
e.preventDefault()
218-
// COMPAT: e.preventDefault(...) on
219-
// "insert-composed-text-unidentified" breaks
220-
// composition and oncompositionend is never
221-
// emitted. In Chrome 84, use of
222-
// document.activeElement.blur(...) appears to
223-
// emit oncompositionend.
224-
const selection = document.getSelection()
225-
if (selection.rangeCount) {
226-
document.activeElement.blur()
227-
const range = {
228-
...state.range,
229-
end: state.range.start,
230-
}
231-
setTimeout(() => {
232-
const userRange = convRangeToUserLiteral(range)
233-
selection.addRange(userRange)
234-
}, 0)
235-
}
236-
dispatch({
237-
type: "INSERT_TEXT",
238-
text: "",
239-
})
240-
}
241-
break
242-
case "insert-tab":
243-
e.preventDefault()
244-
text = "\t"
245-
dispatch({
246-
type: "INSERT_TEXT",
247-
text,
248-
})
249-
break
250-
case "insert-soft-paragraph":
251-
case "insert-hard-paragraph":
252-
case "insert-horizontal-rule":
253-
e.preventDefault()
254-
dispatch({
255-
type: "INSERT_HARD_PARAGRAPH",
256-
})
257-
break
258-
case "delete-rtl-rune":
259-
case "delete-rtl-word":
260-
case "delete-rtl-line":
261-
case "delete-ltr-rune":
262-
case "delete-ltr-word":
263-
e.preventDefault()
264-
deleteType = keyDownType.slice("delete-".length)
265-
dispatch({
266-
type: "DELETE",
267-
deleteType,
268-
})
269-
break
270-
case "undo":
271-
case "redo":
272-
e.preventDefault()
273-
// TODO
274-
break
275-
default:
276-
// No-op
277-
break
278-
}
279-
}}
280-
281-
onCompositionEnd={e => {
282-
const range = getCurrentRange(ref.current)
283-
const children = parseRenderedChildren(document.getElementById(range.start.key))
284-
dispatch({
285-
type: "UNCONTROLLED_INPUT",
286-
range,
287-
children,
288-
noopRender: false, // onCompositionEnd must rerender
289-
})
290-
}}
291-
292-
onInput={e => {
293-
const range = getCurrentRange(ref.current)
294-
const children = parseRenderedChildren(document.getElementById(range.start.key))
295-
dispatch({
296-
type: "UNCONTROLLED_INPUT",
297-
range,
298-
children,
299-
noopRender: e.nativeEvent.isComposing,
300-
})
301-
}}
302-
303-
onCut={e => {
304-
e.preventDefault()
305-
// TODO
306-
}}
307-
308-
// onCopy={e => {
309-
// e.preventDefault()
310-
// // TODO
311-
// }}
312-
313-
onPaste={e => {
314-
e.preventDefault()
315-
// TODO
316-
}}
317-
318-
onDragStart={e => {
319-
e.preventDefault()
320-
}}
321-
322-
contentEditable={state.mounted}
323-
suppressContentEditableWarning={state.mounted}
324-
325-
data-root
326-
/>
10+
"Hello, world!"
32711
)
32812
}
32913

330-
// {process.env.NODE_ENV !== "production" && (
331-
// <pre className="mt-6 text-xs whitespace-pre-wrap break-words" style={tabSize(2)}>
332-
// {JSON.stringify(state, null, "\t")}
333-
// </pre>
334-
// )}
335-
33614
export default Editor

src/Editor/index.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
export * from "./useEditor/useEditor"
21
export { default as Editor } from "./Editor"
3-
export { default as ReadOnlyEditor } from "./ReadOnlyEditor"
2+
export { default as useEditor } from "./useEditor"

0 commit comments

Comments
 (0)