diff --git a/data/components.json b/data/components.json index 328a014..9e8e858 100644 --- a/data/components.json +++ b/data/components.json @@ -539,6 +539,16 @@ "type": "component", "optional": true, "description": "Custom thumb component to display at progress position" + }, + "label": { + "type": "component", + "optional": true, + "description": "Label content for the progress indicator" + }, + "currentValueLabel": { + "type": "component", + "optional": true, + "description": "Custom text for current value label" } } }, @@ -587,6 +597,16 @@ "type": "number", "optional": true, "description": "Width of the stroke line" + }, + "label": { + "type": "component", + "optional": true, + "description": "Label content for the progress indicator" + }, + "currentValueLabel": { + "type": "component", + "optional": true, + "description": "Custom text for current value label" } } }, diff --git a/example/app/testing-grounds/progress.tsx b/example/app/testing-grounds/progress.tsx new file mode 100644 index 0000000..50ee0cc --- /dev/null +++ b/example/app/testing-grounds/progress.tsx @@ -0,0 +1,7 @@ +import React from 'react' + +import ProgressTestingScreen from '~/screens/testing-grounds/progress/ProgressTestingScreen' + +export default function ProgressPage() { + return +} diff --git a/example/screens/testing-grounds/TestingGroundsScreen.tsx b/example/screens/testing-grounds/TestingGroundsScreen.tsx index 95faf98..c546097 100644 --- a/example/screens/testing-grounds/TestingGroundsScreen.tsx +++ b/example/screens/testing-grounds/TestingGroundsScreen.tsx @@ -34,6 +34,13 @@ const TESTING_GROUNDS_SECTIONS = [ 'Learn about static, relative, and absolute positioning modes. See how left, top, and zIndex properties work with visual examples.', route: '/testing-grounds/positioning', }, + { + id: 'progress', + title: 'Progress Indicators', + description: + 'Explore linear and circular progress indicators. Test determinate, indeterminate, and timer-based modes with custom labels and styling.', + route: '/testing-grounds/progress', + }, { id: 'components', title: 'Components', diff --git a/example/screens/testing-grounds/components/ComponentsScreen.tsx b/example/screens/testing-grounds/components/ComponentsScreen.tsx index 40b3861..6eb06fd 100644 --- a/example/screens/testing-grounds/components/ComponentsScreen.tsx +++ b/example/screens/testing-grounds/components/ComponentsScreen.tsx @@ -150,10 +150,21 @@ const COMPONENTS_DATA = [ title: 'Progress Components', description: 'Linear and circular progress indicators for showing completion states.', renderExample: () => ( - - - - + + + Downloading...} + currentValueLabel={75%} + /> + Uptime} + currentValueLabel={45%} + style={{ width: 60, height: 60 }} + /> ), diff --git a/example/screens/testing-grounds/progress/ProgressTestingScreen.tsx b/example/screens/testing-grounds/progress/ProgressTestingScreen.tsx new file mode 100644 index 0000000..42957cc --- /dev/null +++ b/example/screens/testing-grounds/progress/ProgressTestingScreen.tsx @@ -0,0 +1,347 @@ +import { useRouter } from 'expo-router' +import React, { useState } from 'react' +import { ScrollView, StyleSheet, Text, TextInput, useColorScheme, View } from 'react-native' +import { Voltra } from 'voltra' +import { VoltraWidgetPreview } from 'voltra/client' + +import { Button } from '~/components/Button' +import { Card } from '~/components/Card' + +export default function ProgressTestingScreen() { + const router = useRouter() + const colorScheme = useColorScheme() + + // State for interactivity + const [type, setType] = useState<'linear' | 'circular'>('linear') + const [mode, setMode] = useState<'determinate' | 'timer' | 'indeterminate'>('determinate') + const [progressValue, setProgressValue] = useState(65) + const [durationSec, setDurationSec] = useState('60') + const [timerState, setTimerState] = useState<{ startAtMs?: number; endAtMs?: number }>({ + startAtMs: Date.now(), + endAtMs: Date.now() + 60000, + }) + + // Styling state + const [trackColor, setTrackColor] = useState('#333344') + const [progressColor, setProgressColor] = useState('#007AFF') + const [cornerRadius, setCornerRadius] = useState(4) + const [height, setHeight] = useState(8) + const [lineWidth, setLineWidth] = useState(6) + const [useThumb, setUseThumb] = useState(false) + const [countDown, setCountDown] = useState(false) + + const resetTimer = () => { + const duration = (parseInt(durationSec) || 0) * 1000 + const now = Date.now() + setTimerState({ + startAtMs: now, + endAtMs: now + duration, + }) + } + + const widgetPreviewStyle = { + borderRadius: 16, + backgroundColor: colorScheme === 'light' ? 'rgba(0, 0, 0, 0.4)' : 'rgba(255, 255, 255, 0.8)', + } + + // Effect to handle unsupported modes + React.useEffect(() => { + if (type === 'circular' && mode === 'timer') { + setMode('determinate') + } + if (type === 'linear' && mode === 'indeterminate') { + setMode('determinate') + } + }, [type, mode]) + + const renderProgressWidget = () => { + const commonProps: any = { + label: ( + + {type === 'linear' ? 'Linear' : 'Circular'} Progress + + ), + currentValueLabel: + mode === 'determinate' ? ( + {progressValue}% + ) : mode === 'timer' ? ( + + ) : null, + trackColor, + progressColor, + } + + const modeProps = + mode === 'determinate' + ? { value: progressValue, maximumValue: 100 } + : mode === 'timer' + ? { startAtMs: timerState.startAtMs, endAtMs: timerState.endAtMs, countDown } + : {} + + return ( + + + {type === 'linear' ? ( + : undefined} + /> + ) : ( + + )} + + + ) + } + + return ( + + + Progress Testing + + Test VoltraLinearProgressView and VoltraCircularProgressView with new label and styling support. + + + {/* 1. Live Preview */} + + Live Preview + + + {renderProgressWidget()} + + + {mode === 'timer' && ( +