Skip to content

A biblioteca definitiva para Bottom Sheets, Modals e overlays no React Native. Moderna, elegante e 100% personalizável.

Notifications You must be signed in to change notification settings

arnaldo-tomo/react-native-velvet-ui

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

React Native Velvet UI 🎭✨

npm version License: MIT TypeScript

A biblioteca definitiva para Bottom Sheets, Modals e overlays no React Native. Moderna, elegante e 100% personalizável.

"Velvet UI torna cada interação suave como veludo" 🌟

Construída em 🇲🇿 Moçambique para todo o mundo 🌍.


🎯 Por que Velvet UI?

  • 60+ animações pré-definidas com physics avançadas
  • 🎨 100% personalizável - cores, tamanhos, comportamentos
  • 📱 Gestos nativos com haptic feedback
  • 🚀 Performance otimizada com Reanimated 3
  • 💎 Design moderno seguindo Material 3 e iOS guidelines
  • 🔧 TypeScript completo com intellisense
  • 🌍 Suporte completo para iOS e Android
  • 🎭 Temas dinâmicos com modo escuro automático

📦 Instalação

# npm
npm install react-native-velvet-ui

# yarn
yarn add react-native-velvet-ui

# pnpm
pnpm add react-native-velvet-ui

Dependências

# Peer dependencies necessárias
npm install react-native-reanimated react-native-gesture-handler react-native-haptic-feedback

Configuração iOS

cd ios && pod install

Configuração Android

Adicione ao MainActivity.java:

import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

🚀 Uso Básico

Setup Inicial

import { VelvetProvider } from 'react-native-velvet-ui';

export default function App() {
  return (
    <VelvetProvider>
      <YourApp />
    </VelvetProvider>
  );
}

Bottom Sheet Simples

import { VelvetBottomSheet } from 'react-native-velvet-ui';

function MyComponent() {
  const [visible, setVisible] = useState(false);

  return (
    <>
      <Button title="Abrir Bottom Sheet" onPress={() => setVisible(true)} />
      
      <VelvetBottomSheet
        visible={visible}
        onClose={() => setVisible(false)}
        animation="slideUp"
        haptics="light"
      >
        <Text>Conteúdo do Bottom Sheet</Text>
      </VelvetBottomSheet>
    </>
  );
}

Modal Elegante

import { VelvetModal } from 'react-native-velvet-ui';

<VelvetModal
  visible={visible}
  onClose={() => setVisible(false)}
  animation="zoomBounce"
  blur={15}
  theme="dark"
>
  <Text>Modal content here</Text>
</VelvetModal>

🎨 Componentes Principais

VelvetBottomSheet

<VelvetBottomSheet
  visible={true}
  onClose={() => {}}
  
  // Animações
  animation="slideUp" | "fadeSlide" | "bounceUp" | "elasticSlide"
  duration={300}
  easing="bezier(0.25, 0.46, 0.45, 0.94)"
  
  // Tamanhos
  height="auto" | 400 | "50%" | "80%"
  snapPoints={['25%', '50%', '80%']}
  
  // Comportamento
  dismissible={true}
  closeOnBackdrop={true}
  closeOnSwipe={true}
  
  // Estilo
  theme="light" | "dark" | "auto"
  backgroundColor="#ffffff"
  cornerRadius={20}
  
  // Haptics
  haptics="light" | "medium" | "heavy"
>
  {/* Conteúdo */}
</VelvetBottomSheet>

VelvetModal

<VelvetModal
  visible={true}
  onClose={() => {}}
  
  // Animações
  animation="fade" | "scale" | "slideDown" | "zoomBounce"
  duration={250}
  
  // Backdrop
  blur={10}
  backdropColor="rgba(0,0,0,0.5)"
  
  // Posicionamento
  position="center" | "top" | "bottom"
  margin={20}
  
  // Comportamento
  dismissible={true}
  closeOnBackdrop={true}
>
  {/* Conteúdo */}
</VelvetModal>

VelvetActionSheet

<VelvetActionSheet
  visible={true}
  onClose={() => {}}
  title="Escolha uma opção"
  
  options={[
    {
      title: "Editar",
      icon: "edit",
      onPress: () => {},
      style: "default"
    },
    {
      title: "Excluir",
      icon: "trash",
      onPress: () => {},
      style: "destructive"
    }
  ]}
  
  cancelButton={{
    title: "Cancelar",
    style: "cancel"
  }}
/>

🎭 Animações Disponíveis

Bottom Sheet

  • slideUp - Desliza de baixo para cima
  • fadeSlide - Fade + slide suave
  • bounceUp - Bounce elástico
  • elasticSlide - Slide com elastic easing
  • spring - Spring physics natural

Modal

  • fade - Fade simples
  • scale - Scale do centro
  • zoomBounce - Zoom com bounce
  • flipX / flipY - Flip 3D
  • rotate - Rotação 360°
  • glitch - Efeito glitch

🎨 Sistema de Temas

Tema Personalizado

import { createVelvetTheme, VelvetProvider } from 'react-native-velvet-ui';

const customTheme = createVelvetTheme({
  colors: {
    primary: '#007AFF',
    secondary: '#5856D6',
    success: '#34C759',
    
    light: {
      background: '#FFFFFF',
      surface: '#F2F2F7',
      text: '#000000',
    },
    
    dark: {
      background: '#000000',
      surface: '#1C1C1E',
      text: '#FFFFFF',
    }
  },
  
  spacing: {
    xs: 4,
    sm: 8,
    md: 16,
    lg: 24,
    xl: 32
  }
});

export default function App() {
  return (
    <VelvetProvider theme={customTheme}>
      <YourApp />
    </VelvetProvider>
  );
}

Temas Pré-definidos

import { velvetThemes } from 'react-native-velvet-ui';

// Temas disponíveis
velvetThemes.light
velvetThemes.dark
velvetThemes.mozambique  // Verde, amarelo, vermelho
velvetThemes.material    // Material Design 3
velvetThemes.ios         // iOS style
velvetThemes.nature      // Verde natureza
velvetThemes.ocean       // Azul oceano

🎯 Hooks Úteis

useVelvetBottomSheet

import { useVelvetBottomSheet } from 'react-native-velvet-ui';

function MyComponent() {
  const {
    show,
    hide,
    isVisible,
    height,
    setHeight,
    snapToPoint
  } = useVelvetBottomSheet();

  const showSheet = () => {
    show({
      height: '50%',
      animation: 'bounceUp',
      content: <MySheetContent />
    });
  };

  return (
    <Button title="Show Sheet" onPress={showSheet} />
  );
}

useVelvetModal

import { useVelvetModal } from 'react-native-velvet-ui';

function MyComponent() {
  const { show, hide, isVisible } = useVelvetModal();

  const showModal = () => {
    show({
      animation: 'zoomBounce',
      blur: 15,
      content: <MyModalContent />
    });
  };

  return <Button title="Show Modal" onPress={showModal} />;
}

useVelvetHaptics

import { useVelvetHaptics } from 'react-native-velvet-ui';

function MyComponent() {
  const { play, buttonPress, notification } = useVelvetHaptics();

  return (
    <TouchableOpacity
      onPress={() => {
        buttonPress('primary');
        // Sua lógica aqui
      }}
    >
      <Text>Botão com Haptic</Text>
    </TouchableOpacity>
  );
}

🛠️ Componentes UI

VelvetButton

<VelvetButton
  title="Clique aqui"
  variant="primary" | "secondary" | "outline" | "ghost"
  size="small" | "medium" | "large"
  loading={false}
  disabled={false}
  leftIcon="plus"
  rightIcon="arrow-right"
  haptics="light"
  onPress={() => {}}
/>

VelvetCard

<VelvetCard
  elevation={4}
  borderRadius="md"
  padding="lg"
  
  // Animações
  pressAnimation="scale" | "opacity" | "lift"
  
  // Gradientes
  gradient={['#FF6B6B', '#4ECDC4']}
  gradientDirection="horizontal"
  
  onPress={() => {}}
>
  <Text>Conteúdo do card</Text>
</VelvetCard>

VelvetInput

<VelvetInput
  placeholder="Digite aqui"
  value={value}
  onChangeText={setValue}
  
  variant="outline" | "filled" | "underline"
  leftIcon="search"
  rightIcon="eye"
  
  error={errorMessage}
  success={successMessage}
  
  // Validação
  rules={[
    { required: true, message: "Campo obrigatório" },
    { minLength: 3, message: "Mínimo 3 caracteres" }
  ]}
/>

🎵 Sistema de Haptics

import { VelvetHaptics } from 'react-native-velvet-ui';

// Métodos disponíveis
VelvetHaptics.light();        // Toque leve
VelvetHaptics.medium();       // Toque médio  
VelvetHaptics.heavy();        // Toque forte
VelvetHaptics.success();      // Sucesso
VelvetHaptics.warning();      // Aviso
VelvetHaptics.error();        // Erro
VelvetHaptics.selection();    // Seleção
VelvetHaptics.celebrate();    // Celebração

// Uso nos componentes
<VelvetBottomSheet
  haptics="medium"
  onOpen={() => VelvetHaptics.success()}
/>

⚙️ Configuração Global

import { VelvetConfig } from 'react-native-velvet-ui';

VelvetConfig.setDefaults({
  // Animações
  defaultAnimationDuration: 300,
  defaultEasing: 'bezier(0.25, 0.46, 0.45, 0.94)',
  
  // Haptics
  enableHaptics: true,
  defaultHapticIntensity: 'medium',
  
  // Performance
  enableNativeDriver: true,
  enableReanimated: true,
  
  // Localização
  locale: 'pt-MZ', // pt, pt-MZ, pt-BR, en
});

// Configuração para dispositivos low-end
VelvetConfig.setPerformanceMode('balanced');

// Adicionar strings personalizadas
VelvetConfig.addStrings('pt-MZ', {
  close: 'Fechar',
  cancel: 'Cancelar',
  confirm: 'Confirmar',
  loading: 'Carregando...'
});

📱 Exemplo Completo - App E-commerce

import React, { useState } from 'react';
import { View, Text, ScrollView, Image } from 'react-native';
import {
  VelvetProvider,
  VelvetBottomSheet,
  VelvetModal,
  VelvetActionSheet,
  VelvetButton,
  VelvetCard,
  createVelvetTheme,
  useVelvetHaptics
} from 'react-native-velvet-ui';

// Tema personalizado
const ecommerceTheme = createVelvetTheme({
  colors: {
    primary: '#E91E63',
    secondary: '#9C27B0',
    success: '#4CAF50',
  }
});

function ProductCard({ product, onPress }) {
  const { buttonPress } = useVelvetHaptics();

  return (
    <VelvetCard
      pressAnimation="scale"
      onPress={() => {
        buttonPress('primary');
        onPress(product);
      }}
      style={{ margin: 8 }}
    >
      <Image source={{ uri: product.image }} style={styles.productImage} />
      <Text style={styles.productName}>{product.name}</Text>
      <Text style={styles.productPrice}>{product.price} MT</Text>
    </VelvetCard>
  );
}

function ProductDetailSheet({ product, visible, onClose }) {
  const [showOptions, setShowOptions] = useState(false);

  return (
    <>
      <VelvetBottomSheet
        visible={visible}
        onClose={onClose}
        snapPoints={['40%', '80%']}
        animation="elasticSlide"
        header={
          <View style={styles.sheetHeader}>
            <Text style={styles.sheetTitle}>{product?.name}</Text>
          </View>
        }
        footer={
          <View style={styles.sheetFooter}>
            <VelvetButton
              title="Adicionar ao Carrinho"
              variant="primary"
              onPress={() => {}}
              haptics="success"
            />
            <VelvetButton
              title="Opções"
              variant="outline"
              onPress={() => setShowOptions(true)}
            />
          </View>
        }
      >
        <ScrollView style={styles.sheetContent}>
          <Image source={{ uri: product?.image }} style={styles.detailImage} />
          <Text style={styles.description}>{product?.description}</Text>
          <Text style={styles.price}>{product?.price} MT</Text>
        </ScrollView>
      </VelvetBottomSheet>

      <VelvetActionSheet
        visible={showOptions}
        onClose={() => setShowOptions(false)}
        title="Opções do Produto"
        options={[
          {
            title: "Adicionar aos Favoritos",
            icon: "heart",
            onPress: () => {}
          },
          {
            title: "Compartilhar",
            icon: "share",
            onPress: () => {}
          },
          {
            title: "Ver Similares",
            icon: "grid",
            onPress: () => {}
          }
        ]}
      />
    </>
  );
}

export default function EcommerceApp() {
  const [selectedProduct, setSelectedProduct] = useState(null);
  const [showProductDetail, setShowProductDetail] = useState(false);

  const products = [
    { id: 1, name: "iPhone 15", price: "85.000", image: "...", description: "..." },
    { id: 2, name: "Samsung Galaxy", price: "75.000", image: "...", description: "..." },
  ];

  const handleProductPress = (product) => {
    setSelectedProduct(product);
    setShowProductDetail(true);
  };

  return (
    <VelvetProvider theme={ecommerceTheme}>
      <View style={styles.container}>
        <Text style={styles.title}>Loja Velvet</Text>
        
        <ScrollView>
          {products.map(product => (
            <ProductCard
              key={product.id}
              product={product}
              onPress={handleProductPress}
            />
          ))}
        </ScrollView>

        <ProductDetailSheet
          product={selectedProduct}
          visible={showProductDetail}
          onClose={() => setShowProductDetail(false)}
        />
      </View>
    </VelvetProvider>
  );
}

const styles = {
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    textAlign: 'center',
    marginVertical: 20,
  },
  productImage: {
    width: '100%',
    height: 150,
    borderRadius: 8,
  },
  productName: {
    fontSize: 16,
    fontWeight: '600',
    marginTop: 8,
  },
  productPrice: {
    fontSize: 14,
    color: '#E91E63',
    fontWeight: 'bold',
  },
  sheetHeader: {
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
  },
  sheetTitle: {
    fontSize: 20,
    fontWeight: 'bold',
  },
  sheetContent: {
    padding: 16,
  },
  sheetFooter: {
    padding: 16,
    gap: 8,
  },
  detailImage: {
    width: '100%',
    height: 200,
    borderRadius: 12,
  },
  description: {
    fontSize: 16,
    lineHeight: 24,
    marginVertical: 12,
  },
  price: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#E91E63',
  },
};

🧪 Testes

# Executar testes
npm test

# Testes com cobertura
npm run test-coverage

# Lint
npm run lint

# Formatar código
npm run format

🤝 Contribuição

Adoramos contribuições da comunidade!

Como Contribuir

  1. 🍴 Fork do repositório
  2. 🌿 Crie uma branch (git checkout -b feature/nova-funcionalidade)
  3. 📝 Commit das alterações (git commit -am 'Adiciona nova funcionalidade')
  4. 📤 Push para a branch (git push origin feature/nova-funcionalidade)
  5. 🔄 Abra um Pull Request

📄 Licença

MIT License - veja LICENSE para detalhes.


👨‍💻 Autor

Arnaldo Tomo
Full Stack Developer & UI/UX Enthusiast

🇲🇿 Moçambique | 🌍 Criando experiências móveis excepcionais

GitHub LinkedIn Website


🎭 React Native Velvet UI

Deixe sua UI suave como veludo

⭐ Star no GitHub📖 Documentação Completa🎮 Playground


Made with ❤️ in Mozambique

About

A biblioteca definitiva para Bottom Sheets, Modals e overlays no React Native. Moderna, elegante e 100% personalizável.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published