@pareto-engineering/design-system 4.9.1 → 4.9.3
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/a/AreaChart/AreaChart.js +176 -0
- package/dist/cjs/a/AreaChart/index.js +13 -0
- package/dist/cjs/a/AreaChart/styles.scss +89 -0
- package/dist/cjs/a/XMLEditor/XMLEditor.js +1 -1
- package/dist/cjs/a/index.js +8 -1
- package/dist/cjs/f/fields/FileUpload/FileUpload.js +4 -2
- package/dist/es/a/AreaChart/AreaChart.js +163 -0
- package/dist/es/a/AreaChart/index.js +1 -0
- package/dist/es/a/AreaChart/styles.scss +89 -0
- package/dist/es/a/XMLEditor/XMLEditor.js +2 -2
- package/dist/es/a/index.js +2 -1
- package/dist/es/f/fields/FileUpload/FileUpload.js +4 -2
- package/package.json +4 -3
- package/src/stories/a/AreaChart.stories.jsx +118 -0
- package/src/ui/a/AreaChart/AreaChart.jsx +185 -0
- package/src/ui/a/AreaChart/index.js +1 -0
- package/src/ui/a/AreaChart/styles.scss +89 -0
- package/src/ui/a/XMLEditor/XMLEditor.jsx +4 -1
- package/src/ui/a/index.js +1 -0
- package/src/ui/f/fields/FileUpload/FileUpload.jsx +4 -1
- package/tests/__snapshots__/Storyshots.test.js.snap +501 -0
- package/tests/test-setup.js +11 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// front/packages/design-system/src/ui/a/AreaChart/AreaChart.stories.jsx
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { AreaChart } from 'ui'
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title :'a/AreaChart',
|
|
8
|
+
component:AreaChart,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const data = [
|
|
12
|
+
{
|
|
13
|
+
date:'2023-01-01', Average:0.49, Best:0.50, Worst:0.48,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
date:'2023-01-02', Average:0.48, Best:0.49, Worst:0.47,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
date:'2023-01-03', Average:0.47, Best:0.48, Worst:0.46,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
date:'2023-01-04', Average:0.50, Best:0.51, Worst:0.49,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
date:'2023-01-05', Average:0.52, Best:0.53, Worst:0.51,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
date:'2023-01-06', Average:0.51, Best:0.52, Worst:0.50,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
date:'2023-01-07', Average:0.49, Best:0.50, Worst:0.48,
|
|
32
|
+
},
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
const data2 = [
|
|
36
|
+
{
|
|
37
|
+
date:'2023-01-01', Average:0.60, Best:0.62, Worst:0.58,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
date:'2023-01-02', Average:0.59, Best:0.61, Worst:0.57,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
date:'2023-01-03', Average:0.58, Best:0.60, Worst:0.56,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
date:'2023-01-04', Average:0.61, Best:0.63, Worst:0.59,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
date:'2023-01-05', Average:0.63, Best:0.65, Worst:0.61,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
date:'2023-01-06', Average:0.62, Best:0.64, Worst:0.60,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
date:'2023-01-07', Average:0.60, Best:0.62, Worst:0.58,
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
const Template = (args) => (
|
|
60
|
+
<div style={{ height: '100%', width: '100%' }}>
|
|
61
|
+
<AreaChart {...args} />
|
|
62
|
+
</div>
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
export const Default = Template.bind({})
|
|
66
|
+
Default.args = {
|
|
67
|
+
data,
|
|
68
|
+
title :'Approval rate over time',
|
|
69
|
+
xKey :'date',
|
|
70
|
+
yKeys :['Average', 'Best', 'Worst'],
|
|
71
|
+
xLabel:'Date',
|
|
72
|
+
yLabel:'Approval rate',
|
|
73
|
+
colors:['purple', 'green', 'orange'],
|
|
74
|
+
height:400,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const Filled = Template.bind({})
|
|
78
|
+
Filled.args = {
|
|
79
|
+
...Default.args,
|
|
80
|
+
filled:true,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const TemplateSideBySide = (args) => (
|
|
84
|
+
<div style={{ display: 'flex', gap: '20px' }}>
|
|
85
|
+
<div style={{ flex: 1 }}>
|
|
86
|
+
{/* eslint-disable-next-line react/destructuring-assignment */}
|
|
87
|
+
<AreaChart {...args[0]} />
|
|
88
|
+
</div>
|
|
89
|
+
<div style={{ flex: 1 }}>
|
|
90
|
+
{/* eslint-disable-next-line react/destructuring-assignment */}
|
|
91
|
+
<AreaChart {...args[1]} />
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
export const SideBySide = TemplateSideBySide.bind({})
|
|
97
|
+
SideBySide.args = [
|
|
98
|
+
{
|
|
99
|
+
...Default.args,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
...Default.args,
|
|
103
|
+
title:'Submission rate over time',
|
|
104
|
+
data :data2,
|
|
105
|
+
},
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
export const SideBySideFilled = TemplateSideBySide.bind({})
|
|
109
|
+
SideBySideFilled.args = [
|
|
110
|
+
{
|
|
111
|
+
...Filled.args,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
...Filled.args,
|
|
115
|
+
data :data2,
|
|
116
|
+
title:'Submission rate over time',
|
|
117
|
+
},
|
|
118
|
+
]
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// front/packages/design-system/src/ui/a/AreaChart/AreaChart.jsx
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
import PropTypes from 'prop-types'
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
AreaChart as RechartsAreaChart,
|
|
9
|
+
Area,
|
|
10
|
+
XAxis,
|
|
11
|
+
YAxis,
|
|
12
|
+
CartesianGrid,
|
|
13
|
+
Tooltip,
|
|
14
|
+
ResponsiveContainer,
|
|
15
|
+
} from 'recharts'
|
|
16
|
+
|
|
17
|
+
import styleNames from '@pareto-engineering/bem/exports'
|
|
18
|
+
|
|
19
|
+
import './styles.scss'
|
|
20
|
+
|
|
21
|
+
// Local Definitions
|
|
22
|
+
|
|
23
|
+
const baseClassName = styleNames.base
|
|
24
|
+
|
|
25
|
+
const componentClassName = 'area-chart'
|
|
26
|
+
|
|
27
|
+
const AreaChart = ({
|
|
28
|
+
id,
|
|
29
|
+
className: userClassName,
|
|
30
|
+
data,
|
|
31
|
+
title,
|
|
32
|
+
xKey,
|
|
33
|
+
yKeys,
|
|
34
|
+
xLabel,
|
|
35
|
+
yLabel,
|
|
36
|
+
colors,
|
|
37
|
+
filled,
|
|
38
|
+
height,
|
|
39
|
+
width,
|
|
40
|
+
// ...otherProps
|
|
41
|
+
}) => {
|
|
42
|
+
const processedData = data.map((item) => {
|
|
43
|
+
const yValues = yKeys.map((key) => item[key])
|
|
44
|
+
const lowerBound = Math.min(...yValues)
|
|
45
|
+
const upperBound = Math.max(...yValues)
|
|
46
|
+
const margin = (upperBound - lowerBound) * 0.1
|
|
47
|
+
return {
|
|
48
|
+
...item,
|
|
49
|
+
bounds:[lowerBound - margin, upperBound + margin],
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const yAxisBounds = () => {
|
|
54
|
+
const yValues = data.map((item) => yKeys.map((key) => item[key]))
|
|
55
|
+
const min = Math.min(...yValues.flat())
|
|
56
|
+
const max = Math.max(...yValues.flat())
|
|
57
|
+
const margin = (max - min) * 0.1
|
|
58
|
+
return [min - margin, max + margin]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const CustomTooltipContent = ({ active, payload, label }) => {
|
|
62
|
+
if (active && payload && payload.length) {
|
|
63
|
+
const newPayload = payload.filter((item) => item.name !== 'bounds')
|
|
64
|
+
return (
|
|
65
|
+
<div className="custom-tooltip">
|
|
66
|
+
<p className="label">{`${xLabel}: ${label}`}</p>
|
|
67
|
+
{newPayload.map((entry) => (
|
|
68
|
+
<p className="label" key={`${entry.name}`} style={{ color: entry.color }}>
|
|
69
|
+
{`${entry.name}: ${entry.value}`}
|
|
70
|
+
</p>
|
|
71
|
+
))}
|
|
72
|
+
</div>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const CustomLegend = ({ colorsArray, yKeysArray }) => (
|
|
79
|
+
<div className="custom-legend">
|
|
80
|
+
{yKeysArray.map((key, index) => (
|
|
81
|
+
<div key={key} className="item">
|
|
82
|
+
<span
|
|
83
|
+
className="line"
|
|
84
|
+
style={{ backgroundColor: colorsArray[index] }}
|
|
85
|
+
/>
|
|
86
|
+
<span className="text">{key}</span>
|
|
87
|
+
</div>
|
|
88
|
+
))}
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div
|
|
94
|
+
id={id}
|
|
95
|
+
className={[
|
|
96
|
+
baseClassName,
|
|
97
|
+
componentClassName,
|
|
98
|
+
userClassName,
|
|
99
|
+
]
|
|
100
|
+
.filter((e) => e)
|
|
101
|
+
.join(' ')}
|
|
102
|
+
>
|
|
103
|
+
<h3>{title}</h3>
|
|
104
|
+
<CustomLegend colorsArray={colors} yKeysArray={yKeys} />
|
|
105
|
+
<ResponsiveContainer width={width} height={height}>
|
|
106
|
+
<RechartsAreaChart data={processedData}>
|
|
107
|
+
<CartesianGrid strokeDasharray="3 3" />
|
|
108
|
+
<XAxis
|
|
109
|
+
dataKey={xKey}
|
|
110
|
+
label={{ value: xLabel, position: 'insideBottom', offset: -5 }} // Adjusted offset for padding
|
|
111
|
+
axisLine={false}
|
|
112
|
+
tickLine={false}
|
|
113
|
+
tickCount={3}
|
|
114
|
+
/>
|
|
115
|
+
<YAxis
|
|
116
|
+
domain={yAxisBounds}
|
|
117
|
+
label={{
|
|
118
|
+
value:yLabel, angle:-90, position:'insideLeft', offset:15,
|
|
119
|
+
}}
|
|
120
|
+
axisLine={false}
|
|
121
|
+
tickLine={false}
|
|
122
|
+
tickFormatter={(value) => value.toFixed(2)}
|
|
123
|
+
/>
|
|
124
|
+
<Tooltip content={<CustomTooltipContent />} />
|
|
125
|
+
{filled && (
|
|
126
|
+
<Area
|
|
127
|
+
id="bounds"
|
|
128
|
+
type="linear"
|
|
129
|
+
dataKey="bounds"
|
|
130
|
+
stroke="none"
|
|
131
|
+
fill="var(--hard-ui-main-2)"
|
|
132
|
+
fillOpacity={0.4}
|
|
133
|
+
activeDot={false}
|
|
134
|
+
dot={false}
|
|
135
|
+
label={false}
|
|
136
|
+
isAnimationActive={false}
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
139
|
+
{yKeys.map((key, index) => (
|
|
140
|
+
<Area
|
|
141
|
+
id={key}
|
|
142
|
+
key={key}
|
|
143
|
+
type="linear"
|
|
144
|
+
dataKey={key}
|
|
145
|
+
stroke={colors[index]}
|
|
146
|
+
fill="none"
|
|
147
|
+
connectNulls
|
|
148
|
+
dot={false}
|
|
149
|
+
activeDot={{ r: 4 }}
|
|
150
|
+
isAnimationActive={false}
|
|
151
|
+
/>
|
|
152
|
+
))}
|
|
153
|
+
</RechartsAreaChart>
|
|
154
|
+
</ResponsiveContainer>
|
|
155
|
+
</div>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
AreaChart.propTypes = {
|
|
160
|
+
// eslint-disable-next-line react/forbid-prop-types
|
|
161
|
+
data :PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
162
|
+
title :PropTypes.string.isRequired,
|
|
163
|
+
xKey :PropTypes.string.isRequired,
|
|
164
|
+
yKeys :PropTypes.arrayOf(PropTypes.string).isRequired,
|
|
165
|
+
xLabel:PropTypes.string,
|
|
166
|
+
yLabel:PropTypes.string,
|
|
167
|
+
colors:PropTypes.arrayOf(PropTypes.string).isRequired,
|
|
168
|
+
filled:PropTypes.bool,
|
|
169
|
+
height:PropTypes.oneOfType([
|
|
170
|
+
PropTypes.string,
|
|
171
|
+
PropTypes.number,
|
|
172
|
+
]),
|
|
173
|
+
width:PropTypes.oneOfType([
|
|
174
|
+
PropTypes.string,
|
|
175
|
+
PropTypes.number,
|
|
176
|
+
]),
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
AreaChart.defaultProps = {
|
|
180
|
+
filled:false,
|
|
181
|
+
width :'100%',
|
|
182
|
+
height:300,
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export default AreaChart
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as AreaChart } from './AreaChart'
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
@use "@pareto-engineering/bem";
|
|
2
|
+
|
|
3
|
+
$default-margin: 1rem;
|
|
4
|
+
$default-padding: 1rem;
|
|
5
|
+
$default-box-shadow: 0 .25rem .75rem var(--ui-lines);
|
|
6
|
+
$default-text-font-size: calc(var(--s-1) * 1rem);
|
|
7
|
+
$default-border-radius: .25rem;
|
|
8
|
+
$default-legend-gap: .625rem;
|
|
9
|
+
$default-legend-padding: calc($default-padding * .125) calc($default-padding * .625);
|
|
10
|
+
$default-legend-line-width: 1.25rem;
|
|
11
|
+
$default-legend-line-height: .125rem;
|
|
12
|
+
$default-legend-line-margin-right: .3125rem;
|
|
13
|
+
$default-border-line-width: .0625rem;
|
|
14
|
+
|
|
15
|
+
.#{bem.$base} {
|
|
16
|
+
&.area-chart {
|
|
17
|
+
background-color: var(--background-far);
|
|
18
|
+
border-radius: var(--theme-default-border-radius);
|
|
19
|
+
box-shadow: $default-box-shadow;
|
|
20
|
+
margin: $default-margin 0;
|
|
21
|
+
padding: $default-padding;
|
|
22
|
+
|
|
23
|
+
h3 {
|
|
24
|
+
color: var(--subtitle);
|
|
25
|
+
margin: calc($default-margin / 5);
|
|
26
|
+
text-align: left;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.custom-legend {
|
|
30
|
+
display: flex;
|
|
31
|
+
gap: $default-legend-gap;
|
|
32
|
+
justify-content: flex-end;
|
|
33
|
+
padding-bottom: $default-padding;
|
|
34
|
+
padding-right: calc($default-padding * .25);
|
|
35
|
+
|
|
36
|
+
.item {
|
|
37
|
+
align-items: center;
|
|
38
|
+
border: $default-border-line-width solid var(--ui-lines);
|
|
39
|
+
border-radius: $default-border-radius;
|
|
40
|
+
display: flex;
|
|
41
|
+
padding: $default-legend-padding;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.line {
|
|
45
|
+
display: inline-block;
|
|
46
|
+
height: $default-legend-line-height;
|
|
47
|
+
margin-right: $default-legend-line-margin-right;
|
|
48
|
+
width: $default-legend-line-width;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.text {
|
|
52
|
+
color: var(--paragraph);
|
|
53
|
+
font-size: calc($default-text-font-size * .75);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.custom-tooltip {
|
|
58
|
+
background-color: var(--background-far);
|
|
59
|
+
border: $default-border-line-width solid var(--ui-lines);
|
|
60
|
+
border-radius: $default-border-radius;
|
|
61
|
+
padding: calc($default-padding * .25);
|
|
62
|
+
|
|
63
|
+
.label {
|
|
64
|
+
color: var(--hard-paragraph);
|
|
65
|
+
font-size: $default-text-font-size;
|
|
66
|
+
margin: calc($default-margin * .25);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* stylelint-disable selector-max-compound-selectors -- nested elements */
|
|
71
|
+
.recharts-wrapper {
|
|
72
|
+
.recharts-surface {
|
|
73
|
+
.recharts-cartesian-grid line {
|
|
74
|
+
stroke: var(--ui-lines);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.recharts-text {
|
|
78
|
+
fill: var(--soft-paragraph);
|
|
79
|
+
font-size: calc($default-text-font-size * .75);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.recharts-text.recharts-label {
|
|
83
|
+
fill: var(--paragraph);
|
|
84
|
+
font-size: $default-text-font-size;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -23,6 +23,8 @@ import {
|
|
|
23
23
|
import {
|
|
24
24
|
defaultKeymap,
|
|
25
25
|
indentWithTab,
|
|
26
|
+
history,
|
|
27
|
+
historyKeymap,
|
|
26
28
|
} from '@codemirror/commands'
|
|
27
29
|
|
|
28
30
|
import {
|
|
@@ -65,7 +67,7 @@ const XMLEditor = ({
|
|
|
65
67
|
const startState = EditorState.create({
|
|
66
68
|
doc :config,
|
|
67
69
|
extensions:[
|
|
68
|
-
keymap.of([defaultKeymap, indentWithTab]),
|
|
70
|
+
keymap.of([defaultKeymap, indentWithTab, ...historyKeymap]),
|
|
69
71
|
indentOnInput(),
|
|
70
72
|
lineNumbers(),
|
|
71
73
|
bracketMatching(),
|
|
@@ -78,6 +80,7 @@ const XMLEditor = ({
|
|
|
78
80
|
rectangularSelection(),
|
|
79
81
|
crosshairCursor(),
|
|
80
82
|
xml(),
|
|
83
|
+
history(),
|
|
81
84
|
theme,
|
|
82
85
|
EditorState.readOnly.of(readOnly),
|
|
83
86
|
EditorView.updateListener.of((view) => {
|
package/src/ui/a/index.js
CHANGED
|
@@ -98,6 +98,8 @@ const FileUpload = ({
|
|
|
98
98
|
|
|
99
99
|
const acceptOptions = Array.isArray(accept) ? accept?.join(',') : accept
|
|
100
100
|
|
|
101
|
+
const isAnyFileUploading = Object.values(uploadStatus ?? {})?.map((e) => e?.status)?.some((status) => status === 'pending')
|
|
102
|
+
|
|
101
103
|
return (
|
|
102
104
|
<div
|
|
103
105
|
id={id}
|
|
@@ -128,7 +130,7 @@ const FileUpload = ({
|
|
|
128
130
|
type="file"
|
|
129
131
|
accept={acceptOptions}
|
|
130
132
|
multiple={multiple || (maxCount && maxCount > 0)}
|
|
131
|
-
disabled={disabled}
|
|
133
|
+
disabled={disabled || isAnyFileUploading}
|
|
132
134
|
onChange={handleChange}
|
|
133
135
|
/>
|
|
134
136
|
<span className="ai-icon">
|
|
@@ -270,6 +272,7 @@ FileUpload.defaultProps = {
|
|
|
270
272
|
color :'paragraph',
|
|
271
273
|
filePreviewAlignment:'bottom',
|
|
272
274
|
viewOnly :false,
|
|
275
|
+
multiple :true,
|
|
273
276
|
}
|
|
274
277
|
|
|
275
278
|
FileUpload.Preview = Preview
|