@pareto-engineering/design-system 4.0.0-alpha.41 → 4.0.0-alpha.43
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/cjs/b/Button/Button.js +2 -1
- package/dist/cjs/b/Button/styles.scss +3 -3
- package/dist/cjs/f/FormInput/FormInput.js +6 -0
- package/dist/cjs/f/common/Description/Description.js +5 -4
- package/dist/cjs/f/fields/ChoicesInput/styles.scss +1 -1
- package/dist/cjs/f/fields/EditorInput/EditorInput.js +32 -1
- package/dist/cjs/f/fields/EditorInput/common/Toolbar.js +64 -0
- package/dist/cjs/f/fields/EditorInput/styles.scss +28 -0
- package/dist/es/b/Button/Button.js +2 -1
- package/dist/es/b/Button/styles.scss +3 -3
- package/dist/es/f/FormInput/FormInput.js +7 -1
- package/dist/es/f/common/Description/Description.js +5 -4
- package/dist/es/f/fields/ChoicesInput/styles.scss +1 -1
- package/dist/es/f/fields/EditorInput/EditorInput.js +32 -1
- package/dist/es/f/fields/EditorInput/common/Toolbar.js +66 -2
- package/dist/es/f/fields/EditorInput/styles.scss +28 -0
- package/package.json +3 -3
- package/src/stories/a/AppContext.stories.jsx +2 -2
- package/src/stories/b/SocialMediaButton.stories.jsx +2 -2
- package/src/stories/colors.js +2 -0
- package/src/stories/f/EditorInput.stories.jsx +1 -1
- package/src/ui/b/Button/Button.jsx +2 -0
- package/src/ui/b/Button/styles.scss +3 -3
- package/src/ui/f/FormInput/FormInput.jsx +11 -0
- package/src/ui/f/common/Description/Description.jsx +5 -4
- package/src/ui/f/fields/ChoicesInput/styles.scss +1 -1
- package/src/ui/f/fields/EditorInput/EditorInput.jsx +36 -1
- package/src/ui/f/fields/EditorInput/common/Toolbar.jsx +103 -1
- package/src/ui/f/fields/EditorInput/styles.scss +28 -0
- package/tests/__snapshots__/Storyshots.test.js.snap +1008 -11
|
@@ -20,6 +20,7 @@ const Button = ({
|
|
|
20
20
|
children,
|
|
21
21
|
isLoading,
|
|
22
22
|
color,
|
|
23
|
+
textColor,
|
|
23
24
|
isCompact,
|
|
24
25
|
isGhost,
|
|
25
26
|
isSimple,
|
|
@@ -43,6 +44,7 @@ const Button = ({
|
|
|
43
44
|
componentClassName,
|
|
44
45
|
userClassName,
|
|
45
46
|
`x-${color}`,
|
|
47
|
+
textColor && `y-${textColor}`,
|
|
46
48
|
isGhost && styleNames.modifierGhost,
|
|
47
49
|
isCompact && styleNames.modifierCompact,
|
|
48
50
|
isSimple && styleNames.modifierSimple,
|
|
@@ -92,7 +92,7 @@ $default-animation-time: .31s;
|
|
|
92
92
|
&.#{bem.$modifier-ghost} {
|
|
93
93
|
background: transparent;
|
|
94
94
|
border: 1px solid var(--x, var(--#{$default-color}));
|
|
95
|
-
color: var(--x, var(--#{$default-color}));
|
|
95
|
+
color: var(--y, var(--x, var(--#{$default-color})));
|
|
96
96
|
|
|
97
97
|
&:hover,
|
|
98
98
|
&:focus,
|
|
@@ -103,12 +103,12 @@ $default-animation-time: .31s;
|
|
|
103
103
|
&:not(:disabled) {
|
|
104
104
|
&:hover {
|
|
105
105
|
border: 1px solid var(--soft-x, var(--soft-#{$default-color}));
|
|
106
|
-
color: var(--soft-x, var(--soft-#{$default-color}));
|
|
106
|
+
color: var(--soft-y, var(--soft-x, var(--soft-#{$default-color})));
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
&:focus {
|
|
110
110
|
border: 1px solid var(--hard-x, var(--hard-#{$default-color}));
|
|
111
|
-
color: var(--hard-x, var(--hard-#{$default-color}));
|
|
111
|
+
color: var(--hard-y, var(--hard-x, var(--hard-#{$default-color})));
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
Checkbox,
|
|
17
17
|
QueryChoices,
|
|
18
18
|
LinkInput,
|
|
19
|
+
EditorInput,
|
|
19
20
|
} from '../fields'
|
|
20
21
|
|
|
21
22
|
// Local Definitions
|
|
@@ -128,6 +129,16 @@ const FormInput = ({
|
|
|
128
129
|
)
|
|
129
130
|
}
|
|
130
131
|
|
|
132
|
+
if (type === 'editor') {
|
|
133
|
+
return (
|
|
134
|
+
<EditorInput
|
|
135
|
+
className={newClassName}
|
|
136
|
+
disabled={disabled}
|
|
137
|
+
{...otherProps}
|
|
138
|
+
/>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
131
142
|
if (extraTypes?.[type]) {
|
|
132
143
|
const Component = extraTypes[type]
|
|
133
144
|
return (
|
|
@@ -31,9 +31,10 @@ const Description = ({
|
|
|
31
31
|
import('./styles.scss')
|
|
32
32
|
}, [])
|
|
33
33
|
|
|
34
|
-
const [
|
|
34
|
+
const [, meta] = useField(name)
|
|
35
|
+
const hasError = meta.touched && meta.error
|
|
35
36
|
|
|
36
|
-
if (
|
|
37
|
+
if (hasError || description) {
|
|
37
38
|
return (
|
|
38
39
|
<div
|
|
39
40
|
id={id}
|
|
@@ -41,13 +42,13 @@ const Description = ({
|
|
|
41
42
|
baseClassName,
|
|
42
43
|
componentClassName,
|
|
43
44
|
userClassName,
|
|
44
|
-
|
|
45
|
+
hasError ? 'x-error' : `x-${color}`,
|
|
45
46
|
]
|
|
46
47
|
.filter((e) => e)
|
|
47
48
|
.join(' ')}
|
|
48
49
|
style={style}
|
|
49
50
|
>
|
|
50
|
-
{ meta.error
|
|
51
|
+
{ hasError ? meta.error : description}
|
|
51
52
|
</div>
|
|
52
53
|
)
|
|
53
54
|
}
|
|
@@ -57,7 +57,42 @@ const EditorInput = ({
|
|
|
57
57
|
|
|
58
58
|
const setInitialValue = () => {
|
|
59
59
|
const value = formik.values[name]
|
|
60
|
-
|
|
60
|
+
try {
|
|
61
|
+
JSON.parse(value)
|
|
62
|
+
return value
|
|
63
|
+
} catch {
|
|
64
|
+
const defaultValue = {
|
|
65
|
+
root:{
|
|
66
|
+
children:[
|
|
67
|
+
{
|
|
68
|
+
children:[
|
|
69
|
+
{
|
|
70
|
+
detail :0,
|
|
71
|
+
format :0,
|
|
72
|
+
mode :'normal',
|
|
73
|
+
style :'',
|
|
74
|
+
text :'',
|
|
75
|
+
type :'text',
|
|
76
|
+
version:1,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
direction:'ltr',
|
|
80
|
+
format :'',
|
|
81
|
+
indent :0,
|
|
82
|
+
type :'paragraph',
|
|
83
|
+
version :1,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
direction:'ltr',
|
|
87
|
+
format :'',
|
|
88
|
+
indent :0,
|
|
89
|
+
type :'root',
|
|
90
|
+
version :1,
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
defaultValue.root.children[0].children[0].text = value
|
|
94
|
+
return JSON.stringify(defaultValue)
|
|
95
|
+
}
|
|
61
96
|
}
|
|
62
97
|
|
|
63
98
|
const onChange = (state) => {
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/* eslint-disable import/no-extraneous-dependencies -- required here */
|
|
2
2
|
import * as React from 'react'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
useEffect,
|
|
6
|
+
useState,
|
|
7
|
+
useCallback,
|
|
8
|
+
useRef,
|
|
9
|
+
} from 'react'
|
|
5
10
|
|
|
6
11
|
import {
|
|
7
12
|
$getSelection,
|
|
@@ -10,6 +15,8 @@ import {
|
|
|
10
15
|
FORMAT_ELEMENT_COMMAND,
|
|
11
16
|
UNDO_COMMAND,
|
|
12
17
|
REDO_COMMAND,
|
|
18
|
+
COMMAND_PRIORITY_NORMAL,
|
|
19
|
+
createCommand,
|
|
13
20
|
} from 'lexical'
|
|
14
21
|
import {
|
|
15
22
|
INSERT_ORDERED_LIST_COMMAND,
|
|
@@ -27,6 +34,9 @@ import {
|
|
|
27
34
|
} from '@lexical/link'
|
|
28
35
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
29
36
|
import { mergeRegister, $getNearestNodeOfType } from '@lexical/utils'
|
|
37
|
+
|
|
38
|
+
import { Popover } from 'ui'
|
|
39
|
+
|
|
30
40
|
import styleNames from '@pareto-engineering/bem/exports'
|
|
31
41
|
|
|
32
42
|
const baseClassName = styleNames.base
|
|
@@ -47,6 +57,19 @@ const getSelectedNode = (selection) => {
|
|
|
47
57
|
return $isAtNodeEnd(anchor) ? focusNode : anchorNode
|
|
48
58
|
}
|
|
49
59
|
|
|
60
|
+
const defaultColor = 'var(--paragraph)'
|
|
61
|
+
|
|
62
|
+
const colorOptions = [
|
|
63
|
+
'red',
|
|
64
|
+
'blue',
|
|
65
|
+
'green',
|
|
66
|
+
'yellow',
|
|
67
|
+
'orange',
|
|
68
|
+
'purple',
|
|
69
|
+
'pink',
|
|
70
|
+
'brown',
|
|
71
|
+
]
|
|
72
|
+
|
|
50
73
|
const Toolbar = () => {
|
|
51
74
|
const [editor] = useLexicalComposerContext()
|
|
52
75
|
const [isBold, setIsBold] = useState(false)
|
|
@@ -55,6 +78,9 @@ const Toolbar = () => {
|
|
|
55
78
|
const [blockType, setBlockType] = useState('paragraph')
|
|
56
79
|
const [isLink, setIsLink] = useState(false)
|
|
57
80
|
const [isUnderline, setIsUnderline] = useState(false)
|
|
81
|
+
const [color, setColor] = useState(defaultColor)
|
|
82
|
+
|
|
83
|
+
const colorMenuRef = useRef(false)
|
|
58
84
|
|
|
59
85
|
const formatBulletList = () => {
|
|
60
86
|
if (blockType !== 'ul') {
|
|
@@ -99,6 +125,18 @@ const Toolbar = () => {
|
|
|
99
125
|
setBlockType(element)
|
|
100
126
|
}
|
|
101
127
|
|
|
128
|
+
// Check nodes for color
|
|
129
|
+
const nodes = selection.getNodes().filter((node) => node.getType() === 'text')
|
|
130
|
+
nodes.forEach((node) => {
|
|
131
|
+
const style = node.getStyle()
|
|
132
|
+
const colorProperty = style.match(/color: ([^;]+)/)
|
|
133
|
+
if (colorProperty) {
|
|
134
|
+
setColor(colorProperty[1])
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
setColor(false)
|
|
138
|
+
})
|
|
139
|
+
|
|
102
140
|
// Check selection text styles
|
|
103
141
|
setIsBold(selection.hasFormat('bold'))
|
|
104
142
|
setIsItalic(selection.hasFormat('italic'))
|
|
@@ -117,6 +155,24 @@ const Toolbar = () => {
|
|
|
117
155
|
}
|
|
118
156
|
}, [editor])
|
|
119
157
|
|
|
158
|
+
const UPDATE_COLOR_COMMAND = createCommand()
|
|
159
|
+
|
|
160
|
+
editor.registerCommand(UPDATE_COLOR_COMMAND, (payload) => {
|
|
161
|
+
const selection = $getSelection()
|
|
162
|
+
const nodes = selection?.extract().filter((node) => node.getType() === 'text')
|
|
163
|
+
nodes?.forEach((node) => {
|
|
164
|
+
const style = node.getStyle()
|
|
165
|
+
const colorProperty = style?.match(/color: ([^;]+)/)
|
|
166
|
+
if (colorProperty && color !== payload) {
|
|
167
|
+
node.setStyle(style.replace(colorProperty[0], `color: ${payload}`))
|
|
168
|
+
} else if (colorProperty) {
|
|
169
|
+
node.setStyle(`color: ${defaultColor}`)
|
|
170
|
+
} else {
|
|
171
|
+
node.setStyle(`color: ${payload}`)
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
}, COMMAND_PRIORITY_NORMAL)
|
|
175
|
+
|
|
120
176
|
useEffect(() => mergeRegister(
|
|
121
177
|
editor.registerUpdateListener(({ editorState }) => {
|
|
122
178
|
editorState.read(() => {
|
|
@@ -125,6 +181,11 @@ const Toolbar = () => {
|
|
|
125
181
|
}),
|
|
126
182
|
), [updateToolbar, editor])
|
|
127
183
|
|
|
184
|
+
const dispatchUpdateColor = useCallback((e, payload) => {
|
|
185
|
+
e.stopPropagation()
|
|
186
|
+
editor.dispatchCommand(UPDATE_COLOR_COMMAND, payload)
|
|
187
|
+
}, [editor])
|
|
188
|
+
|
|
128
189
|
return (
|
|
129
190
|
<div className={`${baseClassName} ${componentClassName}`}>
|
|
130
191
|
<div className="group">
|
|
@@ -164,6 +225,47 @@ const Toolbar = () => {
|
|
|
164
225
|
?
|
|
165
226
|
</span>
|
|
166
227
|
</button>
|
|
228
|
+
<button
|
|
229
|
+
type="button"
|
|
230
|
+
className={color && color !== defaultColor ? 'active color-menu-button' : 'color-menu-button'}
|
|
231
|
+
onClick={() => editor.dispatchCommand(UPDATE_COLOR_COMMAND,
|
|
232
|
+
color !== defaultColor ? defaultColor : color)}
|
|
233
|
+
ref={colorMenuRef}
|
|
234
|
+
style={{ position: 'relative' }}
|
|
235
|
+
>
|
|
236
|
+
<span
|
|
237
|
+
className="icon"
|
|
238
|
+
style={{
|
|
239
|
+
color,
|
|
240
|
+
}}
|
|
241
|
+
>
|
|
242
|
+
Q
|
|
243
|
+
</span>
|
|
244
|
+
<Popover
|
|
245
|
+
parentRef={colorMenuRef}
|
|
246
|
+
>
|
|
247
|
+
<div className="color-menu">
|
|
248
|
+
{
|
|
249
|
+
colorOptions.map((option) => (
|
|
250
|
+
<span
|
|
251
|
+
role="button"
|
|
252
|
+
className="icon color-option"
|
|
253
|
+
style={{
|
|
254
|
+
color:option,
|
|
255
|
+
}}
|
|
256
|
+
onClick={(e) => dispatchUpdateColor(e, option)}
|
|
257
|
+
onKeyDown={(e) => dispatchUpdateColor(e, option)}
|
|
258
|
+
tabIndex={0}
|
|
259
|
+
key={option}
|
|
260
|
+
>
|
|
261
|
+
o
|
|
262
|
+
</span>
|
|
263
|
+
))
|
|
264
|
+
}
|
|
265
|
+
</div>
|
|
266
|
+
</Popover>
|
|
267
|
+
</button>
|
|
268
|
+
|
|
167
269
|
<button
|
|
168
270
|
type="button"
|
|
169
271
|
className={isLink ? 'active' : undefined}
|
|
@@ -13,7 +13,9 @@ $default-border: var(--theme-default-input-border);
|
|
|
13
13
|
$focus-border: var(--theme-focus-input-border);
|
|
14
14
|
$active-background: var(--hard-background-inputs);
|
|
15
15
|
$default-background: var(--background-inputs);
|
|
16
|
+
$default-icon-color: var(--on-background-inputs);
|
|
16
17
|
$disabled-background: var(--background-inputs-30);
|
|
18
|
+
$default-color-menu-padding: .5em .25em;
|
|
17
19
|
|
|
18
20
|
.#{bem.$base}.editor-input {
|
|
19
21
|
&.#{bem.$base}.input-wrapper {
|
|
@@ -29,6 +31,7 @@ $disabled-background: var(--background-inputs-30);
|
|
|
29
31
|
> button {
|
|
30
32
|
background: $default-background;
|
|
31
33
|
border: $default-border;
|
|
34
|
+
color: $default-icon-color;
|
|
32
35
|
padding: $default-padding;
|
|
33
36
|
|
|
34
37
|
&.active {
|
|
@@ -60,6 +63,31 @@ $disabled-background: var(--background-inputs-30);
|
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
|
|
66
|
+
.color-menu-button {
|
|
67
|
+
&:hover {
|
|
68
|
+
> .#{bem.$base}.popover {
|
|
69
|
+
display: block;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
> .#{bem.$base}.popover {
|
|
74
|
+
padding: $default-color-menu-padding;
|
|
75
|
+
|
|
76
|
+
.color-menu {
|
|
77
|
+
display: flex;
|
|
78
|
+
flex-wrap: wrap;
|
|
79
|
+
gap: calc($default-gap / 2);
|
|
80
|
+
justify-content: center;
|
|
81
|
+
max-width: 10em;
|
|
82
|
+
min-width: 5em;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.color-option:hover {
|
|
86
|
+
opacity: .5;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
63
91
|
> .content-editable {
|
|
64
92
|
background: $default-background;
|
|
65
93
|
border: $default-border;
|