@coinbase/cds-mobile-visualization 3.4.0-beta.13 → 3.4.0-beta.15

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 (41) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dts/chart/CartesianChart.d.ts +35 -1
  3. package/dts/chart/CartesianChart.d.ts.map +1 -1
  4. package/dts/chart/bar/Bar.d.ts +4 -0
  5. package/dts/chart/bar/Bar.d.ts.map +1 -1
  6. package/dts/chart/bar/BarChart.d.ts +6 -3
  7. package/dts/chart/bar/BarChart.d.ts.map +1 -1
  8. package/dts/chart/bar/BarStack.d.ts +11 -2
  9. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  10. package/dts/chart/index.d.ts +1 -0
  11. package/dts/chart/index.d.ts.map +1 -1
  12. package/dts/chart/legend/DefaultLegendEntry.d.ts +5 -0
  13. package/dts/chart/legend/DefaultLegendEntry.d.ts.map +1 -0
  14. package/dts/chart/legend/DefaultLegendShape.d.ts +5 -0
  15. package/dts/chart/legend/DefaultLegendShape.d.ts.map +1 -0
  16. package/dts/chart/legend/Legend.d.ts +168 -0
  17. package/dts/chart/legend/Legend.d.ts.map +1 -0
  18. package/dts/chart/legend/index.d.ts +4 -0
  19. package/dts/chart/legend/index.d.ts.map +1 -0
  20. package/dts/chart/line/LineChart.d.ts.map +1 -1
  21. package/dts/chart/scrubber/Scrubber.d.ts +8 -0
  22. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
  23. package/dts/chart/utils/chart.d.ts +18 -0
  24. package/dts/chart/utils/chart.d.ts.map +1 -1
  25. package/esm/chart/CartesianChart.js +40 -10
  26. package/esm/chart/PeriodSelector.js +5 -1
  27. package/esm/chart/__stories__/CartesianChart.stories.js +3 -3
  28. package/esm/chart/__stories__/PeriodSelector.stories.js +24 -0
  29. package/esm/chart/bar/Bar.js +2 -0
  30. package/esm/chart/bar/BarStack.js +8 -1
  31. package/esm/chart/index.js +1 -0
  32. package/esm/chart/legend/DefaultLegendEntry.js +42 -0
  33. package/esm/chart/legend/DefaultLegendShape.js +64 -0
  34. package/esm/chart/legend/Legend.js +59 -0
  35. package/esm/chart/legend/__stories__/Legend.stories.js +574 -0
  36. package/esm/chart/legend/index.js +3 -0
  37. package/esm/chart/line/LineChart.js +2 -1
  38. package/esm/chart/line/__stories__/LineChart.stories.js +37 -4
  39. package/esm/chart/scrubber/Scrubber.js +2 -1
  40. package/esm/chart/utils/chart.js +13 -0
  41. package/package.json +5 -5
@@ -0,0 +1,574 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import { memo, useCallback, useMemo, useState } from 'react';
3
+ import { ScrollView } from 'react-native';
4
+ import { Chip } from '@coinbase/cds-mobile/chips';
5
+ import { Example, ExampleScreen } from '@coinbase/cds-mobile/examples/ExampleScreen';
6
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
7
+ import { Box, HStack, VStack } from '@coinbase/cds-mobile/layout';
8
+ import { TextLabel1, TextLabel2 } from '@coinbase/cds-mobile/typography';
9
+ import { Canvas, Group, Path as SkiaPath, Skia } from '@shopify/react-native-skia';
10
+ import { XAxis, YAxis } from '../../axis';
11
+ import { BarChart, BarPlot, DefaultBar } from '../../bar';
12
+ import { CartesianChart } from '../../CartesianChart';
13
+ import { LineChart } from '../../line';
14
+ import { Scrubber } from '../../scrubber';
15
+ import { getDottedAreaPath } from '../../utils/path';
16
+ import { DefaultLegendShape } from '../DefaultLegendShape';
17
+ import { Legend } from '../Legend';
18
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
19
+ const spectrumColors = ['blue40', 'green40', 'orange40', 'yellow40', 'gray40', 'indigo40', 'pink40', 'purple40', 'red40', 'teal40'];
20
+ const shapes = ['pill', 'circle', 'squircle', 'square'];
21
+ const Shapes = () => {
22
+ const theme = useTheme();
23
+ return /*#__PURE__*/_jsx(VStack, {
24
+ gap: 2,
25
+ children: shapes.map(shape => /*#__PURE__*/_jsx(HStack, {
26
+ gap: 1,
27
+ children: spectrumColors.map(color => /*#__PURE__*/_jsx(Box, {
28
+ style: {
29
+ width: 10,
30
+ justifyContent: 'center'
31
+ },
32
+ children: /*#__PURE__*/_jsx(DefaultLegendShape, {
33
+ color: "rgb(" + theme.spectrum[color] + ")",
34
+ shape: shape
35
+ })
36
+ }, color))
37
+ }, shape))
38
+ });
39
+ };
40
+ const BasicLegend = () => {
41
+ const theme = useTheme();
42
+ const pages = useMemo(() => ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'], []);
43
+ const pageViews = useMemo(() => [2400, 1398, 9800, 3908, 4800, 3800, 4300], []);
44
+ const uniqueVisitors = useMemo(() => [4000, 3000, 2000, 2780, 1890, 2390, 3490], []);
45
+ const numberFormatter = useCallback(value => new Intl.NumberFormat('en-US', {
46
+ maximumFractionDigits: 0
47
+ }).format(value), []);
48
+ const chartAccessibilityLabel = "Website traffic across " + pages.length + " pages showing page views and unique visitors.";
49
+ return /*#__PURE__*/_jsx(LineChart, {
50
+ enableScrubbing: true,
51
+ legend: true,
52
+ showArea: true,
53
+ accessibilityLabel: chartAccessibilityLabel,
54
+ height: 150,
55
+ legendPosition: "right",
56
+ series: [{
57
+ id: 'pageViews',
58
+ data: pageViews,
59
+ color: "rgb(" + theme.spectrum.green40 + ")",
60
+ label: 'Page Views'
61
+ }, {
62
+ id: 'uniqueVisitors',
63
+ data: uniqueVisitors,
64
+ color: "rgb(" + theme.spectrum.purple40 + ")",
65
+ label: 'Unique Visitors',
66
+ areaType: 'dotted'
67
+ }],
68
+ width: "100%",
69
+ xAxis: {
70
+ data: pages
71
+ },
72
+ yAxis: {
73
+ showGrid: true,
74
+ tickLabelFormatter: numberFormatter
75
+ },
76
+ children: /*#__PURE__*/_jsx(Scrubber, {})
77
+ });
78
+ };
79
+ const Position = () => {
80
+ const theme = useTheme();
81
+ return /*#__PURE__*/_jsxs(CartesianChart, {
82
+ height: 200,
83
+ inset: {
84
+ bottom: 8,
85
+ left: 0,
86
+ right: 0,
87
+ top: 8
88
+ },
89
+ legend: /*#__PURE__*/_jsx(Legend, {
90
+ justifyContent: "flex-end"
91
+ }),
92
+ legendPosition: "bottom",
93
+ series: [{
94
+ id: 'revenue',
95
+ label: 'Revenue',
96
+ data: [455, 520, 380, 455, 285, 235],
97
+ yAxisId: 'revenue',
98
+ color: "rgb(" + theme.spectrum.yellow40 + ")",
99
+ legendShape: 'squircle'
100
+ }, {
101
+ id: 'profitMargin',
102
+ label: 'Profit Margin',
103
+ data: [23, 20, 16, 38, 12, 9],
104
+ yAxisId: 'profitMargin',
105
+ color: theme.color.fgPositive,
106
+ legendShape: 'squircle'
107
+ }],
108
+ width: "100%",
109
+ xAxis: {
110
+ data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
111
+ scaleType: 'band'
112
+ },
113
+ yAxis: [{
114
+ id: 'revenue',
115
+ domain: {
116
+ min: 0
117
+ }
118
+ }, {
119
+ id: 'profitMargin',
120
+ domain: {
121
+ max: 100,
122
+ min: 0
123
+ }
124
+ }],
125
+ children: [/*#__PURE__*/_jsx(XAxis, {
126
+ showLine: true,
127
+ showTickMarks: true
128
+ }), /*#__PURE__*/_jsx(YAxis, {
129
+ showGrid: true,
130
+ showLine: true,
131
+ showTickMarks: true,
132
+ axisId: "revenue",
133
+ position: "left",
134
+ requestedTickCount: 5,
135
+ tickLabelFormatter: value => "$" + value + "k",
136
+ width: 60
137
+ }), /*#__PURE__*/_jsx(YAxis, {
138
+ showLine: true,
139
+ showTickMarks: true,
140
+ axisId: "profitMargin",
141
+ position: "right",
142
+ requestedTickCount: 5,
143
+ tickLabelFormatter: value => value + "%"
144
+ }), /*#__PURE__*/_jsx(BarPlot, {})]
145
+ });
146
+ };
147
+ const ShapeVariants = () => {
148
+ const theme = useTheme();
149
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
150
+ return /*#__PURE__*/_jsx(LineChart, {
151
+ legend: true,
152
+ showArea: true,
153
+ height: 200,
154
+ legendPosition: "left",
155
+ series: [{
156
+ id: 'pill',
157
+ label: 'Pill',
158
+ data: [120, 150, 130, 170, 160, 190],
159
+ color: "rgb(" + theme.spectrum.blue40 + ")",
160
+ legendShape: 'pill'
161
+ }, {
162
+ id: 'circle',
163
+ label: 'Circle',
164
+ data: [80, 110, 95, 125, 115, 140],
165
+ color: "rgb(" + theme.spectrum.green40 + ")",
166
+ legendShape: 'circle'
167
+ }, {
168
+ id: 'square',
169
+ label: 'Square',
170
+ data: [60, 85, 70, 100, 90, 115],
171
+ color: "rgb(" + theme.spectrum.orange40 + ")",
172
+ legendShape: 'square'
173
+ }, {
174
+ id: 'squircle',
175
+ label: 'Squircle',
176
+ data: [40, 60, 50, 75, 65, 85],
177
+ color: "rgb(" + theme.spectrum.purple40 + ")",
178
+ legendShape: 'squircle'
179
+ }],
180
+ width: "100%",
181
+ xAxis: {
182
+ data: months
183
+ },
184
+ yAxis: {
185
+ domain: {
186
+ min: 0
187
+ },
188
+ showGrid: true
189
+ }
190
+ });
191
+ };
192
+ const DynamicData = () => {
193
+ var _seriesConfig$0$data$, _seriesConfig$0$data;
194
+ const theme = useTheme();
195
+ const [scrubberPosition, setScrubberPosition] = useState();
196
+ const timeLabels = useMemo(() => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], []);
197
+ const seriesConfig = useMemo(() => [{
198
+ id: 'candidate-a',
199
+ label: 'Candidate A',
200
+ data: [48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 38],
201
+ color: "rgb(" + theme.spectrum.blue40 + ")",
202
+ legendShape: 'circle'
203
+ }, {
204
+ id: 'candidate-b',
205
+ label: 'Candidate B',
206
+ data: [null, null, null, 6, 10, 14, 18, 22, 26, 29, 32, 35],
207
+ color: "rgb(" + theme.spectrum.orange40 + ")",
208
+ legendShape: 'circle'
209
+ }, {
210
+ id: 'candidate-c',
211
+ label: 'Candidate C',
212
+ data: [52, 53, 54, 49, 46, 43, 40, 37, 34, 32, 30, 27],
213
+ color: "rgb(" + theme.spectrum.gray40 + ")",
214
+ legendShape: 'circle'
215
+ }], [theme.spectrum.blue40, theme.spectrum.gray40, theme.spectrum.orange40]);
216
+ const dataLength = (_seriesConfig$0$data$ = (_seriesConfig$0$data = seriesConfig[0].data) == null ? void 0 : _seriesConfig$0$data.length) != null ? _seriesConfig$0$data$ : 0;
217
+ const dataIndex = scrubberPosition != null ? scrubberPosition : dataLength - 1;
218
+ const chartAccessibilityLabel = "Candidate polling data over " + timeLabels.length + " months showing support percentages for 3 candidates.";
219
+ const ValueLegendEntry = useCallback(_ref => {
220
+ var _seriesData$data;
221
+ let {
222
+ seriesId,
223
+ label,
224
+ color,
225
+ shape
226
+ } = _ref;
227
+ const seriesData = seriesConfig.find(s => s.id === seriesId);
228
+ const rawValue = seriesData == null || (_seriesData$data = seriesData.data) == null ? void 0 : _seriesData$data[dataIndex];
229
+ const formattedValue = rawValue === null || rawValue === undefined ? '--' : Math.round(rawValue) + "%";
230
+ return /*#__PURE__*/_jsxs(HStack, {
231
+ gap: 1,
232
+ style: {
233
+ alignItems: 'center'
234
+ },
235
+ children: [/*#__PURE__*/_jsx(DefaultLegendShape, {
236
+ color: color,
237
+ shape: shape
238
+ }), /*#__PURE__*/_jsx(TextLabel2, {
239
+ children: label
240
+ }), /*#__PURE__*/_jsx(TextLabel1, {
241
+ children: formattedValue
242
+ })]
243
+ });
244
+ }, [seriesConfig, dataIndex]);
245
+ return /*#__PURE__*/_jsx(LineChart, {
246
+ enableScrubbing: true,
247
+ showArea: true,
248
+ accessibilityLabel: chartAccessibilityLabel,
249
+ height: 250,
250
+ legend: /*#__PURE__*/_jsx(Legend, {
251
+ EntryComponent: ValueLegendEntry,
252
+ justifyContent: "flex-start",
253
+ paddingX: 2
254
+ }),
255
+ legendPosition: "top",
256
+ onScrubberPositionChange: setScrubberPosition,
257
+ series: seriesConfig,
258
+ width: "100%",
259
+ xAxis: {
260
+ data: timeLabels
261
+ },
262
+ yAxis: {
263
+ domain: {
264
+ max: 100,
265
+ min: 0
266
+ },
267
+ showGrid: true,
268
+ tickLabelFormatter: value => value + "%"
269
+ },
270
+ children: /*#__PURE__*/_jsx(Scrubber, {})
271
+ });
272
+ };
273
+ const Interactive = () => {
274
+ const theme = useTheme();
275
+ const [emphasizedId, setEmphasizedId] = useState(null);
276
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
277
+ const seriesConfig = useMemo(() => [{
278
+ id: 'revenue',
279
+ label: 'Revenue',
280
+ data: [120, 150, 180, 165, 190, 210, 240, 220, 260, 280, 310, 350],
281
+ baseColor: 'blue'
282
+ }, {
283
+ id: 'expenses',
284
+ label: 'Expenses',
285
+ data: [80, 95, 110, 105, 120, 130, 145, 140, 155, 165, 180, 195],
286
+ baseColor: 'orange'
287
+ }, {
288
+ id: 'profit',
289
+ label: 'Profit',
290
+ data: [40, 55, 70, 60, 70, 80, 95, 80, 105, 115, 130, 155],
291
+ baseColor: 'green'
292
+ }], []);
293
+ const handleToggle = useCallback(seriesId => {
294
+ setEmphasizedId(prev => prev === seriesId ? null : seriesId);
295
+ }, []);
296
+ const ChipLegendEntry = /*#__PURE__*/memo(function ChipLegendEntry(_ref2) {
297
+ var _config$baseColor;
298
+ let {
299
+ seriesId,
300
+ label
301
+ } = _ref2;
302
+ const isEmphasized = emphasizedId === seriesId;
303
+ const config = seriesConfig.find(s => s.id === seriesId);
304
+ const baseColor = (_config$baseColor = config == null ? void 0 : config.baseColor) != null ? _config$baseColor : 'gray';
305
+ const color10 = theme.spectrum[baseColor + "10"];
306
+ const color50 = theme.spectrum[baseColor + "50"];
307
+ const color90 = theme.spectrum[baseColor + "90"];
308
+ return /*#__PURE__*/_jsx(Chip, {
309
+ compact: true,
310
+ accessibilityLabel: (isEmphasized ? 'Remove emphasis from' : 'Emphasize') + " " + label + " series",
311
+ background: "transparent",
312
+ onPress: () => handleToggle(seriesId),
313
+ style: {
314
+ backgroundColor: "rgb(" + (isEmphasized ? color90 : color10) + ")",
315
+ borderWidth: 0,
316
+ borderRadius: theme.borderRadius[1000]
317
+ },
318
+ children: /*#__PURE__*/_jsxs(HStack, {
319
+ gap: 1,
320
+ style: {
321
+ alignItems: 'center'
322
+ },
323
+ children: [/*#__PURE__*/_jsx(DefaultLegendShape, {
324
+ color: "rgb(" + color50 + ")"
325
+ }), /*#__PURE__*/_jsx(TextLabel2, {
326
+ color: isEmphasized ? 'bg' : 'fg',
327
+ children: label
328
+ })]
329
+ })
330
+ });
331
+ });
332
+ const series = useMemo(() => {
333
+ return seriesConfig.map(config => {
334
+ const isEmphasized = emphasizedId === config.id;
335
+ const isDimmed = emphasizedId !== null && !isEmphasized;
336
+ return {
337
+ id: config.id,
338
+ label: config.label,
339
+ data: config.data,
340
+ color: "rgb(" + theme.spectrum[config.baseColor + "40"] + ")",
341
+ opacity: isDimmed ? 0.3 : 1
342
+ };
343
+ });
344
+ }, [emphasizedId, seriesConfig, theme]);
345
+ return /*#__PURE__*/_jsx(LineChart, {
346
+ showArea: true,
347
+ height: 300,
348
+ legend: /*#__PURE__*/_jsx(Legend, {
349
+ EntryComponent: ChipLegendEntry,
350
+ gap: 1,
351
+ paddingTop: 1
352
+ }),
353
+ legendPosition: "top",
354
+ series: series,
355
+ width: "100%",
356
+ xAxis: {
357
+ data: months
358
+ },
359
+ yAxis: {
360
+ domain: {
361
+ min: 0
362
+ },
363
+ showGrid: true,
364
+ tickLabelFormatter: value => "$" + value + "k"
365
+ }
366
+ });
367
+ };
368
+ const Accessible = () => {
369
+ const theme = useTheme();
370
+ const months = useMemo(() => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], []);
371
+ return /*#__PURE__*/_jsx(LineChart, {
372
+ legend: true,
373
+ showArea: true,
374
+ height: 200,
375
+ legendAccessibilityLabel: "Financial performance chart, legend",
376
+ legendPosition: "bottom",
377
+ series: [{
378
+ id: 'revenue',
379
+ label: 'Revenue',
380
+ data: [120, 150, 180, 165, 190, 210],
381
+ color: "rgb(" + theme.spectrum.green40 + ")"
382
+ }, {
383
+ id: 'expenses',
384
+ label: 'Expenses',
385
+ data: [80, 95, 110, 105, 120, 130],
386
+ color: "rgb(" + theme.spectrum.orange40 + ")"
387
+ }],
388
+ width: "100%",
389
+ xAxis: {
390
+ data: months
391
+ },
392
+ yAxis: {
393
+ domain: {
394
+ min: 0
395
+ },
396
+ showGrid: true
397
+ }
398
+ });
399
+ };
400
+ const LegendShapes = () => {
401
+ const theme = useTheme();
402
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
403
+
404
+ // Actual revenue (first 9 months)
405
+ const actualRevenue = [320, 380, 420, 390, 450, 480, 520, 490, 540, null, null, null];
406
+
407
+ // Forecasted revenue (last 3 months)
408
+ const forecastRevenue = [null, null, null, null, null, null, null, null, null, 580, 620, 680];
409
+ const numberFormatter = useCallback(value => "$" + new Intl.NumberFormat('en-US', {
410
+ maximumFractionDigits: 0
411
+ }).format(value) + "k", []);
412
+
413
+ // Pattern settings for dotted fill
414
+ const patternSize = 4;
415
+ const dotSize = 1;
416
+
417
+ // Custom legend indicator that matches the dotted bar pattern
418
+ const DottedLegendIndicator = useMemo(() => {
419
+ // Create a small dotted pattern for the legend indicator
420
+ const indicatorSize = 10;
421
+ const legendPatternSize = patternSize / 2;
422
+ const legendDotSize = dotSize / 2;
423
+ const dottedPath = getDottedAreaPath({
424
+ x: 1,
425
+ y: 1,
426
+ width: indicatorSize - 2,
427
+ height: indicatorSize - 2
428
+ }, legendPatternSize, legendDotSize);
429
+ const skiaPath = Skia.Path.MakeFromSVGString(dottedPath);
430
+ // Create squircle path for clipping
431
+ const squirclePath = Skia.Path.Make();
432
+ squirclePath.addRRect(Skia.RRectXY(Skia.XYWHRect(1, 1, 8, 8), 2, 2));
433
+ return /*#__PURE__*/_jsxs(Canvas, {
434
+ style: {
435
+ width: indicatorSize,
436
+ height: indicatorSize
437
+ },
438
+ children: [/*#__PURE__*/_jsx(Group, {
439
+ clip: squirclePath,
440
+ children: skiaPath && /*#__PURE__*/_jsx(SkiaPath, {
441
+ color: theme.color.fgPositive,
442
+ path: skiaPath,
443
+ style: "fill"
444
+ })
445
+ }), /*#__PURE__*/_jsx(SkiaPath, {
446
+ color: theme.color.fgPositive,
447
+ path: squirclePath,
448
+ strokeWidth: 2,
449
+ style: "stroke"
450
+ })]
451
+ });
452
+ }, [theme.color.fgPositive]);
453
+
454
+ // Custom bar component that renders bars with dotted pattern fill
455
+ const DottedBarComponent = useMemo(() => {
456
+ return /*#__PURE__*/memo(function DottedBar(props) {
457
+ const {
458
+ x,
459
+ y,
460
+ width,
461
+ height,
462
+ fill,
463
+ d
464
+ } = props;
465
+
466
+ // Generate dotted path for this bar's bounds
467
+ const dottedPath = useMemo(() => {
468
+ return getDottedAreaPath({
469
+ x,
470
+ y,
471
+ width,
472
+ height
473
+ }, patternSize, dotSize);
474
+ }, [x, y, width, height]);
475
+
476
+ // Create Skia paths
477
+ const barClipPath = useMemo(() => {
478
+ var _Skia$Path$MakeFromSV;
479
+ return d ? (_Skia$Path$MakeFromSV = Skia.Path.MakeFromSVGString(d)) != null ? _Skia$Path$MakeFromSV : undefined : undefined;
480
+ }, [d]);
481
+ const dotsSkiaPath = useMemo(() => {
482
+ var _Skia$Path$MakeFromSV2;
483
+ return (_Skia$Path$MakeFromSV2 = Skia.Path.MakeFromSVGString(dottedPath)) != null ? _Skia$Path$MakeFromSV2 : undefined;
484
+ }, [dottedPath]);
485
+ return /*#__PURE__*/_jsxs(_Fragment, {
486
+ children: [/*#__PURE__*/_jsx(Group, {
487
+ clip: barClipPath,
488
+ children: dotsSkiaPath && /*#__PURE__*/_jsx(SkiaPath, {
489
+ color: fill,
490
+ path: dotsSkiaPath,
491
+ style: "fill"
492
+ })
493
+ }), /*#__PURE__*/_jsx(DefaultBar, _extends({}, props, {
494
+ fill: undefined,
495
+ stroke: fill,
496
+ strokeWidth: 2
497
+ }))]
498
+ });
499
+ });
500
+ }, []);
501
+ return /*#__PURE__*/_jsx(BarChart, {
502
+ legend: true,
503
+ showXAxis: true,
504
+ showYAxis: true,
505
+ height: 250,
506
+ inset: 0,
507
+ legendPosition: "top",
508
+ series: [{
509
+ id: 'actual',
510
+ label: 'Historical',
511
+ data: actualRevenue,
512
+ color: theme.color.fgPositive,
513
+ legendShape: 'squircle',
514
+ stackId: 'revenue'
515
+ }, {
516
+ id: 'forecast',
517
+ label: 'Forecasted',
518
+ data: forecastRevenue,
519
+ color: theme.color.fgPositive,
520
+ legendShape: DottedLegendIndicator,
521
+ stackId: 'revenue',
522
+ BarComponent: DottedBarComponent
523
+ }],
524
+ xAxis: {
525
+ data: months,
526
+ scaleType: 'band',
527
+ showLine: true,
528
+ showTickMarks: true
529
+ },
530
+ yAxis: {
531
+ domain: {
532
+ min: 0
533
+ },
534
+ showGrid: true,
535
+ showLine: true,
536
+ showTickMarks: true,
537
+ position: 'left',
538
+ tickLabelFormatter: numberFormatter,
539
+ width: 60
540
+ }
541
+ });
542
+ };
543
+ const LegendStories = () => {
544
+ return /*#__PURE__*/_jsx(ScrollView, {
545
+ children: /*#__PURE__*/_jsxs(ExampleScreen, {
546
+ children: [/*#__PURE__*/_jsx(Example, {
547
+ title: "Shapes",
548
+ children: /*#__PURE__*/_jsx(Shapes, {})
549
+ }), /*#__PURE__*/_jsx(Example, {
550
+ title: "Basic Legend",
551
+ children: /*#__PURE__*/_jsx(BasicLegend, {})
552
+ }), /*#__PURE__*/_jsx(Example, {
553
+ title: "Position",
554
+ children: /*#__PURE__*/_jsx(Position, {})
555
+ }), /*#__PURE__*/_jsx(Example, {
556
+ title: "Shape Variants",
557
+ children: /*#__PURE__*/_jsx(ShapeVariants, {})
558
+ }), /*#__PURE__*/_jsx(Example, {
559
+ title: "Dynamic Data",
560
+ children: /*#__PURE__*/_jsx(DynamicData, {})
561
+ }), /*#__PURE__*/_jsx(Example, {
562
+ title: "Interactive Legend",
563
+ children: /*#__PURE__*/_jsx(Interactive, {})
564
+ }), /*#__PURE__*/_jsx(Example, {
565
+ title: "Legend Shapes",
566
+ children: /*#__PURE__*/_jsx(LegendShapes, {})
567
+ }), /*#__PURE__*/_jsx(Example, {
568
+ title: "Accessible Legend",
569
+ children: /*#__PURE__*/_jsx(Accessible, {})
570
+ })]
571
+ })
572
+ });
573
+ };
574
+ export default LegendStories;
@@ -0,0 +1,3 @@
1
+ export * from './DefaultLegendEntry';
2
+ export * from './DefaultLegendShape';
3
+ export * from './Legend';
@@ -45,7 +45,8 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
45
45
  color: s.color,
46
46
  yAxisId: s.yAxisId,
47
47
  stackId: s.stackId,
48
- gradient: s.gradient
48
+ gradient: s.gradient,
49
+ legendShape: s.legendShape
49
50
  }));
50
51
  }, [series]);
51
52
 
@@ -717,6 +717,36 @@ function StylingScrubber() {
717
717
  })
718
718
  });
719
719
  }
720
+ function HideBeaconLabels() {
721
+ const theme = useTheme();
722
+ const pageViews = [2400, 1398, 9800, 3908, 4800, 3800, 4300];
723
+ const uniqueVisitors = [4000, 3000, 2000, 2780, 1890, 2390, 3490];
724
+ return /*#__PURE__*/_jsx(LineChart, {
725
+ enableScrubbing: true,
726
+ legend: true,
727
+ showArea: true,
728
+ height: 200,
729
+ inset: {
730
+ top: 60
731
+ },
732
+ series: [{
733
+ id: 'pageViews',
734
+ data: pageViews,
735
+ color: theme.color.accentBoldGreen,
736
+ label: 'Page Views'
737
+ }, {
738
+ id: 'uniqueVisitors',
739
+ data: uniqueVisitors,
740
+ color: theme.color.accentBoldPurple,
741
+ label: 'Unique Visitors'
742
+ }],
743
+ children: /*#__PURE__*/_jsx(Scrubber, {
744
+ hideBeaconLabels: true,
745
+ labelElevated: true,
746
+ label: dataIndex => "Day " + (dataIndex + 1)
747
+ })
748
+ });
749
+ }
720
750
  function Compact() {
721
751
  const theme = useTheme();
722
752
  const dimensions = {
@@ -992,7 +1022,7 @@ const LegendDot = /*#__PURE__*/memo(props => {
992
1022
  width: 10
993
1023
  }, props));
994
1024
  });
995
- const LegendItem = /*#__PURE__*/memo(_ref0 => {
1025
+ const LegendEntry = /*#__PURE__*/memo(_ref0 => {
996
1026
  let {
997
1027
  color = assets.btc.color,
998
1028
  label,
@@ -1037,15 +1067,15 @@ const PerformanceHeader = /*#__PURE__*/memo(_ref1 => {
1037
1067
  return /*#__PURE__*/_jsxs(HStack, {
1038
1068
  gap: 1,
1039
1069
  paddingX: 1,
1040
- children: [/*#__PURE__*/_jsx(LegendItem, {
1070
+ children: [/*#__PURE__*/_jsx(LegendEntry, {
1041
1071
  color: theme.color.fgPositive,
1042
1072
  label: "High Price",
1043
1073
  value: formatPriceThousands(sparklineTimePeriodDataValues[shownPosition] * 1.2)
1044
- }), /*#__PURE__*/_jsx(LegendItem, {
1074
+ }), /*#__PURE__*/_jsx(LegendEntry, {
1045
1075
  color: assets.btc.color,
1046
1076
  label: "Actual Price",
1047
1077
  value: formatPriceThousands(sparklineTimePeriodDataValues[shownPosition])
1048
- }), /*#__PURE__*/_jsx(LegendItem, {
1078
+ }), /*#__PURE__*/_jsx(LegendEntry, {
1049
1079
  color: theme.color.fgNegative,
1050
1080
  label: "Low Price",
1051
1081
  value: formatPriceThousands(sparklineTimePeriodDataValues[shownPosition] * 0.8)
@@ -2435,6 +2465,9 @@ function ExampleNavigator() {
2435
2465
  }, {
2436
2466
  title: 'Two-Line Scrubber Label',
2437
2467
  component: /*#__PURE__*/_jsx(TwoLineScrubberLabel, {})
2468
+ }, {
2469
+ title: 'Hide Beacon Labels',
2470
+ component: /*#__PURE__*/_jsx(HideBeaconLabels, {})
2438
2471
  }, {
2439
2472
  title: 'Custom Beacon Stroke',
2440
2473
  component: /*#__PURE__*/_jsx(CustomBeaconStroke, {})
@@ -16,6 +16,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
16
  export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
17
17
  let {
18
18
  seriesIds,
19
+ hideBeaconLabels,
19
20
  hideLine,
20
21
  label,
21
22
  lineStroke,
@@ -157,7 +158,7 @@ export const Scrubber = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =>
157
158
  seriesIds: filteredSeriesIds,
158
159
  stroke: beaconStroke,
159
160
  transitions: beaconTransitions
160
- }), beaconLabels.length > 0 && /*#__PURE__*/_jsx(ScrubberBeaconLabelGroup, {
161
+ }), !hideBeaconLabels && beaconLabels.length > 0 && /*#__PURE__*/_jsx(ScrubberBeaconLabelGroup, {
161
162
  BeaconLabelComponent: BeaconLabelComponent,
162
163
  labelFont: beaconLabelFont,
163
164
  labelHorizontalOffset: beaconLabelHorizontalOffset,
@@ -1,6 +1,19 @@
1
1
  import { isSharedValue } from 'react-native-reanimated';
2
2
  import { stack as d3Stack, stackOffsetDiverging, stackOrderNone } from 'd3-shape';
3
3
  export const defaultStackId = 'DEFAULT_STACK_ID';
4
+
5
+ /**
6
+ * Shape variants available for legend items.
7
+ */
8
+
9
+ /**
10
+ * Shape for legend items. Can be a preset variant or a custom ReactNode.
11
+ */
12
+
13
+ /**
14
+ * Position of the legend relative to the chart.
15
+ */
16
+
4
17
  /**
5
18
  * Type guard to check if bounds are complete with both min and max values.
6
19
  * @param bounds - The bounds to validate