@soul-refiner/design-system 0.2.18 → 0.2.20
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/dist/components/editor/index.d.ts +2 -0
- package/dist/components/editor/index.js +1 -0
- package/dist/components/editor/navbar/alignment_dropdown.js +5 -1
- package/dist/components/editor/plugins/text.js +2 -1
- package/dist/components/editor/simple_editor/index.d.ts +2 -0
- package/dist/components/editor/simple_editor/index.js +1 -0
- package/dist/components/editor/simple_editor/navbar.d.ts +8 -0
- package/dist/components/editor/simple_editor/navbar.js +127 -0
- package/dist/components/editor/simple_editor/plugins.d.ts +1 -0
- package/dist/components/editor/simple_editor/plugins.js +90 -0
- package/dist/components/editor/simple_editor/simple_editor.d.ts +10 -0
- package/dist/components/editor/simple_editor/simple_editor.js +85 -0
- package/dist/components/feedback/chip/chip.js +1 -1
- package/dist/components/input/text_input/text_input.d.ts +4 -2
- package/dist/components/input/text_input/text_input.js +53 -2
- package/package.json +1 -1
|
@@ -2,7 +2,11 @@ import React from 'react';
|
|
|
2
2
|
import { setAlign } from '@udecode/plate';
|
|
3
3
|
import { useAlignDropdownMenu, useAlignDropdownMenuState, } from '@udecode/plate-alignment';
|
|
4
4
|
import { Dropdown } from '../../';
|
|
5
|
-
import {
|
|
5
|
+
import { AlignCenter } from '../../../icons/text/align_center';
|
|
6
|
+
import { AlignJustified } from '../../../icons/text/align_justified';
|
|
7
|
+
import { AlignLeft } from '../../../icons/text/align_left';
|
|
8
|
+
import { AlignRight } from '../../../icons/text/align_right';
|
|
9
|
+
import { PlayerListPlay } from '../../../icons';
|
|
6
10
|
import { MenuButton } from './navbar';
|
|
7
11
|
const items = [
|
|
8
12
|
{
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { createPluginFactory, PlateElement, } from '@udecode/plate';
|
|
3
|
-
import {
|
|
3
|
+
import { P } from '../../atoms/typography/paragraph';
|
|
4
|
+
import { H } from '../../atoms/typography/heading';
|
|
4
5
|
import * as Elements from '../constants';
|
|
5
6
|
export const ParagraphElement = React.forwardRef(({ children, ...props }, ref) => {
|
|
6
7
|
const textAlign = props?.style?.textAlign;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SimpleEditor } from './simple_editor';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface EditorBarProps {
|
|
3
|
+
handleUploadImage: (dataURL: File) => Promise<string>;
|
|
4
|
+
}
|
|
5
|
+
export declare const EditorBar: ({ handleUploadImage }: EditorBarProps) => React.JSX.Element;
|
|
6
|
+
export declare const MenuButton: import("styled-components").IStyledComponent<"web", "button", {
|
|
7
|
+
$active?: boolean | undefined;
|
|
8
|
+
}, never>;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { insertImage, useLinkToolbarButton, useLinkToolbarButtonState, useListToolbarButton, useListToolbarButtonState, useMarkToolbarButton, useMarkToolbarButtonState, usePlateEditorRef, } from '@udecode/plate';
|
|
4
|
+
import { Tooltip } from '../../';
|
|
5
|
+
import { Bold, Image, Italic, Link, ListOrdered, ListUnordered, Redo, Underline, Undo, } from '../../../icons';
|
|
6
|
+
import { ELEMENT_OL, ELEMENT_UL, MARK_BOLD, MARK_ITALIC, MARK_UNDERLINE, } from '../constants';
|
|
7
|
+
export const EditorBar = ({ handleUploadImage }) => {
|
|
8
|
+
const editorRef = usePlateEditorRef('main');
|
|
9
|
+
const imageRef = React.useRef(null);
|
|
10
|
+
const boldState = useMarkToolbarButtonState({ nodeType: MARK_BOLD });
|
|
11
|
+
const { props: { pressed: currBold, onClick: handleBold }, } = useMarkToolbarButton(boldState);
|
|
12
|
+
const italicState = useMarkToolbarButtonState({ nodeType: MARK_ITALIC });
|
|
13
|
+
const { props: { pressed: currItalic, onClick: handleItalic }, } = useMarkToolbarButton(italicState);
|
|
14
|
+
const underlineState = useMarkToolbarButtonState({
|
|
15
|
+
nodeType: MARK_UNDERLINE,
|
|
16
|
+
});
|
|
17
|
+
const { props: { pressed: currUnderline, onClick: handleUnderline }, } = useMarkToolbarButton(underlineState);
|
|
18
|
+
const linkState = useLinkToolbarButtonState();
|
|
19
|
+
const { props: { pressed: currLink, onClick: handleLink }, } = useLinkToolbarButton(linkState);
|
|
20
|
+
const orderedListState = useListToolbarButtonState({ nodeType: ELEMENT_OL });
|
|
21
|
+
const { props: { pressed: currOrderedList, onClick: handleOrderedList }, } = useListToolbarButton(orderedListState);
|
|
22
|
+
const unorderedListState = useListToolbarButtonState({
|
|
23
|
+
nodeType: ELEMENT_UL,
|
|
24
|
+
});
|
|
25
|
+
const { props: { pressed: currUnorderedList, onClick: handleUnorderedList }, } = useListToolbarButton(unorderedListState);
|
|
26
|
+
const handleImageChange = async (event) => {
|
|
27
|
+
const file = event.target?.files?.[0];
|
|
28
|
+
if (!file)
|
|
29
|
+
return;
|
|
30
|
+
const imageurl = await handleUploadImage(file);
|
|
31
|
+
if (imageurl) {
|
|
32
|
+
insertImage(editorRef, imageurl);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const handleRedo = () => editorRef.redo();
|
|
36
|
+
const handleUndo = () => editorRef.undo();
|
|
37
|
+
return (React.createElement(Menu, { "aria-label": "editor-navigation" },
|
|
38
|
+
React.createElement(MenuSection, null,
|
|
39
|
+
React.createElement(Tooltip, { content: "Undo", place: "top" },
|
|
40
|
+
React.createElement(MenuButton, { "$active": false, onClick: handleUndo },
|
|
41
|
+
React.createElement(Undo, { size: 24, color: "grey-5" }))),
|
|
42
|
+
React.createElement(Tooltip, { content: "Redo", place: "top" },
|
|
43
|
+
React.createElement(MenuButton, { "$active": false, onClick: handleRedo },
|
|
44
|
+
React.createElement(Redo, { size: 24, color: "grey-5" })))),
|
|
45
|
+
React.createElement(Divider, null),
|
|
46
|
+
React.createElement(MenuSection, null,
|
|
47
|
+
React.createElement(Tooltip, { content: "Bold", place: "top" },
|
|
48
|
+
React.createElement(MenuButton, { "$active": currBold, onClick: handleBold },
|
|
49
|
+
React.createElement(Bold, { size: 24, color: "grey-5" }))),
|
|
50
|
+
React.createElement(Tooltip, { content: "Italic", place: "top" },
|
|
51
|
+
React.createElement(MenuButton, { "$active": currItalic, onClick: handleItalic },
|
|
52
|
+
React.createElement(Italic, { size: 24, color: "grey-5" }))),
|
|
53
|
+
React.createElement(Tooltip, { content: "Underline", place: "top" },
|
|
54
|
+
React.createElement(MenuButton, { "$active": currUnderline, onClick: handleUnderline },
|
|
55
|
+
React.createElement(Underline, { size: 24, color: "grey-5" })))),
|
|
56
|
+
React.createElement(Divider, null),
|
|
57
|
+
React.createElement(MenuSection, null,
|
|
58
|
+
React.createElement(Tooltip, { content: "Link", place: "top" },
|
|
59
|
+
React.createElement(MenuButton, { "$active": currLink, onClick: handleLink },
|
|
60
|
+
React.createElement(Link, { size: 24, color: "grey-5" }))),
|
|
61
|
+
React.createElement(Tooltip, { content: "Image", place: "top" },
|
|
62
|
+
React.createElement(MenuButton, { "$active": false, as: "label", onChange: handleImageChange },
|
|
63
|
+
React.createElement("div", { onClick: () => imageRef.current?.click() },
|
|
64
|
+
React.createElement("input", { accept: "image/*", ref: imageRef, style: { display: 'none' }, type: "file" }),
|
|
65
|
+
React.createElement(Image, { size: 24, color: "grey-5" }))))),
|
|
66
|
+
React.createElement(Divider, null),
|
|
67
|
+
React.createElement(MenuSection, null,
|
|
68
|
+
React.createElement(Tooltip, { content: "Unordered List", place: "top" },
|
|
69
|
+
React.createElement(MenuButton, { "$active": currUnorderedList, onClick: handleUnorderedList },
|
|
70
|
+
React.createElement(ListUnordered, { size: 24, color: "grey-5" }))),
|
|
71
|
+
React.createElement(Tooltip, { content: "Ordered List", place: "top" },
|
|
72
|
+
React.createElement(MenuButton, { "$active": currOrderedList, onClick: handleOrderedList },
|
|
73
|
+
React.createElement(ListOrdered, { size: 24, color: "grey-5" }))))));
|
|
74
|
+
};
|
|
75
|
+
const Menu = styled.nav `
|
|
76
|
+
display: flex;
|
|
77
|
+
gap: 12px;
|
|
78
|
+
justify-content: center;
|
|
79
|
+
max-width: 1200px;
|
|
80
|
+
margin: 0;
|
|
81
|
+
padding: 14px 24px;
|
|
82
|
+
background-color: var(--color-white);
|
|
83
|
+
box-sizing: border-box;
|
|
84
|
+
border-radius: 8px 8px 0px 0px;
|
|
85
|
+
box-shadow: var(--elevation-1);
|
|
86
|
+
`;
|
|
87
|
+
const MenuSection = styled.div `
|
|
88
|
+
display: flex;
|
|
89
|
+
gap: 16px;
|
|
90
|
+
align-items: center;
|
|
91
|
+
width: fit-content;
|
|
92
|
+
flex-shrink: 0;
|
|
93
|
+
`;
|
|
94
|
+
export const MenuButton = styled.button `
|
|
95
|
+
padding: 2px;
|
|
96
|
+
border: none;
|
|
97
|
+
outline: none;
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
box-sizing: border-box;
|
|
100
|
+
height: 28px;
|
|
101
|
+
width: 28px;
|
|
102
|
+
border-radius: 2px;
|
|
103
|
+
|
|
104
|
+
&:hover:not(:disabled) {
|
|
105
|
+
padding: 1px;
|
|
106
|
+
border: 1px solid var(--color-grey-8);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&:active:not(:disabled) {
|
|
110
|
+
background-color: var(--color-grey-9);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
&:disabled {
|
|
114
|
+
background-color: var(--color-white) !important;
|
|
115
|
+
cursor: initial;
|
|
116
|
+
svg {
|
|
117
|
+
fill: var(--color-grey-7) !important;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
background-color: ${({ $active }) => $active ? 'var(--color-grey-9)' : 'transparent'};
|
|
122
|
+
`;
|
|
123
|
+
const Divider = styled.div `
|
|
124
|
+
width: 1px;
|
|
125
|
+
height: 28px;
|
|
126
|
+
background-color: var(--color-grey-9);
|
|
127
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const plugins: import("@udecode/plate").PlatePlugin<any, import("@udecode/plate").Value, import("@udecode/plate").PlateEditor<import("@udecode/plate").Value>>[];
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createPlugins, createHeadingPlugin, createIndentListPlugin, createImagePlugin, createTextIndentPlugin, createListPlugin, createMediaEmbedPlugin, createResetNodePlugin, createBoldPlugin, createCodePlugin, createFontBackgroundColorPlugin, createFontSizePlugin, createFontFamilyPlugin, createItalicPlugin, createStrikethroughPlugin, createSubscriptPlugin, createSuperscriptPlugin, createUnderlinePlugin, createAlignPlugin, createIndentPlugin, createLineHeightPlugin, createLinkPlugin, createExitBreakPlugin, createHistoryPlugin, createSelectOnBackspacePlugin, createSoftBreakPlugin, } from '@udecode/plate';
|
|
2
|
+
import { createParagraphPlugin, createHOnePlugin, createHTwoPlugin, createHThreePlugin, createHFourPlugin, createHFivePlugin, createHSixPlugin, } from '../plugins/text';
|
|
3
|
+
import { ELEMENT_PARAGRAPH, ELEMENT_H1, ELEMENT_H2, ELEMENT_H3, ELEMENT_H4, ELEMENT_H5, ELEMENT_H6, ELEMENT_OL, ELEMENT_UL, } from '../constants';
|
|
4
|
+
import { exitBreakPlugin } from '../plugins/exitBreak';
|
|
5
|
+
import { LinkFloatingMenu } from '../plugins/link';
|
|
6
|
+
import { resetBlockTypePlugin } from '../plugins/resetBlockType';
|
|
7
|
+
import { selectOnBackspace } from '../plugins/selectOnBackspace';
|
|
8
|
+
import { softBreakPlugin } from '../plugins/softBreak';
|
|
9
|
+
import { plateUI } from '../plate';
|
|
10
|
+
export const plugins = createPlugins([
|
|
11
|
+
createHeadingPlugin(),
|
|
12
|
+
createImagePlugin({
|
|
13
|
+
options: {
|
|
14
|
+
disableUploadInsert: true,
|
|
15
|
+
disableCaption: true,
|
|
16
|
+
disableEmbedInsert: true,
|
|
17
|
+
},
|
|
18
|
+
}),
|
|
19
|
+
createTextIndentPlugin(),
|
|
20
|
+
createIndentListPlugin({
|
|
21
|
+
inject: {
|
|
22
|
+
props: {
|
|
23
|
+
validTypes: [
|
|
24
|
+
ELEMENT_PARAGRAPH,
|
|
25
|
+
ELEMENT_H1,
|
|
26
|
+
ELEMENT_H2,
|
|
27
|
+
ELEMENT_H3,
|
|
28
|
+
ELEMENT_H4,
|
|
29
|
+
ELEMENT_H5,
|
|
30
|
+
ELEMENT_H6,
|
|
31
|
+
ELEMENT_OL,
|
|
32
|
+
ELEMENT_UL,
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
createListPlugin(),
|
|
38
|
+
createMediaEmbedPlugin(),
|
|
39
|
+
createParagraphPlugin(),
|
|
40
|
+
createHOnePlugin(),
|
|
41
|
+
createHTwoPlugin(),
|
|
42
|
+
createHThreePlugin(),
|
|
43
|
+
createHFourPlugin(),
|
|
44
|
+
createHFivePlugin(),
|
|
45
|
+
createHSixPlugin(),
|
|
46
|
+
createResetNodePlugin(),
|
|
47
|
+
createBoldPlugin(),
|
|
48
|
+
createCodePlugin(),
|
|
49
|
+
createFontBackgroundColorPlugin(),
|
|
50
|
+
createFontSizePlugin(),
|
|
51
|
+
createFontFamilyPlugin(),
|
|
52
|
+
createItalicPlugin(),
|
|
53
|
+
createStrikethroughPlugin(),
|
|
54
|
+
createSubscriptPlugin(),
|
|
55
|
+
createSuperscriptPlugin(),
|
|
56
|
+
createUnderlinePlugin(),
|
|
57
|
+
createAlignPlugin({
|
|
58
|
+
inject: {
|
|
59
|
+
props: {
|
|
60
|
+
validTypes: [
|
|
61
|
+
ELEMENT_PARAGRAPH,
|
|
62
|
+
ELEMENT_H1,
|
|
63
|
+
ELEMENT_H2,
|
|
64
|
+
ELEMENT_H3,
|
|
65
|
+
ELEMENT_H4,
|
|
66
|
+
ELEMENT_H5,
|
|
67
|
+
ELEMENT_H6,
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
createIndentPlugin({
|
|
73
|
+
inject: {
|
|
74
|
+
props: {
|
|
75
|
+
validTypes: [ELEMENT_PARAGRAPH, ELEMENT_H1],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
}),
|
|
79
|
+
createLineHeightPlugin(),
|
|
80
|
+
createLinkPlugin({
|
|
81
|
+
renderAfterEditable: LinkFloatingMenu,
|
|
82
|
+
}),
|
|
83
|
+
createExitBreakPlugin(exitBreakPlugin),
|
|
84
|
+
createHistoryPlugin(),
|
|
85
|
+
createResetNodePlugin(resetBlockTypePlugin),
|
|
86
|
+
createSelectOnBackspacePlugin(selectOnBackspace),
|
|
87
|
+
createSoftBreakPlugin(softBreakPlugin),
|
|
88
|
+
], {
|
|
89
|
+
components: plateUI,
|
|
90
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TElement } from '@udecode/plate';
|
|
3
|
+
export interface SimpleEditorProps {
|
|
4
|
+
communityName: string;
|
|
5
|
+
editable: boolean;
|
|
6
|
+
handleUploadImage: (dataURL: File) => Promise<string>;
|
|
7
|
+
onChange: (newNodes: TElement[]) => void;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const SimpleEditor: ({ editable, handleUploadImage, onChange, placeholder, }: SimpleEditorProps) => React.JSX.Element;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { Plate, PlateProvider } from '@udecode/plate';
|
|
5
|
+
import { plugins } from './plugins';
|
|
6
|
+
import { EditorBar } from './navbar';
|
|
7
|
+
export const SimpleEditor = ({ editable, handleUploadImage, onChange, placeholder = '', }) => {
|
|
8
|
+
return (React.createElement(PlateProvider, { id: "main", initialValue: [
|
|
9
|
+
{
|
|
10
|
+
type: 'p',
|
|
11
|
+
children: [
|
|
12
|
+
{
|
|
13
|
+
text: '',
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
], onChange: onChange, plugins: plugins },
|
|
18
|
+
React.createElement(Wrapper, null,
|
|
19
|
+
React.createElement(EditorBar, { handleUploadImage: handleUploadImage }),
|
|
20
|
+
React.createElement(InnerWrapper, null,
|
|
21
|
+
React.createElement(Plate, { id: "main", editableProps: {
|
|
22
|
+
readOnly: !editable,
|
|
23
|
+
spellCheck: true,
|
|
24
|
+
autoFocus: true,
|
|
25
|
+
placeholder: placeholder,
|
|
26
|
+
} })))));
|
|
27
|
+
};
|
|
28
|
+
const InnerWrapper = styled.div `
|
|
29
|
+
padding: 24px;
|
|
30
|
+
`;
|
|
31
|
+
const Wrapper = styled.div `
|
|
32
|
+
position: relative;
|
|
33
|
+
max-width: 1200px;
|
|
34
|
+
width: 100%;
|
|
35
|
+
min-height: 224px;
|
|
36
|
+
border: 1px solid var(--color-grey-8);
|
|
37
|
+
border-radius: 8px;
|
|
38
|
+
background-color: var(--color-white);
|
|
39
|
+
|
|
40
|
+
* {
|
|
41
|
+
font-family: Inter;
|
|
42
|
+
outline: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.slate-bold {
|
|
46
|
+
font-weight: 700;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.slate-italic {
|
|
50
|
+
font-style: italic;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.slate-strikethrough {
|
|
54
|
+
text-decoration: line-through;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.slate-underline {
|
|
58
|
+
text-decoration: underline;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
li {
|
|
62
|
+
color: var(--color-grey-3);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.slate-code {
|
|
66
|
+
& > * {
|
|
67
|
+
font-family: 'Roboto Mono';
|
|
68
|
+
& > * {
|
|
69
|
+
font-family: 'Roboto Mono';
|
|
70
|
+
& > * {
|
|
71
|
+
font-family: 'Roboto Mono';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
background-color: var(--color-grey-9);
|
|
77
|
+
padding: 0.4em 0.4em;
|
|
78
|
+
font-size: 0.8em;
|
|
79
|
+
line-height: 0.8em;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
& > [data-slate-editor='true'] > * {
|
|
83
|
+
margin: 24px 0px;
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
@@ -56,7 +56,7 @@ export const Chip = ({ children, color, dot, onDismiss, size }) => {
|
|
|
56
56
|
return (React.createElement(Component, { "$bgColor": bgColor, "$size": size, "$textColor": textColor },
|
|
57
57
|
dot && React.createElement(Dot, { "$secondaryColor": dotColor }),
|
|
58
58
|
children,
|
|
59
|
-
onDismiss && React.createElement(Close, { size: 16 })));
|
|
59
|
+
onDismiss && React.createElement(Close, { size: 16, onClick: onDismiss })));
|
|
60
60
|
};
|
|
61
61
|
const Component = styled.div `
|
|
62
62
|
display: flex;
|
|
@@ -9,11 +9,13 @@ export type Props = {
|
|
|
9
9
|
helperText?: string;
|
|
10
10
|
label?: string;
|
|
11
11
|
maxCharacters?: number;
|
|
12
|
+
multiple?: boolean;
|
|
12
13
|
onChange?: React.ChangeEventHandler<HTMLInputElement>;
|
|
14
|
+
onMultipleChange?: (values: string[]) => void;
|
|
13
15
|
placeholder?: string;
|
|
14
16
|
size?: TextInputSize;
|
|
15
17
|
sx?: string;
|
|
16
|
-
value: string;
|
|
18
|
+
value: string | string[];
|
|
17
19
|
};
|
|
18
20
|
interface DisabledProps extends Props {
|
|
19
21
|
disabled?: true;
|
|
@@ -31,5 +33,5 @@ interface WarningProps extends Props {
|
|
|
31
33
|
warning?: true;
|
|
32
34
|
}
|
|
33
35
|
export type TextInputProps = DisabledProps | SuccessfulProps | WarningProps;
|
|
34
|
-
export declare const TextInput: ({ bg, disabled, helperText, icon, label, maxCharacters, onChange, placeholder, size, successful, sx, value, warning, }: TextInputProps) => React.JSX.Element;
|
|
36
|
+
export declare const TextInput: ({ bg, disabled, helperText, icon, label, maxCharacters, multiple, onChange, onMultipleChange, placeholder, size, successful, sx, value, warning, }: TextInputProps) => React.JSX.Element;
|
|
35
37
|
export {};
|
|
@@ -1,13 +1,57 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
|
+
import { Chip } from '../../feedback/chip/chip';
|
|
4
5
|
import { CheckmarkCircle, AlertCircle } from '../../../icons';
|
|
5
|
-
export const TextInput = ({ bg = 'var(--color-blue-10)', disabled, helperText, icon, label, maxCharacters, onChange, placeholder, size = 'large', successful, sx, value, warning, }) => {
|
|
6
|
+
export const TextInput = ({ bg = 'var(--color-blue-10)', disabled, helperText, icon, label, maxCharacters, multiple, onChange, onMultipleChange, placeholder, size = 'large', successful, sx, value, warning, }) => {
|
|
7
|
+
const id = React.useId();
|
|
8
|
+
const isMultiple = multiple;
|
|
9
|
+
const [multipleValueToAdd, setMultipleValueToAdd] = React.useState('');
|
|
10
|
+
/**
|
|
11
|
+
* @todo make multiple wrapper a form
|
|
12
|
+
* on enter set multiple change and clear local value
|
|
13
|
+
* use local value to be text box
|
|
14
|
+
* have text box be flex shrink competing with chips
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
const handleMultipleValueToAdd = (event) => {
|
|
18
|
+
setMultipleValueToAdd(event.target.value);
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* when there is no text in the input,
|
|
22
|
+
* pop the previous multiple value out
|
|
23
|
+
*/
|
|
24
|
+
const handleMultipleValueDelete = (event) => {
|
|
25
|
+
if (value.length &&
|
|
26
|
+
onMultipleChange &&
|
|
27
|
+
!multipleValueToAdd &&
|
|
28
|
+
(event.key === 'Delete' || event.key === 'Backspace')) {
|
|
29
|
+
onMultipleChange(value.slice(0, value.length - 1));
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const handleMultipleAdd = (event) => {
|
|
33
|
+
event.stopPropagation();
|
|
34
|
+
event.preventDefault();
|
|
35
|
+
const alreadyHasValue = value.includes(multipleValueToAdd);
|
|
36
|
+
if (onMultipleChange && !alreadyHasValue) {
|
|
37
|
+
onMultipleChange([...value, multipleValueToAdd]);
|
|
38
|
+
}
|
|
39
|
+
setMultipleValueToAdd('');
|
|
40
|
+
};
|
|
41
|
+
const handleMultipleItemRemoval = (removalItem) => {
|
|
42
|
+
onMultipleChange &&
|
|
43
|
+
onMultipleChange(value.filter((item) => item !== removalItem));
|
|
44
|
+
};
|
|
6
45
|
return (React.createElement(Label, { "$disabled": disabled, "$size": size, "$sx": sx },
|
|
7
46
|
label,
|
|
8
47
|
React.createElement(InputWrapper, { "$bg": bg, "$size": size, "$successful": successful, "$warning": warning },
|
|
9
48
|
icon,
|
|
10
|
-
React.createElement(
|
|
49
|
+
isMultiple && (React.createElement(MultipleInputWrapper, { onSubmit: handleMultipleAdd },
|
|
50
|
+
value.filter(Boolean).map((item, index) => (React.createElement(Chip, { key: id + item + index, color: "blue", size: "small", onDismiss: () => handleMultipleItemRemoval(item) }, item))),
|
|
51
|
+
React.createElement(Input, { onChange: handleMultipleValueToAdd, onKeyDown: handleMultipleValueDelete, value: multipleValueToAdd, "$size": size }))),
|
|
52
|
+
!isMultiple && (React.createElement(Input, { disabled: disabled, onChange: onChange, placeholder: placeholder, value: maxCharacters
|
|
53
|
+
? value.slice(0, maxCharacters - 1)
|
|
54
|
+
: value, "$size": size })),
|
|
11
55
|
maxCharacters && (React.createElement(MaxCharactersText, { "$size": size },
|
|
12
56
|
value.length,
|
|
13
57
|
" / ",
|
|
@@ -62,10 +106,12 @@ const InputWrapper = styled.div `
|
|
|
62
106
|
${({ $warning }) => $warning ? 'border-color: var(--color-red-4) !important;' : ''}
|
|
63
107
|
`;
|
|
64
108
|
const Input = styled.input `
|
|
109
|
+
padding: 0px;
|
|
65
110
|
flex: 1;
|
|
66
111
|
font-family: Inter;
|
|
67
112
|
font-size: ${({ $size }) => ($size === 'small' ? 14 : 16)}px;
|
|
68
113
|
line-height: ${({ $size }) => ($size === 'small' ? 20 : 24)}px;
|
|
114
|
+
color: var(--color-grey-3);
|
|
69
115
|
border: none;
|
|
70
116
|
outline: none;
|
|
71
117
|
border-radius: 8px;
|
|
@@ -89,3 +135,8 @@ const MaxCharactersText = styled.span `
|
|
|
89
135
|
font-weight: 400;
|
|
90
136
|
line-height: 20px;
|
|
91
137
|
`;
|
|
138
|
+
const MultipleInputWrapper = styled.form `
|
|
139
|
+
display: flex;
|
|
140
|
+
flex-flow: row wrap;
|
|
141
|
+
gap: 8px 16px;
|
|
142
|
+
`;
|