@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
@@ -14,6 +14,64 @@ const baseClassName = styleNames.base
14
14
 
15
15
  const componentClassName = 'custom-tooltip-content'
16
16
 
17
+ const formatValue = (value, isTimeFormat) => {
18
+ if (isTimeFormat) {
19
+ return formatTime(value)
20
+ }
21
+
22
+ if (typeof value === 'number') {
23
+ return Number.isInteger(value) ? value : value.toFixed(2)
24
+ }
25
+
26
+ return value
27
+ }
28
+
29
+ const PayoutPieChartLabel = ({ entry, formatLabelValue }) => (
30
+ <div className="pie-chart-label">
31
+ <div className="status">
32
+ <span
33
+ className="dot"
34
+ style={{ backgroundColor: entry?.payload?.color }}
35
+ />
36
+ <p className="label" key={`${entry.name}`} style={{ color: entry.color, textTransform: 'capitalize' }}>
37
+ {`${snakeCaseToTitleCase(entry.name)} `}
38
+ </p>
39
+ </div>
40
+ <p className="value">
41
+ {`${formatLabelValue(entry.value)}`}
42
+ </p>
43
+ </div>
44
+ )
45
+
46
+ const StandardPieChartLabel = ({ entry, formatLabelValue }) => (
47
+ <>
48
+ <p>Submissions</p>
49
+ <div className="pie-chart-label">
50
+ <div className="status">
51
+ <span
52
+ className="dot"
53
+ style={{ backgroundColor: entry?.payload?.color }}
54
+ />
55
+ <p className="label" key={`${entry.name}`} style={{ color: entry.color, textTransform: 'capitalize' }}>
56
+ {`${snakeCaseToTitleCase(entry.name)} `}
57
+ </p>
58
+ </div>
59
+ <p className="value">
60
+ {`${formatLabelValue(entry.value)}`}
61
+ </p>
62
+ <p className="percentage-title">
63
+ {`${entry?.payload?.percentage}%`}
64
+ </p>
65
+ </div>
66
+ </>
67
+ )
68
+
69
+ const StandardChartLabel = ({ entry, formatLabelValue }) => (
70
+ <p className="label" key={`${entry.name}`} style={{ color: entry.color, textTransform: 'capitalize' }}>
71
+ {`${snakeCaseToTitleCase(entry.name)}: ${formatLabelValue(entry.value)}`}
72
+ </p>
73
+ )
74
+
17
75
  const CustomTooltipContent = ({
18
76
  id,
19
77
  className: userClassName,
@@ -24,131 +82,120 @@ const CustomTooltipContent = ({
24
82
  payload,
25
83
  label,
26
84
  isPieChart,
85
+ isPayOutChart,
27
86
  }) => {
28
- const formatLabelValue = (value) => {
29
- if (isTimeFormat) {
30
- return formatTime(value)
87
+ const formatLabelValue = React.useCallback(
88
+ (value) => formatValue(value, isTimeFormat),
89
+ [isTimeFormat],
90
+ )
91
+
92
+ const renderContent = React.useCallback((entry) => {
93
+ if (isPieChart && isPayOutChart) {
94
+ return <PayoutPieChartLabel entry={entry} formatLabelValue={formatLabelValue} />
31
95
  }
32
96
 
33
- if (typeof value === 'number') {
34
- if (Number.isInteger(value)) return value
35
- return value.toFixed(2)
97
+ if (isPieChart) {
98
+ return <StandardPieChartLabel entry={entry} formatLabelValue={formatLabelValue} />
36
99
  }
37
100
 
38
- return value
39
- }
101
+ return <StandardChartLabel entry={entry} formatLabelValue={formatLabelValue} />
102
+ }, [isPieChart, isPayOutChart, formatLabelValue])
40
103
 
41
- const renderContent = (entry) => {
42
- if (isPieChart) {
43
- return (
44
- <>
45
- <p>Submissions</p>
46
- <div className="pie-chart-label">
47
- <div className="status">
48
- <span
49
- className="dot"
50
- style={{ backgroundColor: entry?.payload?.color }}
51
- />
52
- <p className="label" key={`${entry.name}`} style={{ color: entry.color, textTransform: 'capitalize' }}>
53
- {`${snakeCaseToTitleCase(entry.name)} `}
54
- </p>
55
- </div>
56
- <p className="value">
57
- {`${formatLabelValue(entry.value)}`}
58
- </p>
59
- <p className="percentage-title">
60
- {`${entry?.payload?.percentage}%`}
61
- </p>
62
- </div>
63
- </>
64
- )
65
- }
66
- return (
67
- <p className="label" key={`${entry.name}`} style={{ color: entry.color, textTransform: 'capitalize' }}>
68
- {`${snakeCaseToTitleCase(entry.name)}: ${formatLabelValue(entry.value)}`}
69
- </p>
70
- )
104
+ if (!active || !payload || !payload.length) {
105
+ return null
71
106
  }
72
107
 
73
- if (active && payload && payload?.length) {
74
- const newPayload = payload.filter((item) => item?.name !== 'bounds')
75
- return (
76
- <div
77
- id={id}
78
- className={[
79
- baseClassName,
80
- componentClassName,
81
- userClassName,
82
- ]
83
- .filter((e) => e)
84
- .join(' ')}
85
- >
86
- <p className="label">
87
- {isDateValue ? formatDate(label, dateFormat) : label}
88
- </p>
89
- {newPayload.map((entry) => (
90
- renderContent(entry)
91
- ))}
92
- </div>
93
- )
94
- }
95
- return null
108
+ const filteredPayload = payload.filter((item) => item?.name !== 'bounds')
109
+
110
+ return (
111
+ <div
112
+ id={id}
113
+ className={[
114
+ baseClassName,
115
+ componentClassName,
116
+ userClassName,
117
+ ]
118
+ .filter(Boolean)
119
+ .join(' ')}
120
+ >
121
+ <p className="label">
122
+ {isDateValue ? formatDate(label, dateFormat) : label}
123
+ </p>
124
+ {filteredPayload.map((entry) => (
125
+ <React.Fragment key={entry.name || entry.dataKey}>
126
+ {renderContent(entry)}
127
+ </React.Fragment>
128
+ ))}
129
+ </div>
130
+ )
96
131
  }
97
132
 
98
133
  CustomTooltipContent.propTypes = {
99
134
  /**
100
- * The id of the dropdown component.
101
- */
135
+ * The id of the tooltip component
136
+ */
102
137
  id:PropTypes.string,
103
138
 
104
139
  /**
105
- * Additional class names for the dropdown component.
140
+ * Additional class names for the tooltip component
106
141
  */
107
142
  className:PropTypes.string,
108
143
 
109
144
  /**
110
- * Flag on whether it is a timeformat or not
145
+ * Flag indicating whether values should be formatted as time
111
146
  */
112
147
  isTimeFormat:PropTypes.bool,
113
148
 
114
149
  /**
115
- * The type of format for the datetime value
150
+ * The format to use for date values
116
151
  */
117
152
  dateFormat:PropTypes.oneOf(Object.values(DATE_FORMATS)),
118
153
 
119
154
  /**
120
- * Flag on whether the label is a date value or not
155
+ * Flag indicating whether the label is a date value
121
156
  */
122
157
  isDateValue:PropTypes.bool,
123
158
 
124
159
  /**
125
- * If set true, the tooltip is displayed.
126
- * If set false, the tooltip is hidden, usually calculated internally.
160
+ * If true, the tooltip is displayed
127
161
  */
128
162
  active:PropTypes.bool.isRequired,
129
163
 
130
164
  /**
131
- * The source data of the content to be displayed in the tooltip,
132
- * always calculated internally and cannot be user set.
165
+ * The source data to be displayed in the tooltip
133
166
  */
134
- payload:PropTypes.arrayOf(PropTypes.string).isRequired,
167
+ payload:PropTypes.arrayOf(PropTypes.shape({
168
+ name :PropTypes.string,
169
+ value :PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
170
+ payload:PropTypes.shape({}),
171
+ dataKey:PropTypes.string,
172
+ color :PropTypes.string,
173
+ })).isRequired,
135
174
 
136
175
  /**
137
- *The label value which is active now, usually calculated internally.
176
+ * The label value which is active
138
177
  */
139
178
  label:PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
140
179
 
141
180
  /**
142
- * Flag on whether the chart is a pie chart or not
181
+ * Flag indicating whether the chart is a pie chart
143
182
  */
144
183
  isPieChart:PropTypes.bool,
184
+
185
+ /**
186
+ * Flag indicating whether the chart is a payout chart
187
+ */
188
+ isPayOutChart:PropTypes.bool,
145
189
  }
146
190
 
147
191
  CustomTooltipContent.defaultProps = {
148
- isTimeFormat:false,
149
- isDateValue :true,
150
- dateFormat :DATE_FORMATS.HUMAN_READABLE,
151
- isPieChart :false,
192
+ id :undefined,
193
+ className :undefined,
194
+ isTimeFormat :false,
195
+ isDateValue :true,
196
+ dateFormat :DATE_FORMATS.HUMAN_READABLE,
197
+ isPieChart :false,
198
+ isPayOutChart:false,
152
199
  }
153
200
 
154
- export default CustomTooltipContent
201
+ export default React.memo(CustomTooltipContent)
@@ -32,14 +32,19 @@ const PieChart = ({
32
32
  width,
33
33
  innerRadius,
34
34
  outerRadius,
35
+ formatTotal,
36
+ subtitleToCurrency,
37
+ isPayOutChart,
35
38
  }) => {
36
39
  const total = data.reduce((sum, item) => sum + item[valueKey], 0)
37
40
 
41
+ const displayTotal = formatTotal ? formatTotal(total) : `${total}`
42
+
38
43
  const formattedData = data.map((item) => ({
39
44
  ...item,
40
45
  label :item[labelKey],
41
46
  color :colors[data.indexOf(item)],
42
- percentage:((item[valueKey] / total) * 100).toFixed(0),
47
+ percentage:total === 0 ? 0.0 : ((item[valueKey] / total) * 100).toFixed(0),
43
48
  }))
44
49
 
45
50
  return (
@@ -78,7 +83,15 @@ const PieChart = ({
78
83
  />
79
84
  ))}
80
85
  </Pie>
81
- <Tooltip content={<CustomTooltipContent isDateValue={false} isPieChart />} />
86
+ <Tooltip
87
+ content={(
88
+ <CustomTooltipContent
89
+ isDateValue={false}
90
+ isPieChart
91
+ isPayOutChart={isPayOutChart}
92
+ />
93
+ )}
94
+ />
82
95
 
83
96
  <text
84
97
  x="50%"
@@ -92,7 +105,7 @@ const PieChart = ({
92
105
  Total
93
106
  </tspan>
94
107
  <tspan x="50%" dy="1.2em" fill="var(--heading)" fontSize="22">
95
- {`${total}`}
108
+ {displayTotal}
96
109
  </tspan>
97
110
  </text>
98
111
  </RechartsPieChart>
@@ -105,6 +118,8 @@ const PieChart = ({
105
118
  orientation="vertical"
106
119
  getLegendItemTitle={(entry) => entry[labelKey]}
107
120
  getLegendItemSubtitle={(entry) => entry[valueKey]}
121
+ subtitleToCurrency={subtitleToCurrency}
122
+ isPayOutChart={isPayOutChart}
108
123
  />
109
124
  </div>
110
125
  </div>
@@ -120,23 +135,29 @@ PieChart.propTypes = {
120
135
  PropTypes.number,
121
136
  ]),
122
137
  })).isRequired,
123
- title :PropTypes.string.isRequired,
124
- valueKey :PropTypes.string.isRequired,
125
- labelKey :PropTypes.string.isRequired,
126
- colors :PropTypes.arrayOf(PropTypes.string).isRequired,
127
- height :PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
128
- width :PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
129
- innerRadius:PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
130
- outerRadius:PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
138
+ title :PropTypes.string.isRequired,
139
+ valueKey :PropTypes.string.isRequired,
140
+ labelKey :PropTypes.string.isRequired,
141
+ colors :PropTypes.arrayOf(PropTypes.string).isRequired,
142
+ height :PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
143
+ width :PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
144
+ innerRadius :PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
145
+ outerRadius :PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
146
+ formatTotal :PropTypes.func,
147
+ subtitleToCurrency:PropTypes.bool,
148
+ isPayOutChart :PropTypes.bool,
131
149
  }
132
150
 
133
151
  PieChart.defaultProps = {
134
- id :undefined,
135
- className :undefined,
136
- width :'100%',
137
- height :300,
138
- innerRadius:'50%',
139
- outerRadius:'100%',
152
+ id :undefined,
153
+ className :undefined,
154
+ width :'100%',
155
+ height :300,
156
+ innerRadius :'50%',
157
+ outerRadius :'100%',
158
+ formatTotal :null,
159
+ subtitleToCurrency:false,
160
+ isPayOutChart :false,
140
161
  }
141
162
 
142
163
  export default PieChart
@@ -0,0 +1,90 @@
1
+ import * as React from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import styleNames from '@pareto-engineering/bem/exports'
5
+
6
+ import './styles.scss'
7
+
8
+ // Local Definitions
9
+ const baseClassName = styleNames.base
10
+ const componentClassName = 'throughput-indicator'
11
+
12
+ const ThroughPutIndicator = ({ data, keyName = 'reserved' }) => {
13
+ const renderNoChange = () => (
14
+ <div
15
+ className={[
16
+ baseClassName,
17
+ componentClassName,
18
+ ]
19
+ .filter((e) => e)
20
+ .join(' ')}
21
+ >
22
+ <span className="no-change-text">No change</span>
23
+ </div>
24
+ )
25
+
26
+ const renderChange = (direction, percentage, icon = direction === 'positive' ? 'S' : 'R') => (
27
+ <div
28
+ className={[
29
+ baseClassName,
30
+ componentClassName,
31
+ ]
32
+ .filter((e) => e)
33
+ .join(' ')}
34
+ >
35
+ <span className={`ai-icon ${direction}-throughput-indicator`}>{icon}</span>
36
+ <p>
37
+ {percentage}
38
+ %
39
+ </p>
40
+ </div>
41
+ )
42
+
43
+ // Handle invalid or insufficient data
44
+ if (!data || data.length < 2) {
45
+ return renderNoChange()
46
+ }
47
+
48
+ const first = data[0][keyName]
49
+ const last = data[data.length - 1][keyName]
50
+
51
+ // Handle no change scenarios
52
+ if (first === 0 && last === 0) {
53
+ return renderNoChange()
54
+ }
55
+
56
+ // Handle special case: starting from zero
57
+ if (first === 0 && last !== 0) {
58
+ return renderChange('positive', '100')
59
+ }
60
+
61
+ // Calculate percentage change
62
+ const percentChange = ((last - first) / Math.abs(first)) * 100
63
+ const rounded = Math.abs(percentChange).toFixed(1)
64
+
65
+ // No change
66
+ if (percentChange === 0) {
67
+ return renderNoChange()
68
+ }
69
+
70
+ // Positive or negative change
71
+ const direction = percentChange > 0 ? 'positive' : 'negative'
72
+ const icon = direction === 'positive' ? 'S' : 'R'
73
+
74
+ return renderChange(direction, rounded, icon)
75
+ }
76
+
77
+ ThroughPutIndicator.propTypes = {
78
+ /**
79
+ * The data to be displayed in the throughput indicator
80
+ */
81
+ // eslint-disable-next-line react/forbid-prop-types
82
+ data:PropTypes.arrayOf(PropTypes.object).isRequired,
83
+
84
+ /**
85
+ * The key name to be displayed in the throughput indicator
86
+ */
87
+ keyName:PropTypes.string,
88
+ }
89
+
90
+ export default ThroughPutIndicator
@@ -0,0 +1,2 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+ export { default as ThroughPutIndicator } from './ThroughPutIndicator'
@@ -0,0 +1,35 @@
1
+ /* @pareto-engineering/generator-front 1.0.12 */
2
+
3
+ @use "@pareto-engineering/bem";
4
+
5
+ $default-text-font-size: calc(var(--s-1) * 1rem);
6
+
7
+ .#{bem.$base} {
8
+ .throughput-indicator {
9
+ align-items: center;
10
+ border: 1px solid var(--hard-grey);
11
+ border-radius: 2rem;
12
+ display: flex;
13
+ gap: .5rem;
14
+ height: 3rem;
15
+ padding: .5rem;
16
+
17
+ .positive-throughput-indicator {
18
+ color: var(--success);
19
+ font-size: 1rem;
20
+ }
21
+
22
+ .negative-throughput-indicator {
23
+ color: var(--error);
24
+ font-size: .75rem;
25
+ }
26
+
27
+ .no-change-text {
28
+ color: var(--paragraph);
29
+ }
30
+
31
+ p {
32
+ font-size: 1rem;
33
+ }
34
+ }
35
+ }
@@ -51,7 +51,7 @@ const ToggleSwitch = ({
51
51
  onChange={handleOnChange}
52
52
  />
53
53
  {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
54
- <label htmlFor={inputId} />
54
+ <label htmlFor={inputId} className={checked ? 'checked' : ''} />
55
55
  </button>
56
56
  )
57
57
 
@@ -7,7 +7,7 @@ $default-size: var(--size, 1.2em);
7
7
  $default-slider-color: var(--slider-color, var(--background-far));
8
8
  $default-slider-border-color: var(--slider-border-color, var(--ui-lines));
9
9
  $default-background-color: var(--slider-background-color, var(--interactive));
10
-
10
+ $default-background-disabled: var(--disabled, var(--background-far));
11
11
  .#{bem.$base}.toggle-switch {
12
12
  background: transparent;
13
13
  border: none;
@@ -21,7 +21,6 @@ $default-background-color: var(--slider-background-color, var(--interactive));
21
21
  }
22
22
 
23
23
  >label {
24
- background: $default-background-color;
25
24
  border-radius: $default-border-radius;
26
25
  cursor: pointer;
27
26
  display: block;
@@ -29,6 +28,14 @@ $default-background-color: var(--slider-background-color, var(--interactive));
29
28
  position: relative;
30
29
  width: calc($default-size * 2);
31
30
 
31
+ &.checked {
32
+ background: $default-background-color;
33
+ }
34
+
35
+ &:not(.checked) {
36
+ background: $default-background-disabled;
37
+ }
38
+
32
39
  &::after {
33
40
  background: $default-slider-color;
34
41
  border: 1px solid $default-slider-border-color;
@@ -1,5 +1,6 @@
1
1
  /* @pareto-engineering/generator-front 1.0.12 */
2
2
  import * as React from 'react'
3
+ import { useEffect } from 'react'
3
4
 
4
5
  import PropTypes from 'prop-types'
5
6
 
@@ -21,40 +22,63 @@ const Tooltip = ({
21
22
  className:userClassName,
22
23
  style,
23
24
  position,
25
+ isFloating,
24
26
  color,
25
27
  description,
26
28
  content,
27
29
  children,
28
30
  // ...otherProps
29
- }) => (
30
- <div
31
- id={id}
32
- className={[
33
- baseClassName,
34
- componentClassName,
35
- userClassName,
36
- `x-${color}`,
37
- ]
38
- .filter((e) => e)
39
- .join(' ')}
40
- style={style}
41
-
42
- >
43
- <div
44
- className="tooltip-trigger-wrapper"
45
- aria-describedby={description}
46
- >
47
- {children}
48
- </div>
31
+ }) => {
32
+ useEffect(() => {
33
+ const handleMouseMove = (e) => {
34
+ document.documentElement.style.setProperty('--mouse-x', `${e.clientX}px`)
35
+ document.documentElement.style.setProperty('--mouse-y', `${e.clientY}px`)
36
+ }
37
+
38
+ if (!isFloating) {
39
+ return () => window.removeEventListener('mousemove', handleMouseMove)
40
+ }
41
+
42
+ window.addEventListener('mousemove', handleMouseMove)
43
+
44
+ return () => window.removeEventListener('mousemove', handleMouseMove)
45
+ }, [isFloating])
46
+
47
+ return (
49
48
  <div
50
- className={`tooltip-content ${position}`}
51
- role="tooltip"
52
- id={description}
49
+ id={id}
50
+ className={[
51
+ baseClassName,
52
+ componentClassName,
53
+ userClassName,
54
+ `x-${color}`,
55
+ ]
56
+ .filter((e) => e)
57
+ .join(' ')}
58
+ style={style}
53
59
  >
54
- {content}
60
+ <div
61
+ className="tooltip-trigger-wrapper"
62
+ aria-describedby={description}
63
+ >
64
+ {children}
65
+ </div>
66
+ <div
67
+ className={[
68
+ 'tooltip-content',
69
+ position,
70
+ isFloating ? 'floating' : '',
71
+ ]
72
+ .filter((e) => e)
73
+ .join(' ')}
74
+ role="tooltip"
75
+ id={description}
76
+ >
77
+ {content}
78
+ </div>
55
79
  </div>
56
- </div>
57
- )
80
+ )
81
+ }
58
82
 
59
83
  Tooltip.propTypes = {
60
84
  /**
@@ -92,6 +116,11 @@ Tooltip.propTypes = {
92
116
  */
93
117
  position:PropTypes.oneOf(['top', 'bottom', 'left', 'right']),
94
118
 
119
+ /**
120
+ * Whether or not the tooltip should be floating
121
+ */
122
+ isFloating:PropTypes.bool,
123
+
95
124
  /**
96
125
  * The base color of the tooltip
97
126
  */