@colixsystems/widget-sdk 0.246.0 → 0.248.0
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/README.md +76 -6
- package/dist/board-auto-scroll.js +59 -0
- package/dist/board-view.js +327 -0
- package/dist/chart-logic.js +575 -0
- package/dist/chart-tokens.js +131 -0
- package/dist/chart-view.js +262 -0
- package/dist/chart.js +21 -0
- package/dist/chart.native.js +10 -0
- package/dist/contract.cjs +119 -7
- package/dist/contract.js +119 -7
- package/dist/data-table-logic.js +179 -0
- package/dist/data-table-view.js +388 -0
- package/dist/data-table.js +22 -0
- package/dist/data-table.native.js +14 -0
- package/dist/drag-kit-view.js +310 -0
- package/dist/file-upload-view.js +13 -2
- package/dist/filter-bar-logic.js +143 -0
- package/dist/filter-bar-view.js +381 -0
- package/dist/filter-bar.js +15 -0
- package/dist/filter-bar.native.js +13 -0
- package/dist/form-control-logic.js +20 -3
- package/dist/form-control-view.js +18 -0
- package/dist/form-layout-logic.js +92 -0
- package/dist/form-view.js +268 -0
- package/dist/form.js +15 -0
- package/dist/form.native.js +9 -0
- package/dist/grid-logic.js +222 -0
- package/dist/grid-view.js +109 -0
- package/dist/grid.js +7 -0
- package/dist/grid.native.js +7 -0
- package/dist/host.d.ts +6 -0
- package/dist/host.js +2 -0
- package/dist/index.d.ts +606 -7
- package/dist/index.js +15 -0
- package/dist/index.native.js +15 -0
- package/dist/menu-view.js +5 -2
- package/dist/people-picker-logic.js +203 -0
- package/dist/people-picker-view.js +250 -0
- package/dist/people-picker.js +11 -0
- package/dist/people-picker.native.js +9 -0
- package/dist/radio-group-view.js +7 -3
- package/dist/select-search-logic.js +150 -0
- package/dist/select-view.js +251 -18
- package/dist/select.js +6 -2
- package/dist/select.native.js +5 -3
- package/dist/sortable-list-view.js +228 -0
- package/dist/sortable-logic.js +273 -0
- package/dist/sortable-tokens.js +120 -0
- package/dist/sortable-view.js +24 -0
- package/dist/sortable.js +39 -0
- package/dist/sortable.native.js +30 -0
- package/dist/text-field-view.js +7 -2
- package/package.json +1 -1
- package/src/contract.js +119 -7
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// The colours and corners `<Chart>` paints with, resolved from the theme's
|
|
2
|
+
// `chart` scope and falling back to the theme's own colours. Platform-free,
|
|
3
|
+
// so both hosts draw one chart from the same values.
|
|
4
|
+
|
|
5
|
+
import { DEFAULT_THEME_TOKENS } from "./_theme-tokens.js";
|
|
6
|
+
import { CONTRACT, isHexColor, mixHex } from "./contract.js";
|
|
7
|
+
import { normaliseThemeComponents } from "./theme-components.js";
|
|
8
|
+
|
|
9
|
+
export const CHART_SERIES_TOKENS = Object.freeze(["series1", "series2", "series3", "series4", "series5", "series6"]);
|
|
10
|
+
|
|
11
|
+
// Distinct hues first, so two series rarely share a family.
|
|
12
|
+
const PALETTE_ROLES = Object.freeze(["primary", "warning", "secondary", "danger", "info", "success"]);
|
|
13
|
+
// How far a seventh-and-later series is lightened toward the surface.
|
|
14
|
+
const REPEAT_TINT = 0.45;
|
|
15
|
+
|
|
16
|
+
function themeColors(theme) {
|
|
17
|
+
return { ...DEFAULT_THEME_TOKENS.colors, ...((theme && theme.colors) || {}) };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** The six series colours an unthemed chart uses: the theme's own, deduplicated. */
|
|
21
|
+
function defaultPalette(colors) {
|
|
22
|
+
const seen = new Set();
|
|
23
|
+
const palette = [];
|
|
24
|
+
for (const role of PALETTE_ROLES) {
|
|
25
|
+
const colour = colors[role];
|
|
26
|
+
const key = typeof colour === "string" ? colour.toLowerCase() : "";
|
|
27
|
+
if (!key || seen.has(key)) continue;
|
|
28
|
+
seen.add(key);
|
|
29
|
+
palette.push(colour);
|
|
30
|
+
}
|
|
31
|
+
for (let i = 0; palette.length < CHART_SERIES_TOKENS.length; i += 1) {
|
|
32
|
+
palette.push(mixHex(colors.primary, i % 2 ? colors.surface : colors.onSurface, 0.3 + 0.15 * Math.floor(i / 2)));
|
|
33
|
+
}
|
|
34
|
+
return palette;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Resolve one chart's look: the `chart` scope first, then the theme.
|
|
39
|
+
*
|
|
40
|
+
* @param {object} theme — the resolved workspace theme (`useTheme()` shape).
|
|
41
|
+
* @returns {{ palette: string[], axisColor: string, gridColor: string, barRadius: number, surface: string, fontFamily: string, fontSize: number }}
|
|
42
|
+
*/
|
|
43
|
+
export function resolveChartTokens(theme) {
|
|
44
|
+
const base = theme && typeof theme === "object" ? theme : DEFAULT_THEME_TOKENS;
|
|
45
|
+
const colors = themeColors(base);
|
|
46
|
+
const radii = base.radii || DEFAULT_THEME_TOKENS.radii;
|
|
47
|
+
const typography = base.typography || DEFAULT_THEME_TOKENS.typography;
|
|
48
|
+
const sizes = typography.sizes || DEFAULT_THEME_TOKENS.typography.sizes;
|
|
49
|
+
const scope = normaliseThemeComponents(base.components).chart || {};
|
|
50
|
+
const fallback = defaultPalette(colors);
|
|
51
|
+
return {
|
|
52
|
+
palette: CHART_SERIES_TOKENS.map((token, i) => scope[token] ?? fallback[i]),
|
|
53
|
+
axisColor: scope.axisColor ?? colors.onSurfaceMuted,
|
|
54
|
+
gridColor: scope.gridColor ?? colors.border,
|
|
55
|
+
barRadius: scope.barRadius ?? radii.sm,
|
|
56
|
+
surface: colors.surface,
|
|
57
|
+
fontFamily: typography.fontFamily || DEFAULT_THEME_TOKENS.typography.fontFamily,
|
|
58
|
+
fontSize: sizes.xs || DEFAULT_THEME_TOKENS.typography.sizes.xs,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const RGB = /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*[\d.]+%?\s*)?\)$/i;
|
|
63
|
+
|
|
64
|
+
// A `#rrggbb` for a hex or rgb() colour, so it can be mixed; else null.
|
|
65
|
+
function mixable(colour) {
|
|
66
|
+
if (isHexColor(colour)) return colour;
|
|
67
|
+
const rgb = typeof colour === "string" ? RGB.exec(colour.trim()) : null;
|
|
68
|
+
if (!rgb) return null;
|
|
69
|
+
return `#${rgb.slice(1, 4).map((n) => Math.min(255, Number(n)).toString(16).padStart(2, "0")).join("")}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* How series (or donut slice) `index` is painted: its palette colour, a
|
|
74
|
+
* seventh and later one lighter. A colour that cannot be mixed (a named or
|
|
75
|
+
* hsl() colour) repeats at a lower opacity instead.
|
|
76
|
+
*
|
|
77
|
+
* @returns {{ color: string, opacity: number }}
|
|
78
|
+
*/
|
|
79
|
+
export function chartSeriesPaint(tokens, index) {
|
|
80
|
+
const palette = tokens.palette;
|
|
81
|
+
const colour = palette[index % palette.length];
|
|
82
|
+
const round = Math.floor(index / palette.length);
|
|
83
|
+
if (round === 0) return { color: colour, opacity: 1 };
|
|
84
|
+
const tint = Math.min(0.8, REPEAT_TINT * round);
|
|
85
|
+
const hex = mixable(colour);
|
|
86
|
+
return hex ? { color: mixHex(hex, tokens.surface, tint), opacity: 1 } : { color: colour, opacity: 1 - tint };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The colour of series (or donut slice) `index`; see `chartSeriesPaint`. */
|
|
90
|
+
export function chartSeriesColor(tokens, index) {
|
|
91
|
+
return chartSeriesPaint(tokens, index).color;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The colours `<Chart>` paints with, for a chart a widget draws itself (a
|
|
96
|
+
* scatter plot, a timeline): `series(i)` and `seriesOpacity(i)` for the i-th
|
|
97
|
+
* series' marks, `axis` for labels and the axis line, `grid` for gridlines.
|
|
98
|
+
* Pass it `useTheme()`, so a hand-drawn chart follows Design > Components >
|
|
99
|
+
* Charts exactly as `<Chart>` does.
|
|
100
|
+
*
|
|
101
|
+
* @param {object} theme — the resolved workspace theme (`useTheme()` shape).
|
|
102
|
+
*/
|
|
103
|
+
export function chartColors(theme) {
|
|
104
|
+
const tokens = resolveChartTokens(theme);
|
|
105
|
+
return {
|
|
106
|
+
palette: tokens.palette.slice(),
|
|
107
|
+
axis: tokens.axisColor,
|
|
108
|
+
grid: tokens.gridColor,
|
|
109
|
+
series: (index) => chartSeriesPaint(tokens, index).color,
|
|
110
|
+
seriesOpacity: (index) => chartSeriesPaint(tokens, index).opacity,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* What each `chart` token resolves to while unset, keyed by token name, so
|
|
116
|
+
* the Studio previews the colour each control would replace.
|
|
117
|
+
*
|
|
118
|
+
* @param {object} theme — the resolved workspace theme (`useTheme()` shape).
|
|
119
|
+
*/
|
|
120
|
+
export function chartScopeDefaults(theme) {
|
|
121
|
+
const base = theme && typeof theme === "object" ? theme : DEFAULT_THEME_TOKENS;
|
|
122
|
+
const components = { ...(base.components || {}) };
|
|
123
|
+
delete components.chart;
|
|
124
|
+
const unset = resolveChartTokens({ ...base, components });
|
|
125
|
+
const out = {};
|
|
126
|
+
for (const token of Object.keys(CONTRACT.themeComponents.chart.tokens)) {
|
|
127
|
+
const series = CHART_SERIES_TOKENS.indexOf(token);
|
|
128
|
+
out[token] = series === -1 ? unset[token] : unset.palette[series];
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
// The ONE implementation behind the `<Chart>` SDK primitive. The platform
|
|
2
|
+
// bindings (`chart.js` / `chart.native.js`) differ only in where the
|
|
3
|
+
// primitives and the SVG elements come from, so the hosts cannot drift.
|
|
4
|
+
//
|
|
5
|
+
// Every dashboard widget drew its own chart, each with its own colours, axes
|
|
6
|
+
// and empty state. This one reads the theme's `chart` scope.
|
|
7
|
+
|
|
8
|
+
import React from "react";
|
|
9
|
+
import { useHostLocale, useHostTheme, useHostSharedText } from "./hooks.js";
|
|
10
|
+
import { DEFAULT_THEME_TOKENS } from "./_theme-tokens.js";
|
|
11
|
+
import { CONTRACT } from "./contract.js";
|
|
12
|
+
import { textRoleStyle } from "./text-roles.js";
|
|
13
|
+
import { resolveChartTokens, chartSeriesPaint } from "./chart-tokens.js";
|
|
14
|
+
import {
|
|
15
|
+
normaliseChartType,
|
|
16
|
+
chartHeight,
|
|
17
|
+
normaliseChartData,
|
|
18
|
+
isChartEmpty,
|
|
19
|
+
cartesianLayout,
|
|
20
|
+
donutLayout,
|
|
21
|
+
barPath,
|
|
22
|
+
chartSummary,
|
|
23
|
+
formatChartValue,
|
|
24
|
+
} from "./chart-logic.js";
|
|
25
|
+
|
|
26
|
+
const h = React.createElement;
|
|
27
|
+
const NO_RESULTS_FALLBACK = CONTRACT.sharedTranslationKeys.no_results.en;
|
|
28
|
+
const AREA_OPACITY = 0.18;
|
|
29
|
+
const LINE_WIDTH = 2;
|
|
30
|
+
const DOT_RADIUS = 3;
|
|
31
|
+
const SWATCH_SIZE = 10;
|
|
32
|
+
const HIDDEN = { "aria-hidden": true, importantForAccessibility: "no-hide-descendants" };
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Bind the shared chart to one platform's primitives.
|
|
36
|
+
*
|
|
37
|
+
* @param {{View: any, Text: any, Svg: any, G: any, Path: any, Line: any, Circle: any, SvgText: any, Skeleton: any, EmptyState: any}} rn
|
|
38
|
+
*/
|
|
39
|
+
export function makeChart(rn) {
|
|
40
|
+
const { View, Text, Svg, G, Path, Line, Circle, SvgText, Skeleton, EmptyState } = rn;
|
|
41
|
+
|
|
42
|
+
function Legend({ items, theme, testID }) {
|
|
43
|
+
const typography = theme.typography || DEFAULT_THEME_TOKENS.typography;
|
|
44
|
+
const colors = theme.colors || DEFAULT_THEME_TOKENS.colors;
|
|
45
|
+
const spacing = theme.spacing || DEFAULT_THEME_TOKENS.spacing;
|
|
46
|
+
const label = textRoleStyle("caption", typography, colors);
|
|
47
|
+
return h(
|
|
48
|
+
View,
|
|
49
|
+
{
|
|
50
|
+
style: { flexDirection: "row", flexWrap: "wrap", columnGap: spacing.md, rowGap: spacing.xs, marginTop: spacing.sm },
|
|
51
|
+
testID: testID ? `${testID}-legend` : undefined,
|
|
52
|
+
},
|
|
53
|
+
items.map((item) =>
|
|
54
|
+
h(
|
|
55
|
+
View,
|
|
56
|
+
{ key: item.key, style: { flexDirection: "row", alignItems: "center", gap: spacing.xs, minWidth: 0 } },
|
|
57
|
+
h(View, {
|
|
58
|
+
style: {
|
|
59
|
+
width: SWATCH_SIZE,
|
|
60
|
+
height: SWATCH_SIZE,
|
|
61
|
+
borderRadius: SWATCH_SIZE / 2,
|
|
62
|
+
backgroundColor: item.paint.color,
|
|
63
|
+
opacity: item.paint.opacity,
|
|
64
|
+
},
|
|
65
|
+
}),
|
|
66
|
+
h(Text, { style: label, numberOfLines: 1 }, item.text),
|
|
67
|
+
),
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function axisText(label, i, tokens, prefix) {
|
|
73
|
+
return h(
|
|
74
|
+
SvgText,
|
|
75
|
+
{
|
|
76
|
+
key: `${prefix}-${i}`,
|
|
77
|
+
x: label.x,
|
|
78
|
+
y: label.y,
|
|
79
|
+
fill: tokens.axisColor,
|
|
80
|
+
fontSize: tokens.fontSize,
|
|
81
|
+
fontFamily: tokens.fontFamily,
|
|
82
|
+
textAnchor: label.anchor,
|
|
83
|
+
},
|
|
84
|
+
label.text,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function CartesianMarks({ kind, width, height, model, tokens, valueFormat, locale, paintOf }) {
|
|
89
|
+
const layout = cartesianLayout({ type: kind, width, height, model, fontSize: tokens.fontSize, valueFormat, locale });
|
|
90
|
+
const grid = layout.gridLines.map((line, i) =>
|
|
91
|
+
line.y === undefined
|
|
92
|
+
? h(Line, { key: `grid-${i}`, x1: line.x, x2: line.x, y1: line.y1, y2: line.y2, stroke: tokens.gridColor, strokeWidth: 1 })
|
|
93
|
+
: h(Line, { key: `grid-${i}`, x1: line.x1, x2: line.x2, y1: line.y, y2: line.y, stroke: tokens.gridColor, strokeWidth: 1 }),
|
|
94
|
+
);
|
|
95
|
+
const base = layout.baseline;
|
|
96
|
+
const axis = !base
|
|
97
|
+
? null
|
|
98
|
+
: base.y === undefined
|
|
99
|
+
? h(Line, { x1: base.x, x2: base.x, y1: base.y1, y2: base.y2, stroke: tokens.axisColor, strokeWidth: 1 })
|
|
100
|
+
: h(Line, { x1: base.x1, x2: base.x2, y1: base.y, y2: base.y, stroke: tokens.axisColor, strokeWidth: 1 });
|
|
101
|
+
return h(
|
|
102
|
+
G,
|
|
103
|
+
null,
|
|
104
|
+
kind === "sparkline" ? null : grid,
|
|
105
|
+
layout.areas.map((area) =>
|
|
106
|
+
h(Path, {
|
|
107
|
+
key: `area-${area.seriesIndex}`,
|
|
108
|
+
d: area.d,
|
|
109
|
+
fill: paintOf(area.seriesIndex).color,
|
|
110
|
+
fillOpacity: AREA_OPACITY * paintOf(area.seriesIndex).opacity,
|
|
111
|
+
}),
|
|
112
|
+
),
|
|
113
|
+
layout.bars.map((bar) =>
|
|
114
|
+
h(Path, {
|
|
115
|
+
key: `bar-${bar.seriesIndex}-${bar.index}`,
|
|
116
|
+
d: barPath(bar.rect, tokens.barRadius, bar.edge),
|
|
117
|
+
fill: paintOf(bar.seriesIndex).color,
|
|
118
|
+
fillOpacity: paintOf(bar.seriesIndex).opacity,
|
|
119
|
+
}),
|
|
120
|
+
),
|
|
121
|
+
axis,
|
|
122
|
+
layout.lines.map((line) =>
|
|
123
|
+
h(Path, {
|
|
124
|
+
key: `line-${line.seriesIndex}`,
|
|
125
|
+
d: line.d,
|
|
126
|
+
fill: "none",
|
|
127
|
+
stroke: paintOf(line.seriesIndex).color,
|
|
128
|
+
strokeOpacity: paintOf(line.seriesIndex).opacity,
|
|
129
|
+
strokeWidth: LINE_WIDTH,
|
|
130
|
+
strokeLinejoin: "round",
|
|
131
|
+
strokeLinecap: "round",
|
|
132
|
+
}),
|
|
133
|
+
),
|
|
134
|
+
layout.dots.map((dot, i) =>
|
|
135
|
+
h(Circle, {
|
|
136
|
+
key: `dot-${i}`,
|
|
137
|
+
cx: dot.cx,
|
|
138
|
+
cy: dot.cy,
|
|
139
|
+
r: DOT_RADIUS,
|
|
140
|
+
fill: paintOf(dot.seriesIndex).color,
|
|
141
|
+
fillOpacity: paintOf(dot.seriesIndex).opacity,
|
|
142
|
+
}),
|
|
143
|
+
),
|
|
144
|
+
layout.tickLabels.map((label, i) => axisText(label, i, tokens, "tick")),
|
|
145
|
+
layout.categoryLabels.map((label, i) => axisText(label, i, tokens, "label")),
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function DonutMarks({ width, height, model, tokens, valueFormat, locale, paintOf }) {
|
|
150
|
+
const layout = donutLayout({ width, height, model });
|
|
151
|
+
return h(
|
|
152
|
+
G,
|
|
153
|
+
null,
|
|
154
|
+
layout.slices.map((slice) =>
|
|
155
|
+
h(Path, {
|
|
156
|
+
key: `slice-${slice.index}`,
|
|
157
|
+
d: slice.d,
|
|
158
|
+
fill: paintOf(slice.index).color,
|
|
159
|
+
fillOpacity: paintOf(slice.index).opacity,
|
|
160
|
+
fillRule: "evenodd",
|
|
161
|
+
}),
|
|
162
|
+
),
|
|
163
|
+
h(
|
|
164
|
+
SvgText,
|
|
165
|
+
{
|
|
166
|
+
x: layout.cx,
|
|
167
|
+
y: layout.cy + tokens.fontSize / 3,
|
|
168
|
+
fill: tokens.axisColor,
|
|
169
|
+
fontSize: tokens.fontSize + 2,
|
|
170
|
+
fontWeight: "600",
|
|
171
|
+
fontFamily: tokens.fontFamily,
|
|
172
|
+
textAnchor: "middle",
|
|
173
|
+
},
|
|
174
|
+
formatChartValue(layout.total, valueFormat, locale),
|
|
175
|
+
),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function Chart(props) {
|
|
180
|
+
const {
|
|
181
|
+
type,
|
|
182
|
+
data,
|
|
183
|
+
series,
|
|
184
|
+
valueFormat,
|
|
185
|
+
height,
|
|
186
|
+
loading,
|
|
187
|
+
emptyTitle,
|
|
188
|
+
emptyMessage,
|
|
189
|
+
accessibilityLabel,
|
|
190
|
+
moreText,
|
|
191
|
+
theme: explicitTheme,
|
|
192
|
+
style,
|
|
193
|
+
testID,
|
|
194
|
+
} = props;
|
|
195
|
+
const hostTheme = useHostTheme();
|
|
196
|
+
// A host drawing outside a widget context passes its own theme.
|
|
197
|
+
const theme = explicitTheme || hostTheme || DEFAULT_THEME_TOKENS;
|
|
198
|
+
const noResults = useHostSharedText("no_results", NO_RESULTS_FALLBACK);
|
|
199
|
+
const locale = useHostLocale();
|
|
200
|
+
const [width, setWidth] = React.useState(0);
|
|
201
|
+
const kind = normaliseChartType(type);
|
|
202
|
+
const plotHeight = chartHeight(kind, height);
|
|
203
|
+
const model = React.useMemo(() => normaliseChartData(data, series), [data, series]);
|
|
204
|
+
|
|
205
|
+
if (loading) {
|
|
206
|
+
return h(Skeleton, { shape: "block", height: plotHeight, theme: explicitTheme, style, testID });
|
|
207
|
+
}
|
|
208
|
+
if (isChartEmpty(model, kind)) {
|
|
209
|
+
return h(EmptyState, { title: emptyTitle || noResults, message: emptyMessage, style, testID });
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const tokens = resolveChartTokens(theme);
|
|
213
|
+
const paintOf = (index) => {
|
|
214
|
+
const own = kind === "donut" ? undefined : model.series[index] && model.series[index].color;
|
|
215
|
+
return own ? { color: own, opacity: 1 } : chartSeriesPaint(tokens, index);
|
|
216
|
+
};
|
|
217
|
+
const onLayout = (event) => {
|
|
218
|
+
const next = Math.floor(event.nativeEvent.layout.width);
|
|
219
|
+
if (next !== width) setWidth(next);
|
|
220
|
+
};
|
|
221
|
+
const marks =
|
|
222
|
+
width <= 0
|
|
223
|
+
? null
|
|
224
|
+
: h(
|
|
225
|
+
Svg,
|
|
226
|
+
{ width, height: plotHeight },
|
|
227
|
+
kind === "donut"
|
|
228
|
+
? h(DonutMarks, { width, height: plotHeight, model, tokens, valueFormat, locale, paintOf })
|
|
229
|
+
: h(CartesianMarks, { kind, width, height: plotHeight, model, tokens, valueFormat, locale, paintOf }),
|
|
230
|
+
);
|
|
231
|
+
const legendItems =
|
|
232
|
+
kind === "donut"
|
|
233
|
+
? donutLayout({ width: 1, height: 1, model }).slices.map((slice) => ({
|
|
234
|
+
key: `slice-${slice.index}`,
|
|
235
|
+
paint: paintOf(slice.index),
|
|
236
|
+
text: `${model.labels[slice.index]} ${formatChartValue(model.series[0].values[slice.index], valueFormat, locale)}`,
|
|
237
|
+
}))
|
|
238
|
+
: model.series.length > 1 && kind !== "sparkline"
|
|
239
|
+
? model.series.map((s, i) => ({ key: s.key, paint: paintOf(i), text: s.label }))
|
|
240
|
+
: null;
|
|
241
|
+
|
|
242
|
+
return h(
|
|
243
|
+
View,
|
|
244
|
+
{
|
|
245
|
+
accessible: true,
|
|
246
|
+
accessibilityRole: "image",
|
|
247
|
+
accessibilityLabel: chartSummary({ type: kind, model, valueFormat, lead: accessibilityLabel, locale, moreText }),
|
|
248
|
+
style: [{ width: "100%" }, style],
|
|
249
|
+
testID,
|
|
250
|
+
},
|
|
251
|
+
h(
|
|
252
|
+
View,
|
|
253
|
+
{ ...HIDDEN, onLayout, style: { width: "100%", height: plotHeight }, testID: testID ? `${testID}-plot` : undefined },
|
|
254
|
+
marks,
|
|
255
|
+
),
|
|
256
|
+
legendItems ? h(Legend, { items: legendItems, theme, testID }) : null,
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
Chart.displayName = "Chart";
|
|
260
|
+
|
|
261
|
+
return { Chart };
|
|
262
|
+
}
|
package/dist/chart.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// `<Chart>` (web). Binds ./chart-view.js to react-native-web and the host's
|
|
2
|
+
// react-native-svg; see ./primitives.js for why not the bare specifier.
|
|
3
|
+
|
|
4
|
+
import * as ReactNative from "react-native-web";
|
|
5
|
+
import Svg, { G, Path, Line, Circle, Text as SvgText } from "react-native-svg";
|
|
6
|
+
import { Skeleton } from "./loading.js";
|
|
7
|
+
import { EmptyState } from "./list.js";
|
|
8
|
+
import { makeChart } from "./chart-view.js";
|
|
9
|
+
|
|
10
|
+
export const { Chart } = makeChart({
|
|
11
|
+
View: ReactNative.View,
|
|
12
|
+
Text: ReactNative.Text,
|
|
13
|
+
Svg,
|
|
14
|
+
G,
|
|
15
|
+
Path,
|
|
16
|
+
Line,
|
|
17
|
+
Circle,
|
|
18
|
+
SvgText,
|
|
19
|
+
Skeleton,
|
|
20
|
+
EmptyState,
|
|
21
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// `<Chart>` (native). Binds ./chart-view.js to React Native and
|
|
2
|
+
// react-native-svg; only the imports differ from ./chart.js.
|
|
3
|
+
|
|
4
|
+
import { View, Text } from "react-native";
|
|
5
|
+
import Svg, { G, Path, Line, Circle, Text as SvgText } from "react-native-svg";
|
|
6
|
+
import { Skeleton } from "./loading.native.js";
|
|
7
|
+
import { EmptyState } from "./list.native.js";
|
|
8
|
+
import { makeChart } from "./chart-view.js";
|
|
9
|
+
|
|
10
|
+
export const { Chart } = makeChart({ View, Text, Svg, G, Path, Line, Circle, SvgText, Skeleton, EmptyState });
|