Gyazzみたいなエディタ作りでReact.jsを学ぶ:開発ログ
from Gyazzみたいなエディタ作りでReact.jsを学ぶ
エディタとしての基本機能を実装
https://github.com/inajob/simple-inline-editor/commit/789b18281d8df8d5cd4238c757151675bd8722d7
行の分割や結合も実装した
ここまでは問題なさそう
新たな疑問
テストを作るとしたらどうするのが良いのか・・?
抽象化層が必要かな?
reduxなら出来そうな気がするが、大がかりすぎる
あるイベントが発火したときにlines,rowが意図した変化をするかテストで保証したい気持ちがある
hookにきりだしてテストかなtakker.icon
icon-suggestionのテストがわかりやすい
これ、React以外で作る方法がイメージつかないのだが、ほかのフレームワークでも同じようなノリで作れるものなのだろうか?
https://github.com/inajob/simple-inline-editor/commit/d799909d044742c872af2c8508c8cef60a11af9d
マウスクリックに対応
ここも問題なし
次やること
行を分割するようなEnterが発生したときに次の行に分割後の文字列が入り、カーソルが移動するのは良いのだが、カーソルの左右位置がおかしい
今はRowはReactで制御しているがColumnはエディタコンポーネントに任せているのでそのツケが回ってきている
https://github.com/inajob/simple-inline-editor/commit/822aa44e88c9d244811f1bb55ffddc2926a6fc32
と思ったけどColumn制御は簡単だった
ColumnをいじったときだけuseEffectが発動するのでなんかいい感じになる
ここまででエディタコンポーネントとして割と違和感なく動くようになったような気がする
https://github.com/inajob/simple-inline-editor/commit/ba59eb857933b42ac20ad486e3b7fc0d8507099e
行の末尾で→、行頭で←キーを押したときにカーソルを行移動させる処理を追加
https://github.com/inajob/simple-inline-editor/commit/24b855f43d58120ed4eded8d72a54db9815bc74d
見出し書式に対応
https://gyazo.com/dd78979b234819f5bfe0f49fffaa6bbb
普通のエディタっぽい見た目になった
Lineコンポーネントが見出しを判断する設計で良いかは疑問が残るな
Markdown以外に対応する必要があるか?
https://github.com/inajob/simple-inline-editor/commit/291130cd5fdc566171395b56c06388f6c585bf74
URLっぽい文字があるとリンクにするようにした
https://gyazo.com/b650297af854c6ccd0947ad14bff5304
おーWikiっぽい
フォーカスが当たっていない行をHTMLとしてレンダリングするようにした
微妙に上下位置がずれるのが気になる
スタイルをうまいこと指定したら直った
Wikiパーサーみたいなのを書く羽目になっている
Lineコンポーネントの中に書いてしまったが、外に出した方が良い
文字列→JSXする関数を外から与える方式にすると良さそう
あとは記法をどんどん定義していけばインラインの書式は簡単に増やせる
ここは面白くないので後回し
なんとなくMarkdown風にしているが、Markdownの表とかは対応する気はない
1ペイン編集画面でMarkdownの表記法と見た目の表をうまく両立させる良い方法が思いつかない
https://github.com/inajob/simple-inline-editor/commit/fb61d4df6eb067c93c5fad489f3fc20849c75d25
<Enter>で連続改行できない の解決
なんとなくフォーカスのある行を黄色くした
箇条書きのスタイル
Markdown準拠の箇条書きに対応したい
Scrapbox風でもよいのだが、ここは好み
編集行の箇条書きのバレットをどう表示するか?
a. 編集文字に含める
カーソルが当たったときに表示文字がずれるのが気になる
現行のinlineはこっち
b. 行のスタイルに含め、編集文字に含めない
箇条書きスタイルそのものを消すのがちょっと直観的でない動きになりそう
Scrapboxはこれに近そう(そもそも実装方式が違うので比較できないが)
bで実装した
https://github.com/inajob/simple-inline-editor/commit/37d298a2df3bf116c3023eb29fba1854c884c64f
リスト記法を認識して書式をつける
箇条書きのバレットを表示するのにflexを使った
改行時にリストの深さを維持する
https://github.com/inajob/simple-inline-editor/commit/3c35432afc254728b6fde2438de9a0587f102697
Tab, Shift+Tabでリストのインデントを上げ下げできる
ブロック記法
今のinlineは以下のような記法
code: pre
> type
body
<<
Scrapboxみたいにリスト下にブロック要素を入れられるようにしたい
markdownとの互換性は気にしない
そもそもmarkdownだとリスト下にブロック要素を入れられないからな・・
Markdownってコードブロックをインデントの下に置けないと勝手に思っていたが普通にできた
inlineのときはブロック要素を入れ子にする仕様も考えていたが、、いらないかな
ひとまず通常のブロック記法を実装してみるか
https://github.com/inajob/simple-inline-editor/commit/d31b807e34a7fbb30de65c632ab680ca6bc31106
シンプルなブロック記法を実装した
https://github.com/inajob/simple-inline-editor/commit/c4dbfc0848dd0d17eabb37e31f5408c790cf2584
ブロックのインデントを実装した
ブロック記法のバリエーション
役立つブロック記法を実装して効果を確認したい
プレビューのあるブロック
カンマ区切りテキストを表にするやつ
楽そう、これからやろう
mermaidとかが良いかな?
reactでうまくやる方法を探さないと
Mermaid.jsをReact上でレンダリングする | フューチャー技術ブログ
あった、結構新しい記事で筋が良い
inlineではプレビューは下に出るようにしたが、やはり左右2ペインにしたい
しかしスマートフォンだと下の方が良い
レスポンシブデザインにするか・・
スマートフォンは後回しにしよう
https://github.com/inajob/simple-inline-editor/commit/9f0ed76d0c295490395d4ccfe3c4b2be90e75934
テーブル記法
https://github.com/inajob/simple-inline-editor/commit/befec1b50f4f9add49e71abfa8fb6cf4269f8a0a
ブロック記法編集を左右2ペインにした
https://gyazo.com/ae1fe43724acc56d8ae8a29421bbdd23
これもflexを使ったら簡単だった
ここまででおおむね元の実装に追いついたかな
Mac/Chromeで日本語入力確定時に二重に文字が確定されてしまう
手元環境がWindowsで直すのがつらい・・(Macもあるにはある)
ブラウザでIME確定時のEnterキー入力をハンドリングしない - Qiita
この問題だった
keyCodeを使うのをやめたかったのだが・・
https://github.com/inajob/simple-inline-editor/commit/274dfbb3f8a32f216724148b9c9bedc68bcc30d2
fixed
コピーしたときにMarkdownがコピーされるようにする
list itemは簡単そう
行頭の-は疑似要素で出しているのでコピーできない
font-size:0の要素でコピーしたいMarkdownを用意しておけばOK
https://github.com/inajob/simple-inline-editor/commit/a7b80e3eda353796de38a4b34ea756b797614f3c
できた
block要素はどうすればよいか・・
一旦似たように対応した
https://github.com/inajob/simple-inline-editor/commit/fca1f062b15de3502c5906312062342d4009292b
細かい修正
行選択
https://github.com/inajob/simple-inline-editor/commit/7d7e358f02a57c416c4977dad83f43652c75aa2e
使い勝手が悪いが、切り出しなどを実装する際の布石
reactでselectionchangeイベントがサポートされていないので無理やりくっつける
折り返しがあるとレイアウトが崩れる
https://github.com/inajob/simple-inline-editor/commit/5cc7896cdfae2d46bfab170e04f963bb35214d15
泥臭いtipsがたくさんある・・
display:none の要素のscrollHeightは0になってしまうので、直前でdisplay: blockにしている、最後に戻すので見た目には影響なし
文字のない行の高さが0になる問題が出ていた
fixed https://github.com/inajob/simple-inline-editor/commit/9a7292b64822295e42729fa9fb04a6656452613b
1行内で選択したときも行選択が発動してうざかった
fixed https://github.com/inajob/simple-inline-editor/commit/83f7c6e4efd3aeedf3346b94036efc18ad3ae6b8
スマートフォンで行選択が動かない
https://developer.mozilla.org/ja/docs/Web/API/Node/selectstart_event
Safari on iOSはselectstartをサポートしていない
https://github.com/inajob/simple-inline-editor/commit/d11f106557f93b9032a470e523a54b19dcf597b6
操作性は悪いが修正した
グローバルにイベントハンドラを仕込みっぱなしにするのは微妙だが、仕方ない
Markdownを貼り付けたときにいい感じに整形される
https://github.com/inajob/simple-inline-editor/commit/735815d8ba631f1cf94bc2f0e57a0d2f48b60788
メモ化
https://github.com/inajob/simple-inline-editor/commit/998c5daa39ae4e3f0b057975f6440a27e195ce8d
Gyazzみたいなエディタ作りでReact.jsを学ぶ#6365b19c6eb4060000f6d8ffのあたりが参考になった(今更)
useCallbackの依存とか、「これ、人間が書くのか、、」という気持ちになるな
code actionがほしいですねtakker.icon
それよりvarが視界に入って発狂しそうになったtakker.icon
constつかって
let, constを適切に使うようにしましたinajob.icon
https://github.com/inajob/simple-inline-editor/commit/0c51693c32d6a314b4b3f4397f5908554d8634c5
フォーカスを与える処理をLineからEditorに移動させる
forwardRefに手を出してしまった・・
createRef()の使い道がよくわからないtakker.icon
https://github.com/inajob/simple-inline-editor/commit/bb44f88a7071b9acdafafc3ab353198b2d0173ba
なぜfunctional componentに直にforEachが書かれているの……?takker.icon
ここですかね?inajob.icon
https://code2svg.vercel.app/svg/L102-113/https://raw.githubusercontent.com/inajob/simple-inline-editor/bb44f88a7071b9acdafafc3ab353198b2d0173ba/src/components/Editor.js#.svg https://github.com/inajob/simple-inline-editor/blob/bb44f88a7071b9acdafafc3ab353198b2d0173ba/src/components/Editor.js#L102-L111
単にlinesの個数だけループさせたかっただけでlinesの中身には触っていないです
ループで作られるDOMに対してrefで参照したかったのです
【React】複数useRefを指定するときのTips - Qiita
例示されているコードの設計が根本的におかしいような……takker.icon
refなしで設計できるのを無理やりrefで組もうとしている印象
こんな方法があったんですねtakker.icon
あとで(学期終了後)読んでみます
なんかやばそうな設計してそう
元の設計に戻したほうが良いかも、、inajob.icon
Lineでfocusの処理をするやつ
クリックした時行頭に戻る仕様をなんとかする
クリックされた場所が何文字目かを知る必要がある
これ、Scrapboxは各文字をspanで囲っていたやつでは・・
document.getSelection()のfocusNode, focusOffsetをうまいこと見てやれば何とか文字が数えられそう
泥臭いし書式が増えたときに対応が煩雑になりそう・・
spanで囲む以外に方法なさそう……takker.icon
なんとかしたが、これは・・
必須の機能ではないので、ひとまずコメントにしておこう(上のcommitに混ざってしまっている・・)
編集中の行から行選択を開始できるようにした
https://github.com/inajob/simple-inline-editor/commit/63ace0ef65b062dadb2d74fda48d54d4a608df53
ポップアップメニュー
これはエディタコンポーネントに実装してよいのか?
外から別のメニューコンポーネントを重ねる方が筋が良い?
ポップアップの場所をどうやって伝えるのか?
HOW TO: Where’s the text cursor? 🧐 | by Jhey Tompkins | Medium
同じスタイルのspanを作って選択範囲までの距離測定に使っている
https://github.com/inajob/simple-inline-editor/commit/f7286e52ba5e1fe98ea26e39ec1e2be86c2e20a7
同じスタイルのspanを作って選択範囲までの距離測定に使っている
これで実装してみた、ブロック構文で複数行になった時位置がおかしいけどひとまず気にしない
https://gyazo.com/7d30c5acb43583e13df589e470d848ce
行選択のメニューは別の仕組みで用意した
https://github.com/inajob/simple-inline-editor/commit/f59578be4e287a72697b2513cee987e725f65a82
https://gyazo.com/e4b01daa93c7c61c3017e778217a7881
スマートフォンでおかしな動きをするが、ひとまず気にしない