From b7f4ec8dd51f8cb092bb638040d2c23c8acc24c8 Mon Sep 17 00:00:00 2001
From: Kota <128109461+kota113@users.noreply.github.com>
Date: Sat, 19 Jul 2025 14:53:59 +0900
Subject: [PATCH 01/12] add an option to disable the pan gesture
ScrollView interferes with the pan gesture of the bottom sheet on Android, and date-picker is not functioning properly because of this. This change should be a help to mitigate it.
---
templates/components/ui/bottom-sheet.tsx | 145 +++++++++++++++--------
1 file changed, 96 insertions(+), 49 deletions(-)
diff --git a/templates/components/ui/bottom-sheet.tsx b/templates/components/ui/bottom-sheet.tsx
index 7fb9c14..e852245 100644
--- a/templates/components/ui/bottom-sheet.tsx
+++ b/templates/components/ui/bottom-sheet.tsx
@@ -25,6 +25,73 @@ import Animated, {
const { height: SCREEN_HEIGHT } = Dimensions.get('window');
const MAX_TRANSLATE_Y = -SCREEN_HEIGHT + 50;
+type BottomSheetContentProps = {
+ children: React.ReactNode;
+ title?: string;
+ style?: ViewStyle;
+ rBottomSheetStyle: any;
+ cardColor: string;
+ mutedColor: string;
+};
+
+// Component for the bottom sheet content
+const BottomSheetContent = ({
+ children,
+ title,
+ style,
+ rBottomSheetStyle,
+ cardColor,
+ mutedColor,
+}: BottomSheetContentProps) => {
+ return (
+
+ {/* Handle */}
+
+
+ {/* Title */}
+ {title && (
+
+
+ {title}
+
+
+ )}
+
+ {/* Content */}
+ {children}
+
+ );
+};
+
type BottomSheetProps = {
isVisible: boolean;
onClose: () => void;
@@ -33,6 +100,7 @@ type BottomSheetProps = {
enableBackdropDismiss?: boolean;
title?: string;
style?: ViewStyle;
+ disablePanGesture?: boolean;
};
export function BottomSheet({
@@ -43,6 +111,7 @@ export function BottomSheet({
enableBackdropDismiss = true,
title,
style,
+ disablePanGesture = false,
}: BottomSheetProps) {
const cardColor = useThemeColor({}, 'card');
const mutedColor = useThemeColor({}, 'muted');
@@ -124,8 +193,11 @@ export function BottomSheet({
})
.onUpdate((event) => {
const newY = context.value.y + event.translationY;
- // Limit the dragging range
- if (newY <= 0 && newY >= MAX_TRANSLATE_Y) {
+ // Only allow dragging down when near the top of the sheet or when dragging up
+ // This helps prevent interference with nested ScrollViews
+ const shouldUpdate = event.translationY > 0 || translateY.value > -SCREEN_HEIGHT * 0.1;
+
+ if (shouldUpdate && newY <= 0 && newY >= MAX_TRANSLATE_Y) {
translateY.value = newY;
}
})
@@ -142,7 +214,8 @@ export function BottomSheet({
// Find the closest snap point
const closestSnapPoint = findClosestSnapPoint(currentY);
scrollTo(closestSnapPoint);
- });
+ })
+ .simultaneousWithExternalGesture();
const rBottomSheetStyle = useAnimatedStyle(() => {
return {
@@ -185,53 +258,27 @@ export function BottomSheet({
-
-
- {/* Handle */}
-
+ ) : (
+
+
-
- {/* Title */}
- {title && (
-
-
- {title}
-
-
- )}
-
- {/* Content */}
- {children}
-
-
+
+ )}
From 7adf7158ac38276ea2d743f788d8eee1d12c63d7 Mon Sep 17 00:00:00 2001
From: Kota <128109461+kota113@users.noreply.github.com>
Date: Sat, 19 Jul 2025 14:57:54 +0900
Subject: [PATCH 02/12] disable a pan gesture while editing year/month fields
---
templates/components/ui/date-picker.tsx | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/templates/components/ui/date-picker.tsx b/templates/components/ui/date-picker.tsx
index 0f8eedd..ba91802 100644
--- a/templates/components/ui/date-picker.tsx
+++ b/templates/components/ui/date-picker.tsx
@@ -727,6 +727,8 @@ export function DatePicker(props: DatePickerProps) {
{getBottomSheetContent()}
From 90b0dfa731f57d7230fb189c7de72ad3de07589d Mon Sep 17 00:00:00 2001
From: Kota <128109461+kota113@users.noreply.github.com>
Date: Sat, 19 Jul 2025 15:06:30 +0900
Subject: [PATCH 03/12] revert unnecessary changes
---
templates/components/ui/date-picker.tsx | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/templates/components/ui/date-picker.tsx b/templates/components/ui/date-picker.tsx
index ba91802..14d243a 100644
--- a/templates/components/ui/date-picker.tsx
+++ b/templates/components/ui/date-picker.tsx
@@ -727,8 +727,6 @@ export function DatePicker(props: DatePickerProps) {
From 60edcde5b2c1428e08fb1a5731b987a295021b91 Mon Sep 17 00:00:00 2001
From: Kota <128109461+kota113@users.noreply.github.com>
Date: Sat, 19 Jul 2025 16:31:29 +0900
Subject: [PATCH 04/12] revert unnecessary changes
---
templates/components/ui/bottom-sheet.tsx | 62 ++++++++++++++++--------
1 file changed, 43 insertions(+), 19 deletions(-)
diff --git a/templates/components/ui/bottom-sheet.tsx b/templates/components/ui/bottom-sheet.tsx
index e852245..fdf589c 100644
--- a/templates/components/ui/bottom-sheet.tsx
+++ b/templates/components/ui/bottom-sheet.tsx
@@ -32,6 +32,7 @@ type BottomSheetContentProps = {
rBottomSheetStyle: any;
cardColor: string;
mutedColor: string;
+ onHandlePress?: () => void;
};
// Component for the bottom sheet content
@@ -42,6 +43,7 @@ const BottomSheetContent = ({
rBottomSheetStyle,
cardColor,
mutedColor,
+ onHandlePress,
}: BottomSheetContentProps) => {
return (
- {/* Handle */}
-
+ {/* Handle - Touchable to allow snapping when pan is disabled */}
+
+
+
+
+
{/* Title */}
{title && (
@@ -119,6 +129,7 @@ export function BottomSheet({
const translateY = useSharedValue(0);
const context = useSharedValue({ y: 0 });
const opacity = useSharedValue(0);
+ const currentSnapIndex = useSharedValue(0);
// Convert snap points to actual heights
const snapPointsHeights = snapPoints.map((point) => -SCREEN_HEIGHT * point);
@@ -135,6 +146,8 @@ export function BottomSheet({
stiffness: 400,
});
opacity.value = withTiming(1, { duration: 300 });
+ // Reset to first snap point when opening
+ currentSnapIndex.value = 0;
} else {
// Animate slide down before closing modal
translateY.value = withSpring(0, {
@@ -161,18 +174,31 @@ export function BottomSheet({
'worklet';
let closest = snapPointsHeights[0];
let minDistance = Math.abs(currentY - closest);
+ let closestIndex = 0;
- for (const snapPoint of snapPointsHeights) {
+ for (let i = 0; i < snapPointsHeights.length; i++) {
+ const snapPoint = snapPointsHeights[i];
const distance = Math.abs(currentY - snapPoint);
if (distance < minDistance) {
minDistance = distance;
closest = snapPoint;
+ closestIndex = i;
}
}
+ // Update the current snap index
+ currentSnapIndex.value = closestIndex;
return closest;
};
+ // Function to cycle through snap points when handle is pressed
+ const handlePress = () => {
+ // Move to the next snap point (cycle back to first if at the end)
+ const nextIndex = (currentSnapIndex.value + 1) % snapPointsHeights.length;
+ currentSnapIndex.value = nextIndex;
+ scrollTo(snapPointsHeights[nextIndex]);
+ };
+
const animateClose = () => {
'worklet';
// Animate to slide down position
@@ -193,11 +219,8 @@ export function BottomSheet({
})
.onUpdate((event) => {
const newY = context.value.y + event.translationY;
- // Only allow dragging down when near the top of the sheet or when dragging up
- // This helps prevent interference with nested ScrollViews
- const shouldUpdate = event.translationY > 0 || translateY.value > -SCREEN_HEIGHT * 0.1;
-
- if (shouldUpdate && newY <= 0 && newY >= MAX_TRANSLATE_Y) {
+ // Limit the dragging range
+ if (newY <= 0 && newY >= MAX_TRANSLATE_Y) {
translateY.value = newY;
}
})
@@ -214,8 +237,7 @@ export function BottomSheet({
// Find the closest snap point
const closestSnapPoint = findClosestSnapPoint(currentY);
scrollTo(closestSnapPoint);
- })
- .simultaneousWithExternalGesture();
+ });
const rBottomSheetStyle = useAnimatedStyle(() => {
return {
@@ -266,6 +288,7 @@ export function BottomSheet({
rBottomSheetStyle={rBottomSheetStyle}
cardColor={cardColor}
mutedColor={mutedColor}
+ onHandlePress={() => runOnJS(handlePress)()}
/>
) : (
@@ -276,6 +299,7 @@ export function BottomSheet({
rBottomSheetStyle={rBottomSheetStyle}
cardColor={cardColor}
mutedColor={mutedColor}
+ onHandlePress={() => runOnJS(handlePress)()}
/>
)}
From 78b3ed717991980daae0d3832be4b8036b6f0cd8 Mon Sep 17 00:00:00 2001
From: kota113
Date: Sat, 9 Aug 2025 22:32:28 +0900
Subject: [PATCH 05/12] feat: add alert-dialog component
---
src/registry/alert-dialog.ts | 92 +++++++++
src/registry/index.ts | 2 +
templates/components/ui/alert-dialog.tsx | 176 ++++++++++++++++++
.../demo/alert-dialog/alert-dialog-custom.tsx | 39 ++++
.../demo/alert-dialog/alert-dialog-demo.tsx | 30 +++
.../alert-dialog/alert-dialog-destructive.tsx | 30 +++
6 files changed, 369 insertions(+)
create mode 100644 src/registry/alert-dialog.ts
create mode 100644 templates/components/ui/alert-dialog.tsx
create mode 100644 templates/demo/alert-dialog/alert-dialog-custom.tsx
create mode 100644 templates/demo/alert-dialog/alert-dialog-demo.tsx
create mode 100644 templates/demo/alert-dialog/alert-dialog-destructive.tsx
diff --git a/src/registry/alert-dialog.ts b/src/registry/alert-dialog.ts
new file mode 100644
index 0000000..cc042d1
--- /dev/null
+++ b/src/registry/alert-dialog.ts
@@ -0,0 +1,92 @@
+// Registry configuration for alert-dialog component and demo
+
+export const alertDialogRegistry = {
+ // Main alert-dialog component
+ 'alert-dialog': {
+ name: 'alert-dialog',
+ description: 'A modal dialog that interrupts the user with important content and expects a response.',
+ type: 'registry:ui',
+ dependencies: ['react-native-reanimated'],
+ registryDependencies: ['card', 'button', 'text', 'view'],
+ hooks: [],
+ theme: [],
+ files: [
+ {
+ type: 'registry:ui',
+ path: 'templates/components/ui/alert-dialog.tsx',
+ target: 'components/ui/alert-dialog.tsx',
+ },
+ ],
+ preview: {
+ // todo: prepare preview videos
+ light: 'https://cdn.jsdelivr.net/gh/ahmedbna/bna-ui-demo/alert-dialog-preview.mov',
+ dark: 'https://cdn.jsdelivr.net/gh/ahmedbna/bna-ui-demo/alert-dialog-preview-dark.mov',
+ },
+ },
+
+ // Basic demo
+ 'alert-dialog-demo': {
+ name: 'alert-dialog-demo',
+ description: 'A basic alert dialog with confirmation buttons',
+ type: 'registry:example',
+ registryDependencies: ['alert-dialog'],
+ hooks: [],
+ theme: [],
+ files: [
+ {
+ type: 'registry:example',
+ path: 'templates/demo/alert-dialog/alert-dialog-demo.tsx',
+ target: 'components/demo/alert-dialog/alert-dialog-demo.tsx',
+ },
+ ],
+ preview: {
+ // todo: prepare preview videos
+ light: 'https://cdn.jsdelivr.net/gh/ahmedbna/bna-ui-demo/alert-dialog-demo.mov',
+ dark: 'https://cdn.jsdelivr.net/gh/ahmedbna/bna-ui-demo/alert-dialog-demo-dark.mov',
+ },
+ },
+
+ // Destructive action demo
+ 'alert-dialog-destructive': {
+ name: 'alert-dialog-destructive',
+ description: 'An alert dialog for destructive actions like delete',
+ type: 'registry:example',
+ registryDependencies: ['alert-dialog'],
+ hooks: [],
+ theme: [],
+ files: [
+ {
+ type: 'registry:example',
+ path: 'templates/demo/alert-dialog/alert-dialog-destructive.tsx',
+ target: 'components/demo/alert-dialog/alert-dialog-destructive.tsx',
+ },
+ ],
+ preview: {
+ // todo: prepare preview videos
+ light: 'https://cdn.jsdelivr.net/gh/ahmedbna/bna-ui-demo/alert-dialog-destructive.mov',
+ dark: 'https://cdn.jsdelivr.net/gh/ahmedbna/bna-ui-demo/alert-dialog-destructive-dark.mov',
+ },
+ },
+
+ // Custom styled demo
+ 'alert-dialog-custom': {
+ name: 'alert-dialog-custom',
+ description: 'A custom styled alert dialog with different appearance',
+ type: 'registry:example',
+ registryDependencies: ['alert-dialog'],
+ hooks: [],
+ theme: [],
+ files: [
+ {
+ type: 'registry:example',
+ path: 'templates/demo/alert-dialog/alert-dialog-custom.tsx',
+ target: 'components/demo/alert-dialog/alert-dialog-custom.tsx',
+ },
+ ],
+ preview: {
+ // todo: prepare preview videos
+ light: 'https://cdn.jsdelivr.net/gh/ahmedbna/bna-ui-demo/alert-dialog-custom.mov',
+ dark: 'https://cdn.jsdelivr.net/gh/ahmedbna/bna-ui-demo/alert-dialog-custom-dark.mov',
+ },
+ },
+};
\ No newline at end of file
diff --git a/src/registry/index.ts b/src/registry/index.ts
index 9e808ae..4f56eff 100644
--- a/src/registry/index.ts
+++ b/src/registry/index.ts
@@ -56,11 +56,13 @@ import { themeRegistry } from './theme/index.js';
import { hooksRegistry } from './hooks/index.js';
import { inputRegistry } from './input.js';
import { chartsRegistry } from './charts/index.js';
+import {alertDialogRegistry} from "./alert-dialog";
export const REGISTRY: Record = {
...accordionRegistry,
...actionSheetRegistry,
...alertRegistry,
+ ...alertDialogRegistry,
...audioPlayerRegistry,
...audioRecorderRegistry,
...audioWaveformRegistry,
diff --git a/templates/components/ui/alert-dialog.tsx b/templates/components/ui/alert-dialog.tsx
new file mode 100644
index 0000000..54342f2
--- /dev/null
+++ b/templates/components/ui/alert-dialog.tsx
@@ -0,0 +1,176 @@
+import {Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle} from '@/components/ui/card';
+import {Button} from '@/components/ui/button';
+import {useThemeColor} from '@/hooks/useThemeColor';
+import React, {useEffect} from 'react';
+import {Modal, StyleSheet, TouchableWithoutFeedback, View, ViewStyle} from 'react-native';
+import Animated, {runOnJS, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
+
+export type DialogProps = {
+ isVisible: boolean;
+ onClose: () => void;
+ title?: string;
+ description?: string;
+ children?: React.ReactNode;
+ confirmText?: string;
+ cancelText?: string;
+ onConfirm?: () => void;
+ onCancel?: () => void;
+ dismissible?: boolean;
+ style?: ViewStyle;
+};
+
+// A simple card-like dialog overlay with fade-in animation similar to BottomSheet's backdrop
+export function Dialog({
+ isVisible,
+ onClose,
+ title,
+ description,
+ children,
+ confirmText = 'OK',
+ cancelText = 'Cancel',
+ onConfirm,
+ onCancel,
+ dismissible = true,
+ style,
+ }: DialogProps) {
+ const cardColor = useThemeColor({}, 'card');
+
+ const [modalVisible, setModalVisible] = React.useState(false);
+ const backdropOpacity = useSharedValue(0);
+ const cardOpacity = useSharedValue(0);
+
+ useEffect(() => {
+ if (isVisible) {
+ setModalVisible(true);
+ backdropOpacity.value = withTiming(1, {duration: 250});
+ cardOpacity.value = withTiming(1, {duration: 200});
+ } else {
+ backdropOpacity.value = withTiming(0, {duration: 250}, (finished) => {
+ if (finished) {
+ runOnJS(setModalVisible)(false);
+ }
+ });
+ cardOpacity.value = withTiming(0, {duration: 200});
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [isVisible]);
+
+ const rBackdropStyle = useAnimatedStyle(() => ({
+ opacity: backdropOpacity.value,
+ }));
+
+ const rCardFadeStyle = useAnimatedStyle(() => ({
+ opacity: cardOpacity.value,
+ }));
+
+ const animateClose = () => {
+ 'worklet';
+ backdropOpacity.value = withTiming(0, {duration: 300}, (finished) => {
+ if (finished) {
+ runOnJS(onClose)();
+ }
+ });
+ cardOpacity.value = withTiming(0, {duration: 200});
+ };
+
+ const handleBackdropPress = () => {
+ if (dismissible) {
+ animateClose();
+ if (onCancel) onCancel();
+ }
+ };
+
+ const handleCancel = () => {
+ if (onCancel) onCancel();
+ animateClose();
+ };
+
+ const handleConfirm = () => {
+ if (onConfirm) onConfirm();
+ animateClose();
+ };
+
+ return (
+
+
+
+
+
+
+ {/* Non-animated outer wrapper: handles rounded corners and clipping */}
+
+ {/* Only fade the inner content */}
+
+
+ {(title || description) && (
+
+ {title ? {title} : null}
+ {description ? {description} : null}
+
+ )}
+ {children ? {children} : null}
+
+
+
+
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ backdrop: {
+ flex: 1,
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 24,
+ },
+ backdropTouchableArea: {
+ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0,
+ },
+ // Rounded corners and clipping consolidated here (non-animated)
+ roundedWrapper: {
+ width: '100%',
+ borderRadius: 16,
+ overflow: 'hidden',
+ },
+ // Inner content can render freely (only opacity is animated)
+ innerContent: {
+ width: '100%',
+ },
+});
+
+export function useDialog() {
+ const [isVisible, setIsVisible] = React.useState(false);
+ const open = React.useCallback(() => setIsVisible(true), []);
+ const close = React.useCallback(() => setIsVisible(false), []);
+ const toggle = React.useCallback(() => setIsVisible((v) => !v), []);
+ return {isVisible, open, close, toggle};
+}
\ No newline at end of file
diff --git a/templates/demo/alert-dialog/alert-dialog-custom.tsx b/templates/demo/alert-dialog/alert-dialog-custom.tsx
new file mode 100644
index 0000000..07e7ff1
--- /dev/null
+++ b/templates/demo/alert-dialog/alert-dialog-custom.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { Dialog, useDialog } from '@/components/ui/alert-dialog';
+import { Button } from '@/components/ui/button';
+import { View } from '@/components/ui/view';
+import { Text } from '@/components/ui/text';
+
+export default function AlertDialogCustomDemo() {
+ const dialog = useDialog();
+
+ return (
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/templates/demo/alert-dialog/alert-dialog-demo.tsx b/templates/demo/alert-dialog/alert-dialog-demo.tsx
new file mode 100644
index 0000000..fc4cce8
--- /dev/null
+++ b/templates/demo/alert-dialog/alert-dialog-demo.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { Dialog, useDialog } from '@/components/ui/alert-dialog';
+import { Button } from '@/components/ui/button';
+import { View } from '@/components/ui/view';
+
+export default function AlertDialogDemo() {
+ const dialog = useDialog();
+
+ return (
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/templates/demo/alert-dialog/alert-dialog-destructive.tsx b/templates/demo/alert-dialog/alert-dialog-destructive.tsx
new file mode 100644
index 0000000..ebb921f
--- /dev/null
+++ b/templates/demo/alert-dialog/alert-dialog-destructive.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { Dialog, useDialog } from '@/components/ui/alert-dialog';
+import { Button } from '@/components/ui/button';
+import { View } from '@/components/ui/view';
+
+export default function AlertDialogDestructiveDemo() {
+ const dialog = useDialog();
+
+ return (
+
+
+
+
+ );
+}
\ No newline at end of file
From fb7714c55d664475c9afbec2068948ee5d1bdc78 Mon Sep 17 00:00:00 2001
From: kota113
Date: Sun, 10 Aug 2025 11:05:16 +0900
Subject: [PATCH 06/12] refactor: rename Dialog to AlertDialog and update
references
---
templates/components/ui/alert-dialog.tsx | 8 ++++----
templates/demo/alert-dialog/alert-dialog-custom.tsx | 8 ++++----
templates/demo/alert-dialog/alert-dialog-demo.tsx | 6 +++---
templates/demo/alert-dialog/alert-dialog-destructive.tsx | 6 +++---
4 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/templates/components/ui/alert-dialog.tsx b/templates/components/ui/alert-dialog.tsx
index 54342f2..f687b9a 100644
--- a/templates/components/ui/alert-dialog.tsx
+++ b/templates/components/ui/alert-dialog.tsx
@@ -5,7 +5,7 @@ import React, {useEffect} from 'react';
import {Modal, StyleSheet, TouchableWithoutFeedback, View, ViewStyle} from 'react-native';
import Animated, {runOnJS, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
-export type DialogProps = {
+export type AlertDialogProps = {
isVisible: boolean;
onClose: () => void;
title?: string;
@@ -20,7 +20,7 @@ export type DialogProps = {
};
// A simple card-like dialog overlay with fade-in animation similar to BottomSheet's backdrop
-export function Dialog({
+export function AlertDialog({
isVisible,
onClose,
title,
@@ -32,7 +32,7 @@ export function Dialog({
onCancel,
dismissible = true,
style,
- }: DialogProps) {
+ }: AlertDialogProps) {
const cardColor = useThemeColor({}, 'card');
const [modalVisible, setModalVisible] = React.useState(false);
@@ -167,7 +167,7 @@ const styles = StyleSheet.create({
},
});
-export function useDialog() {
+export function useAlertDialog() {
const [isVisible, setIsVisible] = React.useState(false);
const open = React.useCallback(() => setIsVisible(true), []);
const close = React.useCallback(() => setIsVisible(false), []);
diff --git a/templates/demo/alert-dialog/alert-dialog-custom.tsx b/templates/demo/alert-dialog/alert-dialog-custom.tsx
index 07e7ff1..af496a5 100644
--- a/templates/demo/alert-dialog/alert-dialog-custom.tsx
+++ b/templates/demo/alert-dialog/alert-dialog-custom.tsx
@@ -1,11 +1,11 @@
import React from 'react';
-import { Dialog, useDialog } from '@/components/ui/alert-dialog';
+import { AlertDialog, useAlertDialog } from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
import { View } from '@/components/ui/view';
import { Text } from '@/components/ui/text';
export default function AlertDialogCustomDemo() {
- const dialog = useDialog();
+ const dialog = useAlertDialog();
return (
@@ -13,7 +13,7 @@ export default function AlertDialogCustomDemo() {
Custom Dialog
-
-
+
);
}
\ No newline at end of file
diff --git a/templates/demo/alert-dialog/alert-dialog-demo.tsx b/templates/demo/alert-dialog/alert-dialog-demo.tsx
index fc4cce8..fc7f006 100644
--- a/templates/demo/alert-dialog/alert-dialog-demo.tsx
+++ b/templates/demo/alert-dialog/alert-dialog-demo.tsx
@@ -1,10 +1,10 @@
import React from 'react';
-import { Dialog, useDialog } from '@/components/ui/alert-dialog';
+import { AlertDialog, useAlertDialog } from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
import { View } from '@/components/ui/view';
export default function AlertDialogDemo() {
- const dialog = useDialog();
+ const dialog = useAlertDialog();
return (
@@ -12,7 +12,7 @@ export default function AlertDialogDemo() {
Show Dialog
-
+ }
+ >
+
+ Gradient Overlay Header
+
+ This example shows how to add a gradient overlay to your header image,
+ which is perfect for ensuring text readability over images.
+
+
+ The gradient creates a smooth transition from the image to a darker
+ overlay at the bottom, where you can place text or other UI elements.
+
+
+ This technique is commonly used in hero sections, article headers, and
+ profile screens where you need to overlay content on images.
+
+
+
+ The parallax effect works seamlessly with gradient overlays and
+ maintains smooth performance even with multiple layers.
+
+
+
+ );
+}
+
+```
+
+##### parallax-scrollview-profile
+
+Complete profile screen using parallax scroll view
+
+```tsx
+import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
+import { Badge } from '@/components/ui/badge';
+import { ParallaxScrollView } from '@/components/ui/parallax-scrollview';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { Image } from 'expo-image';
+import { LinearGradient } from 'expo-linear-gradient';
+import React from 'react';
+
+export function ParallaxScrollViewProfile() {
+ return (
+
+
+
+
+
+
+ JD
+
+
+
+ John Doe
+
+
+ Software Engineer
+
+
+
+
+ }
+ >
+
+
+ About
+
+ Passionate software engineer with 5+ years of experience in mobile
+ and web development. Specialized in React Native, TypeScript, and
+ modern UI frameworks.
+
+
+
+
+ Skills
+
+ {[
+ 'React Native',
+ 'TypeScript',
+ 'Node.js',
+ 'GraphQL',
+ 'MongoDB',
+ ].map((skill) => (
+
+ {skill}
+
+ ))}
+
+
+
+
+ Experience
+
+
+ Senior Mobile Developer
+ Tech Corp • 2022 - Present
+
+ Leading mobile development team and architecting scalable React
+ Native applications.
+
+
+
+ Frontend Developer
+ StartupXYZ • 2020 - 2022
+
+ Built responsive web applications using React and modern
+ frontend technologies.
+
+
+
+
+
+
+ Contact
+ 📧 john.doe@example.com
+ 🌐 johndoe.dev
+ 📱 LinkedIn: @johndoe
+
+
+
+ );
+}
+
+```
+
+##### parallax-scrollview-article
+
+Article layout with parallax hero image
+
+```tsx
+import { ParallaxScrollView } from '@/components/ui/parallax-scrollview';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { Image } from 'expo-image';
+import { LinearGradient } from 'expo-linear-gradient';
+import React from 'react';
+
+export function ParallaxScrollViewArticle() {
+ return (
+
+
+
+
+
+
+ TECHNOLOGY
+
+
+
+ The Future of Mobile Development
+
+
+ Published on March 15, 2024 • 8 min read
+
+
+
+ }
+ >
+
+
+ Mobile development has evolved dramatically over the past decade, with
+ new frameworks, tools, and paradigms emerging to meet the ever-growing
+ demands of users and businesses alike.
+
+
+
+ React Native has established itself as a leading cross-platform
+ solution, enabling developers to write once and deploy everywhere. The
+ framework's component-based architecture and hot reloading
+ capabilities have revolutionized the development experience.
+
+
+
+ Key Trends in 2024
+
+ • AI-powered development tools and code generation
+
+
+ • Enhanced performance optimization techniques
+
+
+ • Better cross-platform native module integration
+
+
+ • Improved debugging and testing frameworks
+
+
+
+
+
+ "The best mobile apps are those that feel native to each platform
+ while maintaining a consistent user experience across devices."
+
+
+
+
+ Performance optimization remains a critical consideration. Modern apps
+ need to handle complex animations, large datasets, and real-time
+ updates while maintaining smooth 60fps interactions.
+
+
+
+ Looking Ahead
+
+ The future of mobile development is bright, with emerging
+ technologies like AR/VR integration, improved offline capabilities,
+ and seamless cloud integration opening new possibilities for
+ developers and users alike.
+
+
+
+
+
+
+ JD
+
+
+ John Developer
+
+ Senior Mobile Engineer
+
+
+
+
+
+
+ );
+}
+
+```
+
+##### parallax-scrollview-product
+
+Product detail screen with parallax image gallery
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { ParallaxScrollView } from '@/components/ui/parallax-scrollview';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { Image } from 'expo-image';
+import React from 'react';
+
+export function ParallaxScrollViewProduct() {
+ return (
+
+ }
+ >
+
+
+
+
+ Running Shoes
+
+ Nike Air Zoom Series
+
+
+
+ $159.99
+
+
+
+
+
+ {[1, 2, 3, 4, 5].map((star) => (
+
+ ★
+
+ ))}
+
+ 4.8 (2.1k reviews)
+
+
+
+
+ Description
+
+ Experience ultimate comfort and performance with these premium
+ running shoes. Featuring advanced cushioning technology and
+ breathable mesh construction for all-day comfort.
+
+
+
+
+ Available Sizes
+
+ {['7', '7.5', '8', '8.5', '9', '9.5', '10', '10.5', '11'].map(
+ (size) => (
+
+ US {size}
+
+ )
+ )}
+
+
+
+
+ Color Options
+
+
+
+
+
+
+
+
+
+ Features
+
+
+ ✓
+ Lightweight design for all-day wear
+
+
+ ✓
+ Enhanced arch support
+
+
+
+
+
+ Shipping & Returns
+
+ • Free shipping on orders over $100
+
+ • 30-day return policy
+ • 1-year manufacturer warranty
+
+
+
+ Add to Cart
+
+ Add to Wishlist
+
+
+
+ );
+}
+
+```
+---
+
+### picker
+
+A customizable dropdown picker component with search, sections, and multiple selection support.
+
+**Installation:**
+```bash
+npx bna-ui add picker
+```
+
+**External Dependencies:** lucide-react-native
+
+**Registry Dependencies:** icon, scroll-view, text, view
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Picker } from '@/components/ui/picker';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### picker-demo
+
+A basic picker with simple options
+
+```tsx
+import { Picker } from '@/components/ui/picker';
+import React, { useState } from 'react';
+
+export function PickerDemo() {
+ const [value, setValue] = useState('');
+
+ const options = [
+ { label: 'Apple', value: 'apple' },
+ { label: 'Banana', value: 'banana' },
+ { label: 'Orange', value: 'orange' },
+ { label: 'Grape', value: 'grape' },
+ ];
+
+ return (
+
+ );
+}
+
+```
+
+##### picker-sections
+
+Picker with grouped options in sections
+
+```tsx
+import { Picker } from '@/components/ui/picker';
+import React, { useState } from 'react';
+
+export function PickerSections() {
+ const [value, setValue] = useState('');
+
+ const sections = [
+ {
+ title: 'Fruits',
+ options: [
+ { label: 'Apple', value: 'apple' },
+ { label: 'Banana', value: 'banana' },
+ { label: 'Orange', value: 'orange' },
+ ],
+ },
+ {
+ title: 'Vegetables',
+ options: [
+ { label: 'Carrot', value: 'carrot' },
+ { label: 'Broccoli', value: 'broccoli' },
+ { label: 'Spinach', value: 'spinach' },
+ ],
+ },
+ ];
+
+ return (
+
+ );
+}
+
+```
+
+##### picker-multiple
+
+Picker allowing multiple selections
+
+```tsx
+import { Picker } from '@/components/ui/picker';
+import React, { useState } from 'react';
+
+export function PickerMultiple() {
+ const [values, setValues] = useState([]);
+
+ const options = [
+ { label: 'JavaScript', value: 'js' },
+ { label: 'TypeScript', value: 'ts' },
+ { label: 'Python', value: 'py' },
+ { label: 'Java', value: 'java' },
+ { label: 'C++', value: 'cpp' },
+ { label: 'Rust', value: 'rust' },
+ ];
+
+ return (
+
+ );
+}
+
+```
+
+##### picker-searchable
+
+Picker with search functionality
+
+```tsx
+import { Picker } from '@/components/ui/picker';
+import React, { useState } from 'react';
+
+export function PickerSearchable() {
+ const [value, setValue] = useState('');
+
+ const options = [
+ { label: 'United States', value: 'us' },
+ { label: 'Canada', value: 'ca' },
+ { label: 'United Kingdom', value: 'uk' },
+ { label: 'Germany', value: 'de' },
+ { label: 'France', value: 'fr' },
+ { label: 'Japan', value: 'jp' },
+ { label: 'Australia', value: 'au' },
+ { label: 'Brazil', value: 'br' },
+ { label: 'India', value: 'in' },
+ { label: 'China', value: 'cn' },
+ ];
+
+ return (
+
+ );
+}
+
+```
+
+##### picker-variants
+
+Different picker variants: outline, filled, and group
+
+```tsx
+import { Picker } from '@/components/ui/picker';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function PickerVariants() {
+ const [outlineValue, setOutlineValue] = useState('');
+ const [filledValue, setFilledValue] = useState('');
+ const [groupValue, setGroupValue] = useState('');
+
+ const options = [
+ { label: 'Small', value: 'sm' },
+ { label: 'Medium', value: 'md' },
+ { label: 'Large', value: 'lg' },
+ { label: 'Extra Large', value: 'xl' },
+ ];
+
+ return (
+
+
+
+ Outline Variant
+
+
+
+
+
+
+ Filled Variant
+
+
+
+
+
+
+ Group Variant
+
+
+
+
+ );
+}
+
+```
+
+##### picker-styled
+
+Picker with custom styling, icons, and labels
+
+```tsx
+import { Picker } from '@/components/ui/picker';
+import { MapPin, Settings, User } from 'lucide-react-native';
+import React, { useState } from 'react';
+
+export function PickerStyled() {
+ const [location, setLocation] = useState('');
+ const [user, setUser] = useState('');
+ const [setting, setSetting] = useState('');
+
+ const locations = [
+ { label: 'New York', value: 'ny' },
+ { label: 'Los Angeles', value: 'la' },
+ { label: 'Chicago', value: 'chi' },
+ ];
+
+ const users = [
+ { label: 'John Doe', value: 'john' },
+ { label: 'Jane Smith', value: 'jane' },
+ { label: 'Bob Johnson', value: 'bob' },
+ ];
+
+ const settings = [
+ { label: 'Notifications', value: 'notifications' },
+ { label: 'Privacy', value: 'privacy' },
+ { label: 'Account', value: 'account' },
+ ];
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+}
+
+```
+
+##### picker-form
+
+Picker integrated with form validation and error handling
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { Picker } from '@/components/ui/picker';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function PickerForm() {
+ const [category, setCategory] = useState('');
+ const [priority, setPriority] = useState('');
+ const [errors, setErrors] = useState<{
+ category?: string;
+ priority?: string;
+ }>({});
+
+ const categories = [
+ { label: 'Bug Report', value: 'bug' },
+ { label: 'Feature Request', value: 'feature' },
+ { label: 'General Inquiry', value: 'general' },
+ ];
+
+ const priorities = [
+ { label: 'Low', value: 'low' },
+ { label: 'Medium', value: 'medium' },
+ { label: 'High', value: 'high' },
+ { label: 'Critical', value: 'critical' },
+ ];
+
+ const handleSubmit = () => {
+ const newErrors: { category?: string; priority?: string } = {};
+
+ if (!category) {
+ newErrors.category = 'Please select a category';
+ }
+
+ if (!priority) {
+ newErrors.priority = 'Please select a priority';
+ }
+
+ setErrors(newErrors);
+
+ if (Object.keys(newErrors).length === 0) {
+ // Form is valid
+ console.log('Form submitted:', { category, priority });
+ }
+ };
+
+ return (
+
+ {
+ setCategory(value);
+ if (errors.category) {
+ setErrors((prev) => ({ ...prev, category: undefined }));
+ }
+ }}
+ placeholder='Select category...'
+ label='Category'
+ error={errors.category}
+ variant='outline'
+ />
+
+ {
+ setPriority(value);
+ if (errors.priority) {
+ setErrors((prev) => ({ ...prev, priority: undefined }));
+ }
+ }}
+ placeholder='Select priority...'
+ label='Priority'
+ error={errors.priority}
+ variant='outline'
+ />
+
+ Submit Ticket
+
+ );
+}
+
+```
+
+##### picker-advanced
+
+Picker with descriptions, disabled options, and custom modal title
+
+```tsx
+import { Picker } from '@/components/ui/picker';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function PickerAdvanced() {
+ const [plan, setPlan] = useState('');
+
+ const sections = [
+ {
+ title: 'Individual Plans',
+ options: [
+ {
+ label: 'Basic',
+ value: 'basic',
+ description: '$9/month - Perfect for individuals',
+ },
+ {
+ label: 'Pro',
+ value: 'pro',
+ description: '$19/month - Advanced features included',
+ },
+ ],
+ },
+ {
+ title: 'Team Plans',
+ options: [
+ {
+ label: 'Team',
+ value: 'team',
+ description: '$39/month - Collaboration tools',
+ },
+ {
+ label: 'Enterprise',
+ value: 'enterprise',
+ description: '$99/month - Full enterprise features',
+ },
+ {
+ label: 'Custom',
+ value: 'custom',
+ description: 'Contact us for pricing',
+ disabled: true,
+ },
+ ],
+ },
+ ];
+
+ return (
+
+
+
+ {plan && (
+
+
+ Selected:{' '}
+ {
+ sections.flatMap((s) => s.options).find((o) => o.value === plan)
+ ?.label
+ }
+
+
+ )}
+
+ );
+}
+
+```
+---
+
+### pie-chart
+
+A customizable pie chart component with smooth animations and flexible styling.
+
+**Installation:**
+```bash
+npx bna-ui add pie-chart
+```
+
+**External Dependencies:** react-native-svg, react-native-reanimated, react-native-gesture-handler
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Pie-chart } from '@/components/ui/pie-chart';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### pie-chart-demo
+
+A pie chart with smooth animations
+
+```tsx
+import { PieChart } from '@/components/charts/pie-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Sales', value: 120 },
+ { label: 'Marketing', value: 98 },
+ { label: 'Support', value: 86 },
+ { label: 'Development', value: 140 },
+ { label: 'Design', value: 75 },
+ { label: 'HR', value: 65 },
+];
+
+export function PieChartDemo() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### pie-chart-sample
+
+A sample pie chart
+
+```tsx
+import { PieChart } from '@/components/charts/pie-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Mobile', value: 45 },
+ { label: 'Desktop', value: 35 },
+ { label: 'Tablet', value: 15 },
+ { label: 'Other', value: 5 },
+];
+
+export function PieChartSample() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### pie-chart-styled
+
+A customized pie chart with custom colors and styling
+
+```tsx
+import { PieChart } from '@/components/charts/pie-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React from 'react';
+
+export function PieChartStyled() {
+ const primaryColor = useThemeColor({}, 'primary');
+ const successColor = useThemeColor({}, 'green');
+ const warningColor = useThemeColor({}, 'orange');
+ const errorColor = useThemeColor({}, 'red');
+
+ const styledData = [
+ { label: 'Completed', value: 65, color: successColor },
+ { label: 'In Progress', value: 20, color: primaryColor },
+ { label: 'Pending', value: 10, color: warningColor },
+ { label: 'Failed', value: 5, color: errorColor },
+ ];
+
+ return (
+
+
+
+ );
+}
+
+```
+
+##### pie-chart-large
+
+A pie chart with large dataset
+
+```tsx
+import { PieChart } from '@/components/charts/pie-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const largeData = [
+ { label: 'North America', value: 35 },
+ { label: 'Europe', value: 28 },
+ { label: 'Asia Pacific', value: 22 },
+ { label: 'Latin America', value: 8 },
+ { label: 'Middle East', value: 4 },
+ { label: 'Africa', value: 3 },
+];
+
+export function PieChartLarge() {
+ return (
+
+
+
+ );
+}
+
+```
+---
+
+### polar-area-chart
+
+A customizable polar area chart component with smooth animations and flexible styling for displaying radial data.
+
+**Installation:**
+```bash
+npx bna-ui add polar-area-chart
+```
+
+**External Dependencies:** react-native-svg, react-native-reanimated, react-native-gesture-handler
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Polar-area-chart } from '@/components/ui/polar-area-chart';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### polar-area-chart-demo
+
+A polar area chart with smooth animations
+
+```tsx
+import { PolarAreaChart } from '@/components/charts/polar-area-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Sales', value: 120 },
+ { label: 'Marketing', value: 98 },
+ { label: 'Support', value: 86 },
+ { label: 'Development', value: 140 },
+ { label: 'Design', value: 75 },
+ { label: 'HR', value: 65 },
+];
+
+export function PolarAreaChartDemo() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### polar-area-chart-sample
+
+A sample polar area chart
+
+```tsx
+import { PolarAreaChart } from '@/components/charts/polar-area-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React from 'react';
+
+const skillsData = [
+ { label: 'JavaScript', value: 95 },
+ { label: 'React', value: 88 },
+ { label: 'TypeScript', value: 82 },
+ { label: 'Node.js', value: 78 },
+ { label: 'Python', value: 65 },
+];
+
+export function PolarAreaChartSample() {
+ const primaryColor = useThemeColor({}, 'primary');
+ const blueColor = useThemeColor({}, 'blue');
+ const greenColor = useThemeColor({}, 'green');
+ const orangeColor = useThemeColor({}, 'orange');
+ const purpleColor = useThemeColor({}, 'purple');
+
+ const dataWithColors = skillsData.map((item, index) => ({
+ ...item,
+ color: [primaryColor, blueColor, greenColor, orangeColor, purpleColor][
+ index
+ ],
+ }));
+
+ return (
+
+
+
+ );
+}
+
+```
+
+##### polar-area-chart-styled
+
+A customized polar area chart with custom colors and styling
+
+```tsx
+import { PolarAreaChart } from '@/components/charts/polar-area-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React from 'react';
+
+const marketData = [
+ { label: 'Mobile Apps', value: 45, color: '#FF6B6B' },
+ { label: 'Web Apps', value: 38, color: '#4ECDC4' },
+ { label: 'Desktop', value: 25, color: '#45B7D1' },
+ { label: 'IoT', value: 18, color: '#96CEB4' },
+ { label: 'AI/ML', value: 32, color: '#FFEAA7' },
+ { label: 'Blockchain', value: 15, color: '#DDA0DD' },
+];
+
+export function PolarAreaChartStyled() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### polar-area-chart-large
+
+A polar area chart with large dataset
+
+```tsx
+import { PolarAreaChart } from '@/components/charts/polar-area-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const largeDataset = [
+ { label: 'Q1 Sales', value: 185 },
+ { label: 'Q2 Sales', value: 220 },
+ { label: 'Q3 Sales', value: 195 },
+ { label: 'Q4 Sales', value: 240 },
+ { label: 'Marketing', value: 156 },
+ { label: 'Support', value: 134 },
+ { label: 'Development', value: 189 },
+ { label: 'Design', value: 123 },
+ { label: 'HR', value: 98 },
+ { label: 'Finance', value: 145 },
+ { label: 'Operations', value: 167 },
+ { label: 'Research', value: 112 },
+];
+
+export function PolarAreaChartLarge() {
+ return (
+
+
+
+ );
+}
+
+```
+---
+
+### popover
+
+A contextual overlay that displays rich content triggered by user interaction.
+
+**Installation:**
+```bash
+npx bna-ui add popover
+```
+
+**External Dependencies:** react-native-reanimated
+
+**Registry Dependencies:** button
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Popover } from '@/components/ui/popover';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### popover-demo
+
+A basic popover with trigger button and content
+
+```tsx
+import { Button } from '@/components/ui/button';
+import {
+ Popover,
+ PopoverBody,
+ PopoverClose,
+ PopoverContent,
+ PopoverFooter,
+ PopoverHeader,
+ PopoverTrigger,
+} from '@/components/ui/popover';
+import { Text } from '@/components/ui/text';
+import React from 'react';
+
+export function PopoverDemo() {
+ return (
+
+
+ Open Popover
+
+
+
+ Popover Title
+
+
+
+ This is the popover content. You can put any content here.
+
+
+
+
+
+ Close
+
+
+
+
+
+ );
+}
+
+```
+
+##### popover-positioning
+
+Popovers positioned on different sides of the trigger
+
+```tsx
+import { Button } from '@/components/ui/button';
+import {
+ Popover,
+ PopoverBody,
+ PopoverContent,
+ PopoverTrigger,
+} from '@/components/ui/popover';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function PopoverPositioning() {
+ return (
+
+
+
+ Top
+
+
+
+ Popover content positioned on top
+
+
+
+
+
+
+
+ Left
+
+
+
+ Left positioned
+
+
+
+
+
+
+ Right
+
+
+
+ Right positioned
+
+
+
+
+
+
+
+ Bottom
+
+
+
+ Popover content positioned on bottom
+
+
+
+
+ );
+}
+
+```
+
+##### popover-alignment
+
+Popovers with different alignment options
+
+```tsx
+import { Button } from '@/components/ui/button';
+import {
+ Popover,
+ PopoverBody,
+ PopoverContent,
+ PopoverTrigger,
+} from '@/components/ui/popover';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function PopoverAlignment() {
+ return (
+
+
+ Bottom Side Alignment
+
+
+
+ Start
+
+
+
+ Aligned to start (left)
+
+
+
+
+
+
+ Center
+
+
+
+ Aligned to center
+
+
+
+
+
+
+ End
+
+
+
+ Aligned to end (right)
+
+
+
+
+
+
+
+ Right Side Alignment
+
+
+
+ Start
+
+
+
+ Aligned to start (top)
+
+
+
+
+
+
+ Center
+
+
+
+ Aligned to center
+
+
+
+
+
+
+ End
+
+
+
+ Aligned to end (bottom)
+
+
+
+
+
+
+ );
+}
+
+```
+
+##### popover-controlled
+
+A controlled popover with external state management
+
+```tsx
+import { Button } from '@/components/ui/button';
+import {
+ Popover,
+ PopoverBody,
+ PopoverContent,
+ PopoverHeader,
+ PopoverTrigger,
+} from '@/components/ui/popover';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function PopoverControlled() {
+ const [isOpen, setIsOpen] = useState(false);
+
+ return (
+
+
+ setIsOpen(true)}
+ >
+ Open
+
+ setIsOpen(false)}
+ >
+ Close
+
+
+
+ Status: {isOpen ? 'Open' : 'Closed'}
+
+
+
+ Controlled Popover
+
+
+
+ Controlled Popover
+
+
+
+ This popover's state is controlled externally. You can open and
+ close it using the buttons above or by clicking the trigger.
+
+
+
+
+
+ );
+}
+
+```
+
+##### popover-custom
+
+Popovers with custom content and styling
+
+```tsx
+import { Button } from '@/components/ui/button';
+import {
+ Popover,
+ PopoverBody,
+ PopoverContent,
+ PopoverTrigger,
+} from '@/components/ui/popover';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React from 'react';
+
+export function PopoverCustom() {
+ const primaryColor = useThemeColor({}, 'primary');
+ const mutedColor = useThemeColor({}, 'muted');
+
+ return (
+
+
+
+ Custom Styled
+
+
+
+
+ This popover has custom styling with primary color background
+
+
+
+
+
+
+
+ Large Content
+
+
+
+
+ Large Popover Content
+
+
+ This popover has custom dimensions and can hold more content. It
+ demonstrates how you can customize the appearance and size of
+ popover components to fit your design needs.
+
+
+ The content area is scrollable if it exceeds the maximum height.
+
+
+
+
+
+
+
+ ?
+
+
+
+
+ This is a help tooltip using a custom circular trigger button
+
+
+
+
+
+ );
+}
+
+```
+
+##### popover-form
+
+A popover containing form elements
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import {
+ Popover,
+ PopoverBody,
+ PopoverClose,
+ PopoverContent,
+ PopoverFooter,
+ PopoverHeader,
+ PopoverTrigger,
+} from '@/components/ui/popover';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function PopoverForm() {
+ const [name, setName] = useState('');
+ const [email, setEmail] = useState('');
+
+ const handleSubmit = () => {
+ // Handle form submission
+ console.log('Form submitted:', { name, email });
+ // Reset form
+ setName('');
+ setEmail('');
+ };
+
+ return (
+
+
+ Add Contact
+
+
+
+ Add New Contact
+
+
+
+
+ Name
+
+
+
+ Email
+
+
+
+
+
+
+
+ Cancel
+
+
+
+
+ Add Contact
+
+
+
+
+
+ );
+}
+
+```
+
+##### popover-menu
+
+A popover styled as a dropdown menu
+
+```tsx
+import { Button } from '@/components/ui/button';
+import {
+ Popover,
+ PopoverClose,
+ PopoverContent,
+ PopoverTrigger,
+} from '@/components/ui/popover';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React from 'react';
+import { TouchableOpacity } from 'react-native';
+
+interface MenuItemProps {
+ icon: string;
+ label: string;
+ onPress: () => void;
+ destructive?: boolean;
+}
+
+function MenuItem({
+ icon,
+ label,
+ onPress,
+ destructive = false,
+}: MenuItemProps) {
+ const textColor = useThemeColor(
+ {},
+ destructive ? 'destructive' : 'foreground'
+ );
+ const mutedColor = useThemeColor({}, 'muted');
+
+ return (
+
+
+
+ {icon}
+
+ {label}
+
+
+ );
+}
+
+export function PopoverMenu() {
+ const borderColor = useThemeColor({}, 'border');
+
+ const handleMenuAction = (action: string) => {
+ console.log(`Menu action: ${action}`);
+ };
+
+ return (
+
+
+
+ ⚙️ Options
+
+
+
+
+
+
+
+ ✏️ Actions
+
+
+ handleMenuAction('edit')}
+ />
+ handleMenuAction('copy')}
+ />
+ handleMenuAction('share')}
+ />
+ handleMenuAction('favorite')}
+ />
+
+
+
+ );
+}
+
+```
+---
+
+### progress
+
+A progress bar component to show completion status with optional interactivity.
+
+**Installation:**
+```bash
+npx bna-ui add progress
+```
+
+**External Dependencies:** react-native-gesture-handler, react-native-reanimated
+
+**Registry Dependencies:** view
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Progress } from '@/components/ui/progress';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### progress-demo
+
+A basic progress bar showing completion status
+
+```tsx
+import { Progress } from '@/components/ui/progress';
+import React from 'react';
+
+export function ProgressDemo() {
+ return ;
+}
+
+```
+
+##### progress-interactive
+
+An interactive progress bar that can be dragged or tapped
+
+```tsx
+import { Progress } from '@/components/ui/progress';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function ProgressInteractive() {
+ const [value, setValue] = useState(45);
+ const [isSeking, setIsSeeking] = useState(false);
+
+ return (
+
+
+ {isSeking ? 'Seeking...' : `Progress: ${Math.round(value)}%`}
+
+
+ );
+}
+
+```
+
+##### progress-heights
+
+Progress bars with different heights
+
+```tsx
+import { Progress } from '@/components/ui/progress';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ProgressHeights() {
+ return (
+
+
+ Small (2px)
+
+
+
+
+ Default (4px)
+
+
+
+
+ Medium (8px)
+
+
+
+
+ Large (12px)
+
+
+
+
+ Extra Large (20px)
+
+
+
+ );
+}
+
+```
+
+##### progress-labels
+
+Progress bars with percentage labels and descriptions
+
+```tsx
+import { Progress } from '@/components/ui/progress';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ProgressLabels() {
+ const tasks = [
+ { label: 'Installing dependencies', progress: 100 },
+ { label: 'Building application', progress: 75 },
+ { label: 'Running tests', progress: 45 },
+ { label: 'Deploying to production', progress: 0 },
+ ];
+
+ return (
+
+ {tasks.map((task, index) => (
+
+
+
+ {task.label}
+
+
+ {task.progress}%
+
+
+
+
+ ))}
+
+
+
+
+ Overall Progress
+
+
+ 55%
+
+
+
+
+ 2 of 4 tasks completed
+
+
+
+ );
+}
+
+```
+
+##### progress-animated
+
+Progress bars with smooth animations and transitions
+
+```tsx
+import { Progress } from '@/components/ui/progress';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useEffect, useState } from 'react';
+
+export function ProgressAnimated() {
+ const [progress1, setProgress1] = useState(0);
+ const [progress2, setProgress2] = useState(0);
+ const [progress3, setProgress3] = useState(0);
+
+ useEffect(() => {
+ // Animate first progress bar
+ const timer1 = setTimeout(() => setProgress1(75), 500);
+
+ // Animate second progress bar
+ const timer2 = setTimeout(() => setProgress2(60), 1000);
+
+ // Animate third progress bar
+ const timer3 = setTimeout(() => setProgress3(85), 1500);
+
+ return () => {
+ clearTimeout(timer1);
+ clearTimeout(timer2);
+ clearTimeout(timer3);
+ };
+ }, []);
+
+ const [cycleProgress, setCycleProgress] = useState(0);
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setCycleProgress((prev) => {
+ const newValue = prev + 10;
+ return newValue > 100 ? 0 : newValue;
+ });
+ }, 300);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return (
+
+
+ Staggered Animation
+
+
+ File Upload: {progress1}%
+
+
+
+
+ Processing: {progress2}%
+
+
+
+
+ Optimization: {progress3}%
+
+
+
+
+
+ Continuous Animation
+
+ Loading: {cycleProgress}%
+
+
+
+
+ );
+}
+
+```
+
+##### progress-media
+
+Progress bars styled for media player controls
+
+```tsx
+import { Progress } from '@/components/ui/progress';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+import { TouchableOpacity } from 'react-native';
+
+export function ProgressMedia() {
+ const [progress, setProgress] = useState(35);
+ const [isPlaying, setIsPlaying] = useState(false);
+ const [volume, setVolume] = useState(75);
+
+ const formatTime = (percent: number) => {
+ const totalSeconds = Math.floor((percent / 100) * 180); // 3 minute song
+ const minutes = Math.floor(totalSeconds / 60);
+ const seconds = totalSeconds % 60;
+ return `${minutes}:${seconds.toString().padStart(2, '0')}`;
+ };
+
+ return (
+
+ {/* Media Player */}
+
+
+
+ Song Title
+
+
+ Artist Name
+
+
+
+
+
+
+
+ {formatTime(progress)}
+
+
+ 3:00
+
+
+
+
+
+ setIsPlaying(!isPlaying)}
+ >
+
+ {isPlaying ? '⏸️' : '▶️'}
+
+
+
+
+
+ {/* Volume Control */}
+
+
+ 🔊
+
+
+
+
+ {Math.round(volume)}%
+
+
+
+
+ );
+}
+
+```
+
+##### progress-steps
+
+Multi-step progress indicators
+
+```tsx
+import { Progress } from '@/components/ui/progress';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+import { TouchableOpacity } from 'react-native';
+
+export function ProgressSteps() {
+ const [currentStep, setCurrentStep] = useState(2);
+
+ const steps = ['Account Setup', 'Personal Info', 'Verification', 'Complete'];
+
+ const progress = (currentStep / (steps.length - 1)) * 100;
+
+ return (
+
+ {/* Step Progress */}
+
+
+ Setup Progress
+
+ Step {currentStep + 1} of {steps.length}
+
+
+
+
+
+
+ {steps.map((step, index) => (
+
+
+
+ {index < currentStep ? '✓' : index + 1}
+
+
+
+ {step}
+
+
+ ))}
+
+
+
+ {/* Controls */}
+
+ 0 ? '#007AFF' : '#e5e7eb',
+ borderRadius: 6,
+ }}
+ onPress={() => setCurrentStep(Math.max(0, currentStep - 1))}
+ disabled={currentStep === 0}
+ >
+ 0 ? '#fff' : '#999',
+ fontWeight: '500',
+ }}
+ >
+ Previous
+
+
+
+
+ setCurrentStep(Math.min(steps.length - 1, currentStep + 1))
+ }
+ disabled={currentStep === steps.length - 1}
+ >
+
+ Next
+
+
+
+
+ );
+}
+
+```
+
+##### progress-ring-chart-demo
+
+A circular progress ring with smooth animations
+
+```tsx
+import { ProgressRingChart } from '@/components/charts/progress-ring-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+export function ProgressRingChartDemo() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### progress-ring-chart-sample
+
+A sample progress ring chart
+
+```tsx
+import { ProgressRingChart } from '@/components/charts/progress-ring-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+export function ProgressRingChartSample() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### progress-ring-chart-styled
+
+A customized progress ring with gradient and custom styling
+
+```tsx
+import { ProgressRingChart } from '@/components/charts/progress-ring-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+export function ProgressRingChartStyled() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### progress-ring-chart-large
+
+A large progress ring with center text
+
+```tsx
+import { ProgressRingChart } from '@/components/charts/progress-ring-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+export function ProgressRingChartLarge() {
+ return (
+
+
+
+ );
+}
+
+```
+---
+
+### progress-ring-chart
+
+A customizable circular progress ring component with smooth animations and flexible styling.
+
+**Installation:**
+```bash
+npx bna-ui add progress-ring-chart
+```
+
+**External Dependencies:** react-native-svg, react-native-reanimated, react-native-gesture-handler
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Progress-ring-chart } from '@/components/ui/progress-ring-chart';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### progress-ring-chart-demo
+
+A circular progress ring with smooth animations
+
+```tsx
+import { ProgressRingChart } from '@/components/charts/progress-ring-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+export function ProgressRingChartDemo() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### progress-ring-chart-sample
+
+A sample progress ring chart
+
+```tsx
+import { ProgressRingChart } from '@/components/charts/progress-ring-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+export function ProgressRingChartSample() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### progress-ring-chart-styled
+
+A customized progress ring with gradient and custom styling
+
+```tsx
+import { ProgressRingChart } from '@/components/charts/progress-ring-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+export function ProgressRingChartStyled() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### progress-ring-chart-large
+
+A large progress ring with center text
+
+```tsx
+import { ProgressRingChart } from '@/components/charts/progress-ring-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+export function ProgressRingChartLarge() {
+ return (
+
+
+
+ );
+}
+
+```
+---
+
+### radar-chart
+
+A customizable radar chart component with smooth animations and flexible styling for displaying multi-dimensional data.
+
+**Installation:**
+```bash
+npx bna-ui add radar-chart
+```
+
+**External Dependencies:** react-native-svg, react-native-reanimated, react-native-gesture-handler
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Radar-chart } from '@/components/ui/radar-chart';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### radar-chart-demo
+
+A radar chart with smooth animations
+
+```tsx
+import { RadarChart } from '@/components/charts/radar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Speed', value: 80 },
+ { label: 'Reliability', value: 92 },
+ { label: 'Comfort', value: 75 },
+ { label: 'Safety', value: 88 },
+ { label: 'Efficiency', value: 85 },
+ { label: 'Style', value: 70 },
+];
+
+export function RadarChartDemo() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### radar-chart-sample
+
+A sample radar chart
+
+```tsx
+import { RadarChart } from '@/components/charts/radar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const skillsData = [
+ { label: 'Frontend', value: 95 },
+ { label: 'Backend', value: 82 },
+ { label: 'Mobile', value: 78 },
+ { label: 'DevOps', value: 65 },
+ { label: 'Design', value: 70 },
+];
+
+export function RadarChartSample() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### radar-chart-styled
+
+A customized radar chart with custom colors and styling
+
+```tsx
+import { RadarChart } from '@/components/charts/radar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React from 'react';
+
+const performanceData = [
+ { label: 'Innovation', value: 88 },
+ { label: 'Quality', value: 92 },
+ { label: 'Delivery', value: 85 },
+ { label: 'Customer Satisfaction', value: 90 },
+ { label: 'Cost Efficiency', value: 78 },
+ { label: 'Team Collaboration', value: 95 },
+ { label: 'Process Improvement', value: 82 },
+];
+
+export function RadarChartStyled() {
+ const accentColor = useThemeColor({}, 'accent');
+
+ return (
+
+
+
+ );
+}
+
+```
+
+##### radar-chart-large
+
+A radar chart with large dataset
+
+```tsx
+import { RadarChart } from '@/components/charts/radar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const comprehensiveData = [
+ { label: 'Leadership', value: 85 },
+ { label: 'Communication', value: 90 },
+ { label: 'Technical Skills', value: 88 },
+ { label: 'Problem Solving', value: 92 },
+ { label: 'Creativity', value: 78 },
+ { label: 'Adaptability', value: 86 },
+ { label: 'Time Management', value: 82 },
+ { label: 'Teamwork', value: 94 },
+ { label: 'Strategic Thinking', value: 80 },
+ { label: 'Customer Focus', value: 87 },
+];
+
+export function RadarChartLarge() {
+ return (
+
+
+
+ );
+}
+
+```
+---
+
+### radial-bar-chart
+
+A customizable radial bar chart component with smooth animations, gradient support, and center value display.
+
+**Installation:**
+```bash
+npx bna-ui add radial-bar-chart
+```
+
+**External Dependencies:** react-native-svg, react-native-reanimated, react-native-gesture-handler
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Radial-bar-chart } from '@/components/ui/radial-bar-chart';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### radial-bar-chart-demo
+
+A radial bar chart with smooth animations and center totals
+
+```tsx
+import { RadialBarChart } from '@/components/charts/radial-bar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Sales', value: 120 },
+ { label: 'Marketing', value: 98 },
+ { label: 'Support', value: 86 },
+ { label: 'Development', value: 140 },
+ { label: 'Design', value: 75 },
+];
+
+export function RadialBarChartDemo() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### radial-bar-chart-sample
+
+A sample radial bar chart with custom data
+
+```tsx
+import { RadialBarChart } from '@/components/charts/radial-bar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Mobile', value: 45 },
+ { label: 'Desktop', value: 38 },
+ { label: 'Tablet', value: 17 },
+];
+
+export function RadialBarChartSample() {
+ const blue = useThemeColor({}, 'blue');
+ const green = useThemeColor({}, 'green');
+ const orange = useThemeColor({}, 'orange');
+
+ const dataWithColors = sampleData.map((item, index) => ({
+ ...item,
+ color: [blue, green, orange][index],
+ }));
+
+ return (
+
+
+
+ );
+}
+
+```
+
+##### radial-bar-chart-gradient
+
+A radial bar chart with gradient effects
+
+```tsx
+import { RadialBarChart } from '@/components/charts/radial-bar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Q1 Revenue', value: 85 },
+ { label: 'Q2 Revenue', value: 92 },
+ { label: 'Q3 Revenue', value: 78 },
+ { label: 'Q4 Revenue', value: 96 },
+];
+
+export function RadialBarChartGradient() {
+ const purple = useThemeColor({}, 'purple');
+ const pink = useThemeColor({}, 'pink');
+ const blue = useThemeColor({}, 'blue');
+ const green = useThemeColor({}, 'green');
+
+ const dataWithColors = sampleData.map((item, index) => ({
+ ...item,
+ color: [purple, pink, blue, green][index],
+ }));
+
+ return (
+
+
+
+ );
+}
+
+```
+
+##### radial-bar-chart-large
+
+A radial bar chart with large dataset
+
+```tsx
+import { RadialBarChart } from '@/components/charts/radial-bar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const largeDataset = [
+ { label: 'Product A', value: 156 },
+ { label: 'Product B', value: 142 },
+ { label: 'Product C', value: 98 },
+ { label: 'Product D', value: 124 },
+ { label: 'Product E', value: 89 },
+ { label: 'Product F', value: 167 },
+ { label: 'Product G', value: 78 },
+ { label: 'Product H', value: 134 },
+];
+
+export function RadialBarChartLarge() {
+ return (
+
+
+
+ );
+}
+
+```
+---
+
+### radio
+
+A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.
+
+**Installation:**
+```bash
+npx bna-ui add radio
+```
+
+**External Dependencies:** react-native
+
+**Registry Dependencies:** text
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Radio } from '@/components/ui/radio';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### radio-demo
+
+A basic radio group with multiple options
+
+```tsx
+import { RadioGroup } from '@/components/ui/radio';
+import React, { useState } from 'react';
+
+export function RadioDemo() {
+ const [value, setValue] = useState('option1');
+
+ return (
+
+ );
+}
+
+```
+
+##### radio-horizontal
+
+Radio buttons arranged horizontally
+
+```tsx
+import { RadioGroup } from '@/components/ui/radio';
+import React, { useState } from 'react';
+
+export function RadioHorizontal() {
+ const [value, setValue] = useState('small');
+
+ return (
+
+ );
+}
+
+```
+
+##### radio-disabled
+
+Radio group with some disabled options
+
+```tsx
+import { RadioGroup } from '@/components/ui/radio';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function RadioDisabled() {
+ const [value1, setValue1] = useState('option1');
+ const [value2, setValue2] = useState('option2');
+
+ return (
+
+ {/* Some disabled options */}
+
+
+ With disabled options
+
+
+
+
+ {/* Entire group disabled */}
+
+
+ Entire group disabled
+
+
+
+
+ );
+}
+
+```
+
+##### radio-styled
+
+Radio buttons with custom colors and styling
+
+```tsx
+import { RadioGroup } from '@/components/ui/radio';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React, { useState } from 'react';
+
+export function RadioStyled() {
+ const green = useThemeColor({}, 'green');
+ const card = useThemeColor({}, 'card');
+
+ const [value1, setValue1] = useState('red');
+ const [value2, setValue2] = useState('plan1');
+
+ return (
+
+ {/* Custom colors */}
+
+
+ Card-like options
+
+
+
+
+ {/* Card-like styling */}
+
+
+ Custom styling
+
+
+
+
+ );
+}
+
+```
+
+##### radio-form
+
+Radio group integrated with form validation
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { RadioGroup } from '@/components/ui/radio';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+import { Alert } from 'react-native';
+
+export function RadioForm() {
+ const [experience, setExperience] = useState('');
+ const [notification, setNotification] = useState('email');
+ const [theme, setTheme] = useState('system');
+
+ const handleSubmit = () => {
+ if (!experience) {
+ Alert.alert('Error', 'Please select your experience level');
+ return;
+ }
+
+ Alert.alert(
+ 'Form Submitted',
+ `Experience: ${experience}\nNotifications: ${notification}\nTheme: ${theme}`
+ );
+ };
+
+ return (
+
+ User Preferences
+
+
+
+ Experience Level *
+
+
+
+
+
+
+ Notification Preference
+
+
+
+
+
+
+ Theme Preference
+
+
+
+
+
+ Save Preferences
+
+
+ );
+}
+
+```
+
+##### radio-large
+
+Radio buttons with larger size and spacing
+
+```tsx
+import { RadioGroup } from '@/components/ui/radio';
+import React, { useState } from 'react';
+
+export function RadioLarge() {
+ const [value, setValue] = useState('option1');
+
+ return (
+
+ );
+}
+
+```
+
+##### radio-single
+
+Individual radio button component usage
+
+```tsx
+import { RadioButton } from '@/components/ui/radio';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function RadioSingle() {
+ const [selectedValue, setSelectedValue] = useState('option2');
+
+ const options = [
+ { label: 'First Option', value: 'option1' },
+ { label: 'Second Option', value: 'option2' },
+ { label: 'Third Option', value: 'option3' },
+ { label: 'Disabled Option', value: 'option4', disabled: true },
+ ];
+
+ return (
+
+
+ Individual Radio Buttons
+
+
+
+ {options.map((option) => (
+ setSelectedValue(option.value)}
+ />
+ ))}
+
+
+ Selected: {selectedValue}
+
+ );
+}
+
+```
+---
+
+### scatter-chart
+
+A customizable scatter plot component with smooth animations and flexible styling for visualizing data relationships.
+
+**Installation:**
+```bash
+npx bna-ui add scatter-chart
+```
+
+**External Dependencies:** react-native-svg, react-native-reanimated, react-native-gesture-handler
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Scatter-chart } from '@/components/ui/scatter-chart';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### scatter-chart-demo
+
+A scatter plot with smooth animations
+
+```tsx
+import { ScatterPlot } from '@/components/charts/scatter-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { x: 10, y: 20, label: 'Point A' },
+ { x: 25, y: 35, label: 'Point B' },
+ { x: 40, y: 15, label: 'Point C' },
+ { x: 55, y: 45, label: 'Point D' },
+ { x: 70, y: 30, label: 'Point E' },
+ { x: 85, y: 55, label: 'Point F' },
+ { x: 30, y: 50, label: 'Point G' },
+ { x: 65, y: 25, label: 'Point H' },
+];
+
+export function ScatterChartDemo() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### scatter-chart-sample
+
+A sample scatter chart with various data points
+
+```tsx
+import { ScatterPlot } from '@/components/charts/scatter-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { x: 5, y: 12, label: 'Alpha' },
+ { x: 15, y: 28, label: 'Beta' },
+ { x: 35, y: 42, label: 'Gamma' },
+ { x: 45, y: 18, label: 'Delta' },
+ { x: 25, y: 65, label: 'Epsilon' },
+ { x: 55, y: 38, label: 'Zeta' },
+ { x: 75, y: 52, label: 'Eta' },
+ { x: 65, y: 78, label: 'Theta' },
+ { x: 85, y: 25, label: 'Iota' },
+ { x: 95, y: 88, label: 'Kappa' },
+];
+
+export function ScatterChartSample() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### scatter-chart-styled
+
+A customized scatter chart with custom colors and styling
+
+```tsx
+import { ScatterPlot } from '@/components/charts/scatter-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React from 'react';
+
+const sampleData = [
+ { x: 20, y: 80, label: 'High Performance' },
+ { x: 35, y: 65, label: 'Good Performance' },
+ { x: 50, y: 70, label: 'Average Performance' },
+ { x: 65, y: 45, label: 'Below Average' },
+ { x: 80, y: 55, label: 'Improving' },
+ { x: 25, y: 90, label: 'Excellent' },
+ { x: 75, y: 35, label: 'Needs Work' },
+ { x: 60, y: 85, label: 'Outstanding' },
+];
+
+export function ScatterChartStyled() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### scatter-chart-large
+
+A scatter chart with large dataset
+
+```tsx
+import { ScatterPlot } from '@/components/charts/scatter-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+// Generate a larger dataset for demonstration
+const generateLargeDataset = () => {
+ const data = [];
+ for (let i = 0; i < 30; i++) {
+ data.push({
+ x: Math.random() * 100,
+ y: Math.random() * 100,
+ label: `Point ${i + 1}`,
+ });
+ }
+ return data;
+};
+
+const largeDataset = generateLargeDataset();
+
+export function ScatterChartLarge() {
+ return (
+
+
+
+ );
+}
+
+```
+---
+
+### scroll-view
+
+A scrollable view component that allows content to be scrolled when it exceeds the container size.
+
+**Installation:**
+```bash
+npx bna-ui add scroll-view
+```
+
+**Registry Dependencies:** view
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Scroll-view } from '@/components/ui/scroll-view';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### scroll-view-demo
+
+A basic scrollable view with content
+
+```tsx
+import { ScrollView } from '@/components/ui/scroll-view';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React from 'react';
+
+export function ScrollViewDemo() {
+ const card = useThemeColor({}, 'card');
+
+ return (
+
+
+ {Array.from({ length: 20 }, (_, i) => (
+
+ Scrollable item {i + 1}
+
+ ))}
+
+
+ );
+}
+
+```
+
+##### scroll-view-vertical
+
+Vertical scrolling with multiple items
+
+```tsx
+import { ScrollView } from '@/components/ui/scroll-view';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React from 'react';
+
+export function ScrollViewVertical() {
+ const colors = [
+ '#ef4444',
+ '#f97316',
+ '#eab308',
+ '#22c55e',
+ '#3b82f6',
+ '#8b5cf6',
+ '#ec4899',
+ ];
+
+ return (
+
+
+ {Array.from({ length: 15 }, (_, i) => (
+
+
+ Card {i + 1}
+
+
+ ))}
+
+
+ );
+}
+
+```
+
+##### scroll-view-horizontal
+
+Horizontal scrolling with cards
+
+```tsx
+import { ScrollView } from '@/components/ui/scroll-view';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React from 'react';
+
+export function ScrollViewHorizontal() {
+ const gradients = [
+ ['#ff9a9e', '#fecfef'],
+ ['#a18cd1', '#fbc2eb'],
+ ['#fad0c4', '#ffd1ff'],
+ ['#ffecd2', '#fcb69f'],
+ ['#a8edea', '#fed6e3'],
+ ['#d299c2', '#fef9d7'],
+ ['#89f7fe', '#66a6ff'],
+ ];
+
+ return (
+
+
+ {Array.from({ length: 10 }, (_, i) => (
+
+
+ Item {i + 1}
+
+
+ ))}
+
+
+ );
+}
+
+```
+
+##### scroll-view-nested
+
+ScrollViews nested within each other
+
+```tsx
+import { ScrollView } from '@/components/ui/scroll-view';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React from 'react';
+
+export function ScrollViewNested() {
+ return (
+
+
+
+ Vertical Scroll
+
+
+ {Array.from({ length: 3 }, (_, sectionIndex) => (
+
+
+ Section {sectionIndex + 1}
+
+
+
+
+ {Array.from({ length: 8 }, (_, itemIndex) => (
+
+
+ {sectionIndex + 1}.{itemIndex + 1}
+
+
+ ))}
+
+
+
+ ))}
+
+
+ End of scrollable content
+
+
+
+ );
+}
+
+```
+
+##### scroll-view-refresh
+
+ScrollView with pull-to-refresh functionality
+
+```tsx
+import { ScrollView } from '@/components/ui/scroll-view';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React, { useCallback, useState } from 'react';
+import { RefreshControl } from 'react-native';
+
+export function ScrollViewRefresh() {
+ const card = useThemeColor({}, 'card');
+ const green = useThemeColor({}, 'green');
+
+ const [refreshing, setRefreshing] = useState(false);
+ const [lastRefresh, setLastRefresh] = useState(
+ new Date().toLocaleTimeString()
+ );
+
+ const onRefresh = useCallback(() => {
+ setRefreshing(true);
+ setTimeout(() => {
+ setRefreshing(false);
+ setLastRefresh(new Date().toLocaleTimeString());
+ }, 2000);
+ }, []);
+
+ return (
+
+
+ }
+ >
+
+
+ Pull to Refresh
+
+
+ Last refreshed: {lastRefresh}
+
+
+
+ {Array.from({ length: 15 }, (_, i) => (
+
+
+ News Item {i + 1}
+
+
+ This is a sample news item that demonstrates the pull-to-refresh
+ functionality.
+
+
+ ))}
+
+
+ );
+}
+
+```
+
+##### scroll-view-styled
+
+ScrollView with custom styling and padding
+
+```tsx
+import { ScrollView } from '@/components/ui/scroll-view';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ScrollViewStyled() {
+ return (
+
+
+
+
+ 🌙 Dark Theme ScrollView
+
+
+ This ScrollView uses custom dark styling with rounded corners and
+ shadows.
+
+
+
+ {Array.from({ length: 12 }, (_, i) => (
+
+
+ Card {i + 1}
+
+
+ Beautiful custom styled card with gradient-like colors and
+ shadows.
+
+
+ ))}
+
+
+
+ ✨ End of styled content
+
+
+
+
+ );
+}
+
+```
+
+##### scroll-view-indicators
+
+ScrollView with custom scroll indicators
+
+```tsx
+import { ScrollView } from '@/components/ui/scroll-view';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React from 'react';
+
+export function ScrollViewIndicators() {
+ const card = useThemeColor({}, 'card');
+
+ return (
+
+ {/* Vertical with indicators */}
+
+
+ With Scroll Indicators
+
+
+
+ {Array.from({ length: 12 }, (_, i) => (
+
+ Item {i + 1} - Scroll indicators visible
+
+ ))}
+
+
+
+
+ {/* Horizontal without indicators */}
+
+
+ Without Scroll Indicators
+
+
+
+ {Array.from({ length: 8 }, (_, i) => (
+
+
+ {i + 1}
+
+
+ ))}
+
+
+
+
+ );
+}
+
+```
+
+##### scroll-view-inset
+
+ScrollView with content inset adjustments
+
+```tsx
+import { ScrollView } from '@/components/ui/scroll-view';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React from 'react';
+
+export function ScrollViewInset() {
+ const card = useThemeColor({}, 'card');
+
+ return (
+
+ {/* Standard ScrollView */}
+
+
+ Standard Content
+
+
+
+ {Array.from({ length: 8 }, (_, i) => (
+
+ Standard item {i + 1}
+
+ ))}
+
+
+
+
+ {/* ScrollView with content inset */}
+
+
+ With Content Inset Adjustments
+
+
+
+
+
+ Header with Inset
+
+
+
+ {Array.from({ length: 6 }, (_, i) => (
+
+ Inset adjusted item {i + 1}
+
+ ))}
+
+
+
+ Footer with Inset
+
+
+
+
+
+
+ );
+}
+
+```
+---
+
+### searchbar
+
+A customizable search input with debouncing, loading states, and suggestions.
+
+**Installation:**
+```bash
+npx bna-ui add searchbar
+```
+
+**External Dependencies:** lucide-react-native
+
+**Registry Dependencies:** icon, text, view
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Searchbar } from '@/components/ui/searchbar';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### searchbar-demo
+
+A basic search bar with search functionality
+
+```tsx
+import { SearchBar } from '@/components/ui/searchbar';
+import React, { useState } from 'react';
+
+export function SearchBarDemo() {
+ const [searchQuery, setSearchQuery] = useState('');
+
+ const handleSearch = (query: string) => {
+ console.log('Searching for:', query);
+ };
+
+ return (
+
+ );
+}
+
+```
+
+##### searchbar-loading
+
+Search bar with loading indicator
+
+```tsx
+import { SearchBar } from '@/components/ui/searchbar';
+import React, { useState } from 'react';
+
+export function SearchBarLoading() {
+ const [searchQuery, setSearchQuery] = useState('');
+ const [loading, setLoading] = useState(false);
+
+ const handleSearch = (query: string) => {
+ if (query.trim()) {
+ setLoading(true);
+ // Simulate API call
+ setTimeout(() => {
+ setLoading(false);
+ console.log('Search completed for:', query);
+ }, 2000);
+ }
+ };
+
+ return (
+
+ );
+}
+
+```
+
+##### searchbar-icons
+
+Search bar with custom left and right icons
+
+```tsx
+import { Icon } from '@/components/ui/icon';
+import { SearchBar } from '@/components/ui/searchbar';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { Filter, MapPin, User } from 'lucide-react-native';
+import React, { useState } from 'react';
+
+export function SearchBarIcons() {
+ const [locationQuery, setLocationQuery] = useState('');
+ const [userQuery, setUserQuery] = useState('');
+ const icon = useThemeColor({}, 'icon');
+
+ return (
+
+ {/* Location search with map pin icon */}
+ }
+ onSearch={(query) => console.log('Location search:', query)}
+ />
+
+ {/* User search with custom icons */}
+ }
+ rightIcon={}
+ showClearButton={false}
+ onSearch={(query) => console.log('User search:', query)}
+ />
+
+ );
+}
+
+```
+
+##### searchbar-suggestions
+
+Search bar with dropdown suggestions
+
+```tsx
+import { SearchBarWithSuggestions } from '@/components/ui/searchbar';
+import React, { useState } from 'react';
+
+export function SearchBarSuggestions() {
+ const [searchQuery, setSearchQuery] = useState('');
+
+ const suggestions = [
+ 'React Native',
+ 'React Navigation',
+ 'React Hook Form',
+ 'Redux Toolkit',
+ 'Expo Router',
+ 'TypeScript',
+ 'JavaScript',
+ 'Node.js',
+ 'Next.js',
+ 'Tailwind CSS',
+ ];
+
+ const handleSearch = (query: string) => {
+ console.log('Searching for:', query);
+ };
+
+ const handleSuggestionPress = (suggestion: string) => {
+ setSearchQuery(suggestion);
+ handleSearch(suggestion);
+ };
+
+ return (
+
+ );
+}
+
+```
+
+##### searchbar-styled
+
+Search bar with custom styling and colors
+
+```tsx
+import { SearchBar } from '@/components/ui/searchbar';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function SearchBarStyled() {
+ const [query1, setQuery1] = useState('');
+ const [query2, setQuery2] = useState('');
+ const [query3, setQuery3] = useState('');
+
+ return (
+
+ {/* Rounded with gradient-like background */}
+
+
+ {/* Minimal flat design */}
+
+
+ {/* Dark theme with custom height */}
+
+
+ );
+}
+
+```
+
+##### searchbar-no-clear
+
+Search bar without the clear button
+
+```tsx
+import { SearchBar } from '@/components/ui/searchbar';
+import React, { useState } from 'react';
+
+export function SearchBarNoClear() {
+ const [searchQuery, setSearchQuery] = useState('');
+
+ const handleSearch = (query: string) => {
+ console.log('Searching without clear button:', query);
+ };
+
+ return (
+
+ );
+}
+
+```
+
+##### searchbar-instant
+
+Search bar with no debounce for instant search
+
+```tsx
+import { SearchBar } from '@/components/ui/searchbar';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function SearchBarInstant() {
+ const [searchQuery, setSearchQuery] = useState('');
+ const [searchResults, setSearchResults] = useState([]);
+
+ const mockData = [
+ 'Apple',
+ 'Banana',
+ 'Cherry',
+ 'Date',
+ 'Elderberry',
+ 'Fig',
+ 'Grape',
+ 'Honeydew',
+ 'Kiwi',
+ 'Lemon',
+ ];
+
+ const handleInstantSearch = (query: string) => {
+ if (query.trim()) {
+ const results = mockData.filter((item) =>
+ item.toLowerCase().includes(query.toLowerCase())
+ );
+ setSearchResults(results);
+ } else {
+ setSearchResults([]);
+ }
+ };
+
+ return (
+
+
+
+ {searchResults.length > 0 && (
+
+
+ Found {searchResults.length} results:
+
+ {searchResults.map((result, index) => (
+
+ • {result}
+
+ ))}
+
+ )}
+
+ );
+}
+
+```
+---
+
+### separator
+
+Visually or semantically separates content.
+
+**Installation:**
+```bash
+npx bna-ui add separator
+```
+
+**Registry Dependencies:** view
+
+**Required Hooks:** useThemeColor
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Separator } from '@/components/ui/separator';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### separator-demo
+
+A basic horizontal separator
+
+```tsx
+import { Separator } from '@/components/ui/separator';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SeparatorDemo() {
+ return (
+
+ Above separator
+
+ Below separator
+
+ );
+}
+
+```
+
+##### separator-vertical
+
+A vertical separator for inline content
+
+```tsx
+import { Separator } from '@/components/ui/separator';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SeparatorVertical() {
+ return (
+
+ Left content
+
+ Right content
+
+ );
+}
+
+```
+
+##### separator-thickness
+
+Separators with different thickness values
+
+```tsx
+import { Separator } from '@/components/ui/separator';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SeparatorThickness() {
+ return (
+
+
+ Thin (1px)
+
+
+
+
+ Medium (2px)
+
+
+
+
+ Thick (4px)
+
+
+
+
+ Extra thick (8px)
+
+
+
+ );
+}
+
+```
+
+##### separator-colors
+
+Separators with custom colors and opacity
+
+```tsx
+import { Separator } from '@/components/ui/separator';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SeparatorColors() {
+ return (
+
+
+ Default
+
+
+
+
+ Red
+
+
+
+
+ Blue
+
+
+
+
+ Green
+
+
+
+
+ Semi-transparent
+
+
+
+ );
+}
+
+```
+
+##### separator-spacing
+
+Separators with different margin and padding
+
+```tsx
+import { Separator } from '@/components/ui/separator';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SeparatorSpacing() {
+ return (
+
+ Tight spacing
+
+ Content with minimal spacing
+
+
+
+ Normal spacing
+
+ Standard content spacing
+
+
+
+ Loose spacing
+
+ Generous content spacing
+
+ );
+}
+
+```
+---
+
+### share
+
+A button component for sharing content across platforms with native share functionality.
+
+**Installation:**
+```bash
+npx bna-ui add share
+```
+
+**External Dependencies:** lucide-react-native
+
+**Registry Dependencies:** button, text
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Share } from '@/components/ui/share';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### share-demo
+
+A basic share button with text and URL sharing
+
+```tsx
+import { ShareButton } from '@/components/ui/share';
+import React from 'react';
+
+export function ShareDemo() {
+ return (
+ {
+ console.log('Shared successfully:', activityType);
+ }}
+ onShareError={(error) => {
+ console.error('Share failed:', error);
+ }}
+ >
+ Share
+
+ );
+}
+
+```
+
+##### share-variants
+
+Share buttons with different visual variants
+
+```tsx
+import { ShareButton } from '@/components/ui/share';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ShareVariants() {
+ const shareContent = {
+ message: 'Check out this amazing content!',
+ url: 'https://example.com',
+ };
+
+ return (
+
+
+ Default
+
+
+
+ Secondary
+
+
+
+ Outline
+
+
+
+ Ghost
+
+
+
+ Link
+
+
+
+ Destructive
+
+
+ );
+}
+
+```
+
+##### share-sizes
+
+Share buttons in different sizes
+
+```tsx
+import { ShareButton } from '@/components/ui/share';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ShareSizes() {
+ const shareContent = {
+ message: 'Check out this amazing content!',
+ url: 'https://example.com',
+ };
+
+ return (
+
+
+ Small
+
+
+
+ Default
+
+
+
+ Large
+
+
+
+
+ );
+}
+
+```
+
+##### share-url-only
+
+Share button for sharing URLs without additional text
+
+```tsx
+import { ShareButton } from '@/components/ui/share';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ShareUrlOnly() {
+ return (
+
+
+ Share GitHub
+
+
+
+ Share React Native Docs
+
+
+
+ Share Expo
+
+
+ );
+}
+
+```
+
+##### share-custom-content
+
+Share button with custom title, subject, and content
+
+```tsx
+import { ShareButton } from '@/components/ui/share';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ShareCustomContent() {
+ return (
+
+ {/* Rich content with title and subject */}
+
+ Share Article
+
+
+ {/* App promotion */}
+
+ Share App
+
+
+ {/* Event invitation */}
+
+ Share Event
+
+
+ );
+}
+
+```
+
+##### share-icon-only
+
+Compact share button with icon only
+
+```tsx
+import { ShareButton } from '@/components/ui/share';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ShareIconOnly() {
+ const shareContent = {
+ message: 'Check out this amazing content!',
+ url: 'https://example.com',
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+ );
+}
+
+```
+
+##### share-callbacks
+
+Share button with success, error, and dismiss callbacks
+
+```tsx
+import { ShareButton } from '@/components/ui/share';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function ShareCallbacks() {
+ const [status, setStatus] = useState('Ready to share');
+ const [isLoading, setIsLoading] = useState(false);
+
+ const handleShareStart = () => {
+ setStatus('Starting share...');
+ setIsLoading(true);
+ };
+
+ const handleShareSuccess = (activityType?: string | null) => {
+ setStatus(
+ `Shared successfully${activityType ? ` via ${activityType}` : ''}!`
+ );
+ setIsLoading(false);
+
+ // Reset status after 3 seconds
+ setTimeout(() => setStatus('Ready to share'), 3000);
+ };
+
+ const handleShareError = (error: Error) => {
+ setStatus(`Share failed: ${error.message}`);
+ setIsLoading(false);
+
+ // Reset status after 3 seconds
+ setTimeout(() => setStatus('Ready to share'), 3000);
+ };
+
+ const handleShareDismiss = () => {
+ setStatus('Share cancelled');
+ setIsLoading(false);
+
+ // Reset status after 2 seconds
+ setTimeout(() => setStatus('Ready to share'), 2000);
+ };
+
+ return (
+
+ Status: {status}
+
+
+ Share with Callbacks
+
+
+ );
+}
+
+```
+
+##### share-hook
+
+Using the useShare hook for programmatic sharing
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { useShare } from '@/components/ui/share';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function ShareHook() {
+ const { shareText, shareUrl, shareContent } = useShare();
+ const [status, setStatus] = useState('Choose a sharing method');
+
+ const handleShareText = async () => {
+ try {
+ setStatus('Sharing text...');
+ await shareText(
+ 'Hello from the useShare hook! This is just a plain text message.'
+ );
+ setStatus('Text shared successfully!');
+ } catch (error) {
+ setStatus(`Failed to share text: ${(error as Error).message}`);
+ }
+ };
+
+ const handleShareUrl = async () => {
+ try {
+ setStatus('Sharing URL...');
+ await shareUrl(
+ 'https://reactnative.dev',
+ 'Check out the official React Native documentation!'
+ );
+ setStatus('URL shared successfully!');
+ } catch (error) {
+ setStatus(`Failed to share URL: ${(error as Error).message}`);
+ }
+ };
+
+ const handleShareContent = async () => {
+ try {
+ setStatus('Sharing content...');
+ await shareContent({
+ message:
+ '🚀 Just built an amazing React Native app with this component library!',
+ url: 'https://github.com/example/ui-library',
+ title: 'Amazing UI Library',
+ subject: 'Check out this UI library',
+ });
+ setStatus('Content shared successfully!');
+ } catch (error) {
+ setStatus(`Failed to share content: ${(error as Error).message}`);
+ }
+ };
+
+ return (
+
+ {status}
+
+
+
+ Share Text Only
+
+
+
+ Share URL with Message
+
+
+
+ Share Rich Content
+
+
+
+ );
+}
+
+```
+---
+
+### sheet
+
+A modal component that slides in from the side of the screen, commonly used for navigation menus, filters, and detail views.
+
+**Installation:**
+```bash
+npx bna-ui add sheet
+```
+
+**External Dependencies:** lucide-react-native
+
+**Registry Dependencies:** button, text, view
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Sheet } from '@/components/ui/sheet';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### sheet-demo
+
+A basic sheet that slides in from the right side
+
+```tsx
+import { Button } from '@/components/ui/button';
+import {
+ Sheet,
+ SheetContent,
+ SheetDescription,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from '@/components/ui/sheet';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function SheetDemo() {
+ const [open, setOpen] = useState(false);
+
+ return (
+
+
+ Open Sheet
+
+
+
+ Welcome to the Sheet
+
+ This is a basic sheet component that slides in from the right side
+ of the screen.
+
+
+
+
+ This sheet can contain any content you need. It's perfect for
+ navigation menus, forms, settings, or detailed information.
+
+ setOpen(false)}>Close Sheet
+
+
+
+ );
+}
+
+```
+
+##### sheet-left
+
+A sheet that slides in from the left side
+
+```tsx
+import { Button } from '@/components/ui/button';
+import {
+ Sheet,
+ SheetContent,
+ SheetDescription,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from '@/components/ui/sheet';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function SheetLeft() {
+ const [open, setOpen] = useState(false);
+
+ return (
+
+
+ Open Left Sheet
+
+
+
+ Left Side Sheet
+
+ This sheet slides in from the left side of the screen.
+
+
+
+
+ Left-side sheets are commonly used for navigation menus and primary
+ actions that need to be easily accessible.
+
+ setOpen(false)}>Close Sheet
+
+
+
+ );
+}
+
+```
+
+##### sheet-navigation
+
+A sheet that slides in from the navigation side
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { Icon } from '@/components/ui/icon';
+import {
+ Sheet,
+ SheetContent,
+ SheetDescription,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from '@/components/ui/sheet';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { Bell, Home, Mail, Search, Settings, User } from 'lucide-react-native';
+import React, { useState } from 'react';
+import { StyleSheet, TouchableOpacity } from 'react-native';
+
+export function SheetNavigation() {
+ const [open, setOpen] = useState(false);
+ const [activeItem, setActiveItem] = useState('home');
+
+ const textColor = useThemeColor({}, 'text');
+ const mutedColor = useThemeColor({}, 'textMuted');
+ const borderColor = useThemeColor({}, 'border');
+
+ const navigationItems = [
+ { id: 'home', label: 'Home', icon: Home },
+ { id: 'profile', label: 'Profile', icon: User },
+ { id: 'messages', label: 'Messages', icon: Mail },
+ { id: 'search', label: 'Search', icon: Search },
+ { id: 'notifications', label: 'Notifications', icon: Bell },
+ { id: 'settings', label: 'Settings', icon: Settings },
+ ];
+
+ const handleItemPress = (itemId: string) => {
+ setActiveItem(itemId);
+ setOpen(false);
+ };
+
+ return (
+
+
+ Open Navigation
+
+
+
+ Navigation Menu
+
+ Navigate to different sections of the app.
+
+
+
+ {navigationItems.map((item) => {
+ const name = item.icon;
+ const isActive = activeItem === item.id;
+
+ return (
+ handleItemPress(item.id)}
+ >
+
+
+ {item.label}
+
+
+ );
+ })}
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ navigationContainer: {
+ padding: 16,
+ gap: 8,
+ },
+ navigationItem: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 12,
+ padding: 12,
+ borderRadius: 8,
+ borderWidth: 1,
+ borderColor: 'transparent',
+ },
+ navigationText: {
+ fontSize: 16,
+ fontWeight: '500',
+ },
+});
+
+```
+
+##### sheet-form
+
+A sheet that slides in from the form side
+
+```tsx
+import { Button } from '@/components/ui/button';
+import {
+ Sheet,
+ SheetContent,
+ SheetDescription,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from '@/components/ui/sheet';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import React, { useState } from 'react';
+import { Alert, StyleSheet, TextInput } from 'react-native';
+
+export function SheetForm() {
+ const [open, setOpen] = useState(false);
+ const [formData, setFormData] = useState({
+ name: '',
+ email: '',
+ message: '',
+ });
+
+ const textColor = useThemeColor({}, 'text');
+ const backgroundColor = useThemeColor({}, 'background');
+ const borderColor = useThemeColor({}, 'border');
+ const mutedColor = useThemeColor({}, 'textMuted');
+
+ const handleSubmit = () => {
+ if (!formData.name || !formData.email || !formData.message) {
+ Alert.alert('Error', 'Please fill in all fields');
+ return;
+ }
+
+ Alert.alert('Success', 'Form submitted successfully!');
+ setFormData({ name: '', email: '', message: '' });
+ setOpen(false);
+ };
+
+ const handleReset = () => {
+ setFormData({ name: '', email: '', message: '' });
+ };
+
+ return (
+
+
+ Open Contact Form
+
+
+
+ Contact Us
+
+ Fill out the form below and we'll get back to you soon.
+
+
+
+
+ Name
+
+ setFormData((prev) => ({ ...prev, name: text }))
+ }
+ placeholder='Enter your name'
+ placeholderTextColor={mutedColor}
+ />
+
+
+
+ Email
+
+ setFormData((prev) => ({ ...prev, email: text }))
+ }
+ placeholder='Enter your email'
+ placeholderTextColor={mutedColor}
+ keyboardType='email-address'
+ autoCapitalize='none'
+ />
+
+
+
+ Message
+
+ setFormData((prev) => ({ ...prev, message: text }))
+ }
+ placeholder='Enter your message'
+ placeholderTextColor={mutedColor}
+ multiline
+ numberOfLines={4}
+ textAlignVertical='top'
+ />
+
+
+
+
+ Submit
+
+
+ Reset
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ formContainer: {
+ padding: 24,
+ gap: 20,
+ },
+ fieldContainer: {
+ gap: 8,
+ },
+ label: {
+ fontSize: 16,
+ fontWeight: '500',
+ },
+ input: {
+ borderWidth: 1,
+ borderRadius: 8,
+ padding: 12,
+ fontSize: 16,
+ },
+ textArea: {
+ height: 100,
+ },
+ buttonContainer: {
+ flexDirection: 'row',
+ gap: 12,
+ marginTop: 12,
+ },
+ button: {
+ flex: 1,
+ },
+});
+
+```
+
+##### sheet-filter
+
+A sheet that slides in from the filter side
+
+```tsx
+import { Button } from '@/components/ui/button';
+import {
+ Sheet,
+ SheetContent,
+ SheetDescription,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from '@/components/ui/sheet';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { Filter } from 'lucide-react-native';
+import React, { useState } from 'react';
+import { StyleSheet, TouchableOpacity } from 'react-native';
+
+export function SheetFilter() {
+ const [open, setOpen] = useState(false);
+ const [filters, setFilters] = useState({
+ category: 'all',
+ price: 'all',
+ rating: 'all',
+ brand: 'all',
+ });
+
+ const textColor = useThemeColor({}, 'text');
+ const mutedColor = useThemeColor({}, 'textMuted');
+ const borderColor = useThemeColor({}, 'border');
+
+ const filterOptions = {
+ category: [
+ { value: 'all', label: 'All Categories' },
+ { value: 'electronics', label: 'Electronics' },
+ { value: 'clothing', label: 'Clothing' },
+ { value: 'books', label: 'Books' },
+ { value: 'home', label: 'Home & Garden' },
+ ],
+ price: [
+ { value: 'all', label: 'Any Price' },
+ { value: 'under-25', label: 'Under $25' },
+ { value: '25-50', label: '$25 - $50' },
+ { value: '50-100', label: '$50 - $100' },
+ { value: 'over-100', label: 'Over $100' },
+ ],
+ rating: [
+ { value: 'all', label: 'Any Rating' },
+ { value: '4-plus', label: '4+ Stars' },
+ { value: '3-plus', label: '3+ Stars' },
+ { value: '2-plus', label: '2+ Stars' },
+ ],
+ brand: [
+ { value: 'all', label: 'All Brands' },
+ { value: 'apple', label: 'Apple' },
+ { value: 'samsung', label: 'Samsung' },
+ { value: 'nike', label: 'Nike' },
+ { value: 'adidas', label: 'Adidas' },
+ ],
+ };
+
+ const handleFilterChange = (
+ filterType: keyof typeof filters,
+ value: string
+ ) => {
+ setFilters((prev) => ({ ...prev, [filterType]: value }));
+ };
+
+ const handleApplyFilters = () => {
+ // Apply filters logic here
+ console.log('Applied filters:', filters);
+ setOpen(false);
+ };
+
+ const handleClearFilters = () => {
+ setFilters({
+ category: 'all',
+ price: 'all',
+ rating: 'all',
+ brand: 'all',
+ });
+ };
+
+ const renderFilterSection = (
+ title: string,
+ filterType: keyof typeof filters,
+ options: { value: string; label: string }[]
+ ) => (
+
+ {title}
+
+ {options.map((option) => (
+ handleFilterChange(filterType, option.value)}
+ >
+
+ {option.label}
+
+
+ ))}
+
+
+ );
+
+ return (
+
+
+ Filter
+
+
+
+ Filter Products
+
+ Refine your search results using the filters below.
+
+
+
+ {renderFilterSection('Category', 'category', filterOptions.category)}
+ {renderFilterSection('Price Range', 'price', filterOptions.price)}
+ {renderFilterSection('Rating', 'rating', filterOptions.rating)}
+ {renderFilterSection('Brand', 'brand', filterOptions.brand)}
+
+
+
+ Apply Filters
+
+
+ Clear All
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ filterContainer: {
+ padding: 16,
+ gap: 24,
+ },
+ filterSection: {
+ gap: 12,
+ },
+ sectionTitle: {
+ fontSize: 18,
+ fontWeight: '600',
+ },
+ optionsContainer: {
+ gap: 8,
+ },
+ option: {
+ padding: 12,
+ borderRadius: 8,
+ borderWidth: 1,
+ },
+ optionText: {
+ fontSize: 16,
+ },
+ buttonContainer: {
+ flexDirection: 'row',
+ gap: 12,
+ marginTop: 12,
+ },
+ button: {
+ flex: 1,
+ },
+});
+
+```
+---
+
+### skeleton
+
+A placeholder component to show a loading state while content is being fetched.
+
+**Installation:**
+```bash
+npx bna-ui add skeleton
+```
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Skeleton } from '@/components/ui/skeleton';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### skeleton-demo
+
+A basic skeleton loader with pulsing animation
+
+```tsx
+import { Skeleton } from '@/components/ui/skeleton';
+import React from 'react';
+
+export function SkeletonDemo() {
+ return ;
+}
+
+```
+
+##### skeleton-sizes
+
+Skeletons in various sizes and dimensions
+
+```tsx
+import { Skeleton } from '@/components/ui/skeleton';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SkeletonSizes() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+```
+
+##### skeleton-card
+
+Skeleton placeholders arranged in a card layout
+
+```tsx
+import { Skeleton } from '@/components/ui/skeleton';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React from 'react';
+
+export function SkeletonCard() {
+ const card = useThemeColor({}, 'card');
+
+ return (
+
+ {/* Header */}
+
+
+
+
+
+
+
+
+ {/* Content */}
+
+
+ {/* Footer */}
+
+
+
+
+
+
+ );
+}
+
+```
+
+##### skeleton-profile
+
+Skeleton layout mimicking a user profile
+
+```tsx
+import { Skeleton } from '@/components/ui/skeleton';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React from 'react';
+
+export function SkeletonProfile() {
+ const card = useThemeColor({}, 'card');
+
+ return (
+
+ {/* Profile Picture */}
+
+
+ {/* Name and Title */}
+
+
+
+
+
+ {/* Stats */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Bio */}
+
+
+
+
+
+
+ );
+}
+
+```
+
+##### skeleton-list
+
+Multiple skeleton items arranged in a list
+
+```tsx
+import { Skeleton } from '@/components/ui/skeleton';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React from 'react';
+
+export function SkeletonList() {
+ const card = useThemeColor({}, 'card');
+
+ return (
+
+ {Array.from({ length: 5 }, (_, i) => (
+
+
+
+
+
+
+
+
+ ))}
+
+ );
+}
+
+```
+
+##### skeleton-shapes
+
+Skeletons with custom shapes and styling
+
+```tsx
+import { Skeleton } from '@/components/ui/skeleton';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React from 'react';
+
+export function SkeletonShapes() {
+ const card = useThemeColor({}, 'card');
+
+ return (
+
+ {/* Circle */}
+
+
+ {/* Square */}
+
+
+ {/* Rounded Rectangle */}
+
+
+ {/* Pill */}
+
+
+ {/* Custom styled */}
+
+
+ );
+}
+
+```
+---
+
+### spinner
+
+A loading indicator component with multiple variants and customization options.
+
+**Installation:**
+```bash
+npx bna-ui add spinner
+```
+
+**External Dependencies:** lucide-react-native
+
+**Registry Dependencies:** text
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+#### Types
+
+```typescript
+export type SpinnerVariant = 'default' | 'cirlce' | 'dots' | 'pulse' | 'bars'
+```
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Spinner } from '@/components/ui/spinner';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### spinner-demo
+
+A basic spinner with default styling
+
+```tsx
+import { Spinner } from '@/components/ui/spinner';
+import React from 'react';
+
+export function SpinnerDemo() {
+ return ;
+}
+
+```
+
+##### spinner-variants
+
+Different spinner variants: default, circle, dots, pulse, and bars
+
+```tsx
+import { Spinner } from '@/components/ui/spinner';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SpinnerVariants() {
+ const variants = [
+ { variant: 'default' as const, label: 'Default' },
+ { variant: 'cirlce' as const, label: 'Circle' },
+ { variant: 'dots' as const, label: 'Dots' },
+ { variant: 'pulse' as const, label: 'Pulse' },
+ { variant: 'bars' as const, label: 'Bars' },
+ ];
+
+ return (
+
+ {variants.map(({ variant, label }) => (
+
+
+
+ {label}
+
+
+ ))}
+
+ );
+}
+
+```
+
+##### spinner-sizes
+
+Spinners in different sizes: sm, default, lg, and icon
+
+```tsx
+import { Spinner } from '@/components/ui/spinner';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SpinnerSizes() {
+ const sizes = [
+ { size: 'sm' as const, label: 'Small' },
+ { size: 'default' as const, label: 'Default' },
+ { size: 'lg' as const, label: 'Large' },
+ { size: 'icon' as const, label: 'Icon' },
+ ];
+
+ return (
+
+ {sizes.map(({ size, label }) => (
+
+
+
+ {label}
+
+
+ ))}
+
+ );
+}
+
+```
+
+##### spinner-labels
+
+Spinners with custom loading labels
+
+```tsx
+import { Spinner } from '@/components/ui/spinner';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SpinnerLabels() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+```
+
+##### spinner-speeds
+
+Spinners with different animation speeds: slow, normal, and fast
+
+```tsx
+import { Spinner } from '@/components/ui/spinner';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SpinnerSpeeds() {
+ const speeds = [
+ { speed: 'slow' as const, label: 'Slow' },
+ { speed: 'normal' as const, label: 'Normal' },
+ { speed: 'fast' as const, label: 'Fast' },
+ ];
+
+ return (
+
+ {speeds.map(({ speed, label }) => (
+
+
+
+ {label}
+
+
+ ))}
+
+ );
+}
+
+```
+
+##### spinner-colors
+
+Spinners with custom colors and styling
+
+```tsx
+import { Spinner } from '@/components/ui/spinner';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SpinnerColors() {
+ const colors = [
+ { color: '#3b82f6', label: 'Blue', variant: 'default' as const },
+ { color: '#10b981', label: 'Green', variant: 'dots' as const },
+ { color: '#f59e0b', label: 'Orange', variant: 'pulse' as const },
+ { color: '#ef4444', label: 'Red', variant: 'bars' as const },
+ { color: '#8b5cf6', label: 'Purple', variant: 'cirlce' as const },
+ ];
+
+ return (
+
+ {colors.map(({ color, label, variant }) => (
+
+
+
+ {label}
+
+
+ ))}
+
+ );
+}
+
+```
+
+##### spinner-overlay
+
+Full-screen loading overlay with backdrop
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { LoadingOverlay } from '@/components/ui/spinner';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function SpinnerOverlay() {
+ const [showOverlay, setShowOverlay] = useState(false);
+
+ const handleShowOverlay = () => {
+ setShowOverlay(true);
+ // Auto hide after 3 seconds for demo
+ setTimeout(() => setShowOverlay(false), 3000);
+ };
+
+ return (
+
+
+ Show Loading Overlay
+
+
+
+
+ );
+}
+
+```
+
+##### spinner-inline
+
+Small spinners for inline usage in buttons or text
+
+```tsx
+import { InlineLoader } from '@/components/ui/spinner';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function SpinnerInline() {
+ return (
+
+
+ Loading data
+
+
+
+
+ Processing
+
+
+
+
+
+ Syncing...
+
+
+ );
+}
+
+```
+---
+
+### stacked-area-chart
+
+A customizable stacked area chart component with smooth animations and gradient fills for visualizing multiple data series over time.
+
+**Installation:**
+```bash
+npx bna-ui add stacked-area-chart
+```
+
+**External Dependencies:** react-native-svg, react-native-reanimated, react-native-gesture-handler
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Stacked-area-chart } from '@/components/ui/stacked-area-chart';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### stacked-area-chart-demo
+
+A stacked area chart with smooth animations and gradient fills
+
+```tsx
+import { StackedAreaChart } from '@/components/charts/stacked-area-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { x: 1, y: [20, 30, 25], label: 'Jan' },
+ { x: 2, y: [25, 35, 30], label: 'Feb' },
+ { x: 3, y: [30, 40, 35], label: 'Mar' },
+ { x: 4, y: [35, 45, 40], label: 'Apr' },
+ { x: 5, y: [40, 50, 45], label: 'May' },
+ { x: 6, y: [45, 55, 50], label: 'Jun' },
+];
+
+const categories = ['Product A', 'Product B', 'Product C'];
+
+export function StackedAreaChartDemo() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### stacked-area-chart-sample
+
+A sample stacked area chart with revenue data
+
+```tsx
+import { StackedAreaChart } from '@/components/charts/stacked-area-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { x: 1, y: [45, 55, 35, 25], label: 'Q1' },
+ { x: 2, y: [50, 60, 40, 30], label: 'Q2' },
+ { x: 3, y: [55, 65, 45, 35], label: 'Q3' },
+ { x: 4, y: [60, 70, 50, 40], label: 'Q4' },
+ { x: 5, y: [65, 75, 55, 45], label: 'Q1' },
+ { x: 6, y: [70, 80, 60, 50], label: 'Q2' },
+];
+
+const categories = ['Direct Sales', 'Online', 'Retail', 'Partner'];
+
+export function StackedAreaChartSample() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### stacked-area-chart-styled
+
+A customized stacked area chart with custom colors and styling
+
+```tsx
+import { StackedAreaChart } from '@/components/charts/stacked-area-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { x: 1, y: [120, 80, 60], label: 'Week 1' },
+ { x: 2, y: [140, 90, 70], label: 'Week 2' },
+ { x: 3, y: [160, 100, 80], label: 'Week 3' },
+ { x: 4, y: [180, 110, 90], label: 'Week 4' },
+ { x: 5, y: [200, 120, 100], label: 'Week 5' },
+ { x: 6, y: [220, 130, 110], label: 'Week 6' },
+ { x: 7, y: [240, 140, 120], label: 'Week 7' },
+ { x: 8, y: [260, 150, 130], label: 'Week 8' },
+];
+
+const categories = ['Premium', 'Standard', 'Basic'];
+
+export function StackedAreaChartStyled() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### stacked-area-chart-large
+
+A stacked area chart with large dataset
+
+```tsx
+import { StackedAreaChart } from '@/components/charts/stacked-area-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const generateLargeDataset = () => {
+ const data = [];
+ const months = [
+ 'Jan',
+ 'Feb',
+ 'Mar',
+ 'Apr',
+ 'May',
+ 'Jun',
+ 'Jul',
+ 'Aug',
+ 'Sep',
+ 'Oct',
+ 'Nov',
+ 'Dec',
+ ];
+
+ for (let i = 0; i < 12; i++) {
+ data.push({
+ x: i + 1,
+ y: [
+ Math.floor(Math.random() * 50) + 100, // Desktop
+ Math.floor(Math.random() * 80) + 120, // Mobile
+ Math.floor(Math.random() * 40) + 60, // Tablet
+ Math.floor(Math.random() * 30) + 40, // TV
+ Math.floor(Math.random() * 20) + 20, // Watch
+ ],
+ label: months[i],
+ });
+ }
+
+ return data;
+};
+
+const sampleData = generateLargeDataset();
+const categories = ['Desktop', 'Mobile', 'Tablet', 'TV', 'Watch'];
+
+export function StackedAreaChartLarge() {
+ return (
+
+
+
+ );
+}
+
+```
+---
+
+### stacked-bar-chart
+
+A customizable stacked bar chart component with smooth animations, support for both horizontal and vertical layouts, and flexible styling.
+
+**Installation:**
+```bash
+npx bna-ui add stacked-bar-chart
+```
+
+**External Dependencies:** react-native-svg, react-native-reanimated, react-native-gesture-handler
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Stacked-bar-chart } from '@/components/ui/stacked-bar-chart';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### stacked-bar-chart-demo
+
+A stacked bar chart with smooth animations
+
+```tsx
+import { StackedBarChart } from '@/components/charts/stacked-bar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Q1', values: [120, 98, 86] },
+ { label: 'Q2', values: [140, 110, 95] },
+ { label: 'Q3', values: [160, 130, 105] },
+ { label: 'Q4', values: [180, 150, 115] },
+];
+
+const categories = ['Sales', 'Marketing', 'Support'];
+
+export function StackedBarChartDemo() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### stacked-bar-chart-horizontal
+
+A horizontal stacked bar chart
+
+```tsx
+import { StackedBarChart } from '@/components/charts/stacked-bar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Product A', values: [45, 30, 25] },
+ { label: 'Product B', values: [60, 40, 35] },
+ { label: 'Product C', values: [55, 35, 30] },
+ { label: 'Product D', values: [70, 45, 40] },
+ { label: 'Product E', values: [50, 32, 28] },
+];
+
+const categories = ['Direct Sales', 'Online', 'Retail'];
+
+export function StackedBarChartHorizontal() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### stacked-bar-chart-styled
+
+A customized stacked bar chart with custom colors and styling
+
+```tsx
+import { StackedBarChart } from '@/components/charts/stacked-bar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Mobile', values: [85, 45, 30, 20] },
+ { label: 'Desktop', values: [120, 80, 50, 35] },
+ { label: 'Tablet', values: [65, 35, 25, 15] },
+ { label: 'Smart TV', values: [40, 20, 15, 10] },
+];
+
+const categories = ['Chrome', 'Safari', 'Firefox', 'Edge'];
+
+// Custom colors for different browsers
+const customColors = [
+ '#4285F4', // Chrome blue
+ '#FF9500', // Safari orange
+ '#FF6611', // Firefox orange
+ '#0078D4', // Edge blue
+];
+
+export function StackedBarChartStyled() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### stacked-bar-chart-large
+
+A stacked bar chart with large dataset
+
+```tsx
+import { StackedBarChart } from '@/components/charts/stacked-bar-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Jan', values: [220, 180, 140, 100, 80] },
+ { label: 'Feb', values: [240, 190, 150, 110, 85] },
+ { label: 'Mar', values: [260, 200, 160, 120, 90] },
+ { label: 'Apr', values: [280, 210, 170, 130, 95] },
+ { label: 'May', values: [300, 220, 180, 140, 100] },
+ { label: 'Jun', values: [320, 230, 190, 150, 105] },
+ { label: 'Jul', values: [340, 240, 200, 160, 110] },
+ { label: 'Aug', values: [360, 250, 210, 170, 115] },
+ { label: 'Sep', values: [380, 260, 220, 180, 120] },
+ { label: 'Oct', values: [400, 270, 230, 190, 125] },
+ { label: 'Nov', values: [420, 280, 240, 200, 130] },
+ { label: 'Dec', values: [440, 290, 250, 210, 135] },
+];
+
+const categories = ['Enterprise', 'Professional', 'Standard', 'Basic', 'Free'];
+
+export function StackedBarChartLarge() {
+ return (
+
+
+
+ );
+}
+
+```
+---
+
+### switch
+
+A control that allows the user to toggle between checked and not checked states.
+
+**Installation:**
+```bash
+npx bna-ui add switch
+```
+
+**Registry Dependencies:** text, view
+
+**Required Hooks:** useThemeColor
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Switch } from '@/components/ui/switch';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### switch-demo
+
+A basic switch with label
+
+```tsx
+import { Switch } from '@/components/ui/switch';
+import React, { useState } from 'react';
+
+export function SwitchDemo() {
+ const [isEnabled, setIsEnabled] = useState(false);
+
+ return (
+
+ );
+}
+
+```
+
+##### switch-simple
+
+A switch without label text
+
+```tsx
+import { Switch } from '@/components/ui/switch';
+import React, { useState } from 'react';
+
+export function SwitchSimple() {
+ const [isEnabled, setIsEnabled] = useState(false);
+
+ return ;
+}
+
+```
+
+##### switch-error
+
+Switch with error message and styling
+
+```tsx
+import { Switch } from '@/components/ui/switch';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function SwitchError() {
+ const [isEnabled, setIsEnabled] = useState(false);
+
+ return (
+
+
+
+ {}}
+ error='You must accept the privacy policy'
+ />
+
+ );
+}
+
+```
+
+##### switch-disabled
+
+Switches in disabled state
+
+```tsx
+import { Switch } from '@/components/ui/switch';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function SwitchDisabled() {
+ const [value, setValue] = useState(false);
+
+ return (
+
+
+
+ {}}
+ disabled={true}
+ />
+
+ );
+}
+
+```
+
+##### switch-settings
+
+Multiple switches arranged in a settings list
+
+```tsx
+import { Switch } from '@/components/ui/switch';
+import { View } from '@/components/ui/view';
+import { useThemeColor } from '@/hooks/useThemeColor';
+import { BORDER_RADIUS } from '@/theme/globals';
+import React, { useState } from 'react';
+
+export function SwitchSettings() {
+ const card = useThemeColor({}, 'card');
+
+ const [notifications, setNotifications] = useState(true);
+ const [darkMode, setDarkMode] = useState(false);
+ const [location, setLocation] = useState(true);
+ const [analytics, setAnalytics] = useState(false);
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+```
+
+##### switch-colors
+
+Switches with custom colors and styling
+
+```tsx
+import { Switch } from '@/components/ui/switch';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function SwitchColors() {
+ const [switch1, setSwitch1] = useState(true);
+ const [switch2, setSwitch2] = useState(true);
+ const [switch3, setSwitch3] = useState(true);
+
+ return (
+
+
+
+
+
+ );
+}
+
+```
+---
+
+### table
+
+A flexible data table component with sorting, filtering, pagination, and search functionality.
+
+**Installation:**
+```bash
+npx bna-ui add table
+```
+
+**External Dependencies:** lucide-react-native
+
+**Registry Dependencies:** button, text, view
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+#### Props Interface
+
+```typescript
+export interface TableProps {
+ data: T[];
+ columns: TableColumn[];
+ pagination?: boolean;
+ pageSize?: number;
+ searchable?: boolean;
+ searchPlaceholder?: string;
+ loading?: boolean;
+ emptyMessage?: string;
+ style?: ViewStyle;
+ headerStyle?: ViewStyle;
+ rowStyle?: ViewStyle;
+ cellStyle?: ViewStyle;
+ onRowPress?: (row: T, index: number) => void;
+ sortable?: boolean;
+ filterable?: boolean;
+}
+```
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Table } from '@/components/ui/table';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### table-demo
+
+A basic data table with sample data
+
+```tsx
+import { Table, TableColumn } from '@/components/ui/table';
+import React from 'react';
+
+interface User {
+ id: number;
+ name: string;
+ email: string;
+ role: string;
+ status: 'Active' | 'Inactive';
+}
+
+const sampleData: User[] = [
+ {
+ id: 1,
+ name: 'John Doe',
+ email: 'john@example.com',
+ role: 'Admin',
+ status: 'Active',
+ },
+ {
+ id: 2,
+ name: 'Jane Smith',
+ email: 'jane@example.com',
+ role: 'User',
+ status: 'Active',
+ },
+ {
+ id: 3,
+ name: 'Bob Johnson',
+ email: 'bob@example.com',
+ role: 'Manager',
+ status: 'Inactive',
+ },
+ {
+ id: 4,
+ name: 'Alice Brown',
+ email: 'alice@example.com',
+ role: 'User',
+ status: 'Active',
+ },
+ {
+ id: 5,
+ name: 'Charlie Wilson',
+ email: 'charlie@example.com',
+ role: 'Admin',
+ status: 'Active',
+ },
+];
+
+const columns: TableColumn[] = [
+ {
+ id: 'name',
+ header: 'Name',
+ accessorKey: 'name',
+ sortable: true,
+ filterable: true,
+ },
+ {
+ id: 'email',
+ header: 'Email',
+ accessorKey: 'email',
+ sortable: true,
+ filterable: true,
+ },
+ {
+ id: 'role',
+ header: 'Role',
+ accessorKey: 'role',
+ sortable: true,
+ filterable: true,
+ },
+ {
+ id: 'status',
+ header: 'Status',
+ accessorKey: 'status',
+ sortable: true,
+ filterable: true,
+ },
+];
+
+export function TableDemo() {
+ return (
+
+ );
+}
+
+```
+
+##### table-sortable
+
+Table with sortable columns
+
+```tsx
+import { Table, TableColumn } from '@/components/ui/table';
+import React from 'react';
+
+interface Product {
+ id: number;
+ name: string;
+ price: number;
+ category: string;
+ inStock: boolean;
+ rating: number;
+}
+
+const products: Product[] = [
+ {
+ id: 1,
+ name: 'Laptop Pro',
+ price: 1299.99,
+ category: 'Electronics',
+ inStock: true,
+ rating: 4.5,
+ },
+ {
+ id: 2,
+ name: 'Wireless Mouse',
+ price: 29.99,
+ category: 'Electronics',
+ inStock: true,
+ rating: 4.2,
+ },
+ {
+ id: 3,
+ name: 'Coffee Mug',
+ price: 12.99,
+ category: 'Kitchen',
+ inStock: false,
+ rating: 4.0,
+ },
+ {
+ id: 4,
+ name: 'Desk Chair',
+ price: 199.99,
+ category: 'Furniture',
+ inStock: true,
+ rating: 4.7,
+ },
+ {
+ id: 5,
+ name: 'Notebook',
+ price: 5.99,
+ category: 'Office',
+ inStock: true,
+ rating: 3.8,
+ },
+ {
+ id: 6,
+ name: 'Smartphone',
+ price: 699.99,
+ category: 'Electronics',
+ inStock: true,
+ rating: 4.3,
+ },
+];
+
+const columns: TableColumn[] = [
+ {
+ id: 'name',
+ header: 'Product Name',
+ accessorKey: 'name',
+ sortable: true,
+ filterable: true,
+ minWidth: 150,
+ },
+ {
+ id: 'price',
+ header: 'Price',
+ accessorKey: 'price',
+ sortable: true,
+ align: 'right',
+ cell: (value) => `$${value.toFixed(2)}`,
+ minWidth: 100,
+ },
+ {
+ id: 'category',
+ header: 'Category',
+ accessorKey: 'category',
+ sortable: true,
+ filterable: true,
+ minWidth: 120,
+ },
+ {
+ id: 'inStock',
+ header: 'In Stock',
+ accessorKey: 'inStock',
+ sortable: true,
+ align: 'center',
+ cell: (value) => (value ? '✅' : '❌'),
+ minWidth: 100,
+ },
+ {
+ id: 'rating',
+ header: 'Rating',
+ accessorKey: 'rating',
+ sortable: true,
+ align: 'center',
+ cell: (value) => `⭐ ${value}`,
+ minWidth: 100,
+ },
+];
+
+export function TableSortable() {
+ return (
+
+ );
+}
+
+```
+
+##### table-custom-cells
+
+Table with custom cell renderers and formatting
+
+```tsx
+import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
+import { Badge } from '@/components/ui/badge';
+import { Table, TableColumn } from '@/components/ui/table';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+interface Employee {
+ id: number;
+ name: string;
+ email: string;
+ department: string;
+ salary: number;
+ avatar?: string;
+ joinDate: string;
+ status: 'Active' | 'On Leave' | 'Terminated';
+}
+
+const employees: Employee[] = [
+ {
+ id: 1,
+ name: 'Sarah Johnson',
+ email: 'sarah.j@company.com',
+ department: 'Engineering',
+ salary: 95000,
+ avatar: 'https://avatars.githubusercontent.com/u/1?v=4',
+ joinDate: '2022-01-15',
+ status: 'Active',
+ },
+ {
+ id: 2,
+ name: 'Mike Chen',
+ email: 'mike.c@company.com',
+ department: 'Design',
+ salary: 78000,
+ joinDate: '2023-03-20',
+ status: 'Active',
+ },
+ {
+ id: 3,
+ name: 'Emma Davis',
+ email: 'emma.d@company.com',
+ department: 'Marketing',
+ salary: 65000,
+ avatar: 'https://avatars.githubusercontent.com/u/2?v=4',
+ joinDate: '2021-11-08',
+ status: 'On Leave',
+ },
+ {
+ id: 4,
+ name: 'James Wilson',
+ email: 'james.w@company.com',
+ department: 'Sales',
+ salary: 72000,
+ joinDate: '2020-09-12',
+ status: 'Terminated',
+ },
+];
+
+const columns: TableColumn[] = [
+ {
+ id: 'employee',
+ header: 'Employee',
+ accessorKey: 'name',
+ sortable: true,
+ filterable: true,
+ minWidth: 200,
+ cell: (value, row) => (
+
+
+ {row.avatar && }
+
+ {row.name
+ .split(' ')
+ .map((n) => n[0])
+ .join('')}
+
+
+
+
+ {row.name}
+
+
+ {row.email}
+
+
+
+ ),
+ },
+ {
+ id: 'department',
+ header: 'Department',
+ accessorKey: 'department',
+ sortable: true,
+ filterable: true,
+ minWidth: 120,
+ },
+ {
+ id: 'salary',
+ header: 'Salary',
+ accessorKey: 'salary',
+ sortable: true,
+ align: 'right',
+ minWidth: 120,
+ cell: (value) => (
+
+ ${value.toLocaleString()}
+
+ ),
+ },
+ {
+ id: 'joinDate',
+ header: 'Join Date',
+ accessorKey: 'joinDate',
+ sortable: true,
+ align: 'center',
+ minWidth: 120,
+ cell: (value) => new Date(value).toLocaleDateString(),
+ },
+ {
+ id: 'status',
+ header: 'Status',
+ accessorKey: 'status',
+ sortable: true,
+ filterable: true,
+ align: 'center',
+ minWidth: 120,
+ cell: (value) => (
+
+ {value}
+
+ ),
+ },
+];
+
+export function TableCustomCells() {
+ return (
+
+ );
+}
+
+```
+
+##### table-pagination
+
+Table with pagination controls
+
+```tsx
+import { Table, TableColumn } from '@/components/ui/table';
+import React from 'react';
+
+interface Order {
+ id: string;
+ customer: string;
+ product: string;
+ amount: number;
+ date: string;
+ status: 'Pending' | 'Completed' | 'Cancelled';
+}
+
+// Generate sample data
+const generateOrders = (count: number): Order[] => {
+ const customers = [
+ 'John Doe',
+ 'Jane Smith',
+ 'Bob Johnson',
+ 'Alice Brown',
+ 'Charlie Wilson',
+ 'Diana Ross',
+ 'Frank Miller',
+ 'Grace Lee',
+ ];
+ const products = [
+ 'Laptop',
+ 'Mouse',
+ 'Keyboard',
+ 'Monitor',
+ 'Headphones',
+ 'Webcam',
+ 'Tablet',
+ 'Phone',
+ ];
+ const statuses: Order['status'][] = ['Pending', 'Completed', 'Cancelled'];
+
+ return Array.from({ length: count }, (_, i) => ({
+ id: `ORD-${String(i + 1).padStart(4, '0')}`,
+ customer: customers[i % customers.length],
+ product: products[i % products.length],
+ amount: Math.floor(Math.random() * 1000) + 50,
+ date: new Date(Date.now() - Math.random() * 90 * 24 * 60 * 60 * 1000)
+ .toISOString()
+ .split('T')[0],
+ status: statuses[Math.floor(Math.random() * statuses.length)],
+ }));
+};
+
+const orders = generateOrders(50);
+
+const columns: TableColumn[] = [
+ {
+ id: 'id',
+ header: 'Order ID',
+ accessorKey: 'id',
+ sortable: true,
+ filterable: true,
+ minWidth: 120,
+ },
+ {
+ id: 'customer',
+ header: 'Customer',
+ accessorKey: 'customer',
+ sortable: true,
+ filterable: true,
+ minWidth: 150,
+ },
+ {
+ id: 'product',
+ header: 'Product',
+ accessorKey: 'product',
+ sortable: true,
+ filterable: true,
+ minWidth: 120,
+ },
+ {
+ id: 'amount',
+ header: 'Amount',
+ accessorKey: 'amount',
+ sortable: true,
+ align: 'right',
+ minWidth: 100,
+ cell: (value) => `$${value.toFixed(2)}`,
+ },
+ {
+ id: 'date',
+ header: 'Date',
+ accessorKey: 'date',
+ sortable: true,
+ align: 'center',
+ minWidth: 120,
+ },
+ {
+ id: 'status',
+ header: 'Status',
+ accessorKey: 'status',
+ sortable: true,
+ filterable: true,
+ align: 'center',
+ minWidth: 120,
+ },
+];
+
+export function TablePagination() {
+ return (
+
+ );
+}
+
+```
+
+##### table-search
+
+Table with search functionality
+
+```tsx
+import { Table, TableColumn } from '@/components/ui/table';
+import React from 'react';
+
+interface Book {
+ id: number;
+ title: string;
+ author: string;
+ genre: string;
+ year: number;
+ isbn: string;
+ pages: number;
+}
+
+const books: Book[] = [
+ {
+ id: 1,
+ title: 'The Great Gatsby',
+ author: 'F. Scott Fitzgerald',
+ genre: 'Fiction',
+ year: 1925,
+ isbn: '978-0-7432-7356-5',
+ pages: 180,
+ },
+ {
+ id: 2,
+ title: 'To Kill a Mockingbird',
+ author: 'Harper Lee',
+ genre: 'Fiction',
+ year: 1960,
+ isbn: '978-0-06-112008-4',
+ pages: 281,
+ },
+ {
+ id: 3,
+ title: '1984',
+ author: 'George Orwell',
+ genre: 'Dystopian',
+ year: 1949,
+ isbn: '978-0-452-28423-4',
+ pages: 328,
+ },
+ {
+ id: 4,
+ title: 'Pride and Prejudice',
+ author: 'Jane Austen',
+ genre: 'Romance',
+ year: 1813,
+ isbn: '978-0-14-143951-8',
+ pages: 432,
+ },
+ {
+ id: 5,
+ title: 'The Catcher in the Rye',
+ author: 'J.D. Salinger',
+ genre: 'Fiction',
+ year: 1951,
+ isbn: '978-0-316-76948-0',
+ pages: 277,
+ },
+ {
+ id: 6,
+ title: 'Lord of the Flies',
+ author: 'William Golding',
+ genre: 'Fiction',
+ year: 1954,
+ isbn: '978-0-571-05686-2',
+ pages: 224,
+ },
+ {
+ id: 7,
+ title: 'The Hobbit',
+ author: 'J.R.R. Tolkien',
+ genre: 'Fantasy',
+ year: 1937,
+ isbn: '978-0-547-92822-7',
+ pages: 366,
+ },
+ {
+ id: 8,
+ title: "Harry Potter and the Sorcerer's Stone",
+ author: 'J.K. Rowling',
+ genre: 'Fantasy',
+ year: 1997,
+ isbn: '978-0-439-70818-8',
+ pages: 309,
+ },
+ {
+ id: 9,
+ title: 'The Da Vinci Code',
+ author: 'Dan Brown',
+ genre: 'Mystery',
+ year: 2003,
+ isbn: '978-0-307-47427-5',
+ pages: 689,
+ },
+ {
+ id: 10,
+ title: 'Brave New World',
+ author: 'Aldous Huxley',
+ genre: 'Science Fiction',
+ year: 1932,
+ isbn: '978-0-06-085052-4',
+ pages: 268,
+ },
+];
+
+const columns: TableColumn[] = [
+ {
+ id: 'title',
+ header: 'Title',
+ accessorKey: 'title',
+ sortable: true,
+ filterable: true,
+ minWidth: 200,
+ },
+ {
+ id: 'author',
+ header: 'Author',
+ accessorKey: 'author',
+ sortable: true,
+ filterable: true,
+ minWidth: 150,
+ },
+ {
+ id: 'genre',
+ header: 'Genre',
+ accessorKey: 'genre',
+ sortable: true,
+ filterable: true,
+ minWidth: 120,
+ },
+ {
+ id: 'year',
+ header: 'Year',
+ accessorKey: 'year',
+ sortable: true,
+ align: 'center',
+ minWidth: 80,
+ },
+ {
+ id: 'isbn',
+ header: 'ISBN',
+ accessorKey: 'isbn',
+ filterable: true,
+ minWidth: 150,
+ },
+ {
+ id: 'pages',
+ header: 'Pages',
+ accessorKey: 'pages',
+ sortable: true,
+ align: 'right',
+ minWidth: 80,
+ },
+];
+
+export function TableSearch() {
+ return (
+
+ );
+}
+
+```
+
+##### table-loading
+
+Table showing loading state
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { Table, TableColumn } from '@/components/ui/table';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+interface ApiData {
+ id: number;
+ name: string;
+ value: number;
+ category: string;
+}
+
+const mockData: ApiData[] = [
+ { id: 1, name: 'Item A', value: 100, category: 'Type 1' },
+ { id: 2, name: 'Item B', value: 250, category: 'Type 2' },
+ { id: 3, name: 'Item C', value: 175, category: 'Type 1' },
+ { id: 4, name: 'Item D', value: 320, category: 'Type 3' },
+];
+
+const columns: TableColumn[] = [
+ {
+ id: 'name',
+ header: 'Name',
+ accessorKey: 'name',
+ sortable: true,
+ filterable: true,
+ },
+ {
+ id: 'value',
+ header: 'Value',
+ accessorKey: 'value',
+ sortable: true,
+ align: 'right',
+ },
+ {
+ id: 'category',
+ header: 'Category',
+ accessorKey: 'category',
+ sortable: true,
+ filterable: true,
+ },
+];
+
+export function TableLoading() {
+ const [loading, setLoading] = useState(false);
+ const [data, setData] = useState([]);
+
+ const simulateLoading = () => {
+ setLoading(true);
+ setData([]);
+
+ // Simulate API call
+ setTimeout(() => {
+ setData(mockData);
+ setLoading(false);
+ }, 2000);
+ };
+
+ const clearData = () => {
+ setData([]);
+ setLoading(false);
+ };
+
+ return (
+
+
+
+ Load Data
+
+
+ Clear Data
+
+
+
+
+
+ );
+}
+
+```
+---
+
+### tabs
+
+A foundational View component with transparent background and ref forwarding support.
+
+**Installation:**
+```bash
+npx bna-ui add tabs
+```
+
+**External Dependencies:** react-native-gesture-handler, react-native-reanimated
+
+**Registry Dependencies:** text, view
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Tabs } from '@/components/ui/tabs';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### tabs-demo
+
+Basic tabs container with content
+
+```tsx
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function TabsDemo() {
+ return (
+
+
+ Account
+ Followers
+ Following
+ Password
+ Settings
+ More
+
+
+
+
+
+ Account Settings
+
+
+ Manage your account information and preferences here.
+
+
+
+
+
+
+
+ Followers
+
+
+ Manage your followers information and preferences here.
+
+
+
+
+
+
+
+ Following
+
+
+ Manage your following information and preferences here.
+
+
+
+
+
+
+
+ Password Settings
+
+
+ Change your password and security settings preferences here.
+
+
+
+
+
+
+
+ General Settings
+
+
+ Configure your application preferences and options.
+
+
+
+
+
+
+
+ More
+
+
+ Configure your application preferences and options.
+
+
+
+
+ );
+}
+
+```
+
+##### tabs-vertical
+
+Tabs arranged in vertical orientation
+
+```tsx
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function TabsVertical() {
+ return (
+
+
+ 🧑💼
+
+ 🔔
+ 💰
+
+
+
+
+
+ Profile Information
+
+
+ Update your personal information and profile picture.
+
+
+
+
+
+
+
+ Security Settings
+
+
+ Manage two-factor authentication and login security.
+
+
+
+
+
+
+
+ Notification Preferences
+
+
+ Configure how and when you receive notifications.
+
+
+
+
+
+
+
+ Billing & Subscription
+
+
+ Manage your subscription and payment methods.
+
+
+
+
+ );
+}
+
+```
+
+##### tabs-disabled
+
+Tabs with disabled states
+
+```tsx
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function TabsDisabled() {
+ return (
+
+
+ Available
+ Pending
+
+ Premium
+
+
+ Enterprise
+
+
+
+
+
+
+ Available Features
+
+
+ These features are currently available to you.
+
+
+
+
+
+
+
+ Pending Features
+
+
+ These features are being processed and will be available soon.
+
+
+
+
+
+
+
+ Premium Features
+
+ Upgrade to access premium features.
+
+
+
+
+
+
+ Enterprise Features
+
+ Contact sales for enterprise features.
+
+
+
+ );
+}
+
+```
+
+##### tabs-styled
+
+Tabs with custom colors and styling
+
+```tsx
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import { useState } from 'react';
+
+export function TabsStyled() {
+ const [value, setValue] = useState('design');
+
+ return (
+
+
+
+ Design
+
+
+ Development
+
+
+ Testing
+
+
+
+
+
+
+ Design Phase
+
+
+ Create wireframes, mockups, and design systems for your project.
+
+
+
+
+
+
+
+ Development Phase
+
+
+ Build and implement the features based on the design specifications.
+
+
+
+
+
+
+
+ Testing Phase
+
+
+ Perform quality assurance and user acceptance testing.
+
+
+
+
+ );
+}
+
+```
+---
+
+### text
+
+A foundational View component with transparent background and ref forwarding support.
+
+**Installation:**
+```bash
+npx bna-ui add text
+```
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Text } from '@/components/ui/text';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### text-demo
+
+Basic text component showing different variants
+
+```tsx
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function TextDemo() {
+ return (
+
+ Heading Text
+ Title Text
+ Subtitle Text
+
+ This is body text that demonstrates the default styling for regular
+ content.
+
+ Caption text for additional information
+ Link text with underline
+
+ );
+}
+
+```
+
+##### text-variants
+
+All text variants showing the typography hierarchy
+
+```tsx
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function TextVariants() {
+ return (
+
+
+
+ HEADING (28px, weight 700)
+
+
+ The quick brown fox jumps over the lazy dog
+
+
+
+
+
+ TITLE (24px, weight 700)
+
+ The quick brown fox jumps over the lazy dog
+
+
+
+
+ SUBTITLE (19px, weight 600)
+
+
+ The quick brown fox jumps over the lazy dog
+
+
+
+
+
+ BODY (16px, weight 400)
+
+
+ The quick brown fox jumps over the lazy dog. This is the default text
+ variant used for body content and regular paragraphs.
+
+
+
+
+
+ CAPTION (16px, weight 400, muted)
+
+
+ The quick brown fox jumps over the lazy dog
+
+
+
+
+
+ LINK (16px, weight 500, underlined)
+
+ The quick brown fox jumps over the lazy dog
+
+
+ );
+}
+
+```
+
+##### text-colors
+
+Text with custom light and dark mode colors
+
+```tsx
+import { Text } from '@/components/ui/text';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function TextColors() {
+ return (
+
+
+ Custom Color Examples
+
+
+
+ This text uses custom blue colors for light and dark themes
+
+
+
+ This text uses custom green colors for light and dark themes
+
+
+
+ This text uses custom amber colors for light and dark themes
+
+
+
+ This text uses custom red colors for light and dark themes
+
+
+
+ This text uses custom purple colors for light and dark themes
+
+
+
+
+ Note: These colors automatically adapt based on the current theme
+ (light/dark mode)
+
+
+
+ );
+}
+
+```
+---
+
+### toast
+
+A succinct message that is displayed temporarily with Dynamic Island animation inspired by iOS.
+
+**Installation:**
+```bash
+npx bna-ui add toast
+```
+
+**External Dependencies:** react-native-gesture-handler, react-native-reanimated, lucide-react-native
+
+**Registry Dependencies:** text
+
+#### Types
+
+```typescript
+export type ToastVariant = 'default' | 'success' | 'error' | 'warning' | 'info'
+```
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Toast } from '@/components/ui/toast';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### toast-demo
+
+A basic toast notification with title and description
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { useToast } from '@/components/ui/toast';
+import React from 'react';
+
+export function ToastDemo() {
+ const { toast } = useToast();
+
+ const showToast = () => {
+ toast({
+ title: 'Toast Notification',
+ description:
+ 'This is a basic toast notification with title and description.',
+ variant: 'default',
+ });
+ };
+
+ return Show Toast;
+}
+
+```
+
+##### toast-variants
+
+Toast notifications with different variants (success, error, warning, info)
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { useToast } from '@/components/ui/toast';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ToastVariants() {
+ const { success, error, warning, info } = useToast();
+
+ return (
+
+
+ success('Success!', 'Your action was completed successfully.')
+ }
+ variant='success'
+ >
+ Success
+
+
+
+ error('Error!', 'Something went wrong. Please try again.')
+ }
+ variant='destructive'
+ >
+ Error
+
+
+
+ warning('Warning!', 'Please review your input before continuing.')
+ }
+ variant='secondary'
+ >
+ Warning
+
+
+ info('Info', "Here's some helpful information for you.")}
+ >
+ Info
+
+
+ );
+}
+
+```
+
+##### toast-actions
+
+Toast notifications with action buttons
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { useToast } from '@/components/ui/toast';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ToastActions() {
+ const { toast } = useToast();
+
+ const showToastWithAction = () => {
+ toast({
+ title: 'New message received',
+ description: 'You have a new message from John Doe.',
+ variant: 'info',
+ action: {
+ label: 'View',
+ onPress: () => {
+ console.log('View action pressed');
+ // Navigate to message or perform action
+ },
+ },
+ });
+ };
+
+ const showUndoToast = () => {
+ toast({
+ title: 'Item deleted',
+ description: 'The item has been removed from your list.',
+ variant: 'warning',
+ duration: 8000, // Longer duration for undo action
+ action: {
+ label: 'Undo',
+ onPress: () => {
+ console.log('Undo action pressed');
+ // Restore the deleted item
+ },
+ },
+ });
+ };
+
+ return (
+
+
+ Show with Action
+
+
+
+ Show Undo Toast
+
+
+ );
+}
+
+```
+
+##### toast-duration
+
+Toast notifications with custom durations
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { useToast } from '@/components/ui/toast';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ToastDuration() {
+ const { toast } = useToast();
+
+ return (
+
+
+ toast({
+ title: 'Quick toast',
+ description: 'This disappears in 2 seconds',
+ duration: 2000,
+ variant: 'info',
+ })
+ }
+ variant='outline'
+ >
+ 2 seconds
+
+
+
+ toast({
+ title: 'Standard toast',
+ description: 'This disappears in 4 seconds',
+ duration: 4000,
+ variant: 'default',
+ })
+ }
+ variant='outline'
+ >
+ 4 seconds (default)
+
+
+
+ toast({
+ title: 'Long toast',
+ description: 'This disappears in 8 seconds',
+ duration: 8000,
+ variant: 'warning',
+ })
+ }
+ variant='outline'
+ >
+ 8 seconds
+
+
+
+ toast({
+ title: 'Persistent toast',
+ description: "This won't disappear automatically",
+ duration: 0, // No auto-dismiss
+ variant: 'error',
+ })
+ }
+ variant='outline'
+ >
+ Persistent
+
+
+ );
+}
+
+```
+
+##### toast-multiple
+
+Multiple toast notifications stacked vertically
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { useToast } from '@/components/ui/toast';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ToastMultiple() {
+ const { toast, dismissAll } = useToast();
+
+ const showMultipleToasts = () => {
+ const variants = ['success', 'warning', 'error', 'info'] as const;
+ const messages = [
+ { title: 'Success!', description: 'Operation completed successfully' },
+ { title: 'Warning', description: 'Please check your input' },
+ { title: 'Error', description: 'Something went wrong' },
+ { title: 'Info', description: "Here's some information" },
+ ];
+
+ variants.forEach((variant, index) => {
+ setTimeout(() => {
+ toast({
+ ...messages[index],
+ variant,
+ duration: 6000,
+ });
+ }, index * 500); // Stagger the toasts
+ });
+ };
+
+ const showBatchToasts = () => {
+ // Show multiple toasts at once
+ toast({
+ title: 'First toast',
+ description: 'This is the first toast',
+ variant: 'success',
+ });
+
+ toast({
+ title: 'Second toast',
+ description: 'This is the second toast',
+ variant: 'info',
+ });
+
+ toast({
+ title: 'Third toast',
+ description: 'This is the third toast',
+ variant: 'warning',
+ });
+ };
+
+ return (
+
+
+ Show Staggered Toasts
+
+
+
+ Show Batch Toasts
+
+
+
+ Dismiss All Toasts
+
+
+ );
+}
+
+```
+
+##### toast-compact
+
+Compact toast notifications without title or description
+
+```tsx
+import { Button } from '@/components/ui/button';
+import { useToast } from '@/components/ui/toast';
+import { View } from '@/components/ui/view';
+import React from 'react';
+
+export function ToastCompact() {
+ const { toast } = useToast();
+
+ return (
+
+
+ toast({
+ variant: 'success',
+ })
+ }
+ variant='success'
+ >
+ Success Icon Only
+
+
+
+ toast({
+ variant: 'error',
+ })
+ }
+ variant='destructive'
+ >
+ Error Icon Only
+
+
+
+ toast({
+ variant: 'warning',
+ })
+ }
+ variant='secondary'
+ >
+ Warning Icon Only
+
+
+
+ toast({
+ variant: 'info',
+ })
+ }
+ variant='outline'
+ >
+ Info Icon Only
+
+
+
+ toast({
+ title: 'Title only',
+ })
+ }
+ >
+ Title Only
+
+
+ );
+}
+
+```
+---
+
+### toggle
+
+A two-state button that can be either on or off.
+
+**Installation:**
+```bash
+npx bna-ui add toggle
+```
+
+**External Dependencies:** lucide-react-native
+
+**Registry Dependencies:** text, view, icon
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Toggle } from '@/components/ui/toggle';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### toggle-demo
+
+A basic toggle button with icon
+
+```tsx
+import { Toggle } from '@/components/ui/toggle';
+import { Bold } from 'lucide-react-native';
+import React, { useState } from 'react';
+
+export function ToggleDemo() {
+ const [pressed, setPressed] = useState(false);
+
+ return (
+
+
+
+ );
+}
+
+```
+
+##### toggle-variants
+
+Toggle buttons in different variants
+
+```tsx
+import { Toggle } from '@/components/ui/toggle';
+import { View } from '@/components/ui/view';
+import { Bold, Italic } from 'lucide-react-native';
+import React, { useState } from 'react';
+
+export function ToggleVariants() {
+ const [pressed1, setPressed1] = useState(false);
+ const [pressed2, setPressed2] = useState(true);
+ const [pressed3, setPressed3] = useState(false);
+ const [pressed4, setPressed4] = useState(true);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+```
+
+##### toggle-sizes
+
+Toggle buttons in different sizes
+
+```tsx
+import { Toggle } from '@/components/ui/toggle';
+import { View } from '@/components/ui/view';
+import { Bold } from 'lucide-react-native';
+import React, { useState } from 'react';
+
+export function ToggleSizes() {
+ const [pressed1, setPressed1] = useState(false);
+ const [pressed2, setPressed2] = useState(true);
+
+ return (
+
+
+
+
+
+ Bold
+
+
+ );
+}
+
+```
+
+##### toggle-text
+
+Toggle buttons with text labels
+
+```tsx
+import { Toggle } from '@/components/ui/toggle';
+import { View } from '@/components/ui/view';
+import React, { useState } from 'react';
+
+export function ToggleText() {
+ const [pressed1, setPressed1] = useState(false);
+ const [pressed2, setPressed2] = useState(true);
+ const [pressed3, setPressed3] = useState(false);
+
+ return (
+
+
+ Bold
+
+
+ Italic
+
+
+ Underline
+
+
+ );
+}
+
+```
+
+##### toggle-disabled
+
+Disabled toggle buttons
+
+```tsx
+import { Toggle } from '@/components/ui/toggle';
+import { View } from '@/components/ui/view';
+import { Bold, Italic } from 'lucide-react-native';
+import React from 'react';
+
+export function ToggleDisabled() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+```
+
+##### toggle-group-single
+
+Single selection toggle group
+
+```tsx
+import { ToggleGroupSingle } from '@/components/ui/toggle';
+import { AlignCenter, AlignLeft, AlignRight } from 'lucide-react-native';
+import React, { useState } from 'react';
+
+export function ToggleGroupSingleDemo() {
+ const [value, setValue] = useState('left');
+
+ const items = [
+ { value: 'left', label: 'Left', icon: AlignLeft },
+ { value: 'center', label: 'Center', icon: AlignCenter },
+ { value: 'right', label: 'Right', icon: AlignRight },
+ ];
+
+ return (
+
+ );
+}
+
+```
+
+##### toggle-group-multiple
+
+Multiple selection toggle group
+
+```tsx
+import { ToggleGroupMultiple } from '@/components/ui/toggle';
+import { Bold, Italic, Underline } from 'lucide-react-native';
+import React, { useState } from 'react';
+
+export function ToggleGroupMultipleDemo() {
+ const [value, setValue] = useState(['bold']);
+
+ const items = [
+ { value: 'bold', label: 'Bold', icon: Bold },
+ { value: 'italic', label: 'Italic', icon: Italic },
+ { value: 'underline', label: 'Underline', icon: Underline },
+ ];
+
+ return (
+
+ );
+}
+
+```
+
+##### toggle-group-vertical
+
+Vertical toggle group layout
+
+```tsx
+import { ToggleGroupSingle } from '@/components/ui/toggle';
+import { AlignCenter, AlignLeft, AlignRight } from 'lucide-react-native';
+import React, { useState } from 'react';
+
+export function ToggleGroupVertical() {
+ const [value, setValue] = useState('left');
+
+ const items = [
+ { value: 'left', label: 'Left Align', icon: AlignLeft },
+ { value: 'center', label: 'Center Align', icon: AlignCenter },
+ { value: 'right', label: 'Right Align', icon: AlignRight },
+ ];
+
+ return (
+
+ );
+}
+
+```
+
+##### toggle-group-outline
+
+Toggle group with outline variant
+
+```tsx
+import { ToggleGroupSingle } from '@/components/ui/toggle';
+import { Bold, Italic, Underline } from 'lucide-react-native';
+import React, { useState } from 'react';
+
+export function ToggleGroupOutline() {
+ const [value, setValue] = useState('bold');
+
+ const items = [
+ { value: 'bold', label: 'Bold', icon: Bold },
+ { value: 'italic', label: 'Italic', icon: Italic },
+ { value: 'underline', label: 'Underline', icon: Underline },
+ ];
+
+ return (
+
+ );
+}
+
+```
+---
+
+### treemap-chart
+
+A customizable treemap chart component with hierarchical data visualization, smooth animations, and flexible styling using the squarified treemap algorithm.
+
+**Installation:**
+```bash
+npx bna-ui add treemap-chart
+```
+
+**External Dependencies:** react-native-svg, react-native-reanimated, react-native-gesture-handler
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Treemap-chart } from '@/components/ui/treemap-chart';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### treemap-chart-demo
+
+A treemap chart with smooth animations
+
+```tsx
+import { TreeMapChart } from '@/components/charts/treemap-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Sales', value: 120 },
+ { label: 'Marketing', value: 98 },
+ { label: 'Support', value: 86 },
+ { label: 'Development', value: 140 },
+ { label: 'Design', value: 75 },
+ { label: 'HR', value: 65 },
+];
+
+export function TreeMapChartDemo() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### treemap-chart-sample
+
+A sample treemap chart with various data sizes
+
+```tsx
+import { TreeMapChart } from '@/components/charts/treemap-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const sampleData = [
+ { label: 'Product A', value: 250 },
+ { label: 'Product B', value: 180 },
+ { label: 'Product C', value: 320 },
+ { label: 'Product D', value: 90 },
+ { label: 'Product E', value: 150 },
+ { label: 'Product F', value: 45 },
+ { label: 'Product G', value: 210 },
+ { label: 'Product H', value: 75 },
+];
+
+export function TreeMapChartSample() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### treemap-chart-styled
+
+A customized treemap chart with custom colors and styling
+
+```tsx
+import { TreeMapChart } from '@/components/charts/treemap-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const styledData = [
+ { label: 'Mobile', value: 450, color: '#FF6B6B' },
+ { label: 'Desktop', value: 320, color: '#4ECDC4' },
+ { label: 'Tablet', value: 180, color: '#45B7D1' },
+ { label: 'Watch', value: 90, color: '#FFA07A' },
+ { label: 'TV', value: 150, color: '#98D8C8' },
+ { label: 'Other', value: 60, color: '#F7DC6F' },
+];
+
+export function TreeMapChartStyled() {
+ return (
+
+
+
+ );
+}
+
+```
+
+##### treemap-chart-large
+
+A treemap chart with large dataset
+
+```tsx
+import { TreeMapChart } from '@/components/charts/treemap-chart';
+import { ChartContainer } from '@/components/charts/chart-container';
+import React from 'react';
+
+const largeData = [
+ { label: 'North America', value: 1250 },
+ { label: 'Europe', value: 980 },
+ { label: 'Asia Pacific', value: 1450 },
+ { label: 'South America', value: 320 },
+ { label: 'Africa', value: 180 },
+ { label: 'Middle East', value: 240 },
+ { label: 'Oceania', value: 95 },
+ { label: 'Central Asia', value: 150 },
+ { label: 'Caribbean', value: 85 },
+ { label: 'Eastern Europe', value: 420 },
+ { label: 'Nordic', value: 280 },
+ { label: 'Southeast Asia', value: 650 },
+ { label: 'East Africa', value: 120 },
+ { label: 'West Africa', value: 200 },
+ { label: 'Central America', value: 110 },
+];
+
+export function TreeMapChartLarge() {
+ return (
+
+
+
+ );
+}
+
+```
+---
+
+### video
+
+A video player component with custom controls, gestures, and subtitle support.
+
+**Installation:**
+```bash
+npx bna-ui add video
+```
+
+**External Dependencies:** expo-video, lucide-react-native
+
+**Registry Dependencies:** progress, text, view
+
+**Required Hooks:** useThemeColor
+
+**Theme Dependencies:** globals
+
+**Preview:**
+
+
+
+#### Basic Usage
+
+```tsx
+import { Video } from '@/components/ui/video';
+
+export default function Example() {
+ return (
+
+ );
+}```
+
+
+#### Advanced Examples
+
+##### video-demo
+
+A basic video player with custom controls
+
+```tsx
+import { Video } from '@/components/ui/video';
+
+export function VideoDemo() {
+ return (
+
+ );
+}
+
+```
+
+##### video-native-controls
+
+Video player using native system controls
+
+```tsx
+import { Video } from '@/components/ui/video';
+import React from 'react';
+
+export function VideoNativeControls() {
+ return (
+
+ );
+}
+
+```
+
+##### video-custom-controls
+
+Video player with custom control interface
+
+```tsx
+import { Video } from '@/components/ui/video';
+import React from 'react';
+
+export function VideoCustomControls() {
+ return (
+