@pareto-engineering/design-system 5.2.1 → 5.3.0

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 (62) hide show
  1. package/dist/cjs/a/Charts/AreaChart/AreaChart.js +60 -5
  2. package/dist/cjs/a/Charts/AreaChart/styles.scss +22 -0
  3. package/dist/cjs/a/Charts/Common/CustomLegend/CustomLegend.js +19 -5
  4. package/dist/cjs/a/Charts/Common/CustomTooltipContent/CustomTooltipContent.js +133 -68
  5. package/dist/cjs/a/Charts/PieChart/PieChart.js +20 -7
  6. package/dist/cjs/a/ThroughPutIndicator/ThroughPutIndicator.js +78 -0
  7. package/dist/cjs/a/ThroughPutIndicator/index.js +13 -0
  8. package/dist/cjs/a/ThroughPutIndicator/styles.scss +35 -0
  9. package/dist/cjs/a/ToggleSwitch/ToggleSwitch.js +2 -1
  10. package/dist/cjs/a/ToggleSwitch/styles.scss +9 -2
  11. package/dist/cjs/a/Tooltip/Tooltip.js +19 -2
  12. package/dist/cjs/a/Tooltip/styles.scss +32 -4
  13. package/dist/cjs/a/index.js +8 -1
  14. package/dist/cjs/f/FormInput/FormInput.js +7 -1
  15. package/dist/cjs/f/fields/ToggleInput/ToggleInput.js +126 -0
  16. package/dist/cjs/f/fields/ToggleInput/index.js +13 -0
  17. package/dist/cjs/f/fields/ToggleInput/styles.scss +22 -0
  18. package/dist/cjs/f/fields/index.js +8 -1
  19. package/dist/cjs/utils/formatting.js +27 -18
  20. package/dist/cjs/utils/index.js +6 -0
  21. package/dist/es/a/Charts/AreaChart/AreaChart.js +61 -6
  22. package/dist/es/a/Charts/AreaChart/styles.scss +22 -0
  23. package/dist/es/a/Charts/Common/CustomLegend/CustomLegend.js +19 -5
  24. package/dist/es/a/Charts/Common/CustomTooltipContent/CustomTooltipContent.js +122 -66
  25. package/dist/es/a/Charts/PieChart/PieChart.js +20 -7
  26. package/dist/es/a/ThroughPutIndicator/ThroughPutIndicator.js +66 -0
  27. package/dist/es/a/ThroughPutIndicator/index.js +2 -0
  28. package/dist/es/a/ThroughPutIndicator/styles.scss +35 -0
  29. package/dist/es/a/ToggleSwitch/ToggleSwitch.js +2 -1
  30. package/dist/es/a/ToggleSwitch/styles.scss +9 -2
  31. package/dist/es/a/Tooltip/Tooltip.js +31 -12
  32. package/dist/es/a/Tooltip/styles.scss +32 -4
  33. package/dist/es/a/index.js +2 -1
  34. package/dist/es/f/FormInput/FormInput.js +8 -2
  35. package/dist/es/f/fields/ToggleInput/ToggleInput.js +116 -0
  36. package/dist/es/f/fields/ToggleInput/index.js +2 -0
  37. package/dist/es/f/fields/ToggleInput/styles.scss +22 -0
  38. package/dist/es/f/fields/index.js +2 -1
  39. package/dist/es/utils/formatting.js +25 -17
  40. package/dist/es/utils/index.js +1 -1
  41. package/package.json +5 -5
  42. package/src/ui/a/Charts/AreaChart/AreaChart.jsx +73 -9
  43. package/src/ui/a/Charts/AreaChart/styles.scss +22 -0
  44. package/src/ui/a/Charts/Common/CustomLegend/CustomLegend.jsx +20 -5
  45. package/src/ui/a/Charts/Common/CustomTooltipContent/CustomTooltipContent.jsx +126 -79
  46. package/src/ui/a/Charts/PieChart/PieChart.jsx +38 -17
  47. package/src/ui/a/ThroughPutIndicator/ThroughPutIndicator.jsx +90 -0
  48. package/src/ui/a/ThroughPutIndicator/index.js +2 -0
  49. package/src/ui/a/ThroughPutIndicator/styles.scss +35 -0
  50. package/src/ui/a/ToggleSwitch/ToggleSwitch.jsx +1 -1
  51. package/src/ui/a/ToggleSwitch/styles.scss +9 -2
  52. package/src/ui/a/Tooltip/Tooltip.jsx +55 -26
  53. package/src/ui/a/Tooltip/styles.scss +32 -4
  54. package/src/ui/a/index.js +1 -0
  55. package/src/ui/f/FormInput/FormInput.jsx +11 -0
  56. package/src/ui/f/fields/ToggleInput/ToggleInput.jsx +140 -0
  57. package/src/ui/f/fields/ToggleInput/index.js +2 -0
  58. package/src/ui/f/fields/ToggleInput/styles.scss +22 -0
  59. package/src/ui/f/fields/index.js +1 -0
  60. package/src/ui/utils/formatting.js +38 -29
  61. package/src/ui/utils/index.js +1 -1
  62. package/tests/__snapshots__/Storyshots.test.js.snap +7 -1
@@ -0,0 +1,116 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.3 */
2
+ import * as React from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { useField } from 'formik';
5
+ import styleNames from '@pareto-engineering/bem/exports';
6
+ import { ToggleSwitch } from "../../../a";
7
+ import { FormLabel, FormDescription } from "../../common";
8
+ import "./styles.scss";
9
+
10
+ // Local Definitions
11
+ const baseClassName = styleNames.base;
12
+ const componentClassName = 'toggle-input';
13
+
14
+ /**
15
+ * Toggle input field component that wraps ToggleSwitch for use with Formik
16
+ */
17
+ const ToggleInput = ({
18
+ id,
19
+ className: userClassName,
20
+ style,
21
+ name,
22
+ label,
23
+ color,
24
+ labelColor,
25
+ validate,
26
+ description,
27
+ disabled,
28
+ optional,
29
+ size
30
+ // ...otherProps
31
+ }) => {
32
+ const [field,, helpers] = useField({
33
+ name,
34
+ validate,
35
+ type: 'checkbox'
36
+ });
37
+ const handleChange = () => {
38
+ helpers.setValue(!field.value);
39
+ };
40
+ return /*#__PURE__*/React.createElement("div", {
41
+ id: id,
42
+ className: [baseClassName, componentClassName, userClassName, `y-${color}`].filter(e => e).join(' '),
43
+ style: style
44
+ }, /*#__PURE__*/React.createElement(FormLabel, {
45
+ name: name,
46
+ color: labelColor,
47
+ optional: optional
48
+ }, label), /*#__PURE__*/React.createElement("div", {
49
+ className: "toggle-wrapper"
50
+ }, /*#__PURE__*/React.createElement(ToggleSwitch, {
51
+ checked: Boolean(field.value),
52
+ handleOnChange: handleChange,
53
+ inputId: name,
54
+ size: size,
55
+ disabled: disabled
56
+ })), /*#__PURE__*/React.createElement(FormDescription, {
57
+ className: "s-1",
58
+ description: description,
59
+ name: name
60
+ }));
61
+ };
62
+ ToggleInput.propTypes = {
63
+ /**
64
+ * The HTML id for this element
65
+ */
66
+ id: PropTypes.string,
67
+ /**
68
+ * The HTML class names for this element
69
+ */
70
+ className: PropTypes.string,
71
+ /**
72
+ * The React-written, css properties for this element.
73
+ */
74
+ style: PropTypes.objectOf(PropTypes.string),
75
+ /**
76
+ * The input name (html - and Formik state)
77
+ */
78
+ name: PropTypes.string.isRequired,
79
+ /**
80
+ * The input label
81
+ */
82
+ label: PropTypes.string.isRequired,
83
+ /**
84
+ * The input label color
85
+ */
86
+ labelColor: PropTypes.string,
87
+ /**
88
+ * The input field validator function
89
+ */
90
+ validate: PropTypes.func,
91
+ /**
92
+ * Input description
93
+ */
94
+ description: PropTypes.string,
95
+ /**
96
+ * Whether the toggle input should be disabled
97
+ */
98
+ disabled: PropTypes.bool,
99
+ /**
100
+ * The text input color
101
+ */
102
+ color: PropTypes.string,
103
+ /**
104
+ * Whether the input is optional or not
105
+ */
106
+ optional: PropTypes.bool,
107
+ /**
108
+ * The size of the toggle switch
109
+ */
110
+ size: PropTypes.string
111
+ };
112
+ ToggleInput.defaultProps = {
113
+ color: 'paragraph',
114
+ disabled: false
115
+ };
116
+ export default ToggleInput;
@@ -0,0 +1,2 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.3 */
2
+ export { default as ToggleInput } from "./ToggleInput";
@@ -0,0 +1,22 @@
1
+ /* @pareto-engineering/generator-front 1.1.1-alpha.3 */
2
+
3
+ @use "@pareto-engineering/bem";
4
+ @use "@pareto-engineering/styles/src/mixins";
5
+ @use "@pareto-engineering/styles/src/globals" as *;
6
+
7
+ .#{bem.$base}.toggle-input {
8
+ display: flex;
9
+ flex-direction: column;
10
+
11
+ > .#{bem.$base}.form-label {
12
+ margin-bottom: var(--gap);
13
+ }
14
+
15
+ > .toggle-wrapper {
16
+ align-items: center;
17
+ display: flex;
18
+ margin-bottom: calc(var(--gap) / 2);
19
+ }
20
+ }
21
+
22
+
@@ -10,4 +10,5 @@ export { QueryChoices } from "./QueryChoices";
10
10
  export { LinkInput } from "./LinkInput";
11
11
  export { EditorInput } from "./EditorInput";
12
12
  export { LatexPreviewInput, convertLatexToHtml } from "./LatexPreviewInput";
13
- export { FileUpload, fileUploadOptions, getFileType, getFileTypeFromUrl } from "./FileUpload";
13
+ export { FileUpload, fileUploadOptions, getFileType, getFileTypeFromUrl } from "./FileUpload";
14
+ export { ToggleInput } from "./ToggleInput";
@@ -1,5 +1,6 @@
1
1
  export const DATE_FORMATS = {
2
2
  HUMAN_READABLE: 'human_readable',
3
+ HUMAN_READABLE_WITH_TIME: 'human_readable_with_time',
3
4
  TIME: 'time',
4
5
  DATETIME: 'datetime',
5
6
  CHART_DATE: 'chart_date',
@@ -42,23 +43,6 @@ export const formatTime = seconds => {
42
43
  if (parts.length === 0) return '0s';
43
44
  return parts.join(' ');
44
45
  };
45
- const parseDate = input => {
46
- if (input instanceof Date) return input;
47
- if (typeof input === 'number') return new Date(input);
48
- if (typeof input === 'string') {
49
- if (isTimeSliceFormat(input)) {
50
- return createTimeFromSlice(input);
51
- }
52
- const parsed = new Date(input);
53
- if (isValidDate(parsed)) return parsed;
54
- const timestamp = parseInt(input, 10);
55
- if (!Number.isNaN(timestamp)) {
56
- const date = new Date(timestamp * 1000);
57
- if (isValidDate(date)) return date;
58
- }
59
- }
60
- return null;
61
- };
62
46
  const formatStrategies = {
63
47
  [DATE_FORMATS.CHART_DATE]: date => {
64
48
  const monthDay = date.toLocaleDateString('en-US', {
@@ -75,8 +59,32 @@ const formatStrategies = {
75
59
  day: 'numeric',
76
60
  timeZone: 'UTC'
77
61
  }),
62
+ [DATE_FORMATS.HUMAN_READABLE_WITH_TIME]: date => date.toLocaleString('en-US', {
63
+ year: 'numeric',
64
+ month: 'short',
65
+ day: 'numeric',
66
+ hour: '2-digit',
67
+ timeZone: 'UTC'
68
+ }),
78
69
  default: date => date.toISOString()
79
70
  };
71
+ export const parseDate = input => {
72
+ if (input instanceof Date) return input;
73
+ if (typeof input === 'number') return new Date(input);
74
+ if (typeof input === 'string') {
75
+ if (isTimeSliceFormat(input)) {
76
+ return createTimeFromSlice(input);
77
+ }
78
+ const parsed = new Date(input);
79
+ if (isValidDate(parsed)) return parsed;
80
+ const timestamp = parseInt(input, 10);
81
+ if (!Number.isNaN(timestamp)) {
82
+ const date = new Date(timestamp * 1000);
83
+ if (isValidDate(date)) return date;
84
+ }
85
+ }
86
+ return null;
87
+ };
80
88
  export const formatDate = (input, format = DATE_FORMATS.HUMAN_READABLE) => {
81
89
  try {
82
90
  if (typeof input === 'string' && isTimeSliceFormat(input)) {
@@ -1,3 +1,3 @@
1
1
  export { useWindowSize, useDynamicPosition, useOutsideClick } from "./hooks";
2
- export { formatTime, formatDate, DATE_FORMATS, snakeCaseToTitleCase } from "./formatting";
2
+ export { formatTime, formatDate, DATE_FORMATS, parseDate, snakeCaseToTitleCase } from "./formatting";
3
3
  export { applyCharacterLimit } from "./applyCharacterLimit";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pareto-engineering/design-system",
3
- "version": "5.2.1",
3
+ "version": "5.3.0",
4
4
  "description": "",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/es/index.js",
@@ -60,9 +60,9 @@
60
60
  "@lexical/selection": "0.12.2",
61
61
  "@lexical/table": "0.12.2",
62
62
  "@lexical/utils": "0.12.2",
63
- "@pareto-engineering/assets": "^5.1.1",
64
- "@pareto-engineering/bem": "^5.2.1",
65
- "@pareto-engineering/styles": "^5.2.1",
63
+ "@pareto-engineering/assets": "^5.3.0",
64
+ "@pareto-engineering/bem": "^5.3.0",
65
+ "@pareto-engineering/styles": "^5.3.0",
66
66
  "@pareto-engineering/utils": "^5.0.0",
67
67
  "better-react-mathjax": "^2.0.3",
68
68
  "codemirror": "^6.0.1",
@@ -88,5 +88,5 @@
88
88
  "remark-math": "^6.0.0"
89
89
  },
90
90
  "browserslist": "> 2%",
91
- "gitHead": "dad6ef35dec907ece7e046fdd5697e44e70c8941"
91
+ "gitHead": "74dc91892e6471a3c42e65ce673c62693ce943f5"
92
92
  }
@@ -16,7 +16,11 @@ import {
16
16
 
17
17
  import styleNames from '@pareto-engineering/bem/exports'
18
18
 
19
- import { formatTime, formatDate, DATE_FORMATS } from 'ui/utils'
19
+ import {
20
+ formatTime, formatDate, DATE_FORMATS, parseDate,
21
+ } from 'ui/utils'
22
+
23
+ import { ThroughPutIndicator } from '../../ThroughPutIndicator'
20
24
 
21
25
  import { CustomLegend, CustomTooltipContent, YLabelsDropDown } from '../Common'
22
26
 
@@ -26,6 +30,34 @@ const baseClassName = styleNames.base
26
30
 
27
31
  const componentClassName = 'area-chart'
28
32
 
33
+ /**
34
+ * Determines whether to show only date or date with time based on the data range
35
+ *
36
+ * @param {Array} data - The chart data array
37
+ * @param {string} xKey - The key for the x-axis values (dates)
38
+ * @returns {boolean} - True if only date should be shown, false if date and time should be shown
39
+ */
40
+ const shouldShowOnlyDate = (data, xKey) => {
41
+ if (!data || data.length < 2 || !xKey) return true
42
+
43
+ // Extract dates from the data
44
+ const dates = data.map((item) => parseDate(item[xKey])).filter((date) => date !== null)
45
+
46
+ if (dates.length < 2) return true
47
+
48
+ // Sort dates chronologically
49
+ dates.sort((a, b) => a.getTime() - b.getTime())
50
+
51
+ // Calculate the difference in days between the first and last date
52
+ const firstDate = dates[0]
53
+ const lastDate = dates[dates.length - 1]
54
+ const diffInMs = lastDate.getTime() - firstDate.getTime()
55
+ const diffInDays = diffInMs / (1000 * 60 * 60 * 24)
56
+
57
+ // If the data spans less than 4 days, show only date
58
+ return diffInDays > 4
59
+ }
60
+
29
61
  const AreaChart = ({
30
62
  id,
31
63
  className: userClassName,
@@ -42,6 +74,8 @@ const AreaChart = ({
42
74
  isTimeFormat,
43
75
  dateFormat,
44
76
  capitalizedLegend,
77
+ isWorkerSubmissionChart,
78
+ totalSubmissions,
45
79
  }) => {
46
80
  const allYLabels = yKeys.map((key) => ({
47
81
  label:key,
@@ -55,9 +89,11 @@ const AreaChart = ({
55
89
  const min = Math.min(...yValues.flat())
56
90
  const max = Math.max(...yValues.flat())
57
91
  const margin = (max - min) * 0.1
58
- return [min - margin, max + margin]
92
+ return [Math.max(min - margin, 0), max + margin]
59
93
  }
60
94
 
95
+ const showOnlyDate = shouldShowOnlyDate(data, xKey)
96
+
61
97
  return (
62
98
  <div
63
99
  id={id}
@@ -71,12 +107,20 @@ const AreaChart = ({
71
107
  >
72
108
  <div className="chart-header">
73
109
  <h3>{title}</h3>
110
+
74
111
  <YLabelsDropDown
75
112
  allYLabels={allYLabels}
76
113
  selectedYLabels={selectedYLabels}
77
114
  setSelectedYLabels={setSelectedYLabels}
78
115
  />
79
116
  </div>
117
+
118
+ {isWorkerSubmissionChart && (
119
+ <div className="worker-submissions-total-percentage-container">
120
+ <p className="total-submissions-text">{totalSubmissions}</p>
121
+ <ThroughPutIndicator data={data} keyName="reserved" />
122
+ </div>
123
+ )}
80
124
  <CustomLegend
81
125
  key={id}
82
126
  colorsArray={colors}
@@ -92,7 +136,12 @@ const AreaChart = ({
92
136
  axisLine={false}
93
137
  tickLine={false}
94
138
  tickCount={3}
95
- tickFormatter={(value) => formatDate(value, dateFormat)}
139
+ tickFormatter={(value) => {
140
+ if (showOnlyDate) {
141
+ return formatDate(value, dateFormat)
142
+ }
143
+ return formatDate(value, DATE_FORMATS.HUMAN_READABLE_WITH_TIME)
144
+ }}
96
145
  />
97
146
  <YAxis
98
147
  domain={yAxisBounds}
@@ -112,6 +161,9 @@ const AreaChart = ({
112
161
  if (isTimeFormat) {
113
162
  return formatTime(value)
114
163
  }
164
+ if (isWorkerSubmissionChart) {
165
+ return Math.round(value)
166
+ }
115
167
  return value.toFixed(2)
116
168
  }}
117
169
  />
@@ -228,15 +280,27 @@ AreaChart.propTypes = {
228
280
  * The type of format for the datetime value
229
281
  */
230
282
  dateFormat:PropTypes.oneOf(Object.values(DATE_FORMATS)),
283
+
284
+ /**
285
+ * Flag on whether the chart is a worker submission chart or not
286
+ */
287
+ isWorkerSubmissionChart:PropTypes.bool,
288
+
289
+ /**
290
+ * Total submissions
291
+ */
292
+ totalSubmissions:PropTypes.number,
231
293
  }
232
294
 
233
295
  AreaChart.defaultProps = {
234
- filled :false,
235
- width :'100%',
236
- height :300,
237
- capitalizedLegend:false,
238
- isTimeFormat :false,
239
- dateFormat :DATE_FORMATS.HUMAN_READABLE,
296
+ filled :false,
297
+ width :'100%',
298
+ height :300,
299
+ capitalizedLegend :false,
300
+ isTimeFormat :false,
301
+ dateFormat :DATE_FORMATS.HUMAN_READABLE,
302
+ isWorkerSubmissionChart:false,
303
+
240
304
  }
241
305
 
242
306
  export default AreaChart
@@ -26,6 +26,17 @@ $default-text-font-size: calc(var(--s-1) * 1rem);
26
26
  }
27
27
  }
28
28
 
29
+ .worker-submissions-total-percentage-container {
30
+ align-items: center;
31
+ display: flex;
32
+ gap: 1rem;
33
+ justify-content: flex-start;
34
+
35
+ .total-submissions-text {
36
+ font-size: calc($default-text-font-size * 2);
37
+ }
38
+ }
39
+
29
40
  /* stylelint-disable selector-max-compound-selectors -- nested elements */
30
41
  .recharts-wrapper {
31
42
  .recharts-surface {
@@ -46,3 +57,14 @@ $default-text-font-size: calc(var(--s-1) * 1rem);
46
57
  }
47
58
  }
48
59
  }
60
+
61
+ .worker-submissions-total-percentage-container {
62
+ align-items: center;
63
+ display: flex;
64
+ gap: 1rem;
65
+ justify-content: flex-start;
66
+
67
+ .total-submissions-text {
68
+ font-size: calc($default-text-font-size * 2);
69
+ }
70
+ }
@@ -12,6 +12,11 @@ const baseClassName = styleNames.base
12
12
 
13
13
  const componentClassName = 'custom-legend'
14
14
 
15
+ const toCurrency = (value) => {
16
+ const formatter = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' })
17
+ return formatter.format(value)
18
+ }
19
+
15
20
  const CustomLegend = ({
16
21
  id,
17
22
  className: userClassName,
@@ -21,6 +26,8 @@ const CustomLegend = ({
21
26
  getLegendItemTitle,
22
27
  getLegendItemSubtitle,
23
28
  capitalizedLegend,
29
+ subtitleToCurrency,
30
+ isPayOutChart,
24
31
  }) => (
25
32
  <div
26
33
  id={id}
@@ -51,12 +58,14 @@ const CustomLegend = ({
51
58
  </div>
52
59
  <div className="sub-title-percentage-container">
53
60
  <span className="sub-title">
54
- {getLegendItemSubtitle(key)}
61
+ {subtitleToCurrency
62
+ ? toCurrency(getLegendItemSubtitle(key))
63
+ : getLegendItemSubtitle(key)}
64
+ </span>
65
+ { Object.prototype.hasOwnProperty.call(key, 'percentage') && !isPayOutChart && (
66
+ <span className="percentage-title">
67
+ {`${key?.percentage}%`}
55
68
  </span>
56
- {key.percentage && (
57
- <span className="percentage-title">
58
- {`${key.percentage}%`}
59
- </span>
60
69
  )}
61
70
  </div>
62
71
  </div>
@@ -104,6 +113,11 @@ CustomLegend.propTypes = {
104
113
  * Flag on whether to capitalize legend keys
105
114
  */
106
115
  capitalizedLegend:PropTypes.bool,
116
+
117
+ /**
118
+ * Flag on whether to convert the subtitle to currency
119
+ */
120
+ subtitleToCurrency:PropTypes.bool,
107
121
  }
108
122
 
109
123
  CustomLegend.defaultProps = {
@@ -112,6 +126,7 @@ CustomLegend.defaultProps = {
112
126
  /* eslint-disable no-unused-vars */
113
127
  getLegendItemSubtitle:() => {},
114
128
  capitalizedLegend :false,
129
+ subtitleToCurrency :false,
115
130
  }
116
131
 
117
132
  export default CustomLegend