@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.
@@ -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
@@ -30,3 +30,4 @@ export { ToggleSwitch } from './ToggleSwitch'
30
30
  export { XMLEditor } from './XMLEditor'
31
31
  export { DatePicker } from './DatePicker'
32
32
  export { Tooltip } from './Tooltip'
33
+ export { AreaChart } from './AreaChart'
@@ -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