@pareto-engineering/design-system 5.0.5 → 5.1.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 (78) hide show
  1. package/dist/cjs/a/Charts/AreaChart/AreaChart.js +3 -13
  2. package/dist/cjs/a/Charts/BarChart/BarChart.js +6 -4
  3. package/dist/cjs/a/Charts/Common/CustomLegend/CustomLegend.js +26 -7
  4. package/dist/cjs/a/Charts/Common/CustomLegend/styles.scss +41 -14
  5. package/dist/cjs/a/Charts/Common/CustomTooltipContent/CustomTooltipContent.js +18 -7
  6. package/dist/cjs/a/Charts/Common/YLabelsDropDown/YlabelsDropDown.js +3 -4
  7. package/dist/cjs/a/Charts/Common/YLabelsDropDown/styles.scss +7 -6
  8. package/dist/cjs/a/Charts/PieChart/PieChart.js +99 -0
  9. package/dist/cjs/a/Charts/PieChart/index.js +13 -0
  10. package/dist/cjs/a/Charts/PieChart/styles.scss +48 -0
  11. package/dist/cjs/a/Charts/index.js +8 -1
  12. package/dist/cjs/a/Notification/styles.scss +17 -5
  13. package/dist/cjs/a/index.js +6 -0
  14. package/dist/cjs/f/FormInput/FormInput.js +1 -1
  15. package/dist/cjs/f/fields/LatexPreviewInput/LatexPreviewInput.js +1 -1
  16. package/dist/cjs/f/fields/LatexPreviewInput/styles.scss +1 -0
  17. package/dist/cjs/f/fields/TextareaInput/TextareaInput.js +4 -2
  18. package/dist/cjs/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.js +27 -1
  19. package/dist/cjs/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +15 -0
  20. package/dist/cjs/g/FormBuilder/common/Builder/common/Section/Section.js +6 -2
  21. package/dist/cjs/g/FormBuilder/common/Renderer/Renderer.js +6 -0
  22. package/dist/cjs/utils/applyCharacterLimit.js +75 -0
  23. package/dist/cjs/utils/formatting.js +10 -2
  24. package/dist/cjs/utils/index.js +14 -1
  25. package/dist/es/a/Charts/AreaChart/AreaChart.js +3 -13
  26. package/dist/es/a/Charts/BarChart/BarChart.js +6 -4
  27. package/dist/es/a/Charts/Common/CustomLegend/CustomLegend.js +38 -21
  28. package/dist/es/a/Charts/Common/CustomLegend/styles.scss +41 -14
  29. package/dist/es/a/Charts/Common/CustomTooltipContent/CustomTooltipContent.js +19 -8
  30. package/dist/es/a/Charts/Common/YLabelsDropDown/YlabelsDropDown.js +3 -5
  31. package/dist/es/a/Charts/Common/YLabelsDropDown/styles.scss +7 -6
  32. package/dist/es/a/Charts/PieChart/PieChart.js +89 -0
  33. package/dist/es/a/Charts/PieChart/index.js +1 -0
  34. package/dist/es/a/Charts/PieChart/styles.scss +48 -0
  35. package/dist/es/a/Charts/index.js +2 -1
  36. package/dist/es/a/Notification/styles.scss +17 -5
  37. package/dist/es/a/index.js +1 -1
  38. package/dist/es/f/FormInput/FormInput.js +1 -1
  39. package/dist/es/f/fields/LatexPreviewInput/LatexPreviewInput.js +1 -1
  40. package/dist/es/f/fields/LatexPreviewInput/styles.scss +1 -0
  41. package/dist/es/f/fields/TextareaInput/TextareaInput.js +4 -2
  42. package/dist/es/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.js +27 -1
  43. package/dist/es/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +15 -0
  44. package/dist/es/g/FormBuilder/common/Builder/common/Section/Section.js +6 -2
  45. package/dist/es/g/FormBuilder/common/Renderer/Renderer.js +6 -0
  46. package/dist/es/utils/applyCharacterLimit.js +67 -0
  47. package/dist/es/utils/formatting.js +7 -0
  48. package/dist/es/utils/index.js +2 -1
  49. package/package.json +3 -3
  50. package/src/stories/a/AreaChart.stories.jsx +1 -1
  51. package/src/stories/a/BarChart.stories.jsx +1 -1
  52. package/src/stories/a/PieChart.stories.jsx +53 -0
  53. package/src/ui/a/Charts/AreaChart/AreaChart.jsx +8 -14
  54. package/src/ui/a/Charts/BarChart/BarChart.jsx +4 -2
  55. package/src/ui/a/Charts/Common/CustomLegend/CustomLegend.jsx +54 -29
  56. package/src/ui/a/Charts/Common/CustomLegend/styles.scss +41 -14
  57. package/src/ui/a/Charts/Common/CustomTooltipContent/CustomTooltipContent.jsx +25 -13
  58. package/src/ui/a/Charts/Common/YLabelsDropDown/YlabelsDropDown.jsx +4 -4
  59. package/src/ui/a/Charts/Common/YLabelsDropDown/styles.scss +7 -6
  60. package/src/ui/a/Charts/PieChart/PieChart.jsx +125 -0
  61. package/src/ui/a/Charts/PieChart/index.js +1 -0
  62. package/src/ui/a/Charts/PieChart/styles.scss +48 -0
  63. package/src/ui/a/Charts/index.js +1 -0
  64. package/src/ui/a/Notification/styles.scss +17 -5
  65. package/src/ui/a/index.js +1 -1
  66. package/src/ui/f/FormInput/FormInput.jsx +1 -0
  67. package/src/ui/f/fields/LatexPreviewInput/LatexPreviewInput.jsx +1 -0
  68. package/src/ui/f/fields/LatexPreviewInput/styles.scss +1 -0
  69. package/src/ui/f/fields/TextareaInput/TextareaInput.jsx +2 -0
  70. package/src/ui/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.jsx +34 -0
  71. package/src/ui/g/FormBuilder/common/Builder/common/InputBuilder/styles.scss +15 -0
  72. package/src/ui/g/FormBuilder/common/Builder/common/Section/Section.jsx +10 -2
  73. package/src/ui/g/FormBuilder/common/Renderer/Renderer.jsx +5 -0
  74. package/src/ui/g/FormBuilder/common/Renderer/common/Section/Section.jsx +0 -1
  75. package/src/ui/utils/applyCharacterLimit.js +80 -0
  76. package/src/ui/utils/formatting.js +8 -0
  77. package/src/ui/utils/index.js +4 -1
  78. package/tests/__snapshots__/Storyshots.test.js.snap +1165 -429
@@ -0,0 +1,89 @@
1
+ import * as React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { PieChart as RechartsPieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts';
4
+ import styleNames from '@pareto-engineering/bem/exports';
5
+ import { CustomLegend, CustomTooltipContent } from "../Common";
6
+ import "./styles.scss";
7
+ const baseClassName = styleNames.base;
8
+ const componentClassName = 'pie-chart';
9
+ const PieChart = ({
10
+ id,
11
+ className: userClassName,
12
+ data,
13
+ title,
14
+ valueKey,
15
+ labelKey,
16
+ colors,
17
+ height,
18
+ width,
19
+ innerRadius,
20
+ outerRadius
21
+ }) => {
22
+ const total = data.reduce((sum, item) => sum + item[valueKey], 0);
23
+ const formattedData = data.map(item => ({
24
+ ...item,
25
+ label: item[labelKey],
26
+ color: colors[data.indexOf(item)],
27
+ percentage: (item[valueKey] / total * 100).toFixed(0)
28
+ }));
29
+ return /*#__PURE__*/React.createElement("div", {
30
+ id: id,
31
+ className: [baseClassName, componentClassName, userClassName].filter(e => e).join(' ')
32
+ }, /*#__PURE__*/React.createElement("div", {
33
+ className: "chart-header"
34
+ }, /*#__PURE__*/React.createElement("h3", null, title)), /*#__PURE__*/React.createElement("div", {
35
+ className: "chart-content"
36
+ }, /*#__PURE__*/React.createElement(ResponsiveContainer, {
37
+ width: width,
38
+ height: height
39
+ }, /*#__PURE__*/React.createElement(RechartsPieChart, null, /*#__PURE__*/React.createElement(Pie, {
40
+ data: formattedData,
41
+ dataKey: valueKey,
42
+ nameKey: labelKey,
43
+ cx: "50%",
44
+ cy: "50%",
45
+ innerRadius: innerRadius,
46
+ outerRadius: outerRadius,
47
+ label: false,
48
+ paddingAngle: 0
49
+ }, formattedData.map((entry, index) => /*#__PURE__*/React.createElement(Cell, {
50
+ key: entry[labelKey],
51
+ fill: colors[index],
52
+ strokeWidth: 0
53
+ }))), /*#__PURE__*/React.createElement(Tooltip, {
54
+ content: /*#__PURE__*/React.createElement(CustomTooltipContent, {
55
+ isDateValue: false
56
+ })
57
+ }))), /*#__PURE__*/React.createElement(CustomLegend, {
58
+ colorsArray: colors,
59
+ yKeysArray: formattedData,
60
+ capitalizedLegend: true,
61
+ orientation: "vertical",
62
+ getLegendItemTitle: entry => entry[labelKey],
63
+ getLegendItemSubtitle: entry => entry[valueKey]
64
+ })));
65
+ };
66
+ PieChart.propTypes = {
67
+ id: PropTypes.string,
68
+ className: PropTypes.string,
69
+ data: PropTypes.arrayOf(PropTypes.shape({
70
+ [PropTypes.string]: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
71
+ })).isRequired,
72
+ title: PropTypes.string.isRequired,
73
+ valueKey: PropTypes.string.isRequired,
74
+ labelKey: PropTypes.string.isRequired,
75
+ colors: PropTypes.arrayOf(PropTypes.string).isRequired,
76
+ height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
77
+ width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
78
+ innerRadius: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
79
+ outerRadius: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
80
+ };
81
+ PieChart.defaultProps = {
82
+ id: undefined,
83
+ className: undefined,
84
+ width: '100%',
85
+ height: 300,
86
+ innerRadius: '0%',
87
+ outerRadius: '100%'
88
+ };
89
+ export default PieChart;
@@ -0,0 +1 @@
1
+ export { default as PieChart } from "./PieChart";
@@ -0,0 +1,48 @@
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
+
8
+ .#{bem.$base} {
9
+ &.pie-chart {
10
+ background-color: var(--background-far);
11
+ border-radius: var(--theme-default-border-radius);
12
+ box-shadow: $default-box-shadow;
13
+ margin: $default-margin 0;
14
+ padding: $default-padding;
15
+
16
+ .chart-header {
17
+ align-items: center;
18
+ display: flex;
19
+ justify-content: space-between;
20
+ margin-bottom: $default-margin;
21
+
22
+ h3 {
23
+ color: var(--subtitle);
24
+ margin: calc($default-margin / 5);
25
+ text-align: left;
26
+ }
27
+ }
28
+
29
+ .chart-content {
30
+ align-items: flex-start;
31
+ display: flex;
32
+ }
33
+
34
+ .recharts-wrapper {
35
+ .recharts-surface {
36
+ .recharts-text {
37
+ fill: var(--soft-paragraph);
38
+ font-size: calc($default-text-font-size * .75);
39
+ }
40
+
41
+ .recharts-text.recharts-label {
42
+ fill: var(--paragraph);
43
+ font-size: $default-text-font-size;
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
@@ -1,2 +1,3 @@
1
1
  export { AreaChart } from "./AreaChart";
2
- export { BarChart } from "./BarChart";
2
+ export { BarChart } from "./BarChart";
3
+ export { PieChart } from "./PieChart";
@@ -4,6 +4,7 @@
4
4
  @use "@pareto-engineering/styles/src/mixins";
5
5
  @use "@pareto-engineering/styles/src/globals" as *;
6
6
 
7
+ $default-border: 1px solid var(--x);
7
8
  $default-padding: 1rem;
8
9
  $default-margin: 1rem;
9
10
  $default-border-radius: 1.5rem;
@@ -12,10 +13,11 @@ $default-height: var(--notification-height, 5rem);
12
13
 
13
14
  .#{bem.$base}.notification {
14
15
  align-items: center;
15
- background-color: var(--x);
16
+ background-color: var(--background-far);
17
+ border: $default-border;
16
18
  border-radius: $default-border-radius;
17
19
  bottom: 0;
18
- color: var(--on-x);
20
+ color: var(--paragraph);
19
21
  display: flex;
20
22
  justify-content: space-between;
21
23
  margin-bottom: $default-margin;
@@ -31,8 +33,16 @@ $default-height: var(--notification-height, 5rem);
31
33
  > .message-container {
32
34
  align-items: center;
33
35
  display: flex;
36
+ gap: $default-padding;
34
37
  overflow: auto;
35
38
 
39
+ > .icon {
40
+ background-color: var(--x);
41
+ border-radius: 50%;
42
+ color: var(--white);
43
+ padding: calc($default-padding / 2);
44
+ }
45
+
36
46
  > .message {
37
47
  font-size: calc(var(--s0) * 1rem);
38
48
  margin-left: calc($default-margin / 2);
@@ -44,12 +54,14 @@ $default-height: var(--notification-height, 5rem);
44
54
  }
45
55
 
46
56
  .#{bem.$base}.button {
57
+ background-color: transparent;
58
+ color: var(--paragraph);
47
59
  padding: calc($default-padding / 2);
48
60
 
49
- &:focus {
61
+ &:focus,
62
+ &:hover {
50
63
  background-color: transparent;
64
+ color: var(--hard-paragraph);
51
65
  }
52
66
  }
53
67
  }
54
-
55
-
@@ -28,4 +28,4 @@ export { ToggleSwitch } from "./ToggleSwitch";
28
28
  export { XMLEditor } from "./XMLEditor";
29
29
  export { DatePicker } from "./DatePicker";
30
30
  export { Tooltip } from "./Tooltip";
31
- export { AreaChart, BarChart } from "./Charts";
31
+ export { AreaChart, BarChart, PieChart } from "./Charts";
@@ -22,7 +22,7 @@ const FormInput = ({
22
22
  disabled,
23
23
  ...otherProps
24
24
  }) => {
25
- const newClassName = [className, componentClassName].filter(Boolean).join(' ');
25
+ const newClassName = [className, componentClassName, otherProps.hasCharacterLimit && otherProps.maxLength && `limit-character-count-${otherProps.maxLength}`].filter(Boolean).join(' ');
26
26
  if (type === 'textarea') {
27
27
  return /*#__PURE__*/React.createElement(TextareaInput, _extends({
28
28
  className: newClassName,
@@ -34,7 +34,7 @@ const LatexPreviewInput = ({
34
34
  const LatexPreview = useMemo(() => convertLatexToHtml(values[name]), [values[name]]);
35
35
  return /*#__PURE__*/React.createElement("div", {
36
36
  id: id,
37
- className: [baseClassName, componentClassName, userClassName, 'form-input'].filter(e => e).join(' '),
37
+ className: [baseClassName, componentClassName, className, userClassName, 'form-input'].filter(e => e).join(' '),
38
38
  style: style
39
39
  }, /*#__PURE__*/React.createElement(TextareaInput, _extends({
40
40
  className: "preview-child",
@@ -11,6 +11,7 @@ $default-margin: 1em;
11
11
 
12
12
  > .preview-child {
13
13
  flex: 1;
14
+ position: relative;
14
15
  }
15
16
 
16
17
  > .latex-container {
@@ -31,7 +31,8 @@ const TextareaInput = ({
31
31
  disabled,
32
32
  placeholder,
33
33
  autoComplete,
34
- resize
34
+ resize,
35
+ maxLength
35
36
  // ...otherProps
36
37
  }) => {
37
38
  const [field] = useField({
@@ -56,7 +57,8 @@ const TextareaInput = ({
56
57
  placeholder: placeholder,
57
58
  rows: rows,
58
59
  disabled: disabled,
59
- autoComplete: autoComplete
60
+ autoComplete: autoComplete,
61
+ maxLength: maxLength
60
62
  })), /*#__PURE__*/React.createElement(FormDescription, {
61
63
  className: "s-1",
62
64
  description: description,
@@ -53,6 +53,7 @@ const InputBuilder = ({
53
53
  const handleToggleShowSpecificFileTypes = () => {
54
54
  setFieldValue(`sections.${sectionIndex}.inputs.${inputIndex}.showSpecificFileTypes`, !input.showSpecificFileTypes);
55
55
  };
56
+ const textChoices = ['text', 'number', 'textarea', 'latex-preview-input'];
56
57
  return /*#__PURE__*/React.createElement("div", {
57
58
  id: id,
58
59
  className: [baseClassName, componentClassName, userClassName].filter(e => e).join(' '),
@@ -129,7 +130,32 @@ const InputBuilder = ({
129
130
  label: "Description (optional)",
130
131
  name: `sections.${sectionIndex}.inputs.${inputIndex}.description`,
131
132
  placeholder: "Describe details for the question"
132
- })), shouldRenderOptions && /*#__PURE__*/React.createElement(FieldArray, {
133
+ })), textChoices.includes(input?.type) && /*#__PURE__*/React.createElement("div", {
134
+ className: "character-limit-container"
135
+ }, /*#__PURE__*/React.createElement("div", {
136
+ className: "is-required"
137
+ }, /*#__PURE__*/React.createElement("span", {
138
+ className: "s0"
139
+ }, "Limit number of characters permitted for this input"), /*#__PURE__*/React.createElement(ToggleSwitch, {
140
+ handleOnChange: () => {
141
+ setFieldValue(`sections.${sectionIndex}.inputs.${inputIndex}.hasCharacterLimit`, !input?.hasCharacterLimit);
142
+ if (!input?.hasCharacterLimit) {
143
+ setFieldValue(`sections.${sectionIndex}.inputs.${inputIndex}.maxLength`, '');
144
+ }
145
+ },
146
+ checked: input?.hasCharacterLimit,
147
+ style: getToggleSwitchStyles(!input?.hasCharacterLimit),
148
+ inputId: `sections_${sectionIndex}_inputs.${inputIndex}_character_limit_toggle`
149
+ })), /*#__PURE__*/React.createElement("div", {
150
+ className: "character-limit-input"
151
+ }, input?.hasCharacterLimit && /*#__PURE__*/React.createElement(TextInput, {
152
+ label: "Enter the maximum number of characters permitted.",
153
+ name: `sections.${sectionIndex}.inputs.${inputIndex}.maxLength`,
154
+ placeholder: "",
155
+ type: "number",
156
+ validate: integerAndGreaterThanZero,
157
+ value: input?.maxLength
158
+ }))), shouldRenderOptions && /*#__PURE__*/React.createElement(FieldArray, {
133
159
  name: `sections.${sectionIndex}.inputs.${inputIndex}.options`
134
160
  }, ({
135
161
  push,
@@ -64,6 +64,21 @@ $default-list-width: var(--action-button-width, 18rem);
64
64
  margin-bottom: $default-margin;
65
65
  }
66
66
 
67
+ > .character-limit-container {
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: var(--gap);
71
+
72
+ > .is-required {
73
+ display: flex;
74
+ flex-direction: row;
75
+ }
76
+
77
+ > .character-limit-input {
78
+ flex-direction: column;
79
+ }
80
+ }
81
+
67
82
  > .input-options {
68
83
  display: flex;
69
84
  flex-direction: column;
@@ -49,7 +49,10 @@ const Section = ({
49
49
  inputs
50
50
  } = section;
51
51
  useEffect(() => {
52
- const items = inputs.map((input, indx) => ({
52
+ const orderMap = new Map();
53
+ section.orderedInputDragIds.forEach((identifier, indx) => orderMap.set(identifier, indx));
54
+ const orderedInputs = inputs.sort((a, b) => orderMap.get(a.name) - orderMap.get(b.name));
55
+ const items = orderedInputs.map((input, indx) => ({
53
56
  Content: /*#__PURE__*/React.createElement(InputBuilder, {
54
57
  key: input.name,
55
58
  sectionIndex: index,
@@ -61,6 +64,7 @@ const Section = ({
61
64
  }));
62
65
  setDraggableInputs(items);
63
66
  }, [inputs.length, index]);
67
+ const dragAndDropKey = draggableInputs.map(e => e.identifier).join(',');
64
68
  return /*#__PURE__*/React.createElement("div", {
65
69
  id: id,
66
70
  className: [baseClassName, componentClassName, userClassName].filter(e => e).join(' '),
@@ -92,7 +96,7 @@ const Section = ({
92
96
  const ids = reOrderedItems.map(e => e.identifier);
93
97
  setFieldValue(`sections.${index}.orderedInputDragIds`, ids);
94
98
  },
95
- key: draggableInputs.length
99
+ key: dragAndDropKey
96
100
  }), /*#__PURE__*/React.createElement("button", {
97
101
  type: "button",
98
102
  className: "add-question-cta",
@@ -10,6 +10,7 @@ import "./styles.scss";
10
10
 
11
11
  // Local Definitions
12
12
 
13
+ import { applyCharacterLimit } from "../../../../utils";
13
14
  import { Section } from "./common";
14
15
  const baseClassName = styleNames.base;
15
16
  const componentClassName = 'renderer';
@@ -134,6 +135,11 @@ const Renderer = ({
134
135
  onSave?.(formDataWithValues);
135
136
  }
136
137
  }, [values]);
138
+ useEffect(() => {
139
+ applyCharacterLimit({
140
+ setMaxLength: false
141
+ });
142
+ }, [values]);
137
143
  const hasErrors = Object.keys(errors).length > 0;
138
144
  return /*#__PURE__*/React.createElement(Form, null, updatedFormData.sections.map((section, sectionIndex) => sectionIndex === currentSectionIndex && /*#__PURE__*/React.createElement(Section, _extends({
139
145
  key: `${section.title}`
@@ -0,0 +1,67 @@
1
+ export const applyCharacterLimit = (setMaxLength = true) => {
2
+ setTimeout(() => {
3
+ document.querySelectorAll("[class*='limit-character-count-']").forEach(parent => {
4
+ const match = parent.className.match(/limit-character-count-(\d+)/);
5
+ if (!match) return;
6
+ const maxLength = parseInt(match[1], 10);
7
+ const fields = parent.matches("input[type='text'], input[type='email'], input[type='password'], input[type='search'], textarea") ? [parent] : Array.from(parent.querySelectorAll("input[type='text'], input[type='email'], input[type='password'], input[type='search'], textarea"));
8
+ if (!fields.length) return;
9
+ const characterCounterBaseClassName = 's-2 character-counter';
10
+ const characterCounterClassName = `${characterCounterBaseClassName} x-paragraph c-x`;
11
+ const characterCounterWarningClassName = `${characterCounterBaseClassName} x-orange c-x`;
12
+ const characterCounterErrorClassName = `${characterCounterBaseClassName} x-error c-x`;
13
+ fields.forEach(field => {
14
+ if (field.parentNode.querySelector('.character-counter')) return;
15
+ if (setMaxLength) {
16
+ field.setAttribute('maxlength', maxLength);
17
+ }
18
+ const counter = document.createElement('span');
19
+ counter.className = characterCounterClassName;
20
+ counter.style.position = 'absolute';
21
+ counter.style.right = '10px';
22
+ counter.style.bottom = '-20px';
23
+ counter.style.pointerEvents = 'none';
24
+ let wrapper;
25
+ const {
26
+ parentNode
27
+ } = field;
28
+ const computedStyle = window.getComputedStyle(parentNode);
29
+ if (parentNode.style && parentNode.style.position === 'relative' || computedStyle.getPropertyValue('position') === 'relative') {
30
+ wrapper = parentNode;
31
+ } else {
32
+ wrapper = document.createElement('div');
33
+ wrapper.style.position = 'relative';
34
+ wrapper.style.display = 'inline-block';
35
+ wrapper.style.width = '100%';
36
+ field.parentNode.insertBefore(wrapper, field);
37
+ wrapper.appendChild(field);
38
+ }
39
+ wrapper.appendChild(counter);
40
+ function updateCounter() {
41
+ if (field.value.length > maxLength) {
42
+ // eslint-disable-next-line no-param-reassign
43
+ field.value = field.value.substring(0, maxLength);
44
+ }
45
+ const {
46
+ length
47
+ } = field.value;
48
+ counter.textContent = `${length}/${maxLength}`;
49
+ if (length >= maxLength) {
50
+ counter.className = characterCounterErrorClassName;
51
+ } else if (length >= maxLength * 0.9) {
52
+ counter.className = characterCounterWarningClassName;
53
+ } else {
54
+ counter.className = characterCounterClassName;
55
+ }
56
+ }
57
+ field.removeEventListener('input', updateCounter);
58
+ field.removeEventListener('paste', updateCounter);
59
+ field.addEventListener('input', updateCounter);
60
+ field.addEventListener('paste', () => {
61
+ setTimeout(updateCounter, 0);
62
+ });
63
+ updateCounter();
64
+ });
65
+ });
66
+ }, 100); // Small delay to ensure DOM is ready
67
+ };
@@ -37,6 +37,9 @@ export const formatTime = seconds => {
37
37
  if (hours > 0) parts.push(`${hours}h`);
38
38
  if (minutes > 0 || hours > 0 && remainingSeconds > 0) parts.push(`${minutes}m`);
39
39
  if (remainingSeconds > 0) parts.push(`${remainingSeconds}s`);
40
+
41
+ // Cater for decimal seconds
42
+ if (parts.length === 0) return '0s';
40
43
  return parts.join(' ');
41
44
  };
42
45
  const parseDate = input => {
@@ -99,4 +102,8 @@ export const formatDate = (input, format = DATE_FORMATS.HUMAN_READABLE) => {
99
102
  } catch (error) {
100
103
  return 'Invalid Date';
101
104
  }
105
+ };
106
+ export const snakeCaseToTitleCase = word => {
107
+ const result = word.replace(/([A-Z])/g, ' $1');
108
+ return result.charAt(0).toUpperCase() + result.slice(1);
102
109
  };
@@ -1,2 +1,3 @@
1
1
  export { useWindowSize, useDynamicPosition, useOutsideClick } from "./hooks";
2
- export { formatTime, formatDate, DATE_FORMATS } from "./formatting";
2
+ export { formatTime, formatDate, DATE_FORMATS, snakeCaseToTitleCase } from "./formatting";
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.0.5",
3
+ "version": "5.1.0",
4
4
  "description": "",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/es/index.js",
@@ -59,7 +59,7 @@
59
59
  "@lexical/selection": "0.12.2",
60
60
  "@lexical/table": "0.12.2",
61
61
  "@lexical/utils": "0.12.2",
62
- "@pareto-engineering/assets": "^5.0.0",
62
+ "@pareto-engineering/assets": "^5.1.0",
63
63
  "@pareto-engineering/bem": "^5.0.0",
64
64
  "@pareto-engineering/styles": "^5.0.0",
65
65
  "@pareto-engineering/utils": "^5.0.0",
@@ -87,5 +87,5 @@
87
87
  "remark-math": "^6.0.0"
88
88
  },
89
89
  "browserslist": "> 2%",
90
- "gitHead": "d907245c47d1feee890e349bb9fa1d6d69b775d5"
90
+ "gitHead": "df984562befbec687e458242d3b8696ee7286d1e"
91
91
  }
@@ -4,7 +4,7 @@ import React from 'react'
4
4
  import { AreaChart } from 'ui'
5
5
 
6
6
  export default {
7
- title :'a/AreaChart',
7
+ title :'a/Charts/AreaChart',
8
8
  component:AreaChart,
9
9
  }
10
10
 
@@ -4,7 +4,7 @@ import React from 'react'
4
4
  import { BarChart } from 'ui'
5
5
 
6
6
  export default {
7
- title :'a/BarChart',
7
+ title :'a/Charts/BarChart',
8
8
  component:BarChart,
9
9
  }
10
10
 
@@ -0,0 +1,53 @@
1
+ import React from 'react'
2
+ import { PieChart } from 'ui'
3
+
4
+ export default {
5
+ title :'a/Charts/PieChart',
6
+ component:PieChart,
7
+ }
8
+
9
+ const data = [
10
+ { status: 'pendingReview', value: 230 },
11
+ { status: 'accepted', value: 350 },
12
+ { status: 'rejected', value: 80 },
13
+ { status: 'toRevise', value: 10 },
14
+ { status: 'revised', value: 60 },
15
+ ]
16
+
17
+ const Template = (args) => (
18
+ <div style={{ height: '100%', width: '100%' }}>
19
+ <PieChart {...args} />
20
+ </div>
21
+ )
22
+
23
+ export const Default = Template.bind({})
24
+ Default.args = {
25
+ data,
26
+ valueKey:'value',
27
+ labelKey:'status',
28
+ colors :['#8CB0F8', '#7F7CF6', '#FFD66E', '#E8E9ED', '#F6BC7E'],
29
+ height :400,
30
+ }
31
+
32
+ const TemplateSideBySide = (args) => (
33
+ <div style={{ display: 'flex', gap: '20px' }}>
34
+ <div style={{ flex: 1 }}>
35
+ {/* eslint-disable-next-line react/destructuring-assignment */}
36
+ <PieChart {...args[0]} />
37
+ </div>
38
+ <div style={{ flex: 1 }}>
39
+ {/* eslint-disable-next-line react/destructuring-assignment */}
40
+ <PieChart {...args[1]} />
41
+ </div>
42
+ </div>
43
+ )
44
+
45
+ export const SideBySide = TemplateSideBySide.bind({})
46
+ SideBySide.args = [
47
+ {
48
+ ...Default.args,
49
+ },
50
+ {
51
+ ...Default.args,
52
+ },
53
+ ]
@@ -50,18 +50,6 @@ const AreaChart = ({
50
50
 
51
51
  const [selectedYLabels, setSelectedYLabels] = useState(allYLabels)
52
52
 
53
- const processedData = data.map((item) => {
54
- const yValues = yKeys.map((key) => item[key])
55
- const lowerBound = Math.min(...yValues)
56
- const upperBound = Math.max(...yValues)
57
- const margin = (upperBound - lowerBound) * 0.1
58
- return {
59
- ...item,
60
- bounds:[lowerBound - margin, upperBound + margin],
61
- isTimeFormat,
62
- }
63
- })
64
-
65
53
  const yAxisBounds = () => {
66
54
  const yValues = data.map((item) => yKeys.map((key) => item[key]))
67
55
  const min = Math.min(...yValues.flat())
@@ -95,7 +83,7 @@ const AreaChart = ({
95
83
  capitalizedLegend={capitalizedLegend}
96
84
  />
97
85
  <ResponsiveContainer width={width} height={height}>
98
- <RechartsAreaChart data={processedData}>
86
+ <RechartsAreaChart data={data}>
99
87
  <CartesianGrid strokeDasharray="3 3" />
100
88
  <XAxis
101
89
  dataKey={xKey}
@@ -126,7 +114,13 @@ const AreaChart = ({
126
114
  return value.toFixed(2)
127
115
  }}
128
116
  />
129
- <Tooltip content={<CustomTooltipContent xLabel={xLabel} />} />
117
+ <Tooltip content={(
118
+ <CustomTooltipContent
119
+ dateFormat={dateFormat}
120
+ isTimeFormat={isTimeFormat}
121
+ />
122
+ )}
123
+ />
130
124
  {filled && (
131
125
  <Area
132
126
  id="bounds"
@@ -38,7 +38,8 @@ const BarChart = ({
38
38
  colors,
39
39
  height,
40
40
  width,
41
- // ...otherProps
41
+ isTimeFormat,
42
+ capitalizedLegend,
42
43
  }) => {
43
44
  const allYLabels = yKeys.map((key) => ({
44
45
  label:key,
@@ -69,6 +70,7 @@ const BarChart = ({
69
70
  <CustomLegend
70
71
  colorsArray={selectedYLabels.map((item) => item.color)}
71
72
  yKeysArray={selectedYLabels.map((item) => item.label)}
73
+ capitalizedLegend={capitalizedLegend}
72
74
  />
73
75
  <ResponsiveContainer width={width} height={height}>
74
76
  <RechartsBarChart data={data}>
@@ -87,7 +89,7 @@ const BarChart = ({
87
89
  axisLine={false}
88
90
  tickLine={false}
89
91
  />
90
- <Tooltip content={<CustomTooltipContent xLabel={xLabel} />} />
92
+ <Tooltip content={<CustomTooltipContent isTimeFormat={isTimeFormat} />} />
91
93
  {selectedYLabels.map((key) => (
92
94
  <Bar
93
95
  stackId="a"