@bigbinary/neeto-editor 0.1.15 → 0.2.1

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 (72) hide show
  1. package/index.js +37 -14
  2. package/package.json +18 -4
  3. package/src/App.js +5 -28
  4. package/src/Common/Avatar.js +168 -0
  5. package/src/Common/Button.js +95 -0
  6. package/src/Common/CodeBlock.js +11 -0
  7. package/src/Common/Description.js +8 -0
  8. package/src/Common/Dropdown/index.js +122 -0
  9. package/src/Common/Heading.js +13 -0
  10. package/src/Common/HighlightText.js +7 -0
  11. package/src/Common/Icons/HashtagFilled.js +59 -0
  12. package/src/Common/Icons/TextColor.js +35 -0
  13. package/src/Common/Icons/index.js +2 -0
  14. package/src/Common/Input.js +70 -0
  15. package/src/Common/Label.js +45 -0
  16. package/src/Common/ListItems.js +17 -0
  17. package/src/Common/Modal.js +91 -0
  18. package/src/Common/Tab.js +79 -0
  19. package/src/Common/ToolTip.js +37 -0
  20. package/src/Editor/CustomExtensions/BubbleMenu/index.js +33 -26
  21. package/src/Editor/CustomExtensions/Embeds.js +5 -3
  22. package/src/Editor/CustomExtensions/FixedMenu/FontSizeOption.js +32 -0
  23. package/src/Editor/CustomExtensions/FixedMenu/TextColorOption.js +29 -0
  24. package/src/Editor/CustomExtensions/FixedMenu/constants.js +3 -0
  25. package/src/Editor/CustomExtensions/FixedMenu/index.js +183 -0
  26. package/src/Editor/CustomExtensions/Image/LinkUploader/URLForm.js +39 -0
  27. package/src/Editor/CustomExtensions/Image/LocalUploader.js +21 -0
  28. package/src/Editor/CustomExtensions/Image/ProgressBar.js +34 -0
  29. package/src/Editor/CustomExtensions/Image/Uploader.js +72 -31
  30. package/src/Editor/CustomExtensions/Image/constants.js +5 -0
  31. package/src/Editor/CustomExtensions/Mention/ExtensionConfig.js +66 -0
  32. package/src/Editor/CustomExtensions/Mention/MentionList.js +96 -0
  33. package/src/Editor/CustomExtensions/Mention/helpers.js +23 -0
  34. package/src/Editor/CustomExtensions/Placeholder/ExtensionConfig.js +81 -0
  35. package/src/Editor/CustomExtensions/Placeholder/helpers.js +18 -0
  36. package/src/Editor/CustomExtensions/SlashCommands/Commands.js +5 -10
  37. package/src/Editor/CustomExtensions/SlashCommands/CommandsList.js +15 -16
  38. package/src/Editor/CustomExtensions/SlashCommands/ExtensionConfig.js +200 -155
  39. package/src/Editor/CustomExtensions/Variable/ExtensionConfig.js +208 -0
  40. package/src/Editor/CustomExtensions/Variable/VariableList.js +45 -0
  41. package/src/Editor/CustomExtensions/Variable/VariableSuggestion.js +20 -0
  42. package/src/Editor/CustomExtensions/Variable/helpers.js +31 -0
  43. package/src/Editor/CustomExtensions/Variable/index.js +35 -0
  44. package/src/Editor/CustomExtensions/useCustomExtensions.js +88 -0
  45. package/src/Editor/index.js +59 -41
  46. package/src/constants/regexp.js +1 -0
  47. package/src/examples/constants.js +95 -0
  48. package/src/examples/index.js +186 -0
  49. package/src/hooks/useOutsideClick.js +19 -0
  50. package/src/hooks/useTabBar.js +9 -0
  51. package/src/index.scss +32 -12
  52. package/src/styles/abstracts/_mixins.scss +20 -0
  53. package/src/styles/abstracts/_neeto-ui-variables.scss +107 -0
  54. package/src/styles/abstracts/_variables.scss +13 -0
  55. package/src/styles/components/_avatar.scss +105 -0
  56. package/src/styles/components/_button.scss +161 -0
  57. package/src/styles/components/_codeblock.scss +16 -0
  58. package/src/{Editor/styles/CommandsList.scss → styles/components/_command-list.scss} +12 -1
  59. package/src/styles/components/_dropdown.scss +69 -0
  60. package/src/styles/components/_editor-variables.scss +12 -0
  61. package/src/{Editor/styles/EditorStyles.scss → styles/components/_editor.scss} +33 -7
  62. package/src/styles/components/_fixed-menu.scss +17 -0
  63. package/src/styles/components/_image-uploader.scss +109 -0
  64. package/src/styles/components/_input.scss +165 -0
  65. package/src/styles/components/_tab.scss +74 -0
  66. package/src/styles/components/_tooltip.scss +152 -0
  67. package/src/utils/common.js +13 -0
  68. package/webpack.config.js +7 -0
  69. package/webpack.dev.config.js +7 -0
  70. package/public/logo192.png +0 -0
  71. package/public/logo512.png +0 -0
  72. package/src/logo.svg +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigbinary/neeto-editor",
3
- "version": "0.1.15",
3
+ "version": "0.2.1",
4
4
  "main": "./index.js",
5
5
  "description": "Neeto Editor is the library that drives the rich text experience in all Neeto products built at BigBinary",
6
6
  "keywords": [
@@ -12,26 +12,40 @@
12
12
  "author": "BigBinary",
13
13
  "license": "MIT",
14
14
  "dependencies": {
15
+ "@bigbinary/neeto-icons": "^1.8.6",
15
16
  "@risingstack/react-easy-state": "^6.3.0",
16
17
  "@tailwindcss/typography": "^0.4.0",
18
+ "@tippyjs/react": "^4.2.6",
17
19
  "@tiptap/extension-bubble-menu": "^2.0.0-beta.18",
18
20
  "@tiptap/extension-code-block-lowlight": "^2.0.0-beta.24",
21
+ "@tiptap/extension-color": "^2.0.0-beta.3",
22
+ "@tiptap/extension-document": "^2.0.0-beta.15",
19
23
  "@tiptap/extension-dropcursor": "^2.0.0-beta.13",
20
24
  "@tiptap/extension-highlight": "^2.0.0-beta.13",
21
25
  "@tiptap/extension-image": "^2.0.0-beta.13",
22
26
  "@tiptap/extension-link": "^2.0.0-beta.18",
27
+ "@tiptap/extension-mention": "^2.0.0-beta.80",
23
28
  "@tiptap/extension-placeholder": "^2.0.0-beta.18",
29
+ "@tiptap/extension-text-style": "^2.0.0-beta.17",
24
30
  "@tiptap/extension-typography": "^2.0.0-beta.11",
31
+ "@tiptap/extension-underline": "^2.0.0-beta.21",
25
32
  "@tiptap/react": "^2.0.0-beta.37",
26
33
  "@tiptap/starter-kit": "^2.0.0-beta.57",
27
34
  "@tiptap/suggestion": "^2.0.0-beta.55",
28
- "@uppy/core": "^1.18.1",
29
- "@uppy/react": "^1.11.8",
30
- "@uppy/xhr-upload": "^1.7.2",
35
+ "@uppy/core": "^2.1.2",
36
+ "@uppy/react": "^2.1.1",
37
+ "@uppy/url": "^2.0.4",
38
+ "@uppy/xhr-upload": "^2.0.5",
31
39
  "classnames": "^2.3.1",
40
+ "lodash.isempty": "^4.4.0",
41
+ "lodash.isplainobject": "^4.0.6",
32
42
  "lowlight": "^1.20.0",
33
43
  "peer-deps-externals-webpack-plugin": "1.0.4",
44
+ "react-hotkeys-hook": "^3.4.4",
34
45
  "react-icons": "^4.2.0",
46
+ "react-outside-click-handler": "^1.3.0",
47
+ "react-popper": "^2.2.5",
48
+ "react-router-dom": "^6.0.2",
35
49
  "tippy.js": "^6.3.1"
36
50
  },
37
51
  "devDependencies": {
package/src/App.js CHANGED
@@ -1,31 +1,8 @@
1
- import React, { Component } from "react";
2
- import Editor from "./Editor/index";
3
- import "./index.scss";
4
-
5
- export default class App extends Component {
6
- ref = React.createRef();
1
+ import React from "react";
7
2
 
8
- getHTML = () => {
9
- return this.ref.current.editor.getHTML();
10
- };
3
+ import Example from "./examples";
4
+ import "./index.scss";
11
5
 
12
- render() {
13
- return (
14
- <div style={{ width: 720, margin: "48px auto" }}>
15
- <div className="flex justify-end">
16
- <button
17
- className="px-3 py-1 text-sm font-medium border border-gray-200 rounded shadow-sm"
18
- onClick={() => {
19
- // eslint-disable-next-line no-console
20
- console.log(this.getHTML());
21
- }}
22
- >
23
- Print output to console
24
- </button>
25
- </div>
26
- <hr className="my-2 border-gray-100" />
27
- <Editor ref={this.ref} />
28
- </div>
29
- );
30
- }
6
+ export default function App() {
7
+ return <Example />;
31
8
  }
@@ -0,0 +1,168 @@
1
+ import React, { useState } from "react";
2
+ import PropTypes from "prop-types";
3
+ import classNames from "classnames";
4
+
5
+ const SIZE = {
6
+ small: 24,
7
+ medium: 32,
8
+ large: 40,
9
+ xlarge: 64,
10
+ };
11
+
12
+ const STATUS = {
13
+ online: "online",
14
+ idle: "idle",
15
+ offline: "offline",
16
+ };
17
+
18
+ const COLORS = [
19
+ "#E5E7EB",
20
+ "#FECACA",
21
+ "#FDE68A",
22
+ "#A7F3D0",
23
+ "#BFDBFE",
24
+ "#C7D2FE",
25
+ "#DDD6FE",
26
+ "#FBCFE8",
27
+ ];
28
+
29
+ function Avatar({
30
+ size,
31
+ user,
32
+ isSquare,
33
+ status,
34
+ onClick,
35
+ className,
36
+ ...otherProps
37
+ }) {
38
+ const [loaded, setLoaded] = useState(false);
39
+
40
+ const { name = "", imageUrl } = user;
41
+
42
+ const isMedium = size === "medium";
43
+ const isLarge = size === "large";
44
+ const isXLarge = size === "xlarge";
45
+
46
+ const getInitials = (fullName) => {
47
+ const allNames = fullName.trim().split(" ");
48
+ const initials = allNames.reduce((acc, curr, index) => {
49
+ if (index === 0 || index === allNames.length - 1) {
50
+ acc = `${acc}${curr.charAt(0).toUpperCase()}`;
51
+ }
52
+ return acc;
53
+ }, "");
54
+ return initials;
55
+ };
56
+
57
+ const avatarString = getInitials(name);
58
+
59
+ const getRandomBackgroundColor = () => {
60
+ const charCode =
61
+ (avatarString.charCodeAt(0) || 0) + (avatarString.charCodeAt(1) || 0);
62
+ const bgColor = COLORS[(charCode % 65) % COLORS.length] || COLORS[0];
63
+ return bgColor;
64
+ };
65
+
66
+ const imageContainerStyle = {
67
+ height: SIZE[size],
68
+ width: SIZE[size],
69
+ backgroundColor: getRandomBackgroundColor(),
70
+ };
71
+
72
+ const imageClasses = classNames("neeto-ui-avatar", {
73
+ "neeto-ui-avatar--medium": isMedium,
74
+ "neeto-ui-avatar--large": isLarge,
75
+ "neeto-ui-avatar--xlarge": isXLarge,
76
+ "neeto-ui-avatar--round": !isSquare,
77
+ hidden: !loaded,
78
+ });
79
+
80
+ const placeholderClasses = classNames("neeto-ui-avatar__text", {
81
+ "neeto-ui-avatar__text-medium": isMedium,
82
+ "neeto-ui-avatar__text-large": isLarge,
83
+ "neeto-ui-avatar__text-xlarge": isXLarge,
84
+ });
85
+
86
+ // TODO: Remove 'v2' prefix.
87
+ const statusClasses = classNames("neeto-ui-avatar__status", `${status}`, {
88
+ "neeto-ui-avatar__status-medium": isMedium,
89
+ "neeto-ui-avatar__status-large": isLarge,
90
+ "neeto-ui-avatar__status-xlarge": isXLarge,
91
+ "neeto-ui-avatar__status-square": isSquare,
92
+ });
93
+
94
+ const Indicator = () =>
95
+ status === undefined || status === null ? (
96
+ React.Fragment
97
+ ) : (
98
+ <span className={statusClasses} />
99
+ );
100
+
101
+ const ImagePlaceholder = () => (
102
+ <span className={placeholderClasses}>{avatarString}</span>
103
+ );
104
+
105
+ const shouldDisplayInitials = avatarString && !imageUrl && !loaded;
106
+
107
+ return (
108
+ <div
109
+ onClick={onClick}
110
+ style={imageContainerStyle}
111
+ className={classNames(
112
+ "neeto-ui-avatar--container",
113
+ {
114
+ "neeto-ui-avatar--container-round": !isSquare,
115
+ },
116
+ className
117
+ )}
118
+ {...otherProps}
119
+ >
120
+ <Indicator />
121
+ {shouldDisplayInitials ? (
122
+ <ImagePlaceholder />
123
+ ) : (
124
+ <img
125
+ className={imageClasses}
126
+ onLoad={() => setLoaded(true)}
127
+ onError={() => setLoaded(false)}
128
+ src={imageUrl}
129
+ alt={`avatar-${avatarString}`}
130
+ />
131
+ )}
132
+ </div>
133
+ );
134
+ }
135
+
136
+ Avatar.defaultProps = {
137
+ size: "medium",
138
+ user: {
139
+ imageUrl: "",
140
+ name: "",
141
+ },
142
+ isSquare: false,
143
+ onClick: () => {},
144
+ status: null,
145
+ };
146
+
147
+ Avatar.propTypes = {
148
+ /**
149
+ * Specify the dimension for avatar component.
150
+ */
151
+ size: PropTypes.oneOf(Object.keys(SIZE)),
152
+ user: PropTypes.shape({
153
+ imageUrl: PropTypes.string,
154
+ name: PropTypes.string,
155
+ }),
156
+ isSquare: PropTypes.bool,
157
+ onClick: PropTypes.func,
158
+ /**
159
+ * Specify the status of the user if needed in avatar component.
160
+ */
161
+ status: PropTypes.oneOf(Object.keys(STATUS)),
162
+ /**
163
+ * Specify custom className to be applied on the Avatar Container
164
+ */
165
+ className: PropTypes.string,
166
+ };
167
+
168
+ export default Avatar;
@@ -0,0 +1,95 @@
1
+ import React from "react";
2
+ import classnames from "classnames";
3
+ import { Link } from "react-router-dom";
4
+ import ToolTip from "common/ToolTip";
5
+
6
+ const noop = () => {};
7
+ const BUTTON_STYLES = {
8
+ primary: "primary",
9
+ secondary: "secondary",
10
+ danger: "danger",
11
+ text: "text",
12
+ link: "link",
13
+ };
14
+ const BUTTON_SIZES = { large: "large", default: "default" };
15
+ const ICON_POSITIONS = { left: "left", right: "right" };
16
+
17
+ const Button = React.forwardRef((props, ref) => {
18
+ let {
19
+ icon = null,
20
+ iconPosition = "right",
21
+ iconSize = 16,
22
+ label = "",
23
+ loading = false,
24
+ onClick = noop,
25
+ to = null,
26
+ type = "button",
27
+ style = "primary",
28
+ fullWidth = false,
29
+ className = "",
30
+ disabled = false,
31
+ size = null,
32
+ href = null,
33
+ tooltipProps = null,
34
+ ...otherProps
35
+ } = props;
36
+
37
+ const handleClick = (e) => {
38
+ if (!loading && !disabled) {
39
+ onClick(e);
40
+ }
41
+ };
42
+
43
+ let Parent, elementSpecificProps;
44
+ if (to) {
45
+ Parent = Link;
46
+ elementSpecificProps = { to };
47
+ } else if (href) {
48
+ Parent = "a";
49
+ elementSpecificProps = { href };
50
+ } else {
51
+ Parent = "button";
52
+ elementSpecificProps = {
53
+ type,
54
+ };
55
+ }
56
+
57
+ let Icon =
58
+ typeof icon == "string"
59
+ ? () => <i className={classnames("neeto-ui-btn__icon", [icon])} />
60
+ : icon || React.Fragment;
61
+
62
+ const spinnerMarginSide =
63
+ iconPosition == "left" ? "marginRight" : "marginLeft";
64
+
65
+ return (
66
+ <ToolTip {...tooltipProps} disabled={!tooltipProps}>
67
+ <Parent
68
+ ref={ref}
69
+ onClick={handleClick}
70
+ className={classnames("neeto-ui-btn", [className], {
71
+ "neeto-ui-btn--style-primary": style === BUTTON_STYLES.primary,
72
+ "neeto-ui-btn--style-secondary": style === BUTTON_STYLES.secondary,
73
+ "neeto-ui-btn--style-danger": style === BUTTON_STYLES.danger,
74
+ "neeto-ui-btn--style-text": style === BUTTON_STYLES.text,
75
+ "neeto-ui-btn--style-link": style === BUTTON_STYLES.link,
76
+ "neeto-ui-btn--size-large": size === BUTTON_SIZES.large,
77
+ "neeto-ui-btn--width-full": fullWidth,
78
+ "neeto-ui-btn--icon-left": iconPosition == ICON_POSITIONS.left,
79
+ "neeto-ui-btn--icon-only": !label,
80
+ disabled: disabled,
81
+ })}
82
+ disabled={disabled}
83
+ {...elementSpecificProps}
84
+ {...otherProps}
85
+ >
86
+ {label && <span>{label}</span>}
87
+ {icon ? (
88
+ <Icon key="2" size={iconSize} className="neeto-ui-btn__icon" />
89
+ ) : null}
90
+ </Parent>
91
+ </ToolTip>
92
+ );
93
+ });
94
+
95
+ export default Button;
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+
3
+ const CodeBlock = ({ children }) => {
4
+ return (
5
+ <div className="flex-1 p-3 mx-3 my-2 codeblock__container">
6
+ <pre>{children}</pre>
7
+ </div>
8
+ );
9
+ };
10
+
11
+ export default CodeBlock;
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import classNames from "classnames";
3
+
4
+ const Description = ({ children, className }) => {
5
+ return <p className={classNames({ [className]: className })}>{children}</p>;
6
+ };
7
+
8
+ export default Description;
@@ -0,0 +1,122 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import classnames from "classnames";
3
+ import { usePopper } from "react-popper";
4
+ import { Down } from "@bigbinary/neeto-icons";
5
+ import { useHotkeys } from "react-hotkeys-hook";
6
+ import OutsideClickHandler from "react-outside-click-handler";
7
+
8
+ import { hyphenize } from "../../utils/common";
9
+
10
+ const noop = () => {};
11
+
12
+ const Dropdown = ({
13
+ icon,
14
+ label,
15
+ isOpen,
16
+ onClose = noop,
17
+ ulProps,
18
+ position,
19
+ children,
20
+ autoWidth,
21
+ className,
22
+ buttonStyle = "primary",
23
+ buttonProps,
24
+ customTarget,
25
+ disabled = false,
26
+ closeOnEsc = true,
27
+ closeOnSelect = true,
28
+ closeOnOutsideClick = true,
29
+ dropdownModifiers = [],
30
+ ...otherProps
31
+ }) => {
32
+ const Target = customTarget;
33
+ const isControlled = !(isOpen === undefined || isOpen === null);
34
+
35
+ const [visible, setVisibility] = useState(false);
36
+ const [reference, setReference] = useState(null);
37
+ const [popper, setPopper] = useState(null);
38
+
39
+ const { styles, attributes } = usePopper(reference, popper, {
40
+ placement: position || "bottom-end",
41
+ modifiers: dropdownModifiers,
42
+ });
43
+
44
+ const onPopupClose = () => {
45
+ if (!isControlled) setVisibility(false);
46
+ onClose();
47
+ };
48
+
49
+ const handlePopperClick = () => {
50
+ closeOnSelect && onPopupClose();
51
+ };
52
+
53
+ const handleButtonClick = () => {
54
+ setVisibility(!visible);
55
+ };
56
+
57
+ closeOnEsc && useHotkeys("esc", onPopupClose);
58
+
59
+ if (!isControlled) {
60
+ buttonProps = {
61
+ ...buttonProps,
62
+ onClick: () => {
63
+ handleButtonClick();
64
+ },
65
+ };
66
+ }
67
+
68
+ useEffect(() => {
69
+ isControlled && setVisibility(isOpen);
70
+ }, [isOpen]);
71
+
72
+ return (
73
+ <OutsideClickHandler
74
+ useCapture={true}
75
+ onOutsideClick={() => {
76
+ closeOnOutsideClick && onPopupClose();
77
+ }}
78
+ >
79
+ <div
80
+ className={classnames("neeto-ui-dropdown__wrapper h-full", {
81
+ "neeto-ui-dropdown__wrapper--auto-width": autoWidth,
82
+ [className]: className,
83
+ })}
84
+ {...otherProps}
85
+ >
86
+ {customTarget ? (
87
+ <div
88
+ ref={setReference}
89
+ onClick={handleButtonClick}
90
+ className="h-full"
91
+ >
92
+ <Target />
93
+ </div>
94
+ ) : (
95
+ <div>
96
+ {label}
97
+ <Down />
98
+ </div>
99
+ )}
100
+ {visible && (
101
+ <ul
102
+ className="neeto-ui-dropdown__popup"
103
+ ref={setPopper}
104
+ onClick={handlePopperClick}
105
+ data-cy={`${hyphenize(label)}-dropdown-container`}
106
+ {...ulProps}
107
+ style={{
108
+ display: "block",
109
+ ...styles.offset,
110
+ ...styles.popper,
111
+ }}
112
+ {...attributes.popper}
113
+ >
114
+ {children}
115
+ </ul>
116
+ )}
117
+ </div>
118
+ </OutsideClickHandler>
119
+ );
120
+ };
121
+
122
+ export default Dropdown;
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import classNames from "classnames";
3
+
4
+ const Heading = ({ children, type = "main" }) => {
5
+ const className = classNames({
6
+ "mb-3 mt-14 text-3xl font-extrabold": type === "main",
7
+ "mb-1 mt-8 text-xl font-bold": type === "sub",
8
+ });
9
+
10
+ return <h1 className={className}>{children}</h1>;
11
+ };
12
+
13
+ export default Heading;
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+
3
+ const HighlightText = ({ children }) => (
4
+ <span className="px-1 font-mono bg-gray-100">{children}</span>
5
+ );
6
+
7
+ export default HighlightText;
@@ -0,0 +1,59 @@
1
+ /** Icons generated by create-react-icons. Don't edit this file directly. **/
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+
5
+ export function HashtagFilled(props) {
6
+ const { size, color, bgColor, ...other } = props;
7
+ return (
8
+ <svg viewBox="0 0 24 24" fill="none" height={size} width={size} {...other}>
9
+ <path
10
+ d="M21 7V17C21 19.209 19.209 21 17 21H7C4.791 21 3 19.209 3 17V7C3 4.791 4.791 3 7 3H17C19.209 3 21 4.791 21 7Z"
11
+ fill={bgColor}
12
+ stroke={bgColor}
13
+ strokeWidth="1.5"
14
+ strokeLinecap="round"
15
+ strokeLinejoin="round"
16
+ />
17
+ <path
18
+ d="M10 8V16"
19
+ stroke={color}
20
+ strokeWidth="1.389"
21
+ strokeLinecap="round"
22
+ strokeLinejoin="round"
23
+ />
24
+ <path
25
+ d="M14 8V16"
26
+ stroke={color}
27
+ strokeWidth="1.389"
28
+ strokeLinecap="round"
29
+ strokeLinejoin="round"
30
+ />
31
+ <path
32
+ d="M8 14H16"
33
+ stroke={color}
34
+ strokeWidth="1.389"
35
+ strokeLinecap="round"
36
+ strokeLinejoin="round"
37
+ />
38
+ <path
39
+ d="M8 10H16"
40
+ stroke={color}
41
+ strokeWidth="1.389"
42
+ strokeLinecap="round"
43
+ strokeLinejoin="round"
44
+ />
45
+ </svg>
46
+ );
47
+ }
48
+
49
+ HashtagFilled.defaultProps = {
50
+ color: "white",
51
+ bgColor: "#68737D",
52
+ size: 24,
53
+ };
54
+
55
+ HashtagFilled.propTypes = {
56
+ color: PropTypes.string,
57
+ bgColor: PropTypes.string,
58
+ size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
59
+ };
@@ -0,0 +1,35 @@
1
+ /** Icons generated by create-react-icons. Don't edit this file directly. **/
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+
5
+ export function TextColor(props) {
6
+ const { size, color, underlineColor, ...other } = props;
7
+ return (
8
+ <svg viewBox="0 0 24 24" fill="none" height={size} width={size} {...other}>
9
+ <path
10
+ d="M21 20H3"
11
+ stroke={underlineColor || color}
12
+ strokeWidth="1.5"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ />
16
+ <path
17
+ d="M17.3125 15L12.1562 4L7 15M8.03125 12.8H16.2812"
18
+ stroke={color}
19
+ strokeWidth="1.5"
20
+ strokeLinecap="round"
21
+ strokeLinejoin="round"
22
+ />
23
+ </svg>
24
+ );
25
+ }
26
+
27
+ TextColor.defaultProps = {
28
+ color: "currentColor",
29
+ size: 24,
30
+ };
31
+
32
+ TextColor.propTypes = {
33
+ color: PropTypes.string,
34
+ size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
35
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./TextColor";
2
+ export * from "./HashtagFilled";
@@ -0,0 +1,70 @@
1
+ import React from "react";
2
+ import classnames from "classnames";
3
+
4
+ import Label from "./Label";
5
+ import { hyphenize } from "../utils/common";
6
+
7
+ const Input = React.forwardRef((props, ref) => {
8
+ const {
9
+ id,
10
+ size = "small",
11
+ type = "text",
12
+ label,
13
+ error = null,
14
+ suffix = null,
15
+ prefix = null,
16
+ disabled = false,
17
+ helpText = "",
18
+ className = "",
19
+ nakedInput = false,
20
+ contentSize = null,
21
+ required = false,
22
+ ...otherProps
23
+ } = props;
24
+
25
+ return (
26
+ <div className={classnames(["neeto-ui-input__wrapper", className])}>
27
+ {label && (
28
+ <Label
29
+ required={required}
30
+ data-cy={`${hyphenize(label)}-input-label`}
31
+ htmlFor={id}
32
+ >
33
+ {label}
34
+ </Label>
35
+ )}
36
+ <div
37
+ className={classnames("neeto-ui-input", {
38
+ "neeto-ui-input--naked": !!nakedInput,
39
+ "neeto-ui-input--error": !!error,
40
+ "neeto-ui-input--disabled": !!disabled,
41
+ "neeto-ui-input--small": size === "small",
42
+ })}
43
+ >
44
+ {prefix && <div className="neeto-ui-input__prefix">{prefix}</div>}
45
+ <input
46
+ ref={ref}
47
+ type={type}
48
+ disabled={disabled}
49
+ size={contentSize}
50
+ required={required}
51
+ aria-invalid={!!error}
52
+ data-cy={"input-field"}
53
+ {...otherProps}
54
+ />
55
+ {suffix && <div className="neeto-ui-input__suffix">{suffix}</div>}
56
+ </div>
57
+ {!!error && (
58
+ <p
59
+ data-cy={`${hyphenize(label)}-input-error`}
60
+ className="neeto-ui-input__error"
61
+ >
62
+ {error}
63
+ </p>
64
+ )}
65
+ {helpText && <p className="neeto-ui-input__help-text">{helpText}</p>}
66
+ </div>
67
+ );
68
+ });
69
+
70
+ export default Input;