@pareto-engineering/design-system 5.0.0 → 5.0.2

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 (123) hide show
  1. package/dist/cjs/a/{AreaChart → Charts/AreaChart}/AreaChart.js +89 -73
  2. package/dist/cjs/a/Charts/AreaChart/styles.scss +48 -0
  3. package/dist/cjs/a/Charts/BarChart/BarChart.js +137 -0
  4. package/dist/cjs/a/Charts/BarChart/index.js +13 -0
  5. package/dist/cjs/a/Charts/BarChart/styles.scss +48 -0
  6. package/dist/cjs/a/Charts/Common/CustomLegend/CustomLegend.js +88 -0
  7. package/dist/cjs/a/Charts/Common/CustomLegend/index.js +13 -0
  8. package/dist/cjs/a/Charts/Common/CustomLegend/styles.scss +67 -0
  9. package/dist/cjs/a/Charts/Common/CustomTooltipContent/CustomTooltipContent.js +97 -0
  10. package/dist/cjs/a/Charts/Common/CustomTooltipContent/index.js +13 -0
  11. package/dist/cjs/a/Charts/Common/CustomTooltipContent/styles.scss +22 -0
  12. package/dist/cjs/a/Charts/Common/YLabelsDropDown/YlabelsDropDown.js +97 -0
  13. package/dist/cjs/a/Charts/Common/YLabelsDropDown/index.js +13 -0
  14. package/dist/cjs/a/Charts/Common/YLabelsDropDown/styles.scss +89 -0
  15. package/dist/cjs/a/Charts/Common/index.js +26 -0
  16. package/dist/cjs/a/Charts/PieChart/PieChart.js +99 -0
  17. package/dist/cjs/a/Charts/PieChart/index.js +13 -0
  18. package/dist/cjs/a/Charts/PieChart/styles.scss +48 -0
  19. package/dist/cjs/a/Charts/index.js +26 -0
  20. package/dist/cjs/a/Tooltip/styles.scss +1 -1
  21. package/dist/cjs/a/index.js +14 -2
  22. package/dist/cjs/f/FormInput/FormInput.js +6 -0
  23. package/dist/cjs/f/fields/FileUpload/FileUpload.js +18 -4
  24. package/dist/cjs/f/fields/LatexPreviewInput/LatexPreviewInput.js +78 -0
  25. package/dist/cjs/f/fields/LatexPreviewInput/convertLatexToHtml.js +46 -0
  26. package/dist/cjs/f/fields/LatexPreviewInput/index.js +20 -0
  27. package/dist/cjs/f/fields/LatexPreviewInput/styles.scss +24 -0
  28. package/dist/cjs/f/fields/index.js +13 -0
  29. package/dist/cjs/g/FormBuilder/FormBuilder.js +3 -6
  30. package/dist/cjs/g/FormBuilder/common/Builder/Builder.js +1 -3
  31. package/dist/cjs/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.js +5 -7
  32. package/dist/cjs/g/FormBuilder/common/Builder/common/Section/Section.js +2 -4
  33. package/dist/cjs/g/FormBuilder/common/Renderer/Renderer.js +2 -4
  34. package/dist/cjs/g/FormBuilder/common/Renderer/common/Section/Section.js +2 -10
  35. package/dist/cjs/utils/formatting.js +119 -0
  36. package/dist/cjs/utils/index.js +26 -1
  37. package/dist/es/a/{AreaChart → Charts/AreaChart}/AreaChart.js +88 -69
  38. package/dist/es/a/Charts/AreaChart/styles.scss +48 -0
  39. package/dist/es/a/Charts/BarChart/BarChart.js +128 -0
  40. package/dist/es/a/Charts/BarChart/index.js +1 -0
  41. package/dist/es/a/Charts/BarChart/styles.scss +48 -0
  42. package/dist/es/a/Charts/Common/CustomLegend/CustomLegend.js +76 -0
  43. package/dist/es/a/Charts/Common/CustomLegend/index.js +1 -0
  44. package/dist/es/a/Charts/Common/CustomLegend/styles.scss +67 -0
  45. package/dist/es/a/Charts/Common/CustomTooltipContent/CustomTooltipContent.js +87 -0
  46. package/dist/es/a/Charts/Common/CustomTooltipContent/index.js +1 -0
  47. package/dist/es/a/Charts/Common/CustomTooltipContent/styles.scss +22 -0
  48. package/dist/es/a/Charts/Common/YLabelsDropDown/YlabelsDropDown.js +86 -0
  49. package/dist/es/a/Charts/Common/YLabelsDropDown/index.js +1 -0
  50. package/dist/es/a/Charts/Common/YLabelsDropDown/styles.scss +89 -0
  51. package/dist/es/a/Charts/Common/index.js +3 -0
  52. package/dist/es/a/Charts/PieChart/PieChart.js +89 -0
  53. package/dist/es/a/Charts/PieChart/index.js +1 -0
  54. package/dist/es/a/Charts/PieChart/styles.scss +48 -0
  55. package/dist/es/a/Charts/index.js +3 -0
  56. package/dist/es/a/Tooltip/styles.scss +1 -1
  57. package/dist/es/a/index.js +1 -1
  58. package/dist/es/f/FormInput/FormInput.js +7 -1
  59. package/dist/es/f/fields/FileUpload/FileUpload.js +18 -4
  60. package/dist/es/f/fields/LatexPreviewInput/LatexPreviewInput.js +70 -0
  61. package/dist/es/f/fields/LatexPreviewInput/convertLatexToHtml.js +31 -0
  62. package/dist/es/f/fields/LatexPreviewInput/index.js +3 -0
  63. package/dist/es/f/fields/LatexPreviewInput/styles.scss +24 -0
  64. package/dist/es/f/fields/index.js +1 -0
  65. package/dist/es/g/FormBuilder/FormBuilder.js +3 -6
  66. package/dist/es/g/FormBuilder/common/Builder/Builder.js +1 -3
  67. package/dist/es/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.js +5 -7
  68. package/dist/es/g/FormBuilder/common/Builder/common/Section/Section.js +2 -4
  69. package/dist/es/g/FormBuilder/common/Renderer/Renderer.js +2 -4
  70. package/dist/es/g/FormBuilder/common/Renderer/common/Section/Section.js +32 -42
  71. package/dist/es/utils/formatting.js +109 -0
  72. package/dist/es/utils/index.js +2 -1
  73. package/jest.config.js +3 -0
  74. package/package.json +7 -3
  75. package/src/stories/a/AreaChart.stories.jsx +1 -1
  76. package/src/stories/a/BarChart.stories.jsx +89 -0
  77. package/src/stories/a/PieChart.stories.jsx +53 -0
  78. package/src/ui/a/{AreaChart → Charts/AreaChart}/AreaChart.jsx +114 -65
  79. package/src/ui/a/Charts/AreaChart/styles.scss +48 -0
  80. package/src/ui/a/Charts/BarChart/BarChart.jsx +167 -0
  81. package/src/ui/a/Charts/BarChart/index.js +1 -0
  82. package/src/ui/a/Charts/BarChart/styles.scss +48 -0
  83. package/src/ui/a/Charts/Common/CustomLegend/CustomLegend.jsx +109 -0
  84. package/src/ui/a/Charts/Common/CustomLegend/index.js +1 -0
  85. package/src/ui/a/Charts/Common/CustomLegend/styles.scss +67 -0
  86. package/src/ui/a/Charts/Common/CustomTooltipContent/CustomTooltipContent.jsx +117 -0
  87. package/src/ui/a/Charts/Common/CustomTooltipContent/index.js +1 -0
  88. package/src/ui/a/Charts/Common/CustomTooltipContent/styles.scss +22 -0
  89. package/src/ui/a/Charts/Common/YLabelsDropDown/YlabelsDropDown.jsx +121 -0
  90. package/src/ui/a/Charts/Common/YLabelsDropDown/index.js +1 -0
  91. package/src/ui/a/Charts/Common/YLabelsDropDown/styles.scss +89 -0
  92. package/src/ui/a/Charts/Common/index.js +3 -0
  93. package/src/ui/a/Charts/PieChart/PieChart.jsx +125 -0
  94. package/src/ui/a/Charts/PieChart/index.js +1 -0
  95. package/src/ui/a/Charts/PieChart/styles.scss +48 -0
  96. package/src/ui/a/Charts/index.js +3 -0
  97. package/src/ui/a/Tooltip/styles.scss +1 -1
  98. package/src/ui/a/index.js +1 -1
  99. package/src/ui/f/FormInput/FormInput.jsx +11 -0
  100. package/src/ui/f/fields/FileUpload/FileUpload.jsx +24 -4
  101. package/src/ui/f/fields/LatexPreviewInput/LatexPreviewInput.jsx +91 -0
  102. package/src/ui/f/fields/LatexPreviewInput/convertLatexToHtml.jsx +38 -0
  103. package/src/ui/f/fields/LatexPreviewInput/index.js +3 -0
  104. package/src/ui/f/fields/LatexPreviewInput/styles.scss +24 -0
  105. package/src/ui/f/fields/index.js +4 -0
  106. package/src/ui/g/FormBuilder/FormBuilder.jsx +0 -3
  107. package/src/ui/g/FormBuilder/common/Builder/Builder.jsx +0 -2
  108. package/src/ui/g/FormBuilder/common/Builder/common/InputBuilder/InputBuilder.jsx +4 -7
  109. package/src/ui/g/FormBuilder/common/Builder/common/Section/Section.jsx +0 -2
  110. package/src/ui/g/FormBuilder/common/Renderer/Renderer.jsx +0 -2
  111. package/src/ui/g/FormBuilder/common/Renderer/common/Section/Section.jsx +49 -64
  112. package/src/ui/utils/formatting.js +133 -0
  113. package/src/ui/utils/index.js +3 -0
  114. package/tests/__snapshots__/Storyshots.test.js.snap +2227 -296
  115. package/tests/emptyMock.js +3 -0
  116. package/tests/mockTextEncoder.js +7 -0
  117. package/tests/test-setup.js +7 -0
  118. package/dist/cjs/a/AreaChart/styles.scss +0 -89
  119. package/dist/es/a/AreaChart/styles.scss +0 -89
  120. package/src/ui/a/AreaChart/styles.scss +0 -89
  121. /package/dist/cjs/a/{AreaChart → Charts/AreaChart}/index.js +0 -0
  122. /package/dist/es/a/{AreaChart → Charts/AreaChart}/index.js +0 -0
  123. /package/src/ui/a/{AreaChart → Charts/AreaChart}/index.js +0 -0
@@ -0,0 +1,91 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+ import * as React from 'react'
3
+
4
+ import { memo, useMemo } from 'react'
5
+
6
+ import PropTypes from 'prop-types'
7
+
8
+ import styleNames from '@pareto-engineering/bem/exports'
9
+
10
+ import { useFormikContext } from 'formik'
11
+
12
+ import convertLatexToHtml from './convertLatexToHtml'
13
+
14
+ import { TextareaInput } from '../TextareaInput'
15
+
16
+ import './styles.scss'
17
+
18
+ // Local Definitions
19
+
20
+ const baseClassName = styleNames.base
21
+
22
+ const componentClassName = 'latex-preview-input'
23
+
24
+ /**
25
+ * This is the component description.
26
+ */
27
+ const LatexPreviewInput = ({
28
+ id,
29
+ className,
30
+ userClassName,
31
+ disabled,
32
+ style,
33
+ ...otherProps
34
+ }) => {
35
+ const { name } = otherProps
36
+
37
+ const { values } = useFormikContext()
38
+
39
+ const LatexPreview = useMemo(() => convertLatexToHtml(values[name]), [values[name]])
40
+
41
+ return (
42
+ <div
43
+ id={id}
44
+ className={[
45
+ baseClassName,
46
+ componentClassName,
47
+ userClassName,
48
+ 'form-input',
49
+ ]
50
+ .filter((e) => e)
51
+ .join(' ')}
52
+ style={style}
53
+ >
54
+ <TextareaInput
55
+ className="preview-child"
56
+ disabled={disabled}
57
+ {...otherProps}
58
+ />
59
+ {/* eslint-disable-next-line react/no-danger */}
60
+ <div className="latex-container preview-child" dangerouslySetInnerHTML={{ __html: LatexPreview }} />
61
+ </div>
62
+ )
63
+ }
64
+
65
+ LatexPreviewInput.propTypes = {
66
+ /**
67
+ * The HTML id for this element
68
+ */
69
+ id:PropTypes.string,
70
+
71
+ /**
72
+ * The HTML class names for this element
73
+ */
74
+ className:PropTypes.string,
75
+
76
+ /**
77
+ * The React-written, css properties for this element.
78
+ */
79
+ style:PropTypes.objectOf(PropTypes.string),
80
+
81
+ /**
82
+ * Whether the Form input input should be disabled
83
+ */
84
+ disabled:PropTypes.bool,
85
+ }
86
+
87
+ LatexPreviewInput.defaultProps = {
88
+ disabled:false,
89
+ }
90
+
91
+ export default memo(LatexPreviewInput)
@@ -0,0 +1,38 @@
1
+ import * as React from 'react'
2
+
3
+ import ReactMarkdown from 'react-markdown'
4
+
5
+ import RemarkMathPlugin from 'remark-math'
6
+
7
+ import { MathJax, MathJaxContext } from 'better-react-mathjax'
8
+
9
+ import rehypeMathjax from 'rehype-mathjax/svg'
10
+
11
+ import ReactDOMServer from 'react-dom/server'
12
+
13
+ const convertLatexToHtml = (content) => {
14
+ if (content.includes('https://forte-assets.pareto.ai/')) {
15
+ return content
16
+ }
17
+
18
+ const processedContent = content.replaceAll(/\\\\/g, '\n\n')
19
+
20
+ const renderedContent = ReactDOMServer.renderToString(
21
+ <MathJaxContext>
22
+ <ReactMarkdown
23
+ remarkPlugins={[RemarkMathPlugin]}
24
+ rehypePlugins={[rehypeMathjax]}
25
+ components={{
26
+ math :({ value }) => <MathJax.Node formula={value} />,
27
+ inlineMath:({ value }) => <MathJax.Node inline formula={value} />,
28
+ }}
29
+ >
30
+ {processedContent}
31
+ </ReactMarkdown>
32
+ </MathJaxContext>,
33
+ )
34
+
35
+ return renderedContent
36
+ }
37
+
38
+ export default convertLatexToHtml
@@ -0,0 +1,3 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+ export { default as LatexPreviewInput } from './LatexPreviewInput'
3
+ export { default as convertLatexToHtml } from './convertLatexToHtml'
@@ -0,0 +1,24 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+
3
+ @use "@pareto-engineering/bem";
4
+
5
+ $default-margin: 1em;
6
+
7
+ .#{bem.$base}.latex-preview-input {
8
+ display: flex;
9
+ flex-direction: row;
10
+ gap: $default-margin;
11
+
12
+ > .preview-child {
13
+ flex: 1;
14
+ }
15
+
16
+ > .latex-container {
17
+ border: 1px solid var(--ui-lines);
18
+ border-radius: var(--theme-default-border-radius);
19
+ margin-top: calc($default-margin * 2.5);
20
+ max-width: 50%;
21
+ overflow: auto;
22
+ padding: 0 $default-margin;
23
+ }
24
+ }
@@ -9,6 +9,10 @@ export { Checkbox } from './Checkbox'
9
9
  export { QueryChoices } from './QueryChoices'
10
10
  export { LinkInput } from './LinkInput'
11
11
  export { EditorInput } from './EditorInput'
12
+ export {
13
+ LatexPreviewInput,
14
+ convertLatexToHtml,
15
+ } from './LatexPreviewInput'
12
16
  export {
13
17
  FileUpload,
14
18
  fileUploadOptions,
@@ -36,7 +36,6 @@ const FormBuilder = ({
36
36
  fileUploadStatus,
37
37
  handleFileDelete,
38
38
  taskData,
39
- customInputMap,
40
39
  // ...otherProps
41
40
  }) => {
42
41
  const formattedJson = JSON.stringify(taskData, null, 2)
@@ -68,7 +67,6 @@ const FormBuilder = ({
68
67
  onSave={onBuilderFormSave}
69
68
  onError={onBuilderError}
70
69
  validate={onBuilderValidate}
71
- customInputMap={customInputMap}
72
70
  />
73
71
  )}
74
72
  {mode === 'render' && (
@@ -80,7 +78,6 @@ const FormBuilder = ({
80
78
  fileUploadStatus={fileUploadStatus}
81
79
  handleFileDelete={handleFileDelete}
82
80
  onFileUpload={onFileUpload}
83
- customInputMap={customInputMap}
84
81
  />
85
82
  )}
86
83
  </div>
@@ -43,7 +43,6 @@ const Builder = ({
43
43
  onError,
44
44
  validate,
45
45
  formBuilderId,
46
- customInputMap,
47
46
  initialValues = {},
48
47
  // ...otherProps
49
48
  }) => {
@@ -126,7 +125,6 @@ const Builder = ({
126
125
  handleDeleteSection={() => handleDeleteSection({
127
126
  index, remove, values, setFieldValue,
128
127
  })}
129
- customInputMap={customInputMap}
130
128
  />
131
129
  ))}
132
130
  <div className="section-footer">
@@ -41,7 +41,6 @@ const InputBuilder = ({
41
41
  sectionIndex,
42
42
  inputIndex,
43
43
  onDelete,
44
- customInputMap,
45
44
  // ...otherProps
46
45
  }) => {
47
46
  const { values, setFieldValue } = useFormikContext()
@@ -71,8 +70,6 @@ const InputBuilder = ({
71
70
  setFieldValue(`sections.${sectionIndex}.inputs.${inputIndex}.showSpecificFileTypes`, !input.showSpecificFileTypes)
72
71
  }
73
72
 
74
- const customInputTypes = customInputMap ? Object.keys(customInputMap) : []
75
-
76
73
  return (
77
74
  <div
78
75
  id={id}
@@ -130,10 +127,10 @@ const InputBuilder = ({
130
127
  value:'file',
131
128
  label:'File upload',
132
129
  },
133
- ...(customInputTypes && customInputTypes.map((customInputKey) => ({
134
- value:customInputKey,
135
- label:customInputMap[customInputKey].label,
136
- }))),
130
+ {
131
+ value:'latex-preview-input',
132
+ label:'Textbox with LaTeX preview',
133
+ },
137
134
  ]}
138
135
  />
139
136
  <div className="controls">
@@ -36,7 +36,6 @@ const Section = ({
36
36
  style,
37
37
  index,
38
38
  handleDeleteSection,
39
- customInputMap,
40
39
  // ...otherProps
41
40
  }) => {
42
41
  const { values, setFieldValue } = useFormikContext()
@@ -70,7 +69,6 @@ const Section = ({
70
69
  inputIndex={indx}
71
70
  onDelete={handleDeleteInput}
72
71
  onCopy={handleCopyInput}
73
- customInputMap={customInputMap}
74
72
  />,
75
73
  identifier:input.name,
76
74
  }))
@@ -78,7 +78,6 @@ const Renderer = ({
78
78
  handleFileDelete,
79
79
  onFileUpload,
80
80
  shouldUpdateInputStateInRealTime = true,
81
- customInputMap,
82
81
  // ...otherProps
83
82
  }) => {
84
83
  const [currentSectionIndex, setCurrentSectionIndex] = useState(0)
@@ -179,7 +178,6 @@ const Renderer = ({
179
178
  handleFileDelete={handleFileDelete}
180
179
  onFileUpload={onFileUpload}
181
180
  sectionIndex={sectionIndex}
182
- customInputMap={customInputMap}
183
181
  />
184
182
  )
185
183
  ))}
@@ -40,71 +40,56 @@ const Section = ({
40
40
  handleFileDelete,
41
41
  onFileUpload,
42
42
  sectionIndex,
43
- customInputMap,
44
43
  // ...otherProps
45
- }) => {
46
- const customInputTypes = customInputMap ? Object.keys(customInputMap) : []
47
-
48
- return (
49
- <div
50
- id={id}
51
- className={[
52
- baseClassName,
53
- componentClassName,
54
- userClassName,
55
- ]
56
- .filter((e) => e)
57
- .join(' ')}
58
- style={style}
59
- >
60
- <p className="h3">{title}</p>
61
- <ExpandableLexicalPreview
62
- nodes={description}
63
- name="instructions"
64
- />
65
- {inputs?.map((input, inputIndex) => {
66
- const isFileInput = input.type === 'file'
67
- const isCustomInput = customInputTypes.includes(input.type)
68
- const CustomInputComponent = isCustomInput ? customInputMap[input.type].component : null
69
-
70
- return (
71
- !isCustomInput ? (
72
- <FormInput
73
- key={input.name}
74
- {...input}
75
- disabled={readOnly}
76
- {...(isFileInput && {
77
- uploadStatus:fileUploadStatus,
78
- handleFileDelete,
79
- onChange :(files) => {
80
- const filesToUpload = files
81
- ?.filter((file) => file instanceof File)
82
- .map((file) => ({
83
- file,
84
- name :file.name,
85
- mimeType:file.type,
86
- type :fileTypeMapper[getFileType(file)] || 'Generic',
87
- title :file.name,
88
- sectionIndex,
89
- inputIndex,
90
- }))
91
-
92
- onFileUpload(filesToUpload)
93
- },
94
- })}
95
- />
96
- ) : (
97
- <CustomInputComponent
98
- key={input.name}
99
- {...input}
100
- disabled={readOnly}
101
- />
102
- )
103
- )
104
- })}
105
- </div>
106
- )
107
- }
44
+ }) => (
45
+ <div
46
+ id={id}
47
+ className={[
48
+ baseClassName,
49
+ componentClassName,
50
+ userClassName,
51
+ ]
52
+ .filter((e) => e)
53
+ .join(' ')}
54
+ style={style}
55
+ >
56
+ <p className="h3">{title}</p>
57
+ <ExpandableLexicalPreview
58
+ nodes={description}
59
+ name="instructions"
60
+ />
61
+ {inputs?.map((input, inputIndex) => {
62
+ const isFileInput = input.type === 'file'
63
+
64
+ return (
65
+ <FormInput
66
+ key={input.name}
67
+ {...input}
68
+ disabled={readOnly}
69
+ {...(isFileInput && {
70
+ uploadStatus:fileUploadStatus,
71
+ handleFileDelete,
72
+ onChange :(files) => {
73
+ const filesToUpload = files
74
+ ?.filter((file) => file instanceof File)
75
+ .map((file) => ({
76
+ file,
77
+ name :file.name,
78
+ mimeType:file.type,
79
+ type :fileTypeMapper[getFileType(file)] || 'Generic',
80
+ title :file.name,
81
+ sectionIndex,
82
+ inputIndex,
83
+ }))
84
+
85
+ onFileUpload(filesToUpload)
86
+ },
87
+ })}
88
+ />
89
+ )
90
+ })}
91
+ </div>
92
+ )
108
93
 
109
94
  Section.propTypes = {
110
95
  /**
@@ -0,0 +1,133 @@
1
+ export const DATE_FORMATS = {
2
+ HUMAN_READABLE:'human_readable',
3
+ TIME :'time',
4
+ DATETIME :'datetime',
5
+ CHART_DATE :'chart_date',
6
+ CHART_TIME :'chart_time',
7
+ WEEKDAY_DATE :'weekday_date',
8
+ DAY_VIEW :'day_view',
9
+ }
10
+
11
+ const isValidDate = (date) => date instanceof Date && !Number.isNaN(date)
12
+
13
+ const isTimeSliceFormat = (input) => {
14
+ const timeSliceRegex = /^([01]?[0-9]|2[0-3]):[0-5][0-9]$/
15
+ return timeSliceRegex.test(input)
16
+ }
17
+
18
+ const createTimeFromSlice = (timeSlice) => {
19
+ const [hours, minutes] = timeSlice.split(':').map(Number)
20
+ const date = new Date()
21
+ date.setHours(hours, minutes, 0, 0)
22
+ return date
23
+ }
24
+
25
+ const format12Hour = (date) => {
26
+ const hour = date.getHours()
27
+ const ampm = hour >= 12 ? 'PM' : 'AM'
28
+ const hour12 = hour % 12 || 12
29
+ return `${hour12} ${ampm}`
30
+ }
31
+
32
+ const shouldShowYear = (date) => {
33
+ const currentYear = new Date().getFullYear()
34
+ return date.getFullYear() !== currentYear
35
+ }
36
+
37
+ export const formatTime = (seconds) => {
38
+ if (!seconds) return '0s'
39
+
40
+ const hours = Math.floor(seconds / 3600)
41
+ const minutes = Math.floor((seconds % 3600) / 60)
42
+ const remainingSeconds = Math.floor(seconds % 60)
43
+
44
+ const parts = []
45
+ if (hours > 0) parts.push(`${hours}h`)
46
+ if (minutes > 0 || (hours > 0 && remainingSeconds > 0)) parts.push(`${minutes}m`)
47
+ if (remainingSeconds > 0) parts.push(`${remainingSeconds}s`)
48
+
49
+ // Cater for decimal seconds
50
+ if (parts.length === 0) return '0s'
51
+
52
+ return parts.join(' ')
53
+ }
54
+
55
+ const parseDate = (input) => {
56
+ if (input instanceof Date) return input
57
+ if (typeof input === 'number') return new Date(input)
58
+
59
+ if (typeof input === 'string') {
60
+ if (isTimeSliceFormat(input)) {
61
+ return createTimeFromSlice(input)
62
+ }
63
+
64
+ const parsed = new Date(input)
65
+ if (isValidDate(parsed)) return parsed
66
+
67
+ const timestamp = parseInt(input, 10)
68
+ if (!Number.isNaN(timestamp)) {
69
+ const date = new Date(timestamp * 1000)
70
+ if (isValidDate(date)) return date
71
+ }
72
+ }
73
+
74
+ return null
75
+ }
76
+
77
+ const formatStrategies = {
78
+ [DATE_FORMATS.CHART_DATE]:(date) => {
79
+ const monthDay = date.toLocaleDateString('en-US', {
80
+ month :'short',
81
+ day :'numeric',
82
+ timeZone:'UTC',
83
+ })
84
+ return shouldShowYear(date)
85
+ ? `${monthDay} ${date.getFullYear()}`
86
+ : monthDay
87
+ },
88
+
89
+ [DATE_FORMATS.CHART_TIME]:(date) => format12Hour(date),
90
+
91
+ [DATE_FORMATS.HUMAN_READABLE]:(date) => date.toLocaleDateString('en-US', {
92
+ year :'numeric',
93
+ month :'short',
94
+ day :'numeric',
95
+ timeZone:'UTC',
96
+ }),
97
+
98
+ default:(date) => date.toISOString(),
99
+ }
100
+
101
+ export const formatDate = (input, format = DATE_FORMATS.HUMAN_READABLE) => {
102
+ try {
103
+ if (typeof input === 'string' && isTimeSliceFormat(input)) {
104
+ if (format === DATE_FORMATS.CHART_TIME || format === DATE_FORMATS.TIME) {
105
+ const date = createTimeFromSlice(input)
106
+ if (format === DATE_FORMATS.CHART_TIME) {
107
+ return format12Hour(date)
108
+ }
109
+ return date.toLocaleTimeString('en-US', {
110
+ hour :'2-digit',
111
+ minute :'2-digit',
112
+ timeZone:'UTC',
113
+ })
114
+ }
115
+ return input
116
+ }
117
+
118
+ const date = parseDate(input)
119
+ if (!date && (typeof input === 'string' || typeof input === 'number')) {
120
+ return input.toString()
121
+ }
122
+
123
+ const formatStrategy = formatStrategies[format] || formatStrategies.default
124
+ return formatStrategy(date)
125
+ } catch (error) {
126
+ return 'Invalid Date'
127
+ }
128
+ }
129
+
130
+ export const snakeCaseToTitleCase = (word) => {
131
+ const result = word.replace(/([A-Z])/g, ' $1')
132
+ return result.charAt(0).toUpperCase() + result.slice(1)
133
+ }
@@ -1 +1,4 @@
1
1
  export { useWindowSize, useDynamicPosition, useOutsideClick } from './hooks'
2
+ export {
3
+ formatTime, formatDate, DATE_FORMATS, snakeCaseToTitleCase,
4
+ } from './formatting'