@springmicro/rte 0.1.3 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -5
- package/dist/index.js +7361 -7279
- package/package.json +7 -3
- package/.eslintrc.cjs +0 -18
- package/dist/index.d.ts +0 -10
- package/dist/index.umd.cjs +0 -469
- package/index.html +0 -13
- package/src/App.css +0 -42
- package/src/App.tsx +0 -10
- package/src/contexts/color-context.tsx +0 -53
- package/src/hooks/useSimpleFormik.tsx +0 -74
- package/src/index.css +0 -68
- package/src/index.tsx +0 -3
- package/src/main.tsx +0 -10
- package/src/slate/base-editor.stories.tsx +0 -16
- package/src/slate/base-editor.tsx +0 -116
- package/src/slate/blog-rte.stories.tsx +0 -16
- package/src/slate/blog-rte.tsx +0 -126
- package/src/slate/common/button.tsx +0 -35
- package/src/slate/common/element.tsx +0 -13
- package/src/slate/common/icon.jsx +0 -97
- package/src/slate/components/code-to-text/CodeToTextButton.jsx +0 -19
- package/src/slate/components/code-to-text/HtmlCode.jsx +0 -64
- package/src/slate/components/code-to-text/HtmlContextMenu.jsx +0 -39
- package/src/slate/components/code-to-text/index.jsx +0 -111
- package/src/slate/components/color-picker/color-cursor.stories.tsx +0 -16
- package/src/slate/components/color-picker/color-cursor.tsx +0 -34
- package/src/slate/components/color-picker/color-formats-view.stories.tsx +0 -25
- package/src/slate/components/color-picker/color-formats-view.tsx +0 -115
- package/src/slate/components/color-picker/color-gradient.stories.tsx +0 -48
- package/src/slate/components/color-picker/color-gradient.tsx +0 -128
- package/src/slate/components/color-picker/color-hue.stories.tsx +0 -41
- package/src/slate/components/color-picker/color-hue.tsx +0 -110
- package/src/slate/components/color-picker/color-picker.stories.tsx +0 -25
- package/src/slate/components/color-picker/color-picker.tsx +0 -41
- package/src/slate/components/color-picker/color-popover.stories.tsx +0 -26
- package/src/slate/components/color-picker/color-popover.tsx +0 -58
- package/src/slate/components/color-picker/color-swatch.stories.tsx +0 -16
- package/src/slate/components/color-picker/color-swatch.tsx +0 -76
- package/src/slate/components/color-picker/default-colors.ts +0 -38
- package/src/slate/components/color-picker/slate-color-button.tsx +0 -128
- package/src/slate/components/embed/Embed.jsx +0 -96
- package/src/slate/components/embed/Image.jsx +0 -45
- package/src/slate/components/embed/Video.jsx +0 -65
- package/src/slate/components/equation/Equation.jsx +0 -19
- package/src/slate/components/equation/EquationButton.jsx +0 -68
- package/src/slate/components/id/Id.jsx +0 -57
- package/src/slate/components/image/image.stories.tsx +0 -17
- package/src/slate/components/image/image.tsx +0 -62
- package/src/slate/components/image/insert-image-button.stories.tsx +0 -83
- package/src/slate/components/image/insert-image-button.tsx +0 -132
- package/src/slate/components/image/types.ts +0 -9
- package/src/slate/components/link/Link.jsx +0 -56
- package/src/slate/components/link/LinkButton.tsx +0 -106
- package/src/slate/components/table/Table.jsx +0 -11
- package/src/slate/components/table/TableSelector.jsx +0 -97
- package/src/slate/components/table-context-menu/TableContextMenu.tsx +0 -106
- package/src/slate/custom-types.d.ts +0 -152
- package/src/slate/editor.module.css +0 -226
- package/src/slate/paper-rte.stories.tsx +0 -16
- package/src/slate/paper-rte.tsx +0 -47
- package/src/slate/plugins/withEmbeds.js +0 -33
- package/src/slate/plugins/withEquation.js +0 -8
- package/src/slate/plugins/withImages.ts +0 -69
- package/src/slate/plugins/withLinks.js +0 -9
- package/src/slate/plugins/withTable.js +0 -74
- package/src/slate/serializers/generic.ts +0 -44
- package/src/slate/serializers/types.ts +0 -20
- package/src/slate/toolbar/index.tsx +0 -186
- package/src/slate/toolbar/paper-toolbar.tsx +0 -494
- package/src/slate/toolbar/shortcuts.tsx +0 -77
- package/src/slate/toolbar/toolbar-groups.ts +0 -213
- package/src/slate/types/index.ts +0 -0
- package/src/slate/utils/customHooks/useContextMenu.js +0 -42
- package/src/slate/utils/customHooks/useFormat.js +0 -26
- package/src/slate/utils/customHooks/usePopup.jsx +0 -26
- package/src/slate/utils/customHooks/useResize.js +0 -27
- package/src/slate/utils/embed.js +0 -18
- package/src/slate/utils/equation.js +0 -22
- package/src/slate/utils/index.jsx +0 -267
- package/src/slate/utils/link.js +0 -44
- package/src/slate/utils/p.js +0 -4
- package/src/slate/utils/table.js +0 -131
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.json +0 -32
- package/tsconfig.node.json +0 -10
- package/vite.config.ts +0 -41
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
MdOutlineColorize,
|
|
4
|
-
MdFormatColorText,
|
|
5
|
-
MdFormatColorFill,
|
|
6
|
-
MdFormatBold,
|
|
7
|
-
MdFormatItalic,
|
|
8
|
-
MdStrikethroughS,
|
|
9
|
-
MdFormatUnderlined,
|
|
10
|
-
MdFormatQuote,
|
|
11
|
-
MdFormatAlignLeft,
|
|
12
|
-
MdFormatAlignCenter,
|
|
13
|
-
MdFormatAlignRight,
|
|
14
|
-
MdFormatListNumbered,
|
|
15
|
-
MdFormatListBulleted,
|
|
16
|
-
MdInsertLink,
|
|
17
|
-
MdLinkOff,
|
|
18
|
-
MdVideoLibrary,
|
|
19
|
-
MdImage,
|
|
20
|
-
MdAdd,
|
|
21
|
-
MdSubscript,
|
|
22
|
-
MdSuperscript,
|
|
23
|
-
MdKeyboardArrowRight,
|
|
24
|
-
MdArrowForward,
|
|
25
|
-
MdArrowDropDown,
|
|
26
|
-
} from "react-icons/md";
|
|
27
|
-
import {
|
|
28
|
-
BsTypeH1,
|
|
29
|
-
BsTypeH2,
|
|
30
|
-
BsTypeH3,
|
|
31
|
-
BsCameraVideoFill,
|
|
32
|
-
} from "react-icons/bs";
|
|
33
|
-
import { FaSuperscript, FaSubscript } from "react-icons/fa";
|
|
34
|
-
import {
|
|
35
|
-
AiFillEdit,
|
|
36
|
-
AiOutlineTable,
|
|
37
|
-
AiOutlineInsertRowBelow,
|
|
38
|
-
AiOutlineInsertRowRight,
|
|
39
|
-
AiOutlineDelete,
|
|
40
|
-
AiFillTag,
|
|
41
|
-
AiOutlineUpload,
|
|
42
|
-
AiOutlineArrowsAlt,
|
|
43
|
-
AiOutlineInsertRowAbove,
|
|
44
|
-
AiOutlineInsertRowLeft,
|
|
45
|
-
AiFillHtml5,
|
|
46
|
-
} from "react-icons/ai";
|
|
47
|
-
import { SiLatex } from "react-icons/si";
|
|
48
|
-
|
|
49
|
-
const iconList = {
|
|
50
|
-
bold: <MdFormatBold size={20} />,
|
|
51
|
-
italic: <MdFormatItalic size={20} />,
|
|
52
|
-
strikethrough: <MdStrikethroughS size={20} />,
|
|
53
|
-
underline: <MdFormatUnderlined size={20} />,
|
|
54
|
-
h1: <BsTypeH1 size={20} />,
|
|
55
|
-
h2: <BsTypeH2 size={20} />,
|
|
56
|
-
h3: <BsTypeH3 size={20} />,
|
|
57
|
-
color: <MdFormatColorText size={20} />,
|
|
58
|
-
bgColor: <MdFormatColorFill size={20} />,
|
|
59
|
-
|
|
60
|
-
blockquote: <MdFormatQuote size={20} />,
|
|
61
|
-
superscript: <MdSuperscript size={15} />,
|
|
62
|
-
subscript: <MdSubscript size={15} />,
|
|
63
|
-
alignLeft: <MdFormatAlignLeft size={20} />,
|
|
64
|
-
alignCenter: <MdFormatAlignCenter size={20} />,
|
|
65
|
-
alignRight: <MdFormatAlignRight size={20} />,
|
|
66
|
-
orderedList: <MdFormatListNumbered size={20} />,
|
|
67
|
-
unorderedList: <MdFormatListBulleted size={20} />,
|
|
68
|
-
link: <MdInsertLink size={20} />,
|
|
69
|
-
unlink: <MdLinkOff size={20} />,
|
|
70
|
-
image: <MdImage size={20} />,
|
|
71
|
-
video: <MdVideoLibrary size={20} />,
|
|
72
|
-
add: <MdAdd size={20} />,
|
|
73
|
-
table: <AiOutlineTable size={20} />,
|
|
74
|
-
insertRowBelow: <AiOutlineInsertRowBelow size={25} />,
|
|
75
|
-
insertColumnRight: <AiOutlineInsertRowRight size={25} />,
|
|
76
|
-
insertColumnLeft: <AiOutlineInsertRowLeft size={25} />,
|
|
77
|
-
insertRowAbove: <AiOutlineInsertRowAbove size={25} />,
|
|
78
|
-
trashCan: <AiOutlineDelete size={25} />,
|
|
79
|
-
addId: <AiFillTag size={20} />,
|
|
80
|
-
upload: <AiOutlineUpload size={20} />,
|
|
81
|
-
equation: <SiLatex size={20} />,
|
|
82
|
-
resize: <AiOutlineArrowsAlt size={20} />,
|
|
83
|
-
videoPlayer: <BsCameraVideoFill size={20} />,
|
|
84
|
-
insertHtml: <AiFillHtml5 size={20} />,
|
|
85
|
-
arrowRight: <MdArrowForward size={35} />,
|
|
86
|
-
pen: <AiFillEdit size={20} />,
|
|
87
|
-
colorize: <MdOutlineColorize size={20} />,
|
|
88
|
-
|
|
89
|
-
arrowDown: <MdArrowDropDown size={20} />,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const Icon = (props) => {
|
|
93
|
-
const { icon } = props;
|
|
94
|
-
return iconList[icon];
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export default Icon;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import Button from "../../common/button";
|
|
3
|
-
import Icon from "../../common/icon";
|
|
4
|
-
const CodeToTextButton = (props) => {
|
|
5
|
-
const { handleButtonClick } = props;
|
|
6
|
-
|
|
7
|
-
return (
|
|
8
|
-
<>
|
|
9
|
-
<Button
|
|
10
|
-
format="insert Html"
|
|
11
|
-
onClick={() => handleButtonClick({ showInput: true, action: "insert" })}
|
|
12
|
-
>
|
|
13
|
-
<Icon icon="insertHtml" />
|
|
14
|
-
</Button>
|
|
15
|
-
</>
|
|
16
|
-
);
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export default CodeToTextButton;
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { Interweave } from "interweave";
|
|
2
|
-
import React, { useEffect } from "react";
|
|
3
|
-
import { Transforms, Path, Node } from "slate";
|
|
4
|
-
import {
|
|
5
|
-
useSelected,
|
|
6
|
-
useFocused,
|
|
7
|
-
useSlateStatic,
|
|
8
|
-
ReactEditor,
|
|
9
|
-
} from "slate-react";
|
|
10
|
-
import useFormat from "../../utils/customHooks/useFormat";
|
|
11
|
-
|
|
12
|
-
const HtmlCode = (props) => {
|
|
13
|
-
const { attributes, element, children } = props;
|
|
14
|
-
const selected = useSelected();
|
|
15
|
-
const focused = useFocused();
|
|
16
|
-
const editor = useSlateStatic();
|
|
17
|
-
|
|
18
|
-
const isHtmlEmbed = useFormat(editor, "htmlCode");
|
|
19
|
-
|
|
20
|
-
const handleKeyUp = (e) => {
|
|
21
|
-
if (!isHtmlEmbed) return;
|
|
22
|
-
if (e.keyCode === 13) {
|
|
23
|
-
const parentPath = Path.parent(editor.selection.focus.path);
|
|
24
|
-
const nextPath = Path.next(parentPath);
|
|
25
|
-
Transforms.insertNodes(
|
|
26
|
-
editor,
|
|
27
|
-
{
|
|
28
|
-
type: "p",
|
|
29
|
-
children: [{ text: "" }],
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
at: nextPath,
|
|
33
|
-
select: true, // Focus on this node once inserted
|
|
34
|
-
}
|
|
35
|
-
);
|
|
36
|
-
} else if (e.keyCode === 8) {
|
|
37
|
-
Transforms.removeNodes(editor);
|
|
38
|
-
}
|
|
39
|
-
// console.log(e);
|
|
40
|
-
};
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
document.addEventListener("keyup", handleKeyUp);
|
|
43
|
-
return () => {
|
|
44
|
-
document.removeEventListener("keyup", handleKeyUp);
|
|
45
|
-
};
|
|
46
|
-
}, [isHtmlEmbed]);
|
|
47
|
-
return (
|
|
48
|
-
<div
|
|
49
|
-
{...attributes}
|
|
50
|
-
{...element.attr}
|
|
51
|
-
style={{
|
|
52
|
-
boxShadow: selected && focused && "0 0 3px 3px lightgray",
|
|
53
|
-
marginRight: "20px",
|
|
54
|
-
}}
|
|
55
|
-
>
|
|
56
|
-
<div contentEditable={false}>
|
|
57
|
-
<Interweave content={element.html} />
|
|
58
|
-
</div>
|
|
59
|
-
{children}
|
|
60
|
-
</div>
|
|
61
|
-
);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export default HtmlCode;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
|
2
|
-
import useContextMenu from "../../utils/customHooks/useContextMenu";
|
|
3
|
-
import Icon from "../../common/icon";
|
|
4
|
-
import { Transforms, Editor, Element, Node, Path } from "slate";
|
|
5
|
-
|
|
6
|
-
const HtmlContextMenu = (props) => {
|
|
7
|
-
const { editor, handleCodeToText } = props;
|
|
8
|
-
const [selection, setSelection] = useState();
|
|
9
|
-
const [showMenu, { top, left }] = useContextMenu(
|
|
10
|
-
editor,
|
|
11
|
-
"htmlCode",
|
|
12
|
-
setSelection
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
const handleEditHtml = () => {
|
|
16
|
-
Transforms.select(editor, selection);
|
|
17
|
-
const parentPath = Path.parent(selection.focus.path);
|
|
18
|
-
const htmlNode = Node.get(editor, parentPath);
|
|
19
|
-
handleCodeToText({
|
|
20
|
-
showInput: true,
|
|
21
|
-
html: htmlNode.html,
|
|
22
|
-
action: "update",
|
|
23
|
-
location: selection,
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
return showMenu ? (
|
|
28
|
-
<div className="contextMenu" style={{ top, left }}>
|
|
29
|
-
<div className="menuOption" onClick={handleEditHtml}>
|
|
30
|
-
<Icon icon="pen" />
|
|
31
|
-
<span>Edit HTML</span>
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
) : (
|
|
35
|
-
<></>
|
|
36
|
-
);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export default HtmlContextMenu;
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
-
import Icon from "../../common/icon";
|
|
3
|
-
import { Interweave } from "interweave";
|
|
4
|
-
import { Transforms } from "slate";
|
|
5
|
-
import { useSlateStatic } from "slate-react";
|
|
6
|
-
const CodeToText = (props) => {
|
|
7
|
-
const { html, action, location, handleCodeToText } = props;
|
|
8
|
-
const codeToTextRef = useRef();
|
|
9
|
-
const wrapperRef = useRef();
|
|
10
|
-
|
|
11
|
-
const editor = useSlateStatic();
|
|
12
|
-
const checkClick = (e) => {
|
|
13
|
-
const clickedComponent = e.target;
|
|
14
|
-
if (
|
|
15
|
-
wrapperRef?.current?.contains(clickedComponent) &&
|
|
16
|
-
!codeToTextRef?.current?.contains(clickedComponent)
|
|
17
|
-
) {
|
|
18
|
-
let partialState = {
|
|
19
|
-
showInput: false,
|
|
20
|
-
};
|
|
21
|
-
if (html) {
|
|
22
|
-
partialState.html = action === "update" ? "" : html;
|
|
23
|
-
}
|
|
24
|
-
handleCodeToText(partialState);
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
document.addEventListener("click", checkClick);
|
|
29
|
-
return () => {
|
|
30
|
-
document.removeEventListener("click", checkClick);
|
|
31
|
-
};
|
|
32
|
-
}, []);
|
|
33
|
-
|
|
34
|
-
const codeOnChange = async (e) => {
|
|
35
|
-
// e.preventDefault();
|
|
36
|
-
handleCodeToText({ html: e.target.value });
|
|
37
|
-
};
|
|
38
|
-
const addHtml = () => {
|
|
39
|
-
if (html) {
|
|
40
|
-
if (action === "update") {
|
|
41
|
-
Transforms.setNodes(
|
|
42
|
-
editor,
|
|
43
|
-
{
|
|
44
|
-
html,
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
at: location,
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
} else {
|
|
51
|
-
Transforms.insertNodes(
|
|
52
|
-
editor,
|
|
53
|
-
{
|
|
54
|
-
type: "htmlCode",
|
|
55
|
-
html: html,
|
|
56
|
-
children: [{ text: "" }],
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
select: true,
|
|
60
|
-
}
|
|
61
|
-
);
|
|
62
|
-
Transforms.insertNodes(editor, { type: "p", children: [{ text: "" }] });
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
handleCodeToText({
|
|
66
|
-
showInput: false,
|
|
67
|
-
html: "",
|
|
68
|
-
});
|
|
69
|
-
};
|
|
70
|
-
const clearHtml = () => {
|
|
71
|
-
handleCodeToText({ html: "" });
|
|
72
|
-
};
|
|
73
|
-
return (
|
|
74
|
-
<div className="code-wrapper" ref={wrapperRef}>
|
|
75
|
-
<div ref={codeToTextRef} className="codeToTextWrapper">
|
|
76
|
-
<div className="codeToText">
|
|
77
|
-
<textarea
|
|
78
|
-
name=""
|
|
79
|
-
id=""
|
|
80
|
-
value={html}
|
|
81
|
-
onChange={codeOnChange}
|
|
82
|
-
placeholder="Write html here..."
|
|
83
|
-
></textarea>
|
|
84
|
-
<div
|
|
85
|
-
style={{
|
|
86
|
-
display: "flex",
|
|
87
|
-
alignItems: "center",
|
|
88
|
-
justifyContent: "center",
|
|
89
|
-
color: "white",
|
|
90
|
-
}}
|
|
91
|
-
>
|
|
92
|
-
<Icon icon="arrowRight" />
|
|
93
|
-
</div>
|
|
94
|
-
<div className="textOutput">
|
|
95
|
-
<Interweave content={html} />
|
|
96
|
-
</div>
|
|
97
|
-
</div>
|
|
98
|
-
<div>
|
|
99
|
-
<button onClick={addHtml} className="done">
|
|
100
|
-
Done
|
|
101
|
-
</button>
|
|
102
|
-
<button className="clear" onClick={clearHtml}>
|
|
103
|
-
Clear
|
|
104
|
-
</button>
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
);
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
export default CodeToText;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { ColorCursor, ColorCursorProps } from "./color-cursor";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { StoryFn, Meta } from "@storybook/react";
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
/* 👇 The title prop is optional.
|
|
7
|
-
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
|
|
8
|
-
* to learn how to generate automatic titles
|
|
9
|
-
*/
|
|
10
|
-
title: "Slate Color Picker/Color Cursor",
|
|
11
|
-
component: ColorCursor,
|
|
12
|
-
} as Meta<typeof ColorCursor>;
|
|
13
|
-
|
|
14
|
-
export const Primary = {
|
|
15
|
-
args: { color: "blue" } as ColorCursorProps,
|
|
16
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { useTheme } from "@mui/material";
|
|
2
|
-
|
|
3
|
-
export type ColorCursorProps = {
|
|
4
|
-
color: string;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export function ColorCursor({ color }: ColorCursorProps) {
|
|
8
|
-
const theme = useTheme();
|
|
9
|
-
const r = 16;
|
|
10
|
-
const sw = 4;
|
|
11
|
-
const dim = sw * 2 + r;
|
|
12
|
-
// console.log(color)
|
|
13
|
-
return (
|
|
14
|
-
<svg width={dim} height={dim}>
|
|
15
|
-
<circle
|
|
16
|
-
cx={dim / 2}
|
|
17
|
-
cy={dim / 2}
|
|
18
|
-
r={(sw + r) / 2}
|
|
19
|
-
// @ts-ignore
|
|
20
|
-
stroke={theme.palette.neutral[300]}
|
|
21
|
-
stroke-width={sw}
|
|
22
|
-
fill={color}
|
|
23
|
-
/>
|
|
24
|
-
<circle
|
|
25
|
-
cx={dim / 2}
|
|
26
|
-
cy={dim / 2}
|
|
27
|
-
r={(sw + r) / 2 - 1}
|
|
28
|
-
stroke="white"
|
|
29
|
-
stroke-width={sw}
|
|
30
|
-
fill={"transparent"}
|
|
31
|
-
/>
|
|
32
|
-
</svg>
|
|
33
|
-
);
|
|
34
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { StoryFn, Meta } from "@storybook/react";
|
|
3
|
-
import { ColorFormatsView, ColorFormatsViewProps } from "./color-formats-view";
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
/* 👇 The title prop is optional.
|
|
7
|
-
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
|
|
8
|
-
* to learn how to generate automatic titles
|
|
9
|
-
*/
|
|
10
|
-
title: "Slate Color Picker/Color Formats View",
|
|
11
|
-
component: ColorFormatsView,
|
|
12
|
-
} as Meta<typeof ColorFormatsView>;
|
|
13
|
-
|
|
14
|
-
export const Primary = {
|
|
15
|
-
args: {
|
|
16
|
-
height: 250,
|
|
17
|
-
colorFormats: {
|
|
18
|
-
hex: "008000",
|
|
19
|
-
rgb: "rgb(0,128,0)",
|
|
20
|
-
hsl: "hsl(120, 100%, 25%)",
|
|
21
|
-
hsv: "hsv(120, 100%, 50%)",
|
|
22
|
-
},
|
|
23
|
-
setColorFormats: () => {},
|
|
24
|
-
} as ColorFormatsViewProps,
|
|
25
|
-
};
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, Dispatch, SetStateAction } from "react";
|
|
2
|
-
import {
|
|
3
|
-
Box,
|
|
4
|
-
TableContainer,
|
|
5
|
-
Table,
|
|
6
|
-
TableBody,
|
|
7
|
-
TableCell,
|
|
8
|
-
TableHead,
|
|
9
|
-
TableRow,
|
|
10
|
-
Paper,
|
|
11
|
-
TextField,
|
|
12
|
-
Input,
|
|
13
|
-
InputAdornment,
|
|
14
|
-
FormHelperText,
|
|
15
|
-
} from "@mui/material";
|
|
16
|
-
import useSimpleFormik from "../../../hooks/useSimpleFormik";
|
|
17
|
-
import {
|
|
18
|
-
colorStringToColorFormats,
|
|
19
|
-
hueFromColorFormats,
|
|
20
|
-
isColor,
|
|
21
|
-
newColorFormatsFromHue,
|
|
22
|
-
} from "@springmicro/utils/editor";
|
|
23
|
-
import { ColorFormats } from "@springmicro/utils/types";
|
|
24
|
-
|
|
25
|
-
export type ColorFormatsViewProps = {
|
|
26
|
-
height: number;
|
|
27
|
-
colorFormats: ColorFormats;
|
|
28
|
-
setColorFormats: Dispatch<SetStateAction<ColorFormats>>;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export function ColorFormatsView({
|
|
32
|
-
height,
|
|
33
|
-
colorFormats,
|
|
34
|
-
setColorFormats,
|
|
35
|
-
}: ColorFormatsViewProps) {
|
|
36
|
-
const msg = "Invalid color";
|
|
37
|
-
const formik = useSimpleFormik(colorFormats, {
|
|
38
|
-
hex: { fn: (value: string) => isColor("#" + value), msg },
|
|
39
|
-
rgb: { fn: (value: string) => isColor("" + value), msg },
|
|
40
|
-
hsl: { fn: (value: string) => isColor("" + value), msg },
|
|
41
|
-
hsv: { fn: (value: string) => isColor("" + value), msg },
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
formik.setValues(colorFormats);
|
|
46
|
-
}, [colorFormats]);
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<TableContainer component={Paper} sx={{ height, position: "relative" }}>
|
|
50
|
-
<Table>
|
|
51
|
-
<TableBody>
|
|
52
|
-
{(Object.keys(colorFormats) as Array<string>).map((k) => (
|
|
53
|
-
<TableRow key={k} sx={{ "& td, & th": { py: 1 } }}>
|
|
54
|
-
<TableCell
|
|
55
|
-
component="th"
|
|
56
|
-
scope="row"
|
|
57
|
-
sx={{ textTransform: "uppercase", fontWeight: "bold" }}
|
|
58
|
-
>
|
|
59
|
-
<Box
|
|
60
|
-
component="label"
|
|
61
|
-
htmlFor={`color-${k}`}
|
|
62
|
-
sx={{ display: "inline-block", width: "24px" }}
|
|
63
|
-
>
|
|
64
|
-
{k}
|
|
65
|
-
</Box>
|
|
66
|
-
</TableCell>
|
|
67
|
-
<TableCell>
|
|
68
|
-
<Input
|
|
69
|
-
sx={{ width: 170 }}
|
|
70
|
-
id={`color-${k}`}
|
|
71
|
-
name={k}
|
|
72
|
-
value={formik.values[k]}
|
|
73
|
-
startAdornment={
|
|
74
|
-
k === "hex" ? (
|
|
75
|
-
<InputAdornment position="start">#</InputAdornment>
|
|
76
|
-
) : null
|
|
77
|
-
}
|
|
78
|
-
onChange={(e) => {
|
|
79
|
-
formik.handleChange(e);
|
|
80
|
-
const color =
|
|
81
|
-
k === "hex" ? "#" + e.target.value : e.target.value;
|
|
82
|
-
if (isColor(color)) {
|
|
83
|
-
const newCF = colorStringToColorFormats(color);
|
|
84
|
-
setColorFormats(newCF);
|
|
85
|
-
// formik.setValues(newCF)
|
|
86
|
-
}
|
|
87
|
-
}}
|
|
88
|
-
onBlur={formik.handleBlur}
|
|
89
|
-
/>
|
|
90
|
-
{formik.errors[k] ?? (
|
|
91
|
-
<FormHelperText>{formik.errors[k]}</FormHelperText>
|
|
92
|
-
)}
|
|
93
|
-
</TableCell>
|
|
94
|
-
</TableRow>
|
|
95
|
-
))}
|
|
96
|
-
</TableBody>
|
|
97
|
-
<TableCell
|
|
98
|
-
colSpan={2}
|
|
99
|
-
sx={{
|
|
100
|
-
position: "absolute",
|
|
101
|
-
bottom: 0,
|
|
102
|
-
left: 0,
|
|
103
|
-
right: 0,
|
|
104
|
-
borderBottom: "none",
|
|
105
|
-
backgroundColor: colorFormats.rgb,
|
|
106
|
-
}}
|
|
107
|
-
></TableCell>
|
|
108
|
-
</Table>
|
|
109
|
-
</TableContainer>
|
|
110
|
-
);
|
|
111
|
-
// return <Box>
|
|
112
|
-
|
|
113
|
-
// {JSON.stringify(colorFormats, null, 2)}
|
|
114
|
-
// </Box>
|
|
115
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { StoryFn, Meta } from "@storybook/react";
|
|
3
|
-
import { ColorGradient, ColorGradientProps } from "./color-gradient";
|
|
4
|
-
import { colorStringToColorFormats } from "@springmicro/utils/editor";
|
|
5
|
-
|
|
6
|
-
type ColorGradientWrapperProps = {
|
|
7
|
-
initialColor: string;
|
|
8
|
-
width: number;
|
|
9
|
-
height: number;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
function ColorGradientWrapper({
|
|
13
|
-
initialColor,
|
|
14
|
-
width,
|
|
15
|
-
height,
|
|
16
|
-
}: ColorGradientWrapperProps) {
|
|
17
|
-
const [colorFormats, setColorFormats] = React.useState(
|
|
18
|
-
colorStringToColorFormats(initialColor)
|
|
19
|
-
);
|
|
20
|
-
React.useEffect(() => {
|
|
21
|
-
setColorFormats(colorStringToColorFormats(initialColor));
|
|
22
|
-
}, [initialColor]);
|
|
23
|
-
return (
|
|
24
|
-
<ColorGradient
|
|
25
|
-
width={width}
|
|
26
|
-
height={height}
|
|
27
|
-
colorFormats={colorFormats}
|
|
28
|
-
setColorFormats={setColorFormats}
|
|
29
|
-
/>
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export default {
|
|
34
|
-
/* 👇 The title prop is optional.
|
|
35
|
-
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
|
|
36
|
-
* to learn how to generate automatic titles
|
|
37
|
-
*/
|
|
38
|
-
title: "Slate Color Picker/Color Gradient",
|
|
39
|
-
component: ColorGradientWrapper,
|
|
40
|
-
} as Meta<typeof ColorGradientWrapper>;
|
|
41
|
-
|
|
42
|
-
export const Primary = {
|
|
43
|
-
args: {
|
|
44
|
-
initialColor: "purple",
|
|
45
|
-
width: 360,
|
|
46
|
-
height: 240,
|
|
47
|
-
} as ColorGradientWrapperProps,
|
|
48
|
-
};
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, Dispatch, SetStateAction, useRef } from "react";
|
|
2
|
-
import { Box } from "@mui/material";
|
|
3
|
-
import {
|
|
4
|
-
calculate2DPositionFromColorFormats,
|
|
5
|
-
calculateMouseColors,
|
|
6
|
-
colorConvert,
|
|
7
|
-
hueFromColorFormats,
|
|
8
|
-
isColor,
|
|
9
|
-
} from "@springmicro/utils/editor";
|
|
10
|
-
import { ColorFormats } from "@springmicro/utils/types";
|
|
11
|
-
import { ColorCursor } from "./color-cursor";
|
|
12
|
-
|
|
13
|
-
const calculateInitCursorPosition = (
|
|
14
|
-
width: number,
|
|
15
|
-
height: number,
|
|
16
|
-
colorFormats: ColorFormats
|
|
17
|
-
) => {
|
|
18
|
-
const [sat, val] = (colorFormats.hsv.match(/[0-9]+\%/g) as Array<string>).map(
|
|
19
|
-
(val) => parseInt(val)
|
|
20
|
-
);
|
|
21
|
-
const x = (width * sat) / 100;
|
|
22
|
-
const y = height - (height * val) / 100;
|
|
23
|
-
return {
|
|
24
|
-
x,
|
|
25
|
-
y,
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export type ColorGradientProps = {
|
|
30
|
-
width: number;
|
|
31
|
-
height: number;
|
|
32
|
-
colorFormats: ColorFormats;
|
|
33
|
-
setColorFormats: Dispatch<SetStateAction<ColorFormats>>;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export function ColorGradient({
|
|
37
|
-
width,
|
|
38
|
-
height,
|
|
39
|
-
colorFormats,
|
|
40
|
-
setColorFormats,
|
|
41
|
-
}: ColorGradientProps) {
|
|
42
|
-
const ref = useRef();
|
|
43
|
-
const [mouseIsDown, setMouseIsDown] = useState(false);
|
|
44
|
-
const [cursorPosition, setCursorPosition] = useState(
|
|
45
|
-
calculateInitCursorPosition(width, height, colorFormats)
|
|
46
|
-
);
|
|
47
|
-
const [rect, setRect] = useState<DOMRect>();
|
|
48
|
-
const hue = hueFromColorFormats(colorFormats);
|
|
49
|
-
|
|
50
|
-
const updateColor = (x: number, y: number, w: number, h: number) => {
|
|
51
|
-
const newColors = calculateMouseColors(x, y, w, h, hue);
|
|
52
|
-
if (isColor(newColors.rgb)) {
|
|
53
|
-
setColorFormats(newColors);
|
|
54
|
-
setCursorPosition({ x, y });
|
|
55
|
-
console.log(newColors);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
if (!mouseIsDown)
|
|
61
|
-
setCursorPosition(
|
|
62
|
-
calculate2DPositionFromColorFormats(width, height, colorFormats)
|
|
63
|
-
);
|
|
64
|
-
}, [colorFormats]);
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<Box
|
|
68
|
-
ref={ref}
|
|
69
|
-
onMouseDown={(e) => {
|
|
70
|
-
if (!ref.current) return;
|
|
71
|
-
setMouseIsDown(true);
|
|
72
|
-
const rect = (ref.current as HTMLElement).getBoundingClientRect();
|
|
73
|
-
setRect(rect);
|
|
74
|
-
// e.clientX was not giving the right position within the element
|
|
75
|
-
// calculate instead
|
|
76
|
-
const x = e.pageX - rect.x;
|
|
77
|
-
const y = e.pageY - rect.y;
|
|
78
|
-
updateColor(x, y, rect.width, rect.height);
|
|
79
|
-
}}
|
|
80
|
-
onMouseUp={(e) => {
|
|
81
|
-
setMouseIsDown(false);
|
|
82
|
-
}}
|
|
83
|
-
onMouseMove={(e) => {
|
|
84
|
-
if (mouseIsDown && rect) {
|
|
85
|
-
const x = e.pageX - rect.x;
|
|
86
|
-
const y = e.pageY - rect.y;
|
|
87
|
-
if (x <= width && y <= height && x >= 0 && y >= 0) {
|
|
88
|
-
// console.log(x, y, rect.x, rect.y)
|
|
89
|
-
updateColor(x, y, rect.width, rect.height);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}}
|
|
93
|
-
sx={{
|
|
94
|
-
position: "relative",
|
|
95
|
-
height,
|
|
96
|
-
width,
|
|
97
|
-
background: "#000",
|
|
98
|
-
"&::before": {
|
|
99
|
-
content: '""',
|
|
100
|
-
position: "absolute",
|
|
101
|
-
top: 0,
|
|
102
|
-
left: 0,
|
|
103
|
-
right: 0,
|
|
104
|
-
bottom: 0,
|
|
105
|
-
background: `linear-gradient(
|
|
106
|
-
to right,
|
|
107
|
-
hsl(${hue}, 100%, 100%),
|
|
108
|
-
hsl(${hue}, 100%, 50%)
|
|
109
|
-
)`,
|
|
110
|
-
mask: `linear-gradient(#000, transparent)`,
|
|
111
|
-
borderRadius: 1,
|
|
112
|
-
},
|
|
113
|
-
borderRadius: 1,
|
|
114
|
-
}}
|
|
115
|
-
>
|
|
116
|
-
<Box
|
|
117
|
-
sx={{
|
|
118
|
-
position: "absolute",
|
|
119
|
-
top: cursorPosition.y + "px",
|
|
120
|
-
left: cursorPosition.x + "px",
|
|
121
|
-
transform: "translate(-50%, -50%)",
|
|
122
|
-
}}
|
|
123
|
-
>
|
|
124
|
-
<ColorCursor color={colorFormats.rgb} />
|
|
125
|
-
</Box>
|
|
126
|
-
</Box>
|
|
127
|
-
);
|
|
128
|
-
}
|