Skip to content

Commit

Permalink
add slate example
Browse files Browse the repository at this point in the history
  • Loading branch information
stevejay committed Feb 17, 2021
1 parent 3ae739d commit f32f46b
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 2 deletions.
3 changes: 3 additions & 0 deletions package.json
Expand Up @@ -91,6 +91,7 @@
"fork-ts-checker-webpack-plugin": "^6.0.8",
"gh-pages": "^3.1.0",
"husky": "^4.3.0",
"is-hotkey": "^0.2.0",
"jest": "^26.6.1",
"jsdom": "^16.3.0",
"jspolyfill-array.prototype.findIndex": "^0.1.0",
Expand All @@ -105,6 +106,8 @@
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^4.0.0",
"rollup-plugin-typescript2": "^0.29.0",
"slate": "^0.59.0",
"slate-react": "^0.59.0",
"styled-components": "^5.2.0",
"ts-loader": "^8.0.7",
"typescript": "^4.0.5"
Expand Down
4 changes: 4 additions & 0 deletions src/stories/button.tsx
Expand Up @@ -14,6 +14,10 @@ const Button = styled.button`
margin: 0.5rem;
padding: 0 0.75em;

&:active {
background-color: #d5c2e7;
}

&:focus {
color: white;
background-color: rebeccapurple;
Expand Down
173 changes: 173 additions & 0 deletions src/stories/text-editor.stories.tsx
@@ -0,0 +1,173 @@
import "jspolyfill-array.prototype.findIndex";
import isHotkey from "is-hotkey";
import React, { FC, useCallback, useMemo, useRef, useState } from "react";
import { Editable, withReact, useSlate, Slate } from "slate-react";
import { Editor, createEditor, Node } from "slate";
import { Meta } from "@storybook/react/types-6-0";
import { RovingTabIndexProvider, useRovingTabIndex, useFocusEffect } from "..";
import { Button } from "./button";
import { Toolbar } from "./toolbar";

// The code in this file largely comes from the rich text editor example in the Slate docs:
// https://github.com/ianstormtaylor/slate/blob/master/site/examples/richtext.tsx

const initialValue = [
{
type: "paragraph",
children: [
{ text: "This is editable " },
{ text: "rich", bold: true },
{ text: " text, " },
{ text: "much", italic: true },
{ text: " better than a " },
{ text: "<textarea>", code: true },
{ text: "!" }
]
}
];

const HOTKEYS = {
"mod+b": "bold",
"mod+i": "italic",
"mod+u": "underline",
"mod+`": "code"
};

const Element = ({ attributes, children, element }) => {
switch (element.type) {
case "block-quote":
return <blockquote {...attributes}>{children}</blockquote>;
case "bulleted-list":
return <ul {...attributes}>{children}</ul>;
case "heading-one":
return <h1 {...attributes}>{children}</h1>;
case "heading-two":
return <h2 {...attributes}>{children}</h2>;
case "list-item":
return <li {...attributes}>{children}</li>;
case "numbered-list":
return <ol {...attributes}>{children}</ol>;
default:
return <p {...attributes}>{children}</p>;
}
};

const Leaf = ({ attributes, children, leaf }) => {
if (leaf.bold) {
children = <strong>{children}</strong>;
}

if (leaf.code) {
children = <code>{children}</code>;
}

if (leaf.italic) {
children = <em>{children}</em>;
}

if (leaf.underline) {
children = <u>{children}</u>;
}

return <span {...attributes}>{children}</span>;
};

const isMarkActive = (editor, format) => {
const marks = Editor.marks(editor);
return marks ? marks[format] === true : false;
};

const toggleMark = (editor, format) => {
const isActive = isMarkActive(editor, format);

if (isActive) {
Editor.removeMark(editor, format);
} else {
Editor.addMark(editor, format, true);
}
};

const MarkButton = ({ format, label }) => {
const editor = useSlate();
return (
<ToolbarButton
onMouseDown={(event) => {
event.preventDefault();
toggleMark(editor, format);
}}
>
{label}
</ToolbarButton>
);
};

type ButtonClickHandler = (
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => void;

const ToolbarButton: FC<{
disabled?: boolean;
onClick?: ButtonClickHandler;
onMouseDown: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
}> = ({ disabled = false, children, onClick, onMouseDown }) => {
const ref = useRef<HTMLButtonElement>(null);
const [tabIndex, focused, handleKeyDown] = useRovingTabIndex(ref, disabled);

useFocusEffect(focused, ref);

return (
<Button
ref={ref}
onKeyDown={handleKeyDown}
onMouseDown={(event) => {
onMouseDown(event);
}}
onClick={onClick}
tabIndex={tabIndex}
disabled={disabled}
>
{children}
</Button>
);
};

export const GridExample: FC = () => {
const [value, setValue] = useState<Node[]>(initialValue);
const renderElement = useCallback((props) => <Element {...props} />, []);
const renderLeaf = useCallback((props) => <Leaf {...props} />, []);
const editor = useMemo(() => withReact(createEditor()), []);

return (
<Slate editor={editor} value={value} onChange={(value) => setValue(value)}>
<Toolbar role="toolbar">
<RovingTabIndexProvider>
<MarkButton format="bold" label="Bold" />
<MarkButton format="italic" label="Italic" />
<MarkButton format="underline" label="Underline" />
</RovingTabIndexProvider>
</Toolbar>
<Editable
renderElement={renderElement}
renderLeaf={renderLeaf}
placeholder="Enter some rich text…"
spellCheck
autoFocus
onKeyDown={(event) => {
for (const hotkey in HOTKEYS) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (isHotkey(hotkey, event as any)) {
event.preventDefault();
const mark = HOTKEYS[hotkey];
toggleMark(editor, mark);
}
}
}}
/>
</Slate>
);
};

export default {
title: "Text Editor RovingTabIndex",
component: GridExample
} as Meta;
80 changes: 78 additions & 2 deletions yarn.lock
Expand Up @@ -2254,6 +2254,11 @@
resolved "https://registry.yarnpkg.com/@types/braces/-/braces-3.0.0.tgz#7da1c0d44ff1c7eb660a36ec078ea61ba7eb42cb"
integrity sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw==

"@types/esrever@^0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@types/esrever/-/esrever-0.2.0.tgz#96404a2284b2c7527f08a1e957f8a31705f9880f"
integrity sha512-5NI6TeGzVEy/iBcuYtcPzzIC6EqlfQ2+UZ54vT0ulq8bPNGAy8UJD+XcsAyEOcnYFUjOVWuUV+k4/rVkxt9/XQ==

"@types/estree@*":
version "0.0.45"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884"
Expand Down Expand Up @@ -2314,6 +2319,11 @@
resolved "https://registry.yarnpkg.com/@types/is-function/-/is-function-1.0.0.tgz#1b0b819b1636c7baf0d6785d030d12edf70c3e83"
integrity sha512-iTs9HReBu7evG77Q4EC8hZnqRt57irBDkK9nvmHroiOIVwYMQc4IvYvdRgwKfYepunIY7Oh/dBuuld+Gj9uo6w==

"@types/is-hotkey@^0.1.1":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@types/is-hotkey/-/is-hotkey-0.1.2.tgz#94f00793b5a297a7f7e69c1ef49613da2243a987"
integrity sha512-SUw9LpI3AIwbRNXS7FYy9AlXrTPIdBZGI7y4XxfIEYqgSW1UfFCUM9cMwHE/yCfTl0qeI0UQ/q8TdIxsIFgKPg==

"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
Expand Down Expand Up @@ -2367,6 +2377,11 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.166.tgz#07e7f2699a149219dbc3c35574f126ec8737688f"
integrity sha512-A3YT/c1oTlyvvW/GQqG86EyqWNrT/tisOIh2mW3YCgcx71TNjiTZA3zYZWA5BCmtsOTXjhliy4c4yEkErw6njA==

"@types/lodash@^4.14.149":
version "4.14.168"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008"
integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==

"@types/markdown-to-jsx@^6.11.0":
version "6.11.3"
resolved "https://registry.yarnpkg.com/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.3.tgz#cdd1619308fecbc8be7e6a26f3751260249b020e"
Expand Down Expand Up @@ -5121,6 +5136,11 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.0.0"

direction@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/direction/-/direction-1.0.4.tgz#2b86fb686967e987088caf8b89059370d4837442"
integrity sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==

doctrine@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
Expand Down Expand Up @@ -5669,6 +5689,11 @@ esrecurse@^4.1.0, esrecurse@^4.3.0:
dependencies:
estraverse "^5.2.0"

esrever@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/esrever/-/esrever-0.2.0.tgz#96e9d28f4f1b1a76784cd5d490eaae010e7407b8"
integrity sha1-lunSj08bGnZ4TNXUkOquAQ50B7g=

estraverse@^4.1.1, estraverse@^4.2.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
Expand Down Expand Up @@ -7037,6 +7062,11 @@ immer@1.10.0:
resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==

immer@^5.0.0:
version "5.3.6"
resolved "https://registry.yarnpkg.com/immer/-/immer-5.3.6.tgz#51eab8cbbeb13075fe2244250f221598818cac04"
integrity sha512-pqWQ6ozVfNOUDjrLfm4Pt7q4Q12cGw2HUZgry4Q5+Myxu9nmHRkWBpI0J4+MK0AxbdFtdMTwEGVl7Vd+vEiK+A==

import-cwd@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
Expand Down Expand Up @@ -7465,6 +7495,16 @@ is-hexadecimal@^1.0.0:
resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7"
integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==

is-hotkey@^0.1.6:
version "0.1.8"
resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.1.8.tgz#6b1f4b2d0e5639934e20c05ed24d623a21d36d25"
integrity sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ==

is-hotkey@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.2.0.tgz#1835a68171a91e5c9460869d96336947c8340cef"
integrity sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==

is-map@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127"
Expand Down Expand Up @@ -7527,7 +7567,7 @@ is-plain-obj@^2.0.0:
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==

is-plain-object@3.0.1:
is-plain-object@3.0.1, is-plain-object@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b"
integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==
Expand Down Expand Up @@ -8475,7 +8515,7 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=

lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20:
lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
Expand Down Expand Up @@ -11202,6 +11242,13 @@ schema-utils@^3.0.0:
ajv "^6.12.5"
ajv-keywords "^3.5.2"

scroll-into-view-if-needed@^2.2.20:
version "2.2.26"
resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.26.tgz#e4917da0c820135ff65ad6f7e4b7d7af568c4f13"
integrity sha512-SQ6AOKfABaSchokAmmaxVnL9IArxEnLEX9j4wAZw+x4iUTb40q7irtHG3z4GtAWz5veVZcCnubXDBRyLVQaohw==
dependencies:
compute-scroll-into-view "^1.0.16"

select@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
Expand Down Expand Up @@ -11407,6 +11454,30 @@ slash@^3.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==

slate-react@^0.59.0:
version "0.59.0"
resolved "https://registry.yarnpkg.com/slate-react/-/slate-react-0.59.0.tgz#c8043dce7ea71279f314d9951c32e4f548b1ea0b"
integrity sha512-Fx5vfTi0s1fY5PaXzPH8uA9mW8aevVVYrGGvqX/k363tlPDnQSs/QTibIyFl1Y3MPJ+GdocoyOGjAaZMUIXfIg==
dependencies:
"@types/is-hotkey" "^0.1.1"
"@types/lodash" "^4.14.149"
direction "^1.0.3"
is-hotkey "^0.1.6"
is-plain-object "^3.0.0"
lodash "^4.17.4"
scroll-into-view-if-needed "^2.2.20"

slate@^0.59.0:
version "0.59.0"
resolved "https://registry.yarnpkg.com/slate/-/slate-0.59.0.tgz#3169daf2f036e84aa149f60e0d12ef2fc4c0839e"
integrity sha512-M4UTMkXExxuq8tCD+knn7BtV2pmY8pepay++EF59rmg/v4RB6X1gNzA0xP3aw2rqYl8TmWdOBdy9InFrm3WyXw==
dependencies:
"@types/esrever" "^0.2.0"
esrever "^0.2.0"
immer "^5.0.0"
is-plain-object "^3.0.0"
tiny-warning "^1.0.3"

slice-ansi@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
Expand Down Expand Up @@ -12120,6 +12191,11 @@ tiny-emitter@^2.0.0:
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==

tiny-warning@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==

tinycolor2@^1.4.1:
version "1.4.2"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
Expand Down

0 comments on commit f32f46b

Please sign in to comment.