jfs-components 0.0.84 → 0.0.85
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.
- package/CHANGELOG.md +29 -0
- package/lib/commonjs/components/AppBar/AppBar.js +36 -22
- package/lib/commonjs/components/AreaLineChart/AreaLineChart.js +866 -0
- package/lib/commonjs/components/AreaLineChart/chartMath.js +252 -0
- package/lib/commonjs/components/Attached/Attached.js +34 -4
- package/lib/commonjs/components/BubbleChart/BubbleChart.js +191 -0
- package/lib/commonjs/components/BubbleChart/bubblePacking.js +378 -0
- package/lib/commonjs/components/ClusterBubble/ClusterBubble.js +272 -0
- package/lib/commonjs/components/MetricLegendItem/MetricLegendItem.js +7 -1
- package/lib/commonjs/components/index.js +27 -0
- package/lib/commonjs/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/module/components/AppBar/AppBar.js +36 -22
- package/lib/module/components/AreaLineChart/AreaLineChart.js +859 -0
- package/lib/module/components/AreaLineChart/chartMath.js +242 -0
- package/lib/module/components/Attached/Attached.js +34 -4
- package/lib/module/components/BubbleChart/BubbleChart.js +185 -0
- package/lib/module/components/BubbleChart/bubblePacking.js +370 -0
- package/lib/module/components/ClusterBubble/ClusterBubble.js +267 -0
- package/lib/module/components/MetricLegendItem/MetricLegendItem.js +7 -1
- package/lib/module/components/index.js +3 -0
- package/lib/module/design-tokens/Coin Variables-variables-full.json +1 -1
- package/lib/module/icons/registry.js +1 -1
- package/lib/typescript/src/components/AreaLineChart/AreaLineChart.d.ts +212 -0
- package/lib/typescript/src/components/AreaLineChart/chartMath.d.ts +90 -0
- package/lib/typescript/src/components/BubbleChart/BubbleChart.d.ts +81 -0
- package/lib/typescript/src/components/BubbleChart/bubblePacking.d.ts +83 -0
- package/lib/typescript/src/components/ClusterBubble/ClusterBubble.d.ts +76 -0
- package/lib/typescript/src/components/MetricLegendItem/MetricLegendItem.d.ts +7 -1
- package/lib/typescript/src/components/index.d.ts +3 -0
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/AppBar/AppBar.tsx +37 -24
- package/src/components/AreaLineChart/AreaLineChart.tsx +1161 -0
- package/src/components/AreaLineChart/chartMath.ts +265 -0
- package/src/components/Attached/Attached.tsx +36 -5
- package/src/components/BubbleChart/BubbleChart.tsx +319 -0
- package/src/components/BubbleChart/bubblePacking.ts +397 -0
- package/src/components/ClusterBubble/ClusterBubble.tsx +359 -0
- package/src/components/MetricLegendItem/MetricLegendItem.tsx +20 -6
- package/src/components/index.ts +3 -0
- package/src/design-tokens/Coin Variables-variables-full.json +1 -1
- package/src/icons/registry.ts +1 -1
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import React, { useMemo, useState } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Pressable,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
Text,
|
|
6
|
+
View,
|
|
7
|
+
type LayoutChangeEvent,
|
|
8
|
+
type StyleProp,
|
|
9
|
+
type TextStyle,
|
|
10
|
+
type ViewStyle,
|
|
11
|
+
} from 'react-native'
|
|
12
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
|
|
13
|
+
import { useTokens } from '../../design-tokens/JFSThemeProvider'
|
|
14
|
+
import { EMPTY_MODES } from '../../utils/react-utils'
|
|
15
|
+
|
|
16
|
+
/** Where the value/label text sits relative to the circle. */
|
|
17
|
+
export type ClusterBubbleLabelPlacement = 'inside' | 'outside' | 'auto'
|
|
18
|
+
|
|
19
|
+
/** Which side of the circle an *outside* label is anchored to. */
|
|
20
|
+
export type ClusterBubbleLabelDirection = 'top' | 'bottom' | 'left' | 'right'
|
|
21
|
+
|
|
22
|
+
export type ClusterBubbleProps = {
|
|
23
|
+
/**
|
|
24
|
+
* The bold, primary content rendered in/under the bubble — e.g. `"40%"`,
|
|
25
|
+
* `"₹270K"`. Strings are auto-wrapped in a `<Text>`; pass a node for full
|
|
26
|
+
* control (e.g. a `MoneyValue`).
|
|
27
|
+
*/
|
|
28
|
+
value?: React.ReactNode
|
|
29
|
+
/** The secondary caption shown beside the value — e.g. `"Recommended"`. */
|
|
30
|
+
label?: React.ReactNode
|
|
31
|
+
/** Diameter of the circle in px. Defaults to `120`. */
|
|
32
|
+
size?: number
|
|
33
|
+
/**
|
|
34
|
+
* `Appearance / DataViz` mode used to resolve the fill from the
|
|
35
|
+
* `dataViz/bg` token (e.g. `Primary`, `Secondary`, `Tertiary`).
|
|
36
|
+
* Defaults to `Primary`. The *emphasis* of the fill is taken from the
|
|
37
|
+
* `Emphasis / DataViz` mode in `modes`.
|
|
38
|
+
*/
|
|
39
|
+
appearance?: string
|
|
40
|
+
/** Hard-override the circle fill color (bypasses token resolution). */
|
|
41
|
+
color?: string
|
|
42
|
+
/**
|
|
43
|
+
* Where the text sits. `inside` centers it within the circle, `outside`
|
|
44
|
+
* anchors it just beyond the circle's edge, and `auto` (default) picks
|
|
45
|
+
* `inside` when the bubble is at least `autoInsideMinSize` px, otherwise
|
|
46
|
+
* `outside`.
|
|
47
|
+
*/
|
|
48
|
+
labelPlacement?: ClusterBubbleLabelPlacement
|
|
49
|
+
/**
|
|
50
|
+
* Which side an *outside* label is placed on. The label is positioned
|
|
51
|
+
* exactly `labelGap` px beyond the circle's radius in this direction.
|
|
52
|
+
* Defaults to `bottom`.
|
|
53
|
+
*/
|
|
54
|
+
labelDirection?: ClusterBubbleLabelDirection
|
|
55
|
+
/** Gap in px between the circle's edge and an outside label. Defaults to `8`. */
|
|
56
|
+
labelGap?: number
|
|
57
|
+
/** Diameter (px) at/above which `auto` places the text inside. Defaults to `88`. */
|
|
58
|
+
autoInsideMinSize?: number
|
|
59
|
+
/**
|
|
60
|
+
* Text color when the label sits *inside*. Defaults to an automatic
|
|
61
|
+
* black/white choice based on the fill's luminance for legibility.
|
|
62
|
+
*/
|
|
63
|
+
insideTextColor?: string
|
|
64
|
+
/** Press handler — wraps the bubble in a `Pressable` when provided. */
|
|
65
|
+
onPress?: () => void
|
|
66
|
+
/** Style override for the value text. */
|
|
67
|
+
valueStyle?: StyleProp<TextStyle>
|
|
68
|
+
/** Style override for the label text. */
|
|
69
|
+
labelStyle?: StyleProp<TextStyle>
|
|
70
|
+
/** Style override for the circle view. */
|
|
71
|
+
circleStyle?: StyleProp<ViewStyle>
|
|
72
|
+
/** Style override for the outer container. */
|
|
73
|
+
style?: StyleProp<ViewStyle>
|
|
74
|
+
/** Design token modes for theming (e.g. `{ 'Color Mode': 'Light' }`). */
|
|
75
|
+
modes?: Record<string, any>
|
|
76
|
+
/** Accessibility label. Defaults to a `value + label` composite. */
|
|
77
|
+
accessibilityLabel?: string
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const DEFAULT_FILL = '#5d00b5'
|
|
81
|
+
|
|
82
|
+
/** Parse `#rgb`, `#rrggbb`, `rgb()` / `rgba()` into 0–255 channels. */
|
|
83
|
+
function parseColor(input: string): { r: number; g: number; b: number } | null {
|
|
84
|
+
if (typeof input !== 'string') return null
|
|
85
|
+
const value = input.trim()
|
|
86
|
+
|
|
87
|
+
if (value[0] === '#') {
|
|
88
|
+
let hex = value.slice(1)
|
|
89
|
+
if (hex.length === 3) {
|
|
90
|
+
hex = hex
|
|
91
|
+
.split('')
|
|
92
|
+
.map((ch) => ch + ch)
|
|
93
|
+
.join('')
|
|
94
|
+
}
|
|
95
|
+
if (hex.length >= 6) {
|
|
96
|
+
const r = parseInt(hex.slice(0, 2), 16)
|
|
97
|
+
const g = parseInt(hex.slice(2, 4), 16)
|
|
98
|
+
const b = parseInt(hex.slice(4, 6), 16)
|
|
99
|
+
if ([r, g, b].every((n) => Number.isFinite(n))) return { r, g, b }
|
|
100
|
+
}
|
|
101
|
+
return null
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const match = value.match(/rgba?\(([^)]+)\)/i)
|
|
105
|
+
if (match) {
|
|
106
|
+
const parts = match[1].split(',').map((p) => parseFloat(p))
|
|
107
|
+
if (parts.length >= 3 && parts.slice(0, 3).every((n) => Number.isFinite(n))) {
|
|
108
|
+
return { r: parts[0], g: parts[1], b: parts[2] }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return null
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Pick a legible foreground (near-black or white) for a given background. */
|
|
115
|
+
function readableTextColor(background: string): string {
|
|
116
|
+
const rgb = parseColor(background)
|
|
117
|
+
if (!rgb) return '#ffffff'
|
|
118
|
+
// Perceived luminance (ITU-R BT.601).
|
|
119
|
+
const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255
|
|
120
|
+
return luminance > 0.6 ? '#0f0d0a' : '#ffffff'
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* `ClusterBubble` is the atomic circle that composes a `BubbleChart`. It renders
|
|
125
|
+
* a single token-colored disc with a bold `value` and a secondary `label`. The
|
|
126
|
+
* text can sit inside the circle or anchor just outside its edge on any side
|
|
127
|
+
* (`labelDirection`) at a precise `labelGap` distance — so consumers (or the
|
|
128
|
+
* chart) can steer labels toward free space. The inside text color adapts to
|
|
129
|
+
* the fill for legibility. It is fully usable standalone.
|
|
130
|
+
*
|
|
131
|
+
* @component
|
|
132
|
+
*/
|
|
133
|
+
function ClusterBubble({
|
|
134
|
+
value,
|
|
135
|
+
label,
|
|
136
|
+
size = 120,
|
|
137
|
+
appearance = 'Primary',
|
|
138
|
+
color,
|
|
139
|
+
labelPlacement = 'auto',
|
|
140
|
+
labelDirection = 'bottom',
|
|
141
|
+
labelGap = 8,
|
|
142
|
+
autoInsideMinSize = 88,
|
|
143
|
+
insideTextColor,
|
|
144
|
+
onPress,
|
|
145
|
+
valueStyle,
|
|
146
|
+
labelStyle,
|
|
147
|
+
circleStyle,
|
|
148
|
+
style,
|
|
149
|
+
modes: propModes = EMPTY_MODES,
|
|
150
|
+
accessibilityLabel,
|
|
151
|
+
}: ClusterBubbleProps) {
|
|
152
|
+
const { modes: globalModes } = useTokens()
|
|
153
|
+
const modes = useMemo(() => ({ ...globalModes, ...propModes }), [globalModes, propModes])
|
|
154
|
+
|
|
155
|
+
// Emphasis is read from the `Emphasis / DataViz` mode (defaulting to the
|
|
156
|
+
// token's own default) rather than a dedicated prop.
|
|
157
|
+
const fill = useMemo(() => {
|
|
158
|
+
if (color) return color
|
|
159
|
+
return (
|
|
160
|
+
(getVariableByName('dataViz/bg', {
|
|
161
|
+
...modes,
|
|
162
|
+
'Appearance / DataViz': appearance,
|
|
163
|
+
}) as string | null) ?? DEFAULT_FILL
|
|
164
|
+
)
|
|
165
|
+
}, [color, modes, appearance])
|
|
166
|
+
|
|
167
|
+
const fontFamily =
|
|
168
|
+
(getVariableByName('text/fontFamily', modes) as string | null) ?? 'JioType'
|
|
169
|
+
const outsideTextColor =
|
|
170
|
+
(getVariableByName('text/foreground', modes) as string | null) ?? '#0f0d0a'
|
|
171
|
+
|
|
172
|
+
const placement: 'inside' | 'outside' =
|
|
173
|
+
labelPlacement === 'auto'
|
|
174
|
+
? size >= autoInsideMinSize
|
|
175
|
+
? 'inside'
|
|
176
|
+
: 'outside'
|
|
177
|
+
: labelPlacement
|
|
178
|
+
|
|
179
|
+
// Measure the outside label so it can be anchored precisely on any side
|
|
180
|
+
// without guessing its dimensions.
|
|
181
|
+
const [labelSize, setLabelSize] = useState<{ w: number; h: number } | null>(null)
|
|
182
|
+
const handleLabelLayout = (e: LayoutChangeEvent) => {
|
|
183
|
+
const { width, height } = e.nativeEvent.layout
|
|
184
|
+
setLabelSize((prev) =>
|
|
185
|
+
prev && Math.abs(prev.w - width) < 0.5 && Math.abs(prev.h - height) < 0.5
|
|
186
|
+
? prev
|
|
187
|
+
: { w: width, h: height }
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Default typography scales with the bubble when inside (so it fits the
|
|
192
|
+
// disc); fixed comfortable sizes when anchored outside.
|
|
193
|
+
const valueFontSize =
|
|
194
|
+
placement === 'inside' ? Math.round(Math.min(48, Math.max(13, size * 0.17))) : 24
|
|
195
|
+
const labelFontSize =
|
|
196
|
+
placement === 'inside' ? Math.round(Math.min(18, Math.max(10, size * 0.085))) : 14
|
|
197
|
+
|
|
198
|
+
const textColor =
|
|
199
|
+
placement === 'inside' ? insideTextColor ?? readableTextColor(fill) : outsideTextColor
|
|
200
|
+
|
|
201
|
+
const renderText = (
|
|
202
|
+
node: React.ReactNode,
|
|
203
|
+
baseStyle: TextStyle,
|
|
204
|
+
override: StyleProp<TextStyle>
|
|
205
|
+
) => {
|
|
206
|
+
if (node === undefined || node === null || node === false) return null
|
|
207
|
+
if (typeof node === 'string' || typeof node === 'number') {
|
|
208
|
+
return (
|
|
209
|
+
<Text style={[baseStyle, override]} numberOfLines={2}>
|
|
210
|
+
{node}
|
|
211
|
+
</Text>
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
return node
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const valueNode = renderText(
|
|
218
|
+
value,
|
|
219
|
+
{
|
|
220
|
+
color: textColor,
|
|
221
|
+
fontFamily,
|
|
222
|
+
fontSize: valueFontSize,
|
|
223
|
+
lineHeight: Math.round(valueFontSize * 1.15),
|
|
224
|
+
fontWeight: '700',
|
|
225
|
+
textAlign: 'center',
|
|
226
|
+
letterSpacing: -0.5,
|
|
227
|
+
},
|
|
228
|
+
valueStyle
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
const labelNode = renderText(
|
|
232
|
+
label,
|
|
233
|
+
{
|
|
234
|
+
color: textColor,
|
|
235
|
+
fontFamily,
|
|
236
|
+
fontSize: labelFontSize,
|
|
237
|
+
lineHeight: Math.round(labelFontSize * 1.3),
|
|
238
|
+
fontWeight: '400',
|
|
239
|
+
textAlign: 'center',
|
|
240
|
+
letterSpacing: -0.2,
|
|
241
|
+
},
|
|
242
|
+
labelStyle
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
const hasText = !!valueNode || !!labelNode
|
|
246
|
+
|
|
247
|
+
const textBlock = hasText ? (
|
|
248
|
+
<View style={styles.textBlock}>
|
|
249
|
+
{valueNode}
|
|
250
|
+
{labelNode}
|
|
251
|
+
</View>
|
|
252
|
+
) : null
|
|
253
|
+
|
|
254
|
+
const derivedA11y = [value, label]
|
|
255
|
+
.filter((v) => typeof v === 'string' || typeof v === 'number')
|
|
256
|
+
.join(', ')
|
|
257
|
+
const a11yLabel = accessibilityLabel ?? (derivedA11y || undefined)
|
|
258
|
+
|
|
259
|
+
const circle = (
|
|
260
|
+
<View
|
|
261
|
+
style={[
|
|
262
|
+
styles.circle,
|
|
263
|
+
{ width: size, height: size, borderRadius: size / 2, backgroundColor: fill },
|
|
264
|
+
circleStyle,
|
|
265
|
+
]}
|
|
266
|
+
>
|
|
267
|
+
{placement === 'inside' ? textBlock : null}
|
|
268
|
+
</View>
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
let content: React.ReactNode
|
|
272
|
+
if (placement === 'inside' || !textBlock) {
|
|
273
|
+
content = <View style={[styles.inlineContainer, style]}>{circle}</View>
|
|
274
|
+
} else {
|
|
275
|
+
// Anchor the label exactly `labelGap` beyond the radius on the chosen
|
|
276
|
+
// side. Hidden until measured to avoid a positioning flash.
|
|
277
|
+
const offset = labelOffset(labelDirection, size, labelGap, labelSize)
|
|
278
|
+
content = (
|
|
279
|
+
<View style={[{ width: size, height: size }, style]}>
|
|
280
|
+
{circle}
|
|
281
|
+
<View
|
|
282
|
+
onLayout={handleLabelLayout}
|
|
283
|
+
style={[
|
|
284
|
+
styles.outsideLabel,
|
|
285
|
+
{ left: offset.left, top: offset.top, opacity: labelSize ? 1 : 0 },
|
|
286
|
+
]}
|
|
287
|
+
pointerEvents="none"
|
|
288
|
+
>
|
|
289
|
+
{textBlock}
|
|
290
|
+
</View>
|
|
291
|
+
</View>
|
|
292
|
+
)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (onPress) {
|
|
296
|
+
return (
|
|
297
|
+
<Pressable
|
|
298
|
+
onPress={onPress}
|
|
299
|
+
accessibilityRole="button"
|
|
300
|
+
accessibilityLabel={a11yLabel}
|
|
301
|
+
style={({ pressed }) => (pressed ? styles.pressed : undefined)}
|
|
302
|
+
>
|
|
303
|
+
{content}
|
|
304
|
+
</Pressable>
|
|
305
|
+
)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
<View accessibilityRole="image" accessibilityLabel={a11yLabel}>
|
|
310
|
+
{content}
|
|
311
|
+
</View>
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** Compute the absolute `left/top` of the outside label box for a direction. */
|
|
316
|
+
function labelOffset(
|
|
317
|
+
direction: ClusterBubbleLabelDirection,
|
|
318
|
+
size: number,
|
|
319
|
+
gap: number,
|
|
320
|
+
labelSize: { w: number; h: number } | null
|
|
321
|
+
): { left: number; top: number } {
|
|
322
|
+
const center = size / 2
|
|
323
|
+
const w = labelSize?.w ?? 0
|
|
324
|
+
const h = labelSize?.h ?? 0
|
|
325
|
+
switch (direction) {
|
|
326
|
+
case 'top':
|
|
327
|
+
return { left: center - w / 2, top: -(gap + h) }
|
|
328
|
+
case 'bottom':
|
|
329
|
+
return { left: center - w / 2, top: size + gap }
|
|
330
|
+
case 'left':
|
|
331
|
+
return { left: -(gap + w), top: center - h / 2 }
|
|
332
|
+
case 'right':
|
|
333
|
+
return { left: size + gap, top: center - h / 2 }
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const styles = StyleSheet.create({
|
|
338
|
+
inlineContainer: {
|
|
339
|
+
alignItems: 'center',
|
|
340
|
+
},
|
|
341
|
+
circle: {
|
|
342
|
+
alignItems: 'center',
|
|
343
|
+
justifyContent: 'center',
|
|
344
|
+
overflow: 'hidden',
|
|
345
|
+
},
|
|
346
|
+
textBlock: {
|
|
347
|
+
alignItems: 'center',
|
|
348
|
+
justifyContent: 'center',
|
|
349
|
+
paddingHorizontal: 8,
|
|
350
|
+
},
|
|
351
|
+
outsideLabel: {
|
|
352
|
+
position: 'absolute',
|
|
353
|
+
},
|
|
354
|
+
pressed: {
|
|
355
|
+
opacity: 0.85,
|
|
356
|
+
},
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
export default ClusterBubble
|
|
@@ -22,6 +22,12 @@ export type MetricLegendItemProps = {
|
|
|
22
22
|
* `metricLegendItem/indicator/bg` design token.
|
|
23
23
|
*/
|
|
24
24
|
indicatorColor?: string
|
|
25
|
+
/**
|
|
26
|
+
* Shape of the leading indicator. `'dot'` (default) renders the small
|
|
27
|
+
* circle used in categorical legends; `'line'` renders a short
|
|
28
|
+
* horizontal bar, matching the legend of a line chart.
|
|
29
|
+
*/
|
|
30
|
+
indicatorShape?: 'dot' | 'line'
|
|
25
31
|
/** Design token modes for theming (e.g. `{ 'Color Mode': 'Light' }`). */
|
|
26
32
|
modes?: Record<string, any>
|
|
27
33
|
/** Override container styles. */
|
|
@@ -46,6 +52,7 @@ function MetricLegendItem({
|
|
|
46
52
|
label = 'Current (4 months)',
|
|
47
53
|
value,
|
|
48
54
|
indicatorColor,
|
|
55
|
+
indicatorShape = 'dot',
|
|
49
56
|
modes = EMPTY_MODES,
|
|
50
57
|
style,
|
|
51
58
|
indicatorStyle,
|
|
@@ -107,12 +114,19 @@ function MetricLegendItem({
|
|
|
107
114
|
>
|
|
108
115
|
<View
|
|
109
116
|
style={[
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
indicatorShape === 'line'
|
|
118
|
+
? {
|
|
119
|
+
width: indicatorSize * 2,
|
|
120
|
+
height: Math.max(2, Math.round(indicatorSize / 4)),
|
|
121
|
+
borderRadius: indicatorRadius,
|
|
122
|
+
backgroundColor: indicatorBg,
|
|
123
|
+
}
|
|
124
|
+
: {
|
|
125
|
+
width: indicatorSize,
|
|
126
|
+
height: indicatorSize,
|
|
127
|
+
borderRadius: indicatorRadius,
|
|
128
|
+
backgroundColor: indicatorBg,
|
|
129
|
+
},
|
|
116
130
|
indicatorStyle,
|
|
117
131
|
]}
|
|
118
132
|
/>
|
package/src/components/index.ts
CHANGED
|
@@ -110,6 +110,9 @@ export { default as RadioButton, type RadioButtonProps } from './RadioButton/Rad
|
|
|
110
110
|
export { default as RechargeCard, type RechargeCardProps } from './RechargeCard/RechargeCard';
|
|
111
111
|
export { default as SavingsGoalSummary, type SavingsGoalSummaryProps, type SavingsGoalSummaryItem } from './SavingsGoalSummary/SavingsGoalSummary';
|
|
112
112
|
export { default as DonutChart, type DonutChartProps, type DonutChartSegmentData, type DonutChartSegmentProps, DonutChartSegment } from './DonutChart/DonutChart';
|
|
113
|
+
export { default as AreaLineChart, useChart, type AreaLineChartProps, type ChartSeries, type ChartPoint, type ChartInset, type GoalPinConfig, type ChartGridProps, type ChartXAxisProps, type ChartYAxisProps, type ChartGoalPinProps } from './AreaLineChart/AreaLineChart';
|
|
114
|
+
export { default as ClusterBubble, type ClusterBubbleProps, type ClusterBubbleLabelPlacement, type ClusterBubbleLabelDirection } from './ClusterBubble/ClusterBubble';
|
|
115
|
+
export { default as BubbleChart, type BubbleChartProps, type BubbleDatum } from './BubbleChart/BubbleChart';
|
|
113
116
|
export { default as DonutChartSummary, type DonutChartSummaryProps, type DonutChartSummaryItem } from './DonutChartSummary/DonutChartSummary';
|
|
114
117
|
export { default as RangeTrack, type RangeTrackProps, type RangeTrackTab, type RangeTrackItem } from './RangeTrack/RangeTrack';
|
|
115
118
|
export { default as SegmentedTrack, type SegmentedTrackProps, type SegmentedTrackSegmentData, type SegmentedTrackSegmentProps, SegmentedTrackSegment } from './SegmentedTrack/SegmentedTrack';
|