@coinbase/cds-mobile-visualization 3.4.0-beta.23 → 3.4.0-beta.24

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.
@@ -1,17 +1,22 @@
1
+ import { useCallback } from 'react';
1
2
  import { Example, ExampleScreen } from '@coinbase/cds-mobile/examples/ExampleScreen';
2
3
  import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
3
4
  import { DottedLine } from '../../line';
4
5
  import { Scrubber } from '../../scrubber/Scrubber';
5
6
  import { AreaChart } from '..';
6
7
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
+ const basicData = [24, 13, 98, 39, 48, 38, 43];
7
9
  const BasicExample = () => {
10
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + basicData[index], []);
8
11
  return /*#__PURE__*/_jsx(AreaChart, {
9
12
  enableScrubbing: true,
10
13
  showYAxis: true,
14
+ accessibilityLabel: "Area chart with " + basicData.length + " data points. Swipe to navigate.",
15
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
11
16
  height: 400,
12
17
  series: [{
13
18
  id: 'pageViews',
14
- data: [24, 13, 98, 39, 48, 38, 43]
19
+ data: basicData
15
20
  }],
16
21
  yAxis: {
17
22
  showGrid: true,
@@ -22,21 +27,26 @@ const BasicExample = () => {
22
27
  children: /*#__PURE__*/_jsx(Scrubber, {})
23
28
  });
24
29
  };
30
+ const currentRewardsData = [100, 150, 200, 280, 380, 500, 650, 820, 1020, 1250, 1510, 1800, 2120, 2470, 2850, 3260, 3700, 4170];
31
+ const potentialRewardsData = [150, 220, 300, 400, 520, 660, 820, 1000, 1200, 1420, 1660, 1920, 2200, 2500, 2820, 3160, 3520, 3900];
25
32
  const StackedExample = () => {
26
33
  const theme = useTheme();
34
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": current " + currentRewardsData[index] + ", potential " + potentialRewardsData[index], []);
27
35
  return /*#__PURE__*/_jsx(AreaChart, {
28
36
  enableScrubbing: true,
29
37
  showLines: true,
30
38
  stacked: true,
39
+ accessibilityLabel: "Stacked rewards chart with " + currentRewardsData.length + " data points. Swipe to navigate.",
31
40
  curve: "natural",
41
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
32
42
  height: 256,
33
43
  series: [{
34
44
  id: 'currentRewards',
35
- data: [100, 150, 200, 280, 380, 500, 650, 820, 1020, 1250, 1510, 1800, 2120, 2470, 2850, 3260, 3700, 4170],
45
+ data: currentRewardsData,
36
46
  color: theme.color.fg
37
47
  }, {
38
48
  id: 'potentialRewards',
39
- data: [150, 220, 300, 400, 520, 660, 820, 1000, 1200, 1420, 1660, 1920, 2200, 2500, 2820, 3160, 3520, 3900],
49
+ data: potentialRewardsData,
40
50
  color: theme.color.fgPositive,
41
51
  type: 'dotted',
42
52
  LineComponent: DottedLine
@@ -59,6 +69,8 @@ const AreaChartStories = () => {
59
69
  enableScrubbing: true,
60
70
  showLines: true,
61
71
  showYAxis: true,
72
+ accessibilityLabel: "Area chart with negative values. 7 data points. Swipe to navigate.",
73
+ getScrubberAccessibilityLabel: index => "Point " + (index + 1) + ": " + [24, 13, -98, 39, 48, 38, 43][index],
62
74
  height: 150,
63
75
  series: [{
64
76
  id: 'pageViews',
@@ -101,6 +113,8 @@ const AreaChartStories = () => {
101
113
  showLines: true,
102
114
  showXAxis: true,
103
115
  showYAxis: true,
116
+ accessibilityLabel: "Volume by asset. 5 data points. Swipe to navigate.",
117
+ getScrubberAccessibilityLabel: index => ['BTC', 'ETH', 'SOL', 'DOGE', 'ADA'][index] + ": " + [68, 54, 43, 29, 18][index] + "%",
104
118
  height: 280,
105
119
  layout: "horizontal",
106
120
  series: [{
@@ -53,10 +53,14 @@ const Simple = () => {
53
53
  const pageViews = data.map(d => d.pv);
54
54
  const pageNames = data.map(d => d.name);
55
55
  const pageUniqueVisitors = data.map(d => d.uv);
56
+ const chartAccessibilityLabel = "Page views and unique visitors across " + pageNames.length + " pages. Swipe to navigate.";
57
+ const getScrubberAccessibilityLabel = useCallback(index => pageNames[index] + ": " + pageViews[index] + " views, " + pageUniqueVisitors[index] + " unique visitors", [pageNames, pageViews, pageUniqueVisitors]);
56
58
  return /*#__PURE__*/_jsx(LineChart, {
57
59
  enableScrubbing: true,
58
60
  showXAxis: true,
59
61
  showYAxis: true,
62
+ accessibilityLabel: chartAccessibilityLabel,
63
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
60
64
  height: defaultChartHeight,
61
65
  inset: 32,
62
66
  series: [{
@@ -97,8 +101,8 @@ const Simple = () => {
97
101
  };
98
102
  const TimeOfDayAxesExample = () => {
99
103
  const theme = useTheme();
100
- const lineA = [5, 5, 10, 90, 85, 70, 30, 25, 25];
101
- const lineB = [90, 85, 70, 25, 23, 40, 45, 40, 50];
104
+ const lineA = useMemo(() => [5, 5, 10, 90, 85, 70, 30, 25, 25], []);
105
+ const lineB = useMemo(() => [90, 85, 70, 25, 23, 40, 45, 40, 50], []);
102
106
  const timeData = useMemo(() => [new Date(2023, 7, 31), new Date(2023, 7, 31, 12), new Date(2023, 8, 1), new Date(2023, 8, 1, 12), new Date(2023, 8, 2), new Date(2023, 8, 2, 12), new Date(2023, 8, 3), new Date(2023, 8, 3, 12), new Date(2023, 8, 4)].map(d => d.getTime()), []);
103
107
  const dateFormatter = useCallback(index => {
104
108
  return new Date(timeData[index]).toLocaleDateString('en-US', {
@@ -117,8 +121,12 @@ const TimeOfDayAxesExample = () => {
117
121
  const dateTicks = useMemo(() => {
118
122
  return timeData.map((d, index) => index).filter(d => d % 2 === 0);
119
123
  }, [timeData]);
124
+ const chartAccessibilityLabel = "Chart with " + lineA.length + " data points. Swipe to navigate.";
125
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": lineA " + lineA[index] + ", lineB " + lineB[index], [lineA, lineB]);
120
126
  return /*#__PURE__*/_jsxs(LineChart, {
121
127
  enableScrubbing: true,
128
+ accessibilityLabel: chartAccessibilityLabel,
129
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
122
130
  height: defaultChartHeight,
123
131
  series: [{
124
132
  id: 'lineA',
@@ -150,51 +158,57 @@ const TimeOfDayAxesExample = () => {
150
158
  }), /*#__PURE__*/_jsx(Scrubber, {})]
151
159
  });
152
160
  };
153
- const MultipleYAxesExample = () => /*#__PURE__*/_jsxs(CartesianChart, {
154
- enableScrubbing: true,
155
- height: defaultChartHeight,
156
- series: [{
157
- id: 'linear',
158
- yAxisId: 'linearAxis',
159
- data: [1, 10, 30, 50, 70, 90, 100],
160
- label: 'linear'
161
- }, {
162
- id: 'log',
163
- yAxisId: 'logAxis',
164
- data: [1, 10, 30, 50, 70, 90, 100],
165
- label: 'log'
166
- }],
167
- xAxis: {
168
- data: [1, 10, 30, 50, 70, 90, 100]
169
- },
170
- yAxis: [{
171
- id: 'linearAxis',
172
- scaleType: 'linear'
173
- }, {
174
- id: 'logAxis',
175
- scaleType: 'log'
176
- }],
177
- children: [/*#__PURE__*/_jsx(XAxis, {
178
- showLine: true,
179
- showTickMarks: true
180
- }), /*#__PURE__*/_jsx(YAxis, {
181
- showLine: true,
182
- showTickMarks: true,
183
- axisId: "logAxis",
184
- position: "left"
185
- }), /*#__PURE__*/_jsx(YAxis, {
186
- showLine: true,
187
- showTickMarks: true,
188
- axisId: "linearAxis",
189
- position: "left"
190
- }), /*#__PURE__*/_jsx(Line, {
191
- curve: "natural",
192
- seriesId: "linear"
193
- }), /*#__PURE__*/_jsx(Line, {
194
- curve: "natural",
195
- seriesId: "log"
196
- }), /*#__PURE__*/_jsx(Scrubber, {})]
197
- });
161
+ const multipleYAxesData = [1, 10, 30, 50, 70, 90, 100];
162
+ const MultipleYAxesExample = () => {
163
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": linear " + multipleYAxesData[index] + ", log " + multipleYAxesData[index], []);
164
+ return /*#__PURE__*/_jsxs(CartesianChart, {
165
+ enableScrubbing: true,
166
+ accessibilityLabel: "Chart with linear and log axes. 7 data points. Swipe to navigate.",
167
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
168
+ height: defaultChartHeight,
169
+ series: [{
170
+ id: 'linear',
171
+ yAxisId: 'linearAxis',
172
+ data: multipleYAxesData,
173
+ label: 'linear'
174
+ }, {
175
+ id: 'log',
176
+ yAxisId: 'logAxis',
177
+ data: multipleYAxesData,
178
+ label: 'log'
179
+ }],
180
+ xAxis: {
181
+ data: multipleYAxesData
182
+ },
183
+ yAxis: [{
184
+ id: 'linearAxis',
185
+ scaleType: 'linear'
186
+ }, {
187
+ id: 'logAxis',
188
+ scaleType: 'log'
189
+ }],
190
+ children: [/*#__PURE__*/_jsx(XAxis, {
191
+ showLine: true,
192
+ showTickMarks: true
193
+ }), /*#__PURE__*/_jsx(YAxis, {
194
+ showLine: true,
195
+ showTickMarks: true,
196
+ axisId: "logAxis",
197
+ position: "left"
198
+ }), /*#__PURE__*/_jsx(YAxis, {
199
+ showLine: true,
200
+ showTickMarks: true,
201
+ axisId: "linearAxis",
202
+ position: "left"
203
+ }), /*#__PURE__*/_jsx(Line, {
204
+ curve: "natural",
205
+ seriesId: "linear"
206
+ }), /*#__PURE__*/_jsx(Line, {
207
+ curve: "natural",
208
+ seriesId: "log"
209
+ }), /*#__PURE__*/_jsx(Scrubber, {})]
210
+ });
211
+ };
198
212
  const AxesOnAllSides = () => {
199
213
  const theme = useTheme();
200
214
  const data = [30, 45, 60, 80, 55, 40, 65];
@@ -298,9 +312,12 @@ const DomainLimitType = _ref => {
298
312
  let {
299
313
  limit
300
314
  } = _ref;
301
- const exponentialData = [1, 2, 4, 8, 15, 30, 65, 140, 280, 580, 1200, 2400, 4800, 9500, 19000, 38000, 75000, 150000];
315
+ const exponentialData = useMemo(() => [1, 2, 4, 8, 15, 30, 65, 140, 280, 580, 1200, 2400, 4800, 9500, 19000, 38000, 75000, 150000], []);
316
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + exponentialData[index], [exponentialData]);
302
317
  return /*#__PURE__*/_jsxs(CartesianChart, {
303
318
  enableScrubbing: true,
319
+ accessibilityLabel: "Exponential growth chart with " + exponentialData.length + " data points. Swipe to navigate.",
320
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
304
321
  height: defaultChartHeight,
305
322
  series: [{
306
323
  id: 'growthLinear',
@@ -801,11 +801,17 @@ const CandlesticksChart = /*#__PURE__*/memo(_ref8 => {
801
801
  day: 'numeric'
802
802
  });
803
803
  }, []);
804
+ const getScrubberAccessibilityLabel = useCallback(index => {
805
+ const candle = candlestickStockData[index];
806
+ return formatTime(index) + ": O " + formatThousandsPriceNumber(parseFloat(candle.open)) + " H " + formatThousandsPriceNumber(parseFloat(candle.high)) + " L " + formatThousandsPriceNumber(parseFloat(candle.low)) + " C " + formatThousandsPriceNumber(parseFloat(candle.close));
807
+ }, [formatTime, formatThousandsPriceNumber]);
804
808
  return /*#__PURE__*/_jsxs(CartesianChart, {
805
809
  enableScrubbing: true,
810
+ accessibilityLabel: "Candlestick chart with " + candlesData.length + " data points. Swipe to navigate.",
806
811
  animate: false,
807
812
  "aria-labelledby": infoTextId,
808
813
  borderRadius: 0,
814
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
809
815
  height: 150,
810
816
  inset: {
811
817
  top: 8,
@@ -1,4 +1,4 @@
1
- const _excluded = ["series", "showArea", "areaType", "type", "LineComponent", "AreaComponent", "curve", "points", "strokeWidth", "strokeOpacity", "connectNulls", "transition", "transitions", "opacity", "showXAxis", "showYAxis", "xAxis", "yAxis", "inset", "children"],
1
+ const _excluded = ["series", "showArea", "areaType", "type", "LineComponent", "AreaComponent", "curve", "points", "strokeWidth", "strokeOpacity", "connectNulls", "transition", "transitions", "opacity", "showXAxis", "showYAxis", "xAxis", "yAxis", "inset", "scrubberAccessibilityLabelStep", "layout", "children"],
2
2
  _excluded2 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"],
3
3
  _excluded3 = ["scaleType", "data", "categoryPadding", "domain", "domainLimit", "range", "id"],
4
4
  _excluded4 = ["id", "data", "label", "color", "xAxisId", "yAxisId"];
@@ -10,6 +10,13 @@ import { YAxis } from '../axis/YAxis';
10
10
  import { CartesianChart } from '../CartesianChart';
11
11
  import { Line } from './Line';
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ const getDefaultScrubberAccessibilityStep = function (dataLength, sampleCount) {
14
+ if (sampleCount === void 0) {
15
+ sampleCount = 10;
16
+ }
17
+ if (dataLength <= 0) return 1;
18
+ return Math.max(1, Math.ceil(dataLength / sampleCount));
19
+ };
13
20
  export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
14
21
  let {
15
22
  series,
@@ -31,6 +38,8 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
31
38
  xAxis,
32
39
  yAxis,
33
40
  inset,
41
+ scrubberAccessibilityLabelStep,
42
+ layout = 'vertical',
34
43
  children
35
44
  } = _ref,
36
45
  chartProps = _objectWithoutPropertiesLoose(_ref, _excluded);
@@ -88,9 +97,21 @@ export const LineChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) =
88
97
  domainLimit: yDomainLimit,
89
98
  range: yRange
90
99
  };
100
+ const categoryAxisData = layout === 'horizontal' ? yData : xData;
101
+ const lineChartDataLength = useMemo(() => {
102
+ if (categoryAxisData && categoryAxisData.length > 0) return categoryAxisData.length;
103
+ if (!series || series.length === 0) return 0;
104
+ return series.reduce((max, s) => {
105
+ var _s$data$length, _s$data;
106
+ return Math.max(max, (_s$data$length = (_s$data = s.data) == null ? void 0 : _s$data.length) != null ? _s$data$length : 0);
107
+ }, 0);
108
+ }, [categoryAxisData, series]);
109
+ const resolvedScrubberAccessibilityLabelStep = useMemo(() => scrubberAccessibilityLabelStep != null ? scrubberAccessibilityLabelStep : getDefaultScrubberAccessibilityStep(lineChartDataLength), [scrubberAccessibilityLabelStep, lineChartDataLength]);
91
110
  return /*#__PURE__*/_jsxs(CartesianChart, _extends({}, chartProps, {
92
111
  ref: ref,
93
112
  inset: inset,
113
+ layout: layout,
114
+ scrubberAccessibilityLabelStep: resolvedScrubberAccessibilityLabelStep,
94
115
  series: chartSeries,
95
116
  xAxis: xAxisConfig,
96
117
  yAxis: yAxisConfig,
@@ -34,31 +34,24 @@ import { DottedLine, Line, LineChart, ReferenceLine, SolidLine } from '..';
34
34
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
35
35
  function MultipleLine() {
36
36
  const theme = useTheme();
37
- const [scrubberPosition, setScrubberPosition] = useState();
38
37
  const pages = useMemo(() => ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'], []);
39
38
  const pageViews = useMemo(() => [2400, 1398, 9800, 3908, 4800, 3800, 4300], []);
40
39
  const uniqueVisitors = useMemo(() => [4000, 3000, 2000, 2780, 1890, 2390, 3490], []);
41
40
  const chartAccessibilityLabel = "Website visitors across " + pageViews.length + " pages.";
42
- const scrubberAccessibilityLabel = useCallback(index => {
43
- return pages[index] + " has " + pageViews[index] + " views and " + uniqueVisitors[index] + " unique visitors.";
44
- }, [pages, pageViews, uniqueVisitors]);
41
+ const chartAccessibilityHint = 'Swipe left or right to hear details for each page.';
42
+ const getScrubberAccessibilityLabel = useCallback(index => pages[index] + " has " + pageViews[index] + " views and " + uniqueVisitors[index] + " unique visitors.", [pages, pageViews, uniqueVisitors]);
45
43
  const numberFormatter = useCallback(value => new Intl.NumberFormat('en-US', {
46
44
  maximumFractionDigits: 0
47
45
  }).format(value), []);
48
- const accessibilityLabel = useMemo(() => {
49
- if (scrubberPosition !== undefined) {
50
- return scrubberAccessibilityLabel(scrubberPosition);
51
- }
52
- return chartAccessibilityLabel;
53
- }, [scrubberPosition, chartAccessibilityLabel, scrubberAccessibilityLabel]);
54
46
  return /*#__PURE__*/_jsx(LineChart, {
55
47
  enableScrubbing: true,
56
48
  showArea: true,
57
49
  showXAxis: true,
58
50
  showYAxis: true,
59
- accessibilityLabel: accessibilityLabel,
51
+ accessibilityHint: chartAccessibilityHint,
52
+ accessibilityLabel: chartAccessibilityLabel + " " + chartAccessibilityHint,
53
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
60
54
  height: 200,
61
- onScrubberPositionChange: setScrubberPosition,
62
55
  series: [{
63
56
  id: 'pageViews',
64
57
  data: pageViews,
@@ -85,27 +78,19 @@ function MultipleLine() {
85
78
  });
86
79
  }
87
80
  function DataFormat() {
88
- const [scrubberPosition, setScrubberPosition] = useState();
89
81
  const yData = useMemo(() => [2, 5.5, 2, 8.5, 1.5, 5], []);
90
82
  const xData = useMemo(() => [1, 2, 3, 5, 8, 10], []);
91
83
  const chartAccessibilityLabel = "Chart with custom X and Y data. " + yData.length + " data points";
92
- const scrubberAccessibilityLabel = useCallback(index => {
93
- return "Point " + (index + 1) + ": X value " + xData[index] + ", Y value " + yData[index];
94
- }, [xData, yData]);
95
- const accessibilityLabel = useMemo(() => {
96
- if (scrubberPosition !== undefined) {
97
- return scrubberAccessibilityLabel(scrubberPosition);
98
- }
99
- return chartAccessibilityLabel;
100
- }, [scrubberPosition, chartAccessibilityLabel, scrubberAccessibilityLabel]);
84
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": X value " + xData[index] + ", Y value " + yData[index], [xData, yData]);
101
85
  return /*#__PURE__*/_jsx(LineChart, {
102
86
  enableScrubbing: true,
103
87
  points: true,
104
88
  showArea: true,
105
89
  showXAxis: true,
106
90
  showYAxis: true,
107
- accessibilityLabel: accessibilityLabel,
91
+ accessibilityLabel: chartAccessibilityLabel,
108
92
  curve: "natural",
93
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
109
94
  height: 200,
110
95
  inset: {
111
96
  top: 16,
@@ -113,7 +98,6 @@ function DataFormat() {
113
98
  bottom: 0,
114
99
  left: 0
115
100
  },
116
- onScrubberPositionChange: setScrubberPosition,
117
101
  series: [{
118
102
  id: 'line',
119
103
  data: yData
@@ -144,6 +128,8 @@ function LiveUpdates() {
144
128
  return sparklineInteractiveData.hour.map(d => d.value);
145
129
  }, []);
146
130
  const [priceData, setPriceData] = useState(initialData);
131
+ const chartAccessibilityLabel = "Live price chart with " + priceData.length + " data points.";
132
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + priceData[index], [priceData]);
147
133
  const lastDataPointTimeRef = useRef(Date.now());
148
134
  const updateCountRef = useRef(0);
149
135
  const intervalSeconds = 3600 / initialData.length;
@@ -182,6 +168,8 @@ function LiveUpdates() {
182
168
  return /*#__PURE__*/_jsx(LineChart, {
183
169
  enableScrubbing: true,
184
170
  showArea: true,
171
+ accessibilityLabel: chartAccessibilityLabel,
172
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
185
173
  height: 200,
186
174
  inset: {
187
175
  right: 64
@@ -198,9 +186,17 @@ function LiveUpdates() {
198
186
  }
199
187
  function MissingData() {
200
188
  const theme = useTheme();
201
- const pages = ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'];
202
- const pageViews = [2400, 1398, null, 3908, 4800, 3800, 4300];
203
- const uniqueVisitors = [4000, 3000, null, 2780, 1890, 2390, 3490];
189
+ const pages = useMemo(() => ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'], []);
190
+ const pageViews = useMemo(() => [2400, 1398, null, 3908, 4800, 3800, 4300], []);
191
+ const uniqueVisitors = useMemo(() => [4000, 3000, null, 2780, 1890, 2390, 3490], []);
192
+ const chartAccessibilityLabel = "Website visitors across " + pages.length + " pages. Some data points are missing.";
193
+ const getScrubberAccessibilityLabel = useCallback(index => {
194
+ const pv = pageViews[index];
195
+ const uv = uniqueVisitors[index];
196
+ const pvStr = pv != null ? pv : 'no data';
197
+ const uvStr = uv != null ? uv : 'no data';
198
+ return pages[index] + ": " + pvStr + " views, " + uvStr + " unique visitors.";
199
+ }, [pages, pageViews, uniqueVisitors]);
204
200
  const numberFormatter = useCallback(value => new Intl.NumberFormat('en-US', {
205
201
  maximumFractionDigits: 0
206
202
  }).format(value), []);
@@ -210,6 +206,8 @@ function MissingData() {
210
206
  showArea: true,
211
207
  showXAxis: true,
212
208
  showYAxis: true,
209
+ accessibilityLabel: chartAccessibilityLabel,
210
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
213
211
  height: 200,
214
212
  series: [{
215
213
  id: 'pageViews',
@@ -239,6 +237,9 @@ function MissingData() {
239
237
  }
240
238
  function Interaction() {
241
239
  const [scrubberPosition, setScrubberPosition] = useState();
240
+ const data = useMemo(() => [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58], []);
241
+ const chartAccessibilityLabel = "Price chart with " + data.length + " data points. Swipe to navigate.";
242
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + data[index], [data]);
242
243
  return /*#__PURE__*/_jsxs(VStack, {
243
244
  gap: 2,
244
245
  children: [/*#__PURE__*/_jsx(Text, {
@@ -247,11 +248,13 @@ function Interaction() {
247
248
  }), /*#__PURE__*/_jsx(LineChart, {
248
249
  enableScrubbing: true,
249
250
  showArea: true,
251
+ accessibilityLabel: chartAccessibilityLabel,
252
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
250
253
  height: 200,
251
254
  onScrubberPositionChange: setScrubberPosition,
252
255
  series: [{
253
256
  id: 'prices',
254
- data: [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58]
257
+ data
255
258
  }],
256
259
  children: /*#__PURE__*/_jsx(Scrubber, {})
257
260
  })]
@@ -391,8 +394,12 @@ function Transitions() {
391
394
  color: positiveColor
392
395
  }]
393
396
  };
397
+ const chartAccessibilityLabel = "Price chart with " + data.length + " data points. Swipe to navigate.";
398
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + valueAtIndexFormatter(index), [valueAtIndexFormatter]);
394
399
  return /*#__PURE__*/_jsxs(CartesianChart, {
395
400
  enableScrubbing: true,
401
+ accessibilityLabel: chartAccessibilityLabel,
402
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
396
403
  height: 200,
397
404
  inset: {
398
405
  top: 32,
@@ -433,7 +440,6 @@ function Transitions() {
433
440
  return /*#__PURE__*/_jsx(CustomTransitionsChart, {});
434
441
  }
435
442
  function BasicAccessible() {
436
- const [scrubberPosition, setScrubberPosition] = useState();
437
443
  const data = useMemo(() => [10, 22, 29, 45, 98, 45, 22, 52, 21, 4, 68, 20, 21, 58], []);
438
444
 
439
445
  // Chart-level accessibility label provides overview
@@ -441,24 +447,14 @@ function BasicAccessible() {
441
447
  const currentPrice = data[data.length - 1];
442
448
  return "Price chart showing trend over " + data.length + " data points. Current value: " + currentPrice + ". Use arrow keys to adjust view";
443
449
  }, [data]);
444
-
445
- // Scrubber-level accessibility label provides specific position info
446
- const scrubberAccessibilityLabel = useCallback(index => {
447
- return "Price at position " + (index + 1) + " of " + data.length + ": " + data[index];
448
- }, [data]);
449
- const accessibilityLabel = useMemo(() => {
450
- if (scrubberPosition !== undefined) {
451
- return scrubberAccessibilityLabel(scrubberPosition);
452
- }
453
- return chartAccessibilityLabel;
454
- }, [scrubberPosition, chartAccessibilityLabel, scrubberAccessibilityLabel]);
450
+ const getScrubberAccessibilityLabel = useCallback(index => "Price at position " + (index + 1) + " of " + data.length + ": " + data[index], [data]);
455
451
  return /*#__PURE__*/_jsx(LineChart, {
456
452
  enableScrubbing: true,
457
453
  showArea: true,
458
454
  showYAxis: true,
459
- accessibilityLabel: accessibilityLabel,
455
+ accessibilityLabel: chartAccessibilityLabel,
456
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
460
457
  height: 200,
461
- onScrubberPositionChange: setScrubberPosition,
462
458
  series: [{
463
459
  id: 'prices',
464
460
  data: data
@@ -618,8 +614,12 @@ function GainLossChart() {
618
614
  }
619
615
  }
620
616
  })));
617
+ const chartAccessibilityLabel = "Price chart with " + data.length + " data points. Swipe to navigate.";
618
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + tickLabelFormatter(data[index]), [data, tickLabelFormatter]);
621
619
  return /*#__PURE__*/_jsxs(CartesianChart, {
622
620
  enableScrubbing: true,
621
+ accessibilityLabel: chartAccessibilityLabel,
622
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
623
623
  height: 200,
624
624
  series: [{
625
625
  id: 'prices',
@@ -674,9 +674,11 @@ function HighLowPrice() {
674
674
  }
675
675
  function StylingScrubber() {
676
676
  const theme = useTheme();
677
- const pages = ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'];
678
- const pageViews = [2400, 1398, 9800, 3908, 4800, 3800, 4300];
679
- const uniqueVisitors = [4000, 3000, 2000, 2780, 1890, 2390, 3490];
677
+ const pages = useMemo(() => ['Page A', 'Page B', 'Page C', 'Page D', 'Page E', 'Page F', 'Page G'], []);
678
+ const pageViews = useMemo(() => [2400, 1398, 9800, 3908, 4800, 3800, 4300], []);
679
+ const uniqueVisitors = useMemo(() => [4000, 3000, 2000, 2780, 1890, 2390, 3490], []);
680
+ const chartAccessibilityLabel = "Website visitors across " + pageViews.length + " pages.";
681
+ const getScrubberAccessibilityLabel = useCallback(index => pages[index] + ": " + pageViews[index] + " views, " + uniqueVisitors[index] + " unique visitors.", [pages, pageViews, uniqueVisitors]);
680
682
  const numberFormatter = useCallback(value => new Intl.NumberFormat('en-US', {
681
683
  maximumFractionDigits: 0
682
684
  }).format(value), []);
@@ -685,6 +687,8 @@ function StylingScrubber() {
685
687
  showArea: true,
686
688
  showXAxis: true,
687
689
  showYAxis: true,
690
+ accessibilityLabel: chartAccessibilityLabel,
691
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
688
692
  height: 200,
689
693
  series: [{
690
694
  id: 'pageViews',
@@ -905,6 +909,12 @@ function AssetPriceWithDottedArea() {
905
909
  });
906
910
  return dayOfWeek + ", " + monthDay + ", " + time;
907
911
  }, []);
912
+ const chartAccessibilityLabel = "Bitcoin price chart for " + timePeriod.label + " period. Current price: " + formatPrice(currentPrice) + ".";
913
+ const getScrubberAccessibilityLabel = useCallback(index => {
914
+ const price = formatPrice(sparklineTimePeriodDataValues[index]);
915
+ const date = formatDate(sparklineTimePeriodDataTimestamps[index]);
916
+ return price + " " + date;
917
+ }, [formatDate, formatPrice, sparklineTimePeriodDataTimestamps, sparklineTimePeriodDataValues]);
908
918
  return /*#__PURE__*/_jsxs(VStack, {
909
919
  gap: 2,
910
920
  children: [/*#__PURE__*/_jsx(SectionHeader, {
@@ -927,7 +937,9 @@ function AssetPriceWithDottedArea() {
927
937
  }), /*#__PURE__*/_jsx(LineChart, {
928
938
  enableScrubbing: true,
929
939
  showArea: true,
940
+ accessibilityLabel: chartAccessibilityLabel,
930
941
  areaType: "dotted",
942
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
931
943
  height: 200,
932
944
  inset: {
933
945
  top: 52
@@ -1089,11 +1101,19 @@ const PerformanceChart = /*#__PURE__*/memo(_ref10 => {
1089
1101
  return dayOfWeek + ", " + monthDay + ", " + time;
1090
1102
  }, []);
1091
1103
  const getScrubberLabel = useCallback(d => formatDate(sparklineTimePeriodDataTimestamps[d]), [formatDate, sparklineTimePeriodDataTimestamps]);
1104
+ const chartAccessibilityLabel = "Bitcoin price chart with high, actual, and low series. " + sparklineTimePeriodDataValues.length + " data points. Swipe to navigate.";
1105
+ const getScrubberAccessibilityLabel = useCallback(index => {
1106
+ const price = formatPriceThousands(sparklineTimePeriodDataValues[index]);
1107
+ const date = formatDate(sparklineTimePeriodDataTimestamps[index]);
1108
+ return "Point " + (index + 1) + ": " + price + ", " + date;
1109
+ }, [formatDate, formatPriceThousands, sparklineTimePeriodDataTimestamps, sparklineTimePeriodDataValues]);
1092
1110
  return /*#__PURE__*/_jsx(LineChart, {
1093
1111
  enableScrubbing: true,
1094
1112
  showArea: true,
1095
1113
  showYAxis: true,
1114
+ accessibilityLabel: chartAccessibilityLabel,
1096
1115
  areaType: "dotted",
1116
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
1097
1117
  height: 300,
1098
1118
  inset: {
1099
1119
  top: 52,
@@ -1250,6 +1270,12 @@ function MonotoneAssetPrice() {
1250
1270
  dy: -12,
1251
1271
  horizontalAlignment: "left"
1252
1272
  })), []);
1273
+ const chartAccessibilityLabel = "Price chart with " + prices.length + " data points. Swipe to navigate.";
1274
+ const getScrubberAccessibilityLabel = useCallback(index => {
1275
+ const price = scrubberPriceFormatter.format(prices[index].value);
1276
+ const date = formatDate(prices[index].date);
1277
+ return price + " USD " + date;
1278
+ }, [formatDate, prices, scrubberPriceFormatter]);
1253
1279
  const CustomScrubberBeacon = /*#__PURE__*/memo(_ref11 => {
1254
1280
  let {
1255
1281
  dataX,
@@ -1323,6 +1349,8 @@ function MonotoneAssetPrice() {
1323
1349
  return /*#__PURE__*/_jsx(LineChart, {
1324
1350
  enableScrubbing: true,
1325
1351
  showYAxis: true,
1352
+ accessibilityLabel: chartAccessibilityLabel,
1353
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
1326
1354
  height: 200,
1327
1355
  inset: {
1328
1356
  top: 64
@@ -1397,8 +1425,12 @@ function ServiceAvailability() {
1397
1425
  date: new Date('2022-01-10'),
1398
1426
  availability: 86
1399
1427
  }], []);
1428
+ const chartAccessibilityLabel = "Service availability chart with " + availabilityEvents.length + " data points. Swipe to navigate.";
1429
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + availabilityEvents[index].availability + "% availability on " + availabilityEvents[index].date.toLocaleDateString(), [availabilityEvents]);
1400
1430
  return /*#__PURE__*/_jsxs(CartesianChart, {
1401
1431
  enableScrubbing: true,
1432
+ accessibilityLabel: chartAccessibilityLabel,
1433
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
1402
1434
  height: 200,
1403
1435
  series: [{
1404
1436
  id: 'availability',
@@ -1471,7 +1503,7 @@ function ServiceAvailability() {
1471
1503
  }
1472
1504
  function ForecastAssetPrice() {
1473
1505
  const startYear = 2020;
1474
- const data = [50, 45, 47, 46, 54, 54, 60, 61, 63, 66, 70];
1506
+ const data = useMemo(() => [50, 45, 47, 46, 54, 54, 60, 61, 63, 66, 70], []);
1475
1507
  const currentIndex = 6;
1476
1508
  const strokeWidth = 3;
1477
1509
  // To prevent cutting off the edge of our lines
@@ -1575,8 +1607,12 @@ function ForecastAssetPrice() {
1575
1607
  })]
1576
1608
  });
1577
1609
  });
1610
+ const chartAccessibilityLabel = "Forecast chart with " + data.length + " data points. Swipe to navigate.";
1611
+ const getScrubberAccessibilityLabel = useCallback(index => "Point " + (index + 1) + ": " + axisFormatter(index) + ", value " + data[index], [axisFormatter, data]);
1578
1612
  return /*#__PURE__*/_jsxs(CartesianChart, {
1579
1613
  enableScrubbing: true,
1614
+ accessibilityLabel: chartAccessibilityLabel,
1615
+ getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
1580
1616
  height: 200,
1581
1617
  series: [{
1582
1618
  id: 'price',
@@ -1875,6 +1911,8 @@ function ExampleNavigator() {
1875
1911
  component: /*#__PURE__*/_jsxs(LineChart, {
1876
1912
  enableScrubbing: true,
1877
1913
  showArea: true,
1914
+ accessibilityLabel: "Price chart with reference line. 14 data points. Swipe to navigate.",
1915
+ getScrubberAccessibilityLabel: index => "Point " + (index + 1),
1878
1916
  height: 200,
1879
1917
  series: [{
1880
1918
  id: 'prices',