diff --git a/android/src/main/java/voltra/generated/ShortNames.kt b/android/src/main/java/voltra/generated/ShortNames.kt index e883a51..a0a2d72 100644 --- a/android/src/main/java/voltra/generated/ShortNames.kt +++ b/android/src/main/java/voltra/generated/ShortNames.kt @@ -67,6 +67,7 @@ object ShortNames { "fvar" to "fontVariant", "fw" to "fontWeight", "fgs" to "foregroundStyle", + "fss" to "foregroundStyleScale", "f" to "frame", "g" to "gap", "gs" to "gaugeStyle", @@ -83,6 +84,7 @@ object ShortNames { "ly" to "layout", "lp" to "layoutPriority", "l" to "left", + "lgv" to "legendVisibility", "ls" to "letterSpacing", "lh" to "lineHeight", "ll" to "lineLimit", @@ -95,6 +97,7 @@ object ShortNames { "mr" to "marginRight", "mt" to "marginTop", "mv" to "marginVertical", + "mrk" to "marks", "me" to "maskElement", "maxh" to "maxHeight", "max" to "maximumValue", @@ -163,6 +166,10 @@ object ShortNames { "valig" to "verticalAlignment", "wt" to "weight", "w" to "width", + "xgs" to "xAxisGridStyle", + "xav" to "xAxisVisibility", + "ygs" to "yAxisGridStyle", + "yav" to "yAxisVisibility", "zi" to "zIndex", ) diff --git a/data/components.json b/data/components.json index 23f2723..2901442 100644 --- a/data/components.json +++ b/data/components.json @@ -149,7 +149,14 @@ "scaleEffect": "sce", "rotationEffect": "re", "border": "bd", - "clipped": "clip" + "clipped": "clip", + "foregroundStyleScale": "fss", + "legendVisibility": "lgv", + "marks": "mrk", + "xAxisGridStyle": "xgs", + "xAxisVisibility": "xav", + "yAxisGridStyle": "ygs", + "yAxisVisibility": "yav" }, "styleProperties": [ "padding", @@ -1238,6 +1245,56 @@ "swiftAvailability": "iOS 16.0, macOS 13.0", "hasChildren": true, "parameters": {} + }, + { + "name": "Chart", + "description": "SwiftUI Charts component for data visualization", + "swiftAvailability": "iOS 16.0, macOS 13.0", + "hasChildren": true, + "parameters": { + "marks": { + "type": "array", + "optional": true, + "jsonEncoded": true, + "description": "Compact mark data encoded from children by toJSON" + }, + "xAxisVisibility": { + "type": "string", + "optional": true, + "enum": ["automatic", "visible", "hidden"], + "description": "Show or hide the x-axis" + }, + "xAxisGridStyle": { + "type": "object", + "optional": true, + "jsonEncoded": true, + "description": "Configure x-axis grid line style" + }, + "yAxisVisibility": { + "type": "string", + "optional": true, + "enum": ["automatic", "visible", "hidden"], + "description": "Show or hide the y-axis" + }, + "yAxisGridStyle": { + "type": "object", + "optional": true, + "jsonEncoded": true, + "description": "Configure y-axis grid line style" + }, + "legendVisibility": { + "type": "string", + "optional": true, + "enum": ["automatic", "visible", "hidden"], + "description": "Show or hide the chart legend" + }, + "foregroundStyleScale": { + "type": "object", + "optional": true, + "jsonEncoded": true, + "description": "Map of series name to color string" + } + } } ] } diff --git a/example/app/testing-grounds/chart-playground.tsx b/example/app/testing-grounds/chart-playground.tsx new file mode 100644 index 0000000..03d633a --- /dev/null +++ b/example/app/testing-grounds/chart-playground.tsx @@ -0,0 +1,5 @@ +import ChartPlaygroundScreen from '~/screens/testing-grounds/chart-playground/ChartPlaygroundScreen' + +export default function ChartPlaygroundIndex() { + return +} diff --git a/example/screens/testing-grounds/TestingGroundsScreen.tsx b/example/screens/testing-grounds/TestingGroundsScreen.tsx index 9e9ecba..d8a8a05 100644 --- a/example/screens/testing-grounds/TestingGroundsScreen.tsx +++ b/example/screens/testing-grounds/TestingGroundsScreen.tsx @@ -55,6 +55,13 @@ const TESTING_GROUNDS_SECTIONS = [ 'Interactive playground for experimenting with flex layout properties. Test alignItems, justifyContent, flexDirection, spacing, and padding with live visual feedback.', route: '/testing-grounds/flex-playground', }, + { + id: 'chart-playground', + title: 'Chart Playground', + description: + 'Explore all SwiftUI chart mark types: BarMark, LineMark, AreaMark, PointMark, RuleMark, and SectorMark. Randomize data to see animated transitions.', + route: '/testing-grounds/chart-playground', + }, { id: 'image-preloading', title: 'Image Preloading', diff --git a/example/screens/testing-grounds/chart-playground/ChartPlaygroundScreen.tsx b/example/screens/testing-grounds/chart-playground/ChartPlaygroundScreen.tsx new file mode 100644 index 0000000..73274b5 --- /dev/null +++ b/example/screens/testing-grounds/chart-playground/ChartPlaygroundScreen.tsx @@ -0,0 +1,339 @@ +import { Link } from 'expo-router' +import React, { useCallback, useState } from 'react' +import { ScrollView, StyleSheet, Text, View } from 'react-native' +import { Voltra } from 'voltra' +import { VoltraView } from 'voltra/client' + +import { Button } from '~/components/Button' +import { Card } from '~/components/Card' + +// ─── data helpers ─────────────────────────────────────────────────────────── + +const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] + +const randomValue = (min: number, max: number) => Math.round(Math.random() * (max - min) + min) + +const randomBarData = () => MONTHS.map((m) => ({ x: m, y: randomValue(20, 120) })) + +const randomMultiSeriesData = () => [ + ...MONTHS.map((m) => ({ x: m, y: randomValue(20, 100), series: 'A' })), + ...MONTHS.map((m) => ({ x: m, y: randomValue(20, 100), series: 'B' })), +] + +const randomLineData = () => MONTHS.map((m) => ({ x: m, y: randomValue(30, 100) })) + +const randomAreaData = () => MONTHS.map((m) => ({ x: m, y: randomValue(10, 90) })) + +const randomPointData = () => Array.from({ length: 12 }, (_, i) => ({ x: randomValue(0, 100), y: randomValue(0, 100) })) + +const randomSectorData = () => { + const raw = [ + { category: 'Work', value: randomValue(20, 50) }, + { category: 'Sleep', value: randomValue(20, 40) }, + { category: 'Leisure', value: randomValue(10, 30) }, + { category: 'Exercise', value: randomValue(5, 20) }, + ] + return raw +} + +const randomRuleY = () => randomValue(30, 80) +const randomRuleX = () => MONTHS[randomValue(0, MONTHS.length - 1)] ?? MONTHS[0] +const randomPointRuleY = () => randomValue(0, 100) +const randomPointRuleX = () => randomValue(0, 100) + +// ─── chart preview wrapper ─────────────────────────────────────────────────── + +function ChartPreview({ children }: { children: React.ReactNode }) { + return {children} +} + +// ─── screen ───────────────────────────────────────────────────────────────── + +export default function ChartPlaygroundScreen() { + const [barData, setBarData] = useState(randomBarData) + const [multiData, setMultiData] = useState(randomMultiSeriesData) + const [lineData, setLineData] = useState(randomLineData) + const [areaData, setAreaData] = useState(randomAreaData) + const [pointData, setPointData] = useState(randomPointData) + const [pointRuleY, setPointRuleY] = useState(randomPointRuleY) + const [pointRuleX, setPointRuleX] = useState(randomPointRuleX) + const [sectorData, setSectorData] = useState(randomSectorData) + const [ruleY, setRuleY] = useState(randomRuleY) + const [ruleX, setRuleX] = useState(randomRuleX) + const [comboBarData, setComboBarData] = useState(randomBarData) + const [comboLineData, setComboLineData] = useState(randomLineData) + + const randomizeAll = useCallback(() => { + setBarData(randomBarData()) + setMultiData(randomMultiSeriesData()) + setLineData(randomLineData()) + setAreaData(randomAreaData()) + setPointData(randomPointData()) + setPointRuleY(randomPointRuleY()) + setPointRuleX(randomPointRuleX()) + setSectorData(randomSectorData()) + setRuleY(randomRuleY()) + setRuleX(randomRuleX()) + setComboBarData(randomBarData()) + setComboLineData(randomLineData()) + }, []) + + return ( + + + Chart Playground + + All SwiftUI chart mark types powered by Voltra. Tap Randomize to animate between data sets. + + + +