@react-magma/charts 13.0.4-next.0 → 14.0.0-next.1
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/dist/charts.js +447 -27
- package/dist/charts.js.map +1 -1
- package/dist/charts.modern.module.js +443 -30
- package/dist/charts.modern.module.js.map +1 -1
- package/dist/charts.umd.js +1303 -153
- package/dist/charts.umd.js.map +1 -1
- package/dist/components/CarbonChart/CarbonChart.d.ts +41 -0
- package/dist/components/ChartTable/ChartDataTable.d.ts +19 -0
- package/dist/components/ChartTable/ChartFullscreenButton.d.ts +26 -0
- package/dist/components/ChartTable/ChartMoreOptionsButton.d.ts +18 -0
- package/dist/components/ChartTable/ChartTable.stories.d.ts +116 -0
- package/dist/components/ChartTable/ChartTable.test.d.ts +1 -0
- package/dist/components/ChartTable/ChartTableButton.d.ts +24 -0
- package/dist/components/ChartTable/ChartTableModal.d.ts +44 -0
- package/dist/components/ChartTable/ChartToolbar.d.ts +19 -0
- package/dist/components/ChartTable/chartToolbarI18n.d.ts +16 -0
- package/dist/components/ChartTable/index.d.ts +14 -0
- package/dist/components/LineChart/DataTable.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/package.json +5 -5
- package/src/components/CarbonChart/CarbonChart.test.js +143 -2
- package/src/components/CarbonChart/CarbonChart.tsx +603 -15
- package/src/components/ChartTable/ChartDataTable.tsx +72 -0
- package/src/components/ChartTable/ChartFullscreenButton.tsx +59 -0
- package/src/components/ChartTable/ChartMoreOptionsButton.tsx +47 -0
- package/src/components/ChartTable/ChartTable.stories.tsx +152 -0
- package/src/components/ChartTable/ChartTable.test.tsx +444 -0
- package/src/components/ChartTable/ChartTableButton.tsx +55 -0
- package/src/components/ChartTable/ChartTableModal.tsx +135 -0
- package/src/components/ChartTable/ChartToolbar.tsx +50 -0
- package/src/components/ChartTable/chartToolbarI18n.ts +55 -0
- package/src/components/ChartTable/index.ts +23 -0
- package/src/components/LineChart/DataTable.tsx +3 -3
- package/src/components/LineChart/LineChart.tsx +1 -1
- package/src/index.ts +1 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Table,
|
|
5
|
+
TableBody,
|
|
6
|
+
TableCell,
|
|
7
|
+
TableHead,
|
|
8
|
+
TableHeaderCell,
|
|
9
|
+
TableRow,
|
|
10
|
+
} from 'react-magma-dom';
|
|
11
|
+
|
|
12
|
+
export interface ChartDataTableColumn {
|
|
13
|
+
/** Header text for this column */
|
|
14
|
+
header: string;
|
|
15
|
+
/** Key to read from each row object */
|
|
16
|
+
key: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ChartDataTableProps {
|
|
20
|
+
/** Column definitions (header + key). If omitted, columns are auto-derived from the dataset object keys with the first character capitalized (e.g. "group" → "Group"). */
|
|
21
|
+
columns?: ChartDataTableColumn[];
|
|
22
|
+
/** Array of data objects. Each object should have keys matching the column `key` values. */
|
|
23
|
+
dataSet: Array<Record<string, React.ReactNode>>;
|
|
24
|
+
/**
|
|
25
|
+
* If true, the table uses inverse (dark) styling.
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
isInverse?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function deriveColumns(
|
|
32
|
+
dataSet: Array<Record<string, React.ReactNode>>
|
|
33
|
+
): ChartDataTableColumn[] {
|
|
34
|
+
if (!dataSet.length) return [];
|
|
35
|
+
return Object.keys(dataSet[0]).map(key => ({
|
|
36
|
+
header: key.charAt(0).toUpperCase() + key.slice(1),
|
|
37
|
+
key,
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function ChartDataTable({
|
|
42
|
+
columns,
|
|
43
|
+
dataSet,
|
|
44
|
+
isInverse,
|
|
45
|
+
}: ChartDataTableProps) {
|
|
46
|
+
const resolvedColumns = columns || deriveColumns(dataSet);
|
|
47
|
+
return (
|
|
48
|
+
<Table isInverse={isInverse}>
|
|
49
|
+
<TableHead>
|
|
50
|
+
<TableRow>
|
|
51
|
+
{resolvedColumns.map(col => (
|
|
52
|
+
<TableHeaderCell key={col.key}>{col.header}</TableHeaderCell>
|
|
53
|
+
))}
|
|
54
|
+
</TableRow>
|
|
55
|
+
</TableHead>
|
|
56
|
+
<TableBody>
|
|
57
|
+
{dataSet.map((row, index) => {
|
|
58
|
+
const rowKey = resolvedColumns
|
|
59
|
+
.map(col => String(row[col.key] ?? ''))
|
|
60
|
+
.join('-');
|
|
61
|
+
return (
|
|
62
|
+
<TableRow key={`${rowKey}-${index}`}>
|
|
63
|
+
{resolvedColumns.map(col => (
|
|
64
|
+
<TableCell key={col.key}>{row[col.key]}</TableCell>
|
|
65
|
+
))}
|
|
66
|
+
</TableRow>
|
|
67
|
+
);
|
|
68
|
+
})}
|
|
69
|
+
</TableBody>
|
|
70
|
+
</Table>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { ButtonVariant, IconButton, Tooltip } from 'react-magma-dom';
|
|
4
|
+
|
|
5
|
+
import { useChartToolbarI18n } from './chartToolbarI18n';
|
|
6
|
+
|
|
7
|
+
export interface ChartFullscreenButtonProps {
|
|
8
|
+
/** Accessible label for the button, e.g. "View Overall Performance in full screen" */
|
|
9
|
+
ariaLabel: string;
|
|
10
|
+
/** Icon rendered when not in fullscreen mode */
|
|
11
|
+
icon: React.ReactElement;
|
|
12
|
+
/** Icon rendered when in fullscreen mode. Falls back to `icon` if omitted. */
|
|
13
|
+
exitIcon?: React.ReactElement;
|
|
14
|
+
/**
|
|
15
|
+
* If true, the button uses inverse (dark) styling.
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
isInverse?: boolean;
|
|
19
|
+
/** Whether the chart is currently in fullscreen mode */
|
|
20
|
+
isFullscreen: boolean;
|
|
21
|
+
/** Click handler – should toggle fullscreen */
|
|
22
|
+
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
|
|
23
|
+
/** Optional ref forwarded to the underlying IconButton */
|
|
24
|
+
buttonRef?: React.Ref<HTMLButtonElement>;
|
|
25
|
+
/**
|
|
26
|
+
* Tooltip text shown on hover.
|
|
27
|
+
* @default "Make full screen" / "Exit full screen" based on state (i18n overridable)
|
|
28
|
+
*/
|
|
29
|
+
tooltipContent?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function ChartFullscreenButton({
|
|
33
|
+
ariaLabel,
|
|
34
|
+
buttonRef,
|
|
35
|
+
exitIcon,
|
|
36
|
+
icon,
|
|
37
|
+
isInverse,
|
|
38
|
+
isFullscreen,
|
|
39
|
+
onClick,
|
|
40
|
+
tooltipContent,
|
|
41
|
+
}: ChartFullscreenButtonProps) {
|
|
42
|
+
const t = useChartToolbarI18n();
|
|
43
|
+
const resolvedTooltip =
|
|
44
|
+
tooltipContent ?? (isFullscreen ? t.exitFullScreen : t.makeFullScreen);
|
|
45
|
+
const resolvedIcon = isFullscreen && exitIcon ? exitIcon : icon;
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Tooltip content={resolvedTooltip} isInverse={isInverse}>
|
|
49
|
+
<IconButton
|
|
50
|
+
aria-label={ariaLabel}
|
|
51
|
+
icon={resolvedIcon}
|
|
52
|
+
isInverse={isInverse}
|
|
53
|
+
onClick={onClick}
|
|
54
|
+
ref={buttonRef}
|
|
55
|
+
variant={ButtonVariant.link}
|
|
56
|
+
/>
|
|
57
|
+
</Tooltip>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ButtonVariant,
|
|
5
|
+
Dropdown,
|
|
6
|
+
DropdownButton,
|
|
7
|
+
DropdownContent,
|
|
8
|
+
} from 'react-magma-dom';
|
|
9
|
+
|
|
10
|
+
import { useChartToolbarI18n } from './chartToolbarI18n';
|
|
11
|
+
|
|
12
|
+
export interface ChartMoreOptionsButtonProps {
|
|
13
|
+
/**
|
|
14
|
+
* Accessible label for the trigger button.
|
|
15
|
+
* @default "More options" (i18n overridable)
|
|
16
|
+
*/
|
|
17
|
+
ariaLabel?: string;
|
|
18
|
+
/** Menu items rendered inside the dropdown (DropdownMenuItem, DropdownDivider, etc.) */
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
/** Icon element rendered inside the trigger button */
|
|
21
|
+
icon: React.ReactElement;
|
|
22
|
+
/**
|
|
23
|
+
* If true, the dropdown uses inverse (dark) styling.
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
isInverse?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function ChartMoreOptionsButton({
|
|
30
|
+
ariaLabel,
|
|
31
|
+
children,
|
|
32
|
+
icon,
|
|
33
|
+
isInverse,
|
|
34
|
+
}: ChartMoreOptionsButtonProps) {
|
|
35
|
+
const t = useChartToolbarI18n();
|
|
36
|
+
const resolvedAriaLabel = ariaLabel ?? t.moreOptionsAriaLabel;
|
|
37
|
+
return (
|
|
38
|
+
<Dropdown isInverse={isInverse}>
|
|
39
|
+
<DropdownButton
|
|
40
|
+
aria-label={resolvedAriaLabel}
|
|
41
|
+
icon={icon}
|
|
42
|
+
variant={ButtonVariant.link}
|
|
43
|
+
/>
|
|
44
|
+
<DropdownContent>{children}</DropdownContent>
|
|
45
|
+
</Dropdown>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { StoryFn, Meta } from '@storybook/react/types-6-0';
|
|
4
|
+
import { Card } from 'react-magma-dom';
|
|
5
|
+
|
|
6
|
+
import { CarbonChart, CarbonChartProps, CarbonChartType } from '../CarbonChart';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
component: CarbonChart,
|
|
10
|
+
title: 'CarbonChart/ChartToolbar',
|
|
11
|
+
argTypes: {
|
|
12
|
+
isInverse: {
|
|
13
|
+
control: { type: 'boolean' },
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
} as Meta;
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Shared data
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
const donutDataSet = [
|
|
23
|
+
{ group: 'Not attempted', value: 5 },
|
|
24
|
+
{ group: 'Poor performance (Score less than 33%)', value: 15 },
|
|
25
|
+
{ group: 'High performance (Score greater than 66%)', value: 50 },
|
|
26
|
+
{ group: 'Average performance (Score between 33% and 66%)', value: 30 },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const barDataSet = [
|
|
30
|
+
{ group: 'Chapter 1', value: 85 },
|
|
31
|
+
{ group: 'Chapter 2', value: 72 },
|
|
32
|
+
{ group: 'Chapter 3', value: 91 },
|
|
33
|
+
{ group: 'Chapter 4', value: 64 },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Full toolbar – Donut chart (all buttons via chartToolbar prop)
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Full toolbar with Show as Table, Full Screen, and More Options buttons,
|
|
42
|
+
* driven entirely by the `chartToolbar` prop on CarbonChart.
|
|
43
|
+
*
|
|
44
|
+
* Carbon's built-in toolbar is automatically disabled when `chartToolbar`
|
|
45
|
+
* is provided. The Magma toolbar renders accessible replacements with
|
|
46
|
+
* proper ARIA attributes, focus management, and heading semantics.
|
|
47
|
+
*/
|
|
48
|
+
const FullToolbarTemplate: StoryFn<CarbonChartProps> = args => (
|
|
49
|
+
<Card isInverse={args.isInverse} style={{ padding: '12px' }}>
|
|
50
|
+
<CarbonChart {...args} />
|
|
51
|
+
</Card>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
export const DonutWithToolbar = {
|
|
55
|
+
render: FullToolbarTemplate,
|
|
56
|
+
args: {
|
|
57
|
+
isInverse: false,
|
|
58
|
+
type: CarbonChartType.donut,
|
|
59
|
+
dataSet: donutDataSet,
|
|
60
|
+
options: {
|
|
61
|
+
title: 'Overall Activity Performance',
|
|
62
|
+
resizable: true,
|
|
63
|
+
height: '400px',
|
|
64
|
+
donut: {
|
|
65
|
+
center: { label: 'Questions' },
|
|
66
|
+
},
|
|
67
|
+
legend: {
|
|
68
|
+
truncation: { type: 'none' },
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
chartToolbar: {},
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Bar chart with custom table columns
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
export const BarWithToolbar = {
|
|
80
|
+
render: FullToolbarTemplate,
|
|
81
|
+
args: {
|
|
82
|
+
isInverse: false,
|
|
83
|
+
type: CarbonChartType.bar,
|
|
84
|
+
dataSet: barDataSet,
|
|
85
|
+
options: {
|
|
86
|
+
title: 'Chapter Performance',
|
|
87
|
+
axes: {
|
|
88
|
+
left: { mapsTo: 'value' },
|
|
89
|
+
bottom: { mapsTo: 'group', scaleType: 'labels' },
|
|
90
|
+
},
|
|
91
|
+
height: '400px',
|
|
92
|
+
},
|
|
93
|
+
chartToolbar: {
|
|
94
|
+
tableColumns: [
|
|
95
|
+
{ header: 'Chapter', key: 'group' },
|
|
96
|
+
{ header: 'Score (%)', key: 'value' },
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Inverse theme
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
export const InverseTheme = {
|
|
107
|
+
render: FullToolbarTemplate,
|
|
108
|
+
args: {
|
|
109
|
+
isInverse: true,
|
|
110
|
+
type: CarbonChartType.donut,
|
|
111
|
+
dataSet: donutDataSet,
|
|
112
|
+
options: {
|
|
113
|
+
title: 'Inverse Theme Demo',
|
|
114
|
+
resizable: true,
|
|
115
|
+
height: '400px',
|
|
116
|
+
donut: {
|
|
117
|
+
center: { label: 'Questions' },
|
|
118
|
+
},
|
|
119
|
+
legend: {
|
|
120
|
+
truncation: { type: 'none' },
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
chartToolbar: {},
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Table only (no fullscreen or more options)
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
export const TableOnly = {
|
|
132
|
+
render: FullToolbarTemplate,
|
|
133
|
+
args: {
|
|
134
|
+
isInverse: false,
|
|
135
|
+
type: CarbonChartType.donut,
|
|
136
|
+
dataSet: donutDataSet,
|
|
137
|
+
options: {
|
|
138
|
+
title: 'Table Only (No Fullscreen)',
|
|
139
|
+
resizable: true,
|
|
140
|
+
height: '400px',
|
|
141
|
+
donut: {
|
|
142
|
+
center: { label: 'Questions' },
|
|
143
|
+
},
|
|
144
|
+
legend: {
|
|
145
|
+
truncation: { type: 'none' },
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
chartToolbar: {
|
|
149
|
+
fullscreen: false,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
};
|