Skip to content

Commit 54042f6

Browse files
committed
feat(showcase): expose accessibility data details
1 parent 8a6ba09 commit 54042f6

14 files changed

Lines changed: 497 additions & 20 deletions

apps/expo-showcase/App.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ export default function App() {
397397
<View style={styles.storyGrid}>
398398
{group.stories.map((story) => {
399399
const StoryComponent = story.Component;
400+
const StoryDetails = story.Details;
400401
const tags = storyFeatureTags[story.id] ?? [];
401402

402403
return (
@@ -413,6 +414,9 @@ export default function App() {
413414
onScrubStart={() => setIsScrubbing(true)}
414415
onScrubEnd={() => setIsScrubbing(false)}
415416
/>
417+
{StoryDetails ? (
418+
<StoryDetails width={chartWidth} />
419+
) : null}
416420
{tags.length > 0 ? (
417421
<Text
418422
style={[
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { describe, expect, it, vi } from "vitest";
2+
3+
const { makeDataTable } = vi.hoisted(() => ({
4+
makeDataTable: () => ({
5+
columns: [{ key: "value", label: "Value" }],
6+
rows: [
7+
{
8+
dateLabel: "Jan 1",
9+
formattedClose: "$104",
10+
formattedHigh: "$108",
11+
formattedLow: "$98",
12+
formattedOpen: "$101",
13+
formattedValue: "Value",
14+
formattedValues: { value: "Value" },
15+
index: 0,
16+
label: "Sample",
17+
percentageLabel: "50%",
18+
xLabel: "Sample"
19+
}
20+
]
21+
})
22+
}));
23+
24+
vi.mock("react-native", () => ({
25+
Pressable: () => null,
26+
StyleSheet: { create: (styles: unknown) => styles },
27+
Text: () => null,
28+
View: () => null
29+
}));
30+
31+
vi.mock("@chart-kit/react-native", () => ({
32+
BarChart: () => null,
33+
ContributionGraph: () => null,
34+
DonutChart: () => null,
35+
LineChart: () => null,
36+
PieChart: () => null,
37+
ProgressChart: () => null,
38+
ProgressRing: () => null,
39+
getBarChartDataTable: makeDataTable,
40+
getContributionGraphDataTable: makeDataTable,
41+
getLineChartDataTable: makeDataTable,
42+
getPieChartDataTable: makeDataTable,
43+
getProgressChartDataTable: makeDataTable,
44+
useChartKitTheme: () => ({ mode: "light" })
45+
}));
46+
47+
vi.mock("@chart-kit/react-native/pro-preview", () => ({
48+
CandlestickChart: () => null,
49+
CombinedChart: () => null,
50+
LineChartRangeSelector: () => null,
51+
getCandlestickEmergencyClosureSessions: () => [],
52+
getCandlestickChartDataTable: makeDataTable,
53+
getCombinedChartDataTable: makeDataTable
54+
}));
55+
56+
vi.mock("@chart-kit/svg-renderer", () => ({
57+
SvgRect: () => null
58+
}));
59+
60+
import { publicChartMode } from "./publicChartMode";
61+
import { barOverviewStories } from "./stories/barOverviewStories";
62+
import { combinedOverviewStories } from "./stories/combinedOverviewStories";
63+
import { contributionOverviewStories } from "./stories/contributionOverviewStories";
64+
import { financialOverviewStories } from "./stories/financialOverviewStories";
65+
import { lineOverviewStories } from "./stories/lineOverviewStories";
66+
import { pieOverviewStories } from "./stories/pieOverviewStories";
67+
import { progressOverviewStories } from "./stories/progressOverviewStories";
68+
import type { ShowcasePage, ShowcaseStory } from "./stories/storyPrimitives";
69+
70+
const pagesRequiringTableFallback = [
71+
"line-charts",
72+
"bar-charts",
73+
"combined-charts",
74+
"financial-charts",
75+
"pie-donut",
76+
"progress",
77+
"heatmaps"
78+
];
79+
80+
const storiesWithAccessibilityDetails: ShowcaseStory[] = [
81+
...lineOverviewStories,
82+
...barOverviewStories,
83+
...combinedOverviewStories,
84+
...financialOverviewStories,
85+
...pieOverviewStories,
86+
...progressOverviewStories,
87+
...contributionOverviewStories
88+
];
89+
90+
const getPageStoryIds = (page: ShowcasePage) =>
91+
page.storyGroups?.flatMap((group) => group.storyIds) ?? page.storyIds ?? [];
92+
93+
describe("showcase accessibility data details", () => {
94+
it("keeps a table fallback story on every accessibility QA page", () => {
95+
for (const pageId of pagesRequiringTableFallback) {
96+
const page = publicChartMode.pages.find((item) => item.id === pageId);
97+
expect(
98+
page,
99+
`${pageId} should be part of the public chart mode`
100+
).toBeDefined();
101+
102+
if (!page) {
103+
continue;
104+
}
105+
106+
const pageStories = getPageStoryIds(page).map((storyId) =>
107+
storiesWithAccessibilityDetails.find((story) => story.id === storyId)
108+
);
109+
110+
expect(
111+
pageStories.some((story) => story?.Details !== undefined),
112+
`${pageId} should expose at least one collapsed data details panel`
113+
).toBe(true);
114+
}
115+
});
116+
});

apps/expo-showcase/src/stories/barOverviewStories.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useEffect, useMemo, useState } from "react";
22
import { Pressable, Text } from "react-native";
33

4-
import { BarChart } from "@chart-kit/react-native";
4+
import { BarChart, getBarChartDataTable } from "@chart-kit/react-native";
55
import { SvgRect } from "@chart-kit/svg-renderer";
66

77
import {
@@ -16,6 +16,7 @@ import {
1616
storyStyles,
1717
type NativeStoryProps
1818
} from "./storyPrimitives";
19+
import { ChartDataDetails, createFormattedValueDetails } from "./dataDetails";
1920

2021
const formatThousands = (value: number) => `${value}k`;
2122
const formatPercent = (value: number) => `${value}%`;
@@ -181,6 +182,20 @@ const V2GroupedBar = ({ width }: NativeStoryProps) => (
181182
</ChartSection>
182183
);
183184

185+
const acquisitionMixDetails = createFormattedValueDetails({
186+
categoryLabel: "Month",
187+
table: getBarChartDataTable({
188+
data: acquisitionByChannel,
189+
formatYLabel: formatThousands,
190+
xKey: "month",
191+
yKeys: ["organic", "paid"]
192+
})
193+
});
194+
195+
const V2GroupedBarDetails = () => (
196+
<ChartDataDetails title="Acquisition mix" {...acquisitionMixDetails} />
197+
);
198+
184199
const V2SelectableBar = ({ width }: NativeStoryProps) => (
185200
<ChartSection title="Paid acquisition" kicker="Tap selection">
186201
<BarChart
@@ -380,7 +395,8 @@ export const barOverviewStories = [
380395
{
381396
id: "v2-bar-grouped",
382397
title: "Grouped Bars",
383-
Component: V2GroupedBar
398+
Component: V2GroupedBar,
399+
Details: V2GroupedBarDetails
384400
},
385401
{
386402
id: "v2-bar-selection",

apps/expo-showcase/src/stories/combinedOverviewStories.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ import { useState } from "react";
22
import { Pressable, StyleSheet, Text, View } from "react-native";
33

44
import { useChartKitTheme } from "@chart-kit/react-native";
5-
import { CombinedChart } from "@chart-kit/react-native/pro-preview";
5+
import {
6+
CombinedChart,
7+
getCombinedChartDataTable
8+
} from "@chart-kit/react-native/pro-preview";
69

710
import { revenueMargin } from "../fixtures/v2Combined";
811
import { ChartSection, type NativeStoryProps } from "./storyPrimitives";
12+
import { ChartDataDetails, createFormattedValueDetails } from "./dataDetails";
913

1014
const formatCurrency = (value: number) => `$${value}k`;
1115
const formatPercent = (value: number) => `${value}%`;
@@ -61,6 +65,22 @@ const V2CombinedRevenueMargin = ({ width }: NativeStoryProps) => (
6165
</ChartSection>
6266
);
6367

68+
const revenueMarginDetails = createFormattedValueDetails({
69+
categoryLabel: "Month",
70+
table: getCombinedChartDataTable({
71+
bars: [{ yKey: "revenue", label: "Revenue" }],
72+
data: revenueMargin,
73+
formatLeftYLabel: formatCurrency,
74+
formatRightYLabel: formatPercent,
75+
lines: [{ yKey: "margin", label: "Margin" }],
76+
xKey: "month"
77+
})
78+
});
79+
80+
const V2CombinedRevenueMarginDetails = () => (
81+
<ChartDataDetails title="Revenue and margin" {...revenueMarginDetails} />
82+
);
83+
6484
const V2CombinedSharedTooltip = ({ width }: NativeStoryProps) => (
6585
<ChartSection title="Pipeline inspection" kicker="Shared tooltip">
6686
<CombinedChart
@@ -179,7 +199,8 @@ export const combinedOverviewStories = [
179199
{
180200
id: "v2-combined-revenue-margin",
181201
title: "Revenue + Margin",
182-
Component: V2CombinedRevenueMargin
202+
Component: V2CombinedRevenueMargin,
203+
Details: V2CombinedRevenueMarginDetails
183204
},
184205
{
185206
id: "v2-combined-shared-tooltip",

apps/expo-showcase/src/stories/contributionOverviewStories.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { ContributionGraph } from "@chart-kit/react-native";
1+
import {
2+
ContributionGraph,
3+
getContributionGraphDataTable
4+
} from "@chart-kit/react-native";
25

36
import {
47
productUsage,
@@ -9,6 +12,24 @@ import {
912
quietUsageNumDays
1013
} from "../fixtures/v2Contribution";
1114
import { ChartSection, type NativeStoryProps } from "./storyPrimitives";
15+
import { ChartDataDetails } from "./dataDetails";
16+
17+
const productUsageTable = getContributionGraphDataTable({
18+
endDate: productUsageEndDate,
19+
formatValue: (value) => `${value} events`,
20+
numDays: productUsageNumDays,
21+
values: productUsage
22+
});
23+
const productUsageDetails = {
24+
columns: [
25+
{ key: "date", label: "Date" },
26+
{ key: "events", label: "Events" }
27+
],
28+
rows: productUsageTable.rows.slice(-8).map((row) => ({
29+
key: `${row.index}`,
30+
values: [row.dateLabel, row.formattedValue]
31+
}))
32+
};
1233

1334
const V2ContributionUsage = ({ width }: NativeStoryProps) => (
1435
<ChartSection title="Product usage" kicker="Contribution heatmap">
@@ -24,6 +45,10 @@ const V2ContributionUsage = ({ width }: NativeStoryProps) => (
2445
</ChartSection>
2546
);
2647

48+
const V2ContributionUsageDetails = () => (
49+
<ChartDataDetails title="Product usage" {...productUsageDetails} />
50+
);
51+
2752
const V2ContributionQuiet = ({ width }: NativeStoryProps) => (
2853
<ChartSection title="Quiet workspace" kicker="Empty heatmap">
2954
<ContributionGraph
@@ -43,7 +68,8 @@ export const contributionOverviewStories = [
4368
{
4469
id: "v2-contribution-usage",
4570
title: "Product Usage Heatmap",
46-
Component: V2ContributionUsage
71+
Component: V2ContributionUsage,
72+
Details: V2ContributionUsageDetails
4773
},
4874
{
4975
id: "v2-contribution-empty",

0 commit comments

Comments
 (0)