@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.
Files changed (87) hide show
  1. package/README.md +50 -5
  2. package/dist/index.js +7361 -7279
  3. package/package.json +7 -3
  4. package/.eslintrc.cjs +0 -18
  5. package/dist/index.d.ts +0 -10
  6. package/dist/index.umd.cjs +0 -469
  7. package/index.html +0 -13
  8. package/src/App.css +0 -42
  9. package/src/App.tsx +0 -10
  10. package/src/contexts/color-context.tsx +0 -53
  11. package/src/hooks/useSimpleFormik.tsx +0 -74
  12. package/src/index.css +0 -68
  13. package/src/index.tsx +0 -3
  14. package/src/main.tsx +0 -10
  15. package/src/slate/base-editor.stories.tsx +0 -16
  16. package/src/slate/base-editor.tsx +0 -116
  17. package/src/slate/blog-rte.stories.tsx +0 -16
  18. package/src/slate/blog-rte.tsx +0 -126
  19. package/src/slate/common/button.tsx +0 -35
  20. package/src/slate/common/element.tsx +0 -13
  21. package/src/slate/common/icon.jsx +0 -97
  22. package/src/slate/components/code-to-text/CodeToTextButton.jsx +0 -19
  23. package/src/slate/components/code-to-text/HtmlCode.jsx +0 -64
  24. package/src/slate/components/code-to-text/HtmlContextMenu.jsx +0 -39
  25. package/src/slate/components/code-to-text/index.jsx +0 -111
  26. package/src/slate/components/color-picker/color-cursor.stories.tsx +0 -16
  27. package/src/slate/components/color-picker/color-cursor.tsx +0 -34
  28. package/src/slate/components/color-picker/color-formats-view.stories.tsx +0 -25
  29. package/src/slate/components/color-picker/color-formats-view.tsx +0 -115
  30. package/src/slate/components/color-picker/color-gradient.stories.tsx +0 -48
  31. package/src/slate/components/color-picker/color-gradient.tsx +0 -128
  32. package/src/slate/components/color-picker/color-hue.stories.tsx +0 -41
  33. package/src/slate/components/color-picker/color-hue.tsx +0 -110
  34. package/src/slate/components/color-picker/color-picker.stories.tsx +0 -25
  35. package/src/slate/components/color-picker/color-picker.tsx +0 -41
  36. package/src/slate/components/color-picker/color-popover.stories.tsx +0 -26
  37. package/src/slate/components/color-picker/color-popover.tsx +0 -58
  38. package/src/slate/components/color-picker/color-swatch.stories.tsx +0 -16
  39. package/src/slate/components/color-picker/color-swatch.tsx +0 -76
  40. package/src/slate/components/color-picker/default-colors.ts +0 -38
  41. package/src/slate/components/color-picker/slate-color-button.tsx +0 -128
  42. package/src/slate/components/embed/Embed.jsx +0 -96
  43. package/src/slate/components/embed/Image.jsx +0 -45
  44. package/src/slate/components/embed/Video.jsx +0 -65
  45. package/src/slate/components/equation/Equation.jsx +0 -19
  46. package/src/slate/components/equation/EquationButton.jsx +0 -68
  47. package/src/slate/components/id/Id.jsx +0 -57
  48. package/src/slate/components/image/image.stories.tsx +0 -17
  49. package/src/slate/components/image/image.tsx +0 -62
  50. package/src/slate/components/image/insert-image-button.stories.tsx +0 -83
  51. package/src/slate/components/image/insert-image-button.tsx +0 -132
  52. package/src/slate/components/image/types.ts +0 -9
  53. package/src/slate/components/link/Link.jsx +0 -56
  54. package/src/slate/components/link/LinkButton.tsx +0 -106
  55. package/src/slate/components/table/Table.jsx +0 -11
  56. package/src/slate/components/table/TableSelector.jsx +0 -97
  57. package/src/slate/components/table-context-menu/TableContextMenu.tsx +0 -106
  58. package/src/slate/custom-types.d.ts +0 -152
  59. package/src/slate/editor.module.css +0 -226
  60. package/src/slate/paper-rte.stories.tsx +0 -16
  61. package/src/slate/paper-rte.tsx +0 -47
  62. package/src/slate/plugins/withEmbeds.js +0 -33
  63. package/src/slate/plugins/withEquation.js +0 -8
  64. package/src/slate/plugins/withImages.ts +0 -69
  65. package/src/slate/plugins/withLinks.js +0 -9
  66. package/src/slate/plugins/withTable.js +0 -74
  67. package/src/slate/serializers/generic.ts +0 -44
  68. package/src/slate/serializers/types.ts +0 -20
  69. package/src/slate/toolbar/index.tsx +0 -186
  70. package/src/slate/toolbar/paper-toolbar.tsx +0 -494
  71. package/src/slate/toolbar/shortcuts.tsx +0 -77
  72. package/src/slate/toolbar/toolbar-groups.ts +0 -213
  73. package/src/slate/types/index.ts +0 -0
  74. package/src/slate/utils/customHooks/useContextMenu.js +0 -42
  75. package/src/slate/utils/customHooks/useFormat.js +0 -26
  76. package/src/slate/utils/customHooks/usePopup.jsx +0 -26
  77. package/src/slate/utils/customHooks/useResize.js +0 -27
  78. package/src/slate/utils/embed.js +0 -18
  79. package/src/slate/utils/equation.js +0 -22
  80. package/src/slate/utils/index.jsx +0 -267
  81. package/src/slate/utils/link.js +0 -44
  82. package/src/slate/utils/p.js +0 -4
  83. package/src/slate/utils/table.js +0 -131
  84. package/src/vite-env.d.ts +0 -1
  85. package/tsconfig.json +0 -32
  86. package/tsconfig.node.json +0 -10
  87. 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
- }