UNPKG

@tanstack/charts

Version:

A chart grammar for TypeScript and JavaScript. Marks consume your data directly, channels describe visual encodings, and the engine compiles them into a renderer-neutral keyed scene. TanStack's compact scales cover common numeric and categorical mappings.

229 lines (228 loc) 5.87 kB
import { jsx, jsxs } from "react/jsx-runtime"; import * as React from "react"; import { Text, View } from "react-native"; import { createChartTooltipContent, orderChartTooltipPoints, resolveChartTooltipAnchor, resolveChartTooltipPlacement } from "@tanstack/charts/tooltip/model"; import { resolveNativeSolidPaint } from "./paint.js"; function NativeChartTooltip({ scene, width, height, points: unorderedPoints, pointer, focusSource, options, pinned, color, resolvePaint, dismiss, render }) { const [size, setSize] = React.useState({ width: 0, height: 0 }); const points = React.useMemo( () => orderChartTooltipPoints(unorderedPoints, scene, options?.sort), [options?.sort, scene, unorderedPoints] ); const point = unorderedPoints[0]; if (!point) return null; const content = createChartTooltipContent( points, scene, pinned, options, point ); const sceneAnchor = resolveChartTooltipAnchor( point, points, scene, pointer, options, { primary: point, group: unorderedPoints, source: focusSource, pinned } ); const anchor = { x: sceneAnchor.x / scene.width * width, y: sceneAnchor.y / scene.height * height }; const position = placeNativeTooltip( anchor, size, { width, height }, options?.placement, options?.offset ); const defaultBody = /* @__PURE__ */ jsx( DefaultNativeTooltipBody, { content, color, resolvePaint } ); const body = render ? render({ points, content, pinned, dismiss, defaultBody }) : defaultBody; const accessibilityLabel = tooltipAccessibilityLabel(content); const handleLayout = (event) => { const next = event.nativeEvent.layout; if (next.width !== size.width || next.height !== size.height) { setSize({ width: next.width, height: next.height }); } }; return /* @__PURE__ */ jsx( View, { accessibilityLabel, accessibilityLiveRegion: pinned ? "none" : "polite", accessibilityRole: pinned ? "summary" : void 0, onLayout: handleLayout, onStartShouldSetResponder: () => pinned, pointerEvents: pinned ? "auto" : "none", style: [tooltipStyle, { left: position.left, top: position.top }], children: body } ); } const tooltip = { id: "react-native-tooltip", __chartExtensionType: "tooltip", __chartTooltipHost: "react-native", create: () => NativeChartTooltip }; function DefaultNativeTooltipBody({ content, color, resolvePaint }) { if (typeof content === "string") { return /* @__PURE__ */ jsx(Text, { style: tooltipTextStyle, children: content }); } return /* @__PURE__ */ jsxs(View, { children: [ content.title ? /* @__PURE__ */ jsxs(View, { style: titleStyle, children: [ content.color ? /* @__PURE__ */ jsx( View, { style: [ swatchStyle, { backgroundColor: resolveNativeSolidPaint( content.color, { color }, resolvePaint ) } ] } ) : null, /* @__PURE__ */ jsx(Text, { style: titleTextStyle, children: content.title }) ] }) : null, content.rows.map((row, index) => /* @__PURE__ */ jsxs(View, { style: rowStyle, children: [ /* @__PURE__ */ jsx( View, { style: [ swatchStyle, { backgroundColor: row.color ? resolveNativeSolidPaint(row.color, { color }, resolvePaint) : "transparent" } ] } ), /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: rowLabelStyle, children: row.label }), /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: rowValueStyle, children: row.value }) ] }, `${row.label}:${index}`)) ] }); } function createNativeTooltipContent(points, scene, pinned = false, options, primaryPoint) { return createChartTooltipContent(points, scene, pinned, options, primaryPoint); } function resolveNativeTooltipAnchor(point, points, scene, pointer, focusSource, pinned, options, focusPoints = points) { return resolveChartTooltipAnchor(point, points, scene, pointer, options, { primary: point, group: focusPoints, source: focusSource, pinned }); } function placeNativeTooltip(anchor, tooltip2, boundary, placement, offset) { return resolveChartTooltipPlacement( anchor, tooltip2, { left: 0, top: 0, right: boundary.width, bottom: boundary.height }, placement, offset ); } function tooltipAccessibilityLabel(content) { return typeof content === "string" ? content : [ content.title, ...content.rows.map((row) => `${row.label}: ${row.value}`) ].filter(Boolean).join("\n"); } const tooltipStyle = { position: "absolute", zIndex: 1, maxWidth: "80%", paddingHorizontal: 9, paddingVertical: 7, borderWidth: 1, borderColor: "rgba(17, 24, 39, 0.16)", borderRadius: 7, backgroundColor: "#ffffff", shadowColor: "#000000", shadowOffset: { width: 0, height: 6 }, shadowOpacity: 0.14, shadowRadius: 12, elevation: 4 }; const tooltipTextStyle = { color: "#111827", fontSize: 12, fontWeight: "500" }; const titleStyle = { flexDirection: "row", alignItems: "center", gap: 6, marginBottom: 4 }; const titleTextStyle = { color: "#111827", fontSize: 12, fontWeight: "700" }; const rowStyle = { flexDirection: "row", alignItems: "center", gap: 6 }; const swatchStyle = { width: 9, height: 9, borderRadius: 2 }; const rowLabelStyle = { flexGrow: 1, flexShrink: 1, color: "#374151", fontSize: 12 }; const rowValueStyle = { color: "#111827", fontSize: 12, fontVariant: ["tabular-nums"] }; export { NativeChartTooltip, createNativeTooltipContent, placeNativeTooltip, resolveNativeTooltipAnchor, tooltip };