npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fitcard-ui-react-native

v2.0.4

Published

Componentes React Native do design system Grafit, com suporte a temas por marca, alto contraste e Liquid Glass.

Readme

fitcard-ui-react-native

Biblioteca de componentes React Native do design system Grafit, compartilhada por todos os apps.

  • 7 marcas: fitcard, fitmoby, euro, loop, link, neo, prime.
  • 4 modos: claro, escuro, claro alto contraste e escuro alto contraste.
  • Liquid Glass (iOS 26) injetado pelo app, com fallback opaco em todas as outras plataformas.
  • Zero dependências nativas próprias: tudo que é nativo é peerDependency, então os apps não precisam de resolutions.

Começando agora? Siga o Getting Started. Vindo da v1? Veja o guia de migração. Publicando uma versão? Siga o PUBLISHING.md · histórico no CHANGELOG.

Sumário

Instalação

yarn add fitcard-ui-react-native
yarn add styled-components phosphor-react-native react-native-svg \
  react-native-safe-area-context react-native-reanimated react-native-worklets \
  react-native-gesture-handler @react-native-community/datetimepicker

| Peer | Versão mínima | |---|---| | react | 19.0 | | react-native | 0.78 (testado na 0.87.1) | | styled-components | 6 | | phosphor-react-native | 3 | | react-native-svg | 15 | | react-native-safe-area-context | 4.10 | | react-native-reanimated | 4.1 | | react-native-worklets | 0.5 | | react-native-gesture-handler | 2.20 (com o GestureHandlerRootView na raiz do app) | | @react-native-community/datetimepicker | 7 |

Fontes Inter: adicione ./node_modules/fitcard-ui-react-native/assets/fonts aos assets do react-native.config.js do app e rode npx react-native-asset. O passo a passo completo está no Getting Started.

<SafeAreaProvider>
  <GrafitProvider brand="link" colorScheme="system" glass={glass}>
    <ToastProvider>
      <App />
    </ToastProvider>
  </GrafitProvider>
</SafeAreaProvider>

Tema

GrafitProvider

Configura o tema e o ThemeProvider do styled-components (os styled do app recebem o mesmo tema).

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | brand | GrafitBrand | 'fitcard' | Marca (tema) do Grafit. Padrão: fitcard. | | colorScheme | GrafitColorScheme \| 'system' | 'system' | Esquema de cor. system acompanha o aparelho. Padrão: system. | | highContrast | boolean | false | Ativa os modos de alto contraste (lightHC/darkHC). | | overrides | GrafitThemeOverrides | | Sobrescritas pontuais de tokens (cores, strokes e extensões da lib). | | theme | GrafitTheme | | Tema já montado (ex.: createGrafitTheme). Quando informado, ignora brand, colorScheme e highContrast. | | glass | LiquidGlassAdapter \| null | | Liquid Glass do app. Ex.: { View: LiquidGlassView, isSupported: isLiquidGlassSupported }. | | children * | ReactNode | | |

Memoize overrides e glass; objetos novos a cada render recriam o tema.

Ícones e tamanho do bundle

Importe ícones do Phosphor pelo caminho do ícone, não pelo índice do pacote:

import { BellIcon } from 'phosphor-react-native/src/icons/Bell';   // ✅ só este ícone
import { BellIcon } from 'phosphor-react-native';                  // ❌ inclui os ~1.500 ícones

O Metro não remove código não usado. Um único import pelo índice coloca o Phosphor inteiro no bundle: medimos 5,3 MB, 72% do bundle de produção do app de exemplo. A lib já importa ícone por ícone e, sem o índice, o Phosphor cai para 50 KB.

Por isso o GrafitProvider não configura o IconContext do Phosphor; ele só existe no índice do pacote. Os componentes da lib já aplicam weight="bold" e as cores do tema. Para ícones do app, prefira o Icon da lib (<Icon icon={BellIcon} color="primary" />).

Lendo o tema

const theme = useGrafitTheme();

theme.color.primary;            // cor da marca no modo atual
theme.color.onPrimary_soft;     // conteúdo sobre primary_soft
theme.spacing.x200;             // 16
theme.radius.full;              // 999
theme.font.label_md;            // { fontFamily, fontSize, lineHeight }
theme.stroke.input;             // { width, style, color }
theme.transition.natural_fast;  // { duration, delay, timingFunction }
theme.scheme;                   // 'light' | 'dark'
theme.mode;                     // 'light' | 'dark' | 'lightHC' | 'darkHC'

useTheme() é um alias de useGrafitTheme(). O tema também expõe colors e fonts no formato da v1 (derivados do Grafit, @deprecated) para apps em migração.

Helpers para styled-components

| Helper | Gera | |---|---| | typography(theme.font.label_md) | font-family, font-size e line-height do papel | | inputTypography(theme.font.paragraph_md) | Igual, sem line-height (TextInput de uma linha) | | strokeBorder(theme.stroke.input) | border-width, border-style e border-color | | toEasing(theme.easing.natural) | Easing.bezier do Reanimated | | toTimingConfig(theme.transition.enter) | { duration, easing } para withTiming | | typographyStyle(theme.font.label_md) | Objeto de estilo (fora do styled) |

export const Title = styled.Text`
  ${({ theme }) => typography(theme.font.header_sm)}
  color: ${({ theme }) => theme.color.foreground_high};
`;

Overrides

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | color | Partial<GrafitThemedTokens['color']> | | | | stroke | { [Key in GrafitStrokeToken]?: Partial<GrafitStroke> } | | | | fontFamily | Partial<Record<GrafitFontWeightName, string>> | | Troca a família de fonte por peso (ex.: app que ainda não embarcou a Inter). | | extension | Partial<GrafitLibraryExtension> | | |

createGrafitTheme({ brand, scheme, highContrast, overrides }) monta o mesmo tema fora do React (testes, Storybook, theme do provider).

Aparências: tone, variant e size

Todos os componentes interativos e de feedback falam a mesma língua:

| Prop | Valores | Uso | |---|---|---| | tone | primary, secondary, success, warning, danger, neutral | Cor/intenção | | variant | solid, soft, strong, outline, ghost | Peso visual | | size | sm, md, lg | Altura (40/48/56), padding, papel tipográfico e tamanho do ícone |

| variant | Fundo | Conteúdo | |---|---|---| | solid | color.{tone} | color.on{Tone} | | soft | color.{tone}_soft | color.on{Tone}_soft | | strong | color.{tone}_strong | color.on{Tone}_strong | | outline | sem fundo + stroke.button | color.on{Tone}_soft | | ghost | sem fundo | color.on{Tone}_soft |

  • neutral usa as superfícies: surface_medium (solid), surface_low (soft), surface_high (strong), com conteúdo foreground_high.
  • Desabilitado é sempre surface_medium com foreground_low.
  • O resolvedor é exportado (resolveToneTokens(tone, variant)), para componentes do app seguirem a mesma tabela.

Liquid Glass

A lib não importa nenhum módulo nativo de vidro. O app entrega a view:

import { LiquidGlassView, isLiquidGlassSupported } from '@callstack/liquid-glass';

const glass = useMemo(
  () => ({ View: LiquidGlassView, isSupported: isLiquidGlassSupported, enabled: true, intensity: 'regular' }),
  [],
);

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | View * | ComponentType<LiquidGlassViewLikeProps> | | | | isSupported * | boolean | | | | enabled | boolean | | Liga/desliga o vidro no app inteiro (ex.: preferência do usuário). Padrão: true. | | intensity | GlassIntensity | | Intensidade do vidro: material + opacidade da tinta surface_high. Padrão: regular. |

Quais componentes viram vidro

O vidro só fica bom quando há conteúdo passando por trás. Vidro sobre fundo liso ou vidro sobre vidro fica estranho. Por isso, só superfícies flutuantes são elegíveis:

| Componente | Vidro | Comportamento | |---|---|---| | NavBar, CustomNavBar | ✅ automático | Flutua sobre o conteúdo (type="secondary" vira cápsula) | | AnimatedHeader (AnimatedScrollablePage, PagedList) | ✅ automático | Cabeçalho que aparece ao rolar | | PageFooter | ✅ automático | Cápsula com a ação principal acima da safe area | | FloatingTabBar | ✅ automático | Barra e indicador de vidro | | BottomSheet, Sheet | ✅ automático | Folha sobre a tela | | Toast | ✅ automático | Pílula flutuante | | IconButton, Stencil | ☑️ opt-in (glass) | Para uso sobre mapa, foto ou lista | | PhotoSlot | interno | Legenda e botão de remover sobre a foto | | Botões de texto, campos, cards, listas, menus, tags, avisos, estados, containers | ❌ | Ficam no fluxo do conteúdo, sobre fundo liso |

  • Todos os componentes funcionam com o vidro ligado no app; só os elegíveis mudam de aparência.
  • glass={false} desliga o vidro só naquele componente.
  • Leitura: readable deixa o vidro quase opaco (material regular com fundo sólido surface_high, ignorando a intensity do provider) para textos que precisam ser lidos sobre qualquer fundo. Já vem ligado no Toast, no Sheet e no BottomSheet (passe readable={false} para o vidro normal); nos demais é opt-in. Sem vidro nativo não muda nada, porque o fallback já é opaco.
  • Sem suporte (Android ou iOS anterior ao 26): o componente vira uma superfície opaca surface_low com borda stroke_medium, mantendo o layout flutuante. A tela é a mesma em todas as plataformas.
  • Recuo do conteúdo: barras flutuantes informam a altura por onHeightChange; repasse para contentInsetTop/contentInsetBottom do ScrollablePage.

Glass e useGlass

Para superfícies de vidro próprias do app:

const { isGlass, isNativeGlass } = useGlass(); // padrão do provider, ou useGlass(false)

<Glass interactive fallbackColor="background" style={styles.bubble}>
  <Text>Sobre o mapa</Text>
</Glass>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | fallbackColor | Extract<GrafitColorToken, 'background' \| 'surface_low' \| 'surface_medium' \| 'surface_high'> | 'surface_low' | Cor opaca usada quando o Liquid Glass não está disponível. | | interactive | boolean | false | Vidro reage ao toque (efeito interativo do iOS 26). | | readable | boolean | false | Vidro quase opaco para texto que precisa ser lido sobre qualquer fundo (ex.: toast, sheet). Ignora a intensidade do GrafitProvider. | | style | StyleProp<ViewStyle> | | | | children | ReactNode | | |

Também aceita as props de ViewProps.

Componentes

Convenções de todas as props:

  • Ícones são componentes do Phosphor: icon={BellIcon}. O peso é sempre bold.
  • Cores são nomes de token: color="foreground_low", iconColor="primary". Nunca hex.
  • Props marcadas como Obsoleto existem para compatibilidade com a v1.
  • * na tabela = obrigatória.

Navegação

NavBar

Barra de topo com título, voltar e ações. Com vidro, flutua sobre o conteúdo.

<NavBar
  title="Pedido #1234"
  subtitle={<StatusPill tone="success">Pago</StatusPill>}
  onBack={navigation.goBack}
  rightComponent={<NavBar.Action icon={ShareIcon} onPress={share} accessibilityLabel="Compartilhar" />}
  onHeightChange={setHeaderHeight}
>
  <ProgressBar progress={60} showValue={false} size="sm" />
</NavBar>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | title | string | | | | subtitle | ReactNode | | | | onBack | () => void | | Atalho para um NavBar.BackAction à esquerda. | | leftComponent | ReactNode | | | | rightComponent | ReactNode | | | | children | ReactNode | | Conteúdo abaixo da linha do título (ex.: ProgressBar, busca). | | glass | boolean | | Liquid Glass. A barra passa a flutuar sobre o conteúdo; use onHeightChange para recuar a tela. Padrão: segue o GrafitProvider. | | readable | boolean | | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: false. | | type | 'primary' \| 'secondary' | 'primary' | primary (ponta a ponta) ou secondary (cápsula flutuante). | | flat | boolean | true | Remove a divisória inferior da barra opaca. Padrão: true. | | safeArea | boolean | true | | | onHeightChange | (height: number) => void | | | | textStyle | StyleProp<TextStyle> | | | | containerStyle | StyleProp<ViewStyle> | | |

NavBar.Action (= NavBarAction) e NavBar.BackAction (= NavBarBackAction):

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | icon * | IconComponent | | | | onPress | () => void | | | | color | GrafitColorToken | 'foreground_high' | | | size | number | | | | accessibilityLabel | string | | | | disabled | boolean | false | | | testID | string | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | onPress | () => void | | | | color | GrafitColorToken | 'foreground_high' | | | size | number | | | | accessibilityLabel | string | 'Voltar' | | | testID | string | | |

CustomNavBar

Barra com três slots livres, para busca, logo ou seletor no centro.

<CustomNavBar
  leftComponent={<NavBar.BackAction onPress={goBack} />}
  middleComponent={<TextInput size="sm" placeholder="Buscar" leftIcon={MagnifyingGlassIcon} />}
/>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | leftComponent | ReactNode | | | | middleComponent | ReactNode | | | | rightComponent | ReactNode | | | | children | ReactNode | | | | glass | boolean | | | | readable | boolean | | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: false. | | type | 'primary' \| 'secondary' | 'primary' | | | flat | boolean | false | | | safeArea | boolean | true | | | onHeightChange | (height: number) => void | | | | containerStyle | StyleProp<ViewStyle> | | |

AnimatedHeader

Cabeçalho que recebe uma opacidade animada (o AnimatedScrollablePage e o PagedList já o controlam).

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | opacity | Animated.AnimatedInterpolation<number> \| Animated.Value | | | | title | string | | | | glass | boolean | | | | readable | boolean | false | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: false. | | safeArea | boolean | true | Recua o título para fora da status bar e da Dynamic Island quando o cabeçalho encosta no topo da tela. Mede a posição na janela, então não soma o recuo se o pai já aplica a safe area. Padrão: true. | | style | StyleProp<ViewStyle> | | |

PageFooter

Rodapé fixo com a ação principal. Com vidro, vira uma cápsula flutuante acima da safe area.

<PageFooter onHeightChange={setFooterHeight}>
  <Button text="Confirmar pagamento" onPress={pay} />
  <Button text="Cancelar" variant="ghost" onPress={cancel} />
</PageFooter>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | glass | boolean | | Liquid Glass: cápsula flutuante acima da safe area, sobre o conteúdo que rola. Padrão: segue o GrafitProvider. | | readable | boolean | false | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: false. | | safeArea | boolean | true | | | onHeightChange | (height: number) => void | | | | style | StyleProp<ViewStyle> | | | | children * | ReactNode | | |

FloatingTabBar

Tab bar em cápsula flutuante, compatível com o tabBar do @react-navigation/bottom-tabs. Ao tocar em qualquer ponto da barra, o indicador vai até o dedo, acompanha o arraste (a aba sob ele já fica destacada) e encaixa na aba mais próxima ao soltar, como no Oficinas e no Credenciado. O gesto roda na thread de UI com o react-native-gesture-handler (peer), então o app precisa do GestureHandlerRootView na raiz. O leitor de tela seleciona as abas pela ação activate. tabBarBadge aparece como badge.

<Tab.Navigator tabBar={props => <FloatingTabBar {...props} />} screenOptions={{ headerShown: false }}>
  <Tab.Screen name="Home" component={Home} options={{ title: 'Início', tabBarIcon: ({ color, size }) => <HouseIcon color={color} size={size} /> }} />
</Tab.Navigator>

// no fim de cada tela das abas
<FloatingTabBarSafeArea />

// ou em listas
const { contentBottomInset } = useFloatingTabBarInsets();

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | state * | { index: number; routes: TabRoute[] } | | | | descriptors * | Record<string, { options: TabOptions }> | | | | navigation * | TabNavigation | | | | glass | boolean | | Liquid Glass. Padrão: segue o GrafitProvider. | | readable | boolean | false | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: false. |

StatusBar

Status bar que acompanha o modo do tema (light-content no escuro, dark-content no claro). Aceita as props do StatusBar do React Native.

<StatusBar />

Containers e layout

PageWrapper

Container raiz de toda tela (flex: 1, fundo background).

<PageWrapper safeArea edges={['top']}>{/* … */}</PageWrapper>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | safeArea | boolean | false | Respeita a safe area (todas as bordas ou as informadas em edges). | | edges | Edge[] | | | | background | Extract<GrafitColorToken, 'background' \| 'canvas' \| 'surface_low'> | 'background' | Fundo da página. Padrão: background. | | children | ReactNode | | |

Também aceita as props de ViewProps.

ScrollablePage

ScrollView da página, com padding lateral x300, gap x200 entre os filhos e recuos para barras flutuantes. Aceita ref e as props de ScrollView.

<ScrollablePage contentInsetTop={headerHeight} refreshControl={<RefreshControl refreshing={loading} onRefresh={reload} />}>
  <Card title="Saldo" />
  <Card title="Extrato" />
</ScrollablePage>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | children | ReactNode | | |

Também aceita as props de ScrollViewProps, PageInsets.

AnimatedScrollablePage

ScrollablePage com um AnimatedHeader que aparece ao rolar.

<AnimatedScrollablePage title="Configurações">{/* … */}</AnimatedScrollablePage>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | title | string | | Título do cabeçalho que aparece ao rolar. | | glass | boolean | | | | readable | boolean | | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: false. | | containerStyle | StyleProp<ViewStyle> | | | | children | ReactNode | | |

Também aceita as props de ScrollViewProps, PageInsets.

PagedList

FlatList com paginação infinita: chama onEndReached uma vez por página, enquanto page < totalPages.

<PagedList
  data={orders}
  page={page}
  totalPages={totalPages}
  onEndReached={() => fetchPage(page + 1)}
  keyExtractor={order => order.id}
  renderItem={({ item }) => <ListItem title={item.title} description={item.date} onPress={() => open(item)} />}
  ListEmptyComponent={<EmptyState icon={ReceiptIcon} title="Nenhum pedido" />}
/>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | data * | Item[] | | | | page * | number | | Página atual (começando em 1). | | totalPages * | number | | | | onEndReached | () => void | | Chamado ao chegar no fim da lista enquanto houver páginas. | | useHeader | boolean | false | Mostra um AnimatedHeader que aparece ao rolar. | | title | string | | | | glass | boolean | | | | readable | boolean | | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: false. |

Também aceita as props de Omit<FlatListProps<Item>, 'data'>.

SectionCardHeader, SectionCardItem, SectionCardBox

Seções agrupadas em cards, no estilo de ajustes do iOS. Itens consecutivos formam um único card com divisórias.

<SectionCardHeader title="Veículo" right={<TextButton onPress={edit}>Editar</TextButton>} />
<SectionCardItem first>
  <ListItem title="Placa" rightComponent={<Stencil>abc1d23</Stencil>} divider={false} />
</SectionCardItem>
<SectionCardItem last>
  <ListItem title="Modelo" description="Onix 1.0" divider={false} />
</SectionCardItem>

<SectionCardBox>
  <Paragraph>Conteúdo livre dentro de um card de seção.</Paragraph>
</SectionCardBox>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | title * | string | | | | right | ReactNode | | | | style | StyleProp<ViewStyle> | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | first | boolean | false | Primeiro item do grupo: arredonda o topo e remove a divisória. | | last | boolean | false | Último item do grupo: arredonda a base. | | inset | boolean | true | Recuo lateral de spacing.x200. Padrão: true. | | style | StyleProp<ViewStyle> | | | | children | ReactNode | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | inset | boolean | true | | | style | StyleProp<ViewStyle> | | | | children | ReactNode | | |

Spacer

<Spacer size="x300" />            // token
<Spacer height={headerHeight} />  // altura medida em runtime

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | size | GrafitSpacingToken | | Token de spacing para a altura. | | height | number | | Altura em pontos (ex.: altura medida de um NavBar de vidro). | | width | number | 0 | |

Divider e SectionBand

<Divider gap="x200" />
<Divider vertical />
<SectionBand />   // faixa `canvas` de ponta a ponta entre blocos

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | gap | GrafitSpacingToken | | Espaço antes e depois da linha (token de spacing). | | vertical | boolean | false | | | style | StyleProp<ViewStyle> | | |

Sheet

Folha inferior com altura pelo conteúdo, alça, título e descrição. Sobe com o teclado, fecha pelo fundo e pelo botão voltar do Android, e é animada com transition.enter/exit.

<Sheet visible={visible} onClose={close} title="Filtrar" description="Escolha o período">
  <SegmentedControl options={PERIODS} selected={period} onChange={setPeriod} />
  <Button text="Aplicar" onPress={apply} />
</Sheet>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | visible * | boolean | | | | onClose * | () => void | | | | title | string | | | | description | string | | | | dismissible | boolean | true | Permite fechar pelo fundo e pelo botão voltar. Padrão: true. | | glass | boolean | | Liquid Glass no painel. Padrão: segue o GrafitProvider. | | readable | boolean | true | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: true. | | closeAccessibilityLabel | string | 'Fechar' | | | children | ReactNode | | |

BottomSheet e BottomSheetContainer

Folha de altura fixa embutida na tela, sem Modal, para conteúdo persistente sobre um mapa, por exemplo. Para diálogos, prefira Sheet.

<BottomSheet visible={visible} height={320} onBackdropPress={close}>
  <BottomSheetContainer>{/* … */}</BottomSheetContainer>
</BottomSheet>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | visible * | boolean | | | | height * | number | | Altura do conteúdo (a safe area inferior é somada). | | showBackdrop | boolean | true | | | onBackdropPress | () => void | | | | glass | boolean | | Liquid Glass na folha. Padrão: segue o GrafitProvider. | | readable | boolean | true | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: true. | | style | StyleProp<ViewStyle> | | | | backdropStyle | StyleProp<ViewStyle> | | | | backdropAccessibilityLabel | string | 'Fechar' | | | children | ReactNode | | |

RefreshControl

RefreshControl com as cores do tema; aceita as props do RefreshControl do React Native.

<ScrollablePage refreshControl={<RefreshControl refreshing={loading} onRefresh={reload} />} />

Texto, ícones e identificadores

Text e presets

variant é o papel tipográfico do Grafit e color é o token. O peso vem do papel; nunca use fontWeight.

<Text variant="display_md" color="primary">R$ 1.250,00</Text>
<H1>Título de página</H1>          // header_lg
<H2>Seção principal</H2>           // header_md
<H3>Subseção</H3>                  // header_sm
<Paragraph>Texto corrido.</Paragraph>       // paragraph_md, foreground_medium
<Description>Texto auxiliar.</Description>  // paragraph_sm, foreground_low
<Medium>Rótulo curto</Medium>               // label_sm, foreground_medium
<Caption>Legenda</Caption>                  // caption_lg, foreground_low

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | variant | GrafitFontToken | 'paragraph_md' | Papel tipográfico do Grafit. Padrão: paragraph_md. | | color | GrafitColorToken | 'foreground_high' | Token de cor do texto. Padrão: foreground_high. | | align | 'auto' \| 'left' \| 'right' \| 'center' \| 'justify' | 'auto' | | | children | ReactNode | | |

Também aceita as props de NativeTextProps.

Icon

<Icon icon={BellIcon} size={24} color="danger" />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | icon * | IconComponent | | Ícone do Phosphor, ex.: import { BellIcon } from 'phosphor-react-native'. | | size | number | | Tamanho em pontos. Padrão: spacing.x250 (20). | | color | GrafitColorToken | 'foreground_high' | Token de cor. Padrão: foreground_high. |

Também aceita as props de Omit<PhosphorIconProps, 'color' | 'weight' | 'size'>.

IconTile

Ícone sobre um quadrado tonal.

<IconTile icon={GasPumpIcon} tone="warning" />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | icon * | IconComponent | | | | tone | GrafitTone | 'primary' | Cor. Padrão: primary. | | variant | Extract<GrafitVariant, 'solid' \| 'soft' \| 'strong'> | 'soft' | Aparência. Padrão: soft. | | size | number | | Lado do quadrado. Padrão: spacing.x500 (40). | | iconSize | number | | | | style | StyleProp<ViewStyle> | | |

Avatar

Foto ou iniciais (primeira e última palavra do nome).

<Avatar name="Maria da Silva" />
<Avatar source={{ uri: user.photo }} size={64} ring />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | name | string | '' | Nome usado para as iniciais (primeira e última palavra). | | source | ImageSourcePropType | | | | size | number | | Diâmetro. Padrão: spacing.x600 (48). | | tone | AvatarTone | 'accent' | | | ring | boolean | false | Contorno fino na cor do conteúdo. | | style | StyleProp<ViewStyle> | | |

Stencil

Identificador em "carimbo": placa, número de OS, código.

<Stencil>abc1d23</Stencil>                         // ABC1D23
<Stencil variant="os" tone="accent">4821</Stencil>  // #4821
<Stencil glass size="lg">abc1d23</Stencil>          // sobre uma foto

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | children * | string \| number | | | | variant | StencilVariant | 'plate' | plate (placa, em maiúsculas) ou os (número com #). | | tone | StencilTone | 'default' | inverse é para uso sobre fundo primary. | | size | GrafitSize | 'md' | | | glass | boolean | false | Vidro sobre foto ou mapa. Opt-in, padrão false. | | readable | boolean | false | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: false. | | style | StyleProp<ViewStyle> | | |


Botões e seleção

Button

<Button text="Salvar" onPress={save} />
<Button text="Cancelar" variant="outline" tone="neutral" onPress={cancel} />
<Button text="Excluir" tone="danger" variant="soft" leftIcon={TrashIcon} onPress={remove} />
<Button text="Enviando" loading onPress={send} />
<Button text="Filtro" size="sm" shape="pill" fullWidth={false} onPress={openFilter} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | text * | string | | Texto do botão. | | onPress * | () => void | | | | variant | GrafitVariant | | Aparência: solid (padrão), soft, strong, outline ou ghost. | | tone | GrafitTone | 'primary' | Cor: primary (padrão), secondary, success, warning, danger ou neutral. | | size | GrafitSize | 'md' | | | shape | ButtonShape | 'rounded' | | | fullWidth | boolean | true | Ocupa toda a largura disponível. Padrão: true. | | leftIcon | IconComponent | | | | rightIcon | IconComponent | | | | loading | boolean | false | | | disabled | boolean | false | | | light | boolean | false | Obsoleto. Use variant="soft". | | containerStyle | StyleProp<ViewStyle> | | | | textStyle | StyleProp<TextStyle> | | | | accessibilityLabel | string | | | | testID | string | | |

IconButton

<IconButton icon={PlusIcon} onPress={add} accessibilityLabel="Adicionar" />
<IconButton icon={CrosshairIcon} glass onPress={centerMap} accessibilityLabel="Centralizar" />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | icon * | IconComponent | | | | onPress * | () => void | | | | variant | GrafitVariant | | Aparência. Padrão: soft. | | tone | GrafitTone | 'primary' | | | size | GrafitSize | 'md' | | | disabled | boolean | false | | | glass | boolean | | Botão flutuante de vidro, para uso sobre listas, mapas ou fotos. Opt-in, padrão false: botões dentro do conteúdo não viram vidro. | | readable | boolean | false | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: false. | | noBackground | boolean | false | Obsoleto. Use variant="ghost". | | accessibilityLabel | string | | | | style | StyleProp<ViewStyle> | | | | testID | string | | |

TextButton

<TextButton onPress={forgot}>Esqueci minha senha</TextButton>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | onPress | () => void | | | | tone | GrafitTone | 'primary' | | | color | GrafitColorToken | | Token de cor que substitui o tone (ex.: o on* do fundo). | | size | GrafitSize | 'md' | | | disabled | boolean | false | | | bold | boolean | | Obsoleto. O peso agora vem do papel tipográfico label. | | style | StyleProp<TextStyle> | | | | accessibilityLabel | string | | | | testID | string | | | | children | ReactNode | | |

TagButton e OptionList

Pílula selecionável e uma lista horizontal rolável delas.

<OptionList
  options={[{ text: 'Todos', value: 'all' }, { text: 'Pagos', value: 'paid' }, { text: 'Pendentes', value: 'pending' }]}
  selected={selectedIndex}
  onChange={setSelectedIndex}
/>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | text * | string | | | | onPress * | () => void | | | | active | boolean | false | Selecionado: usa activeVariant no tone. | | tone | GrafitTone | 'primary' | | | activeVariant | GrafitVariant | 'solid' | Aparência quando ativo. Padrão: solid. | | inactiveVariant | GrafitVariant | 'soft' | Aparência quando inativo. Padrão: soft em neutral. | | icon | IconComponent | | | | disabled | boolean | false | | | containerStyle | StyleProp<ViewStyle> | | | | textStyle | StyleProp<TextStyle> | | | | testID | string | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | options * | Option[] | | | | onChange * | (itemIndex: number) => void | | Chamado com o índice da opção escolhida. | | selected | number | | Índice da opção selecionada. | | keyExtractor | (option: Option) => string \| number | defaultKeyExtractor | | | tone | GrafitTone | 'primary' | | | optionContainerStyle | StyleProp<ViewStyle> | | | | optionTextStyle | StyleProp<TextStyle> | | |

Também aceita as props de Omit<ScrollViewProps, 'horizontal'>.

SegmentedControl

De 2 a 4 opções mutuamente exclusivas, com indicador deslizante animado. Para muitas opções, use OptionList.

<SegmentedControl
  options={[{ label: 'Dia', value: 'day' }, { label: 'Semana', value: 'week' }, { label: 'Mês', value: 'month' }]}
  selected={period}
  onChange={setPeriod}
/>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | options * | SegmentedControlOption<Value>[] | | | | selected * | Value | | | | onChange * | (value: Value) => void | | | | style | StyleProp<ViewStyle> | | |

ChoiceChip e ColorDot

Opção em pílula com check. ColorDot mostra uma cor cadastrada pelo cliente. É dado, não tema: nunca use essa cor como fundo de texto.

{colors.map(option => (
  <ChoiceChip key={option.id} label={option.name} color={option.hex} selected={option.id === value} onPress={() => setValue(option.id)} />
))}

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | label * | string | | | | selected * | boolean | | | | onPress * | () => void | | | | color | string | | Mostra um ColorDot com a cor informada. | | role | 'radio' \| 'checkbox' | 'radio' | radio (escolha única, padrão) ou checkbox (múltipla). | | disabled | boolean | false | | | style | StyleProp<ViewStyle> | | |

SelectableCard

Card marcável (checkbox), com ícone opcional. Em grades de 2 colunas, passe style={{ width: '48%' }}.

<SelectableCard title="Combustível" icon={GasPumpIcon} selected={selected.fuel} onPress={() => toggle('fuel')} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | title * | string | | | | onPress * | () => void | | | | selected | boolean | false | | | icon | IconComponent | | | | disabled | boolean | false | | | style | StyleProp<ViewStyle> | | Defina a largura aqui (ex.: { width: '48%' } numa grade de 2 colunas). |

Switch

Switch nativo com as cores do Grafit; aceita as props do Switch do React Native.

<ListItem title="Notificações" rightComponent={<Switch value={enabled} onValueChange={setEnabled} />} />

Formulários

Todos os campos compartilham a mesma caixa: fundo surface_low, borda stroke.input, anel de foco stroke.input_focus externo (sem deslocar o layout), borda danger no erro e estado desabilitado visual (surface_medium + foreground_low). error aceita boolean ou a mensagem.

Field e PasswordField

Atalho para label + campo + erro + ajuda. É o jeito recomendado de montar formulários.

<Field label="E-mail" required keyboardType="email-address" value={email} onChangeText={setEmail} error={errors.email} hint="Usaremos para enviar o comprovante" />
<Field label="Valor" icon={CurrencyDollarIcon} right={<Text variant="label_sm" color="foreground_low">R$</Text>} />
<PasswordField label="Senha" value={password} onChangeText={setPassword} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | label | string | | | | required | boolean | false | | | error | string | | Mensagem de erro abaixo do campo. | | hint | string | | Texto de ajuda abaixo do campo quando não há erro. | | icon | TextInputProps['leftIcon'] | | Ícone à esquerda. | | right | TextInputProps['rightAccessory'] | | Conteúdo à direita (mesmo que rightAccessory). | | style | StyleProp<ViewStyle> | | Estilo do grupo (label + campo + mensagens). |

Também aceita as props de Omit<TextInputProps, 'error' | 'leftIcon'>.

FormGroup

Label, erro e ajuda em volta de qualquer campo. Repassa error e accessibilityLabel ao filho.

<FormGroup label="Cidade" required error={errors.city}>
  <SearchablePicker items={cities} selected={city} onChange={setCity} modalTitle="Cidade" />
</FormGroup>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | label | string | | | | error | string | | Mensagem de erro. Também é repassada como error para o campo filho. | | helperText | string | | Texto de ajuda exibido abaixo do campo quando não há erro. | | required | boolean | false | | | style | StyleProp<ViewStyle> | | | | children * | ReactNode | | |

TextInput e TextArea

<TextInput placeholder="Buscar" leftIcon={MagnifyingGlassIcon} showClearButton value={query} onChangeText={setQuery} />
<TextInput placeholder="Senha" secureTextEntry />
<TextArea placeholder="Observações" value={notes} onChangeText={setNotes} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | disabled | boolean | false | | | error | boolean \| string | false | Estado de erro. Aceita a mensagem do FormGroup. | | size | FieldSize | 'md' | sm ou md (padrão). small/normal continuam aceitos. | | showClearButton | boolean | false | | | onClear | () => void | | | | leftIcon | IconComponent | | | | rightAccessory | ReactNode | | Conteúdo à direita do campo (ex.: botão, unidade, ícone de ação). | | containerStyle | StyleProp<ViewStyle> | | | | clearAccessibilityLabel | string | 'Limpar campo' | | | toggleSecretAccessibilityLabel | string | 'Mostrar ou ocultar senha' | |

Também aceita as props de Omit<NativeTextInputProps, 'editable'>.

TextArea aceita as mesmas props, exceto multiline, secureTextEntry e showClearButton.

MaskedTextInput

Campo com máscara (react-native-mask-input).

import { Masks } from 'react-native-mask-input';

<MaskedTextInput mask={Masks.BRL_CPF} value={cpf} onChangeText={(masked, raw) => setCpf(raw)} keyboardType="number-pad" />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | mask | Mask | | | | value | string | | | | defaultValue | string | '' | | | onChangeText | (formatted: string, extracted?: string) => void | | | | disabled | boolean | false | | | error | boolean \| string | false | | | size | FieldSize | 'md' | | | containerStyle | StyleProp<ViewStyle> | | |

Também aceita as props de Omit<NativeTextInputProps, 'editable' | 'onChangeText' | 'value' | 'defaultValue'>.

InputCurrency

<InputCurrency value={amount} onChangeValue={setAmount} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | value | number \| null | 0 | | | onChangeValue * | (value: number) => void | | | | onChangeText | (text: string) => void | | | | precision | number | 2 | | | prefix | string | 'R$ ' | | | delimiter | string | '.' | | | separator | string | ',' | | | maxValue | number | DEFAULT_MAX_VALUE | | | minValue | number | 0 | | | disabled | boolean | false | | | error | boolean \| string | false | | | size | FieldSize | 'md' | | | style | StyleProp<ViewStyle> | | Obsoleto. Use containerStyle. | | containerStyle | StyleProp<ViewStyle> | | |

Também aceita as props de Omit<TextInputProps, 'value' | 'editable' | 'onChangeText' | 'defaultValue'>.

Picker

Seleção única numa folha de opções, com busca opcional.

<Picker
  items={banks}
  selectedValue={bankCode}
  onValueChange={setBankCode}
  keyExtractor={bank => bank.code}
  labelExtractor={bank => bank.name}
  valueExtractor={bank => bank.code}
  placeholder="Banco"
  searchable
/>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | items * | Item[] | | | | selectedValue | string | | | | onValueChange * | (itemValue: string) => void | | | | keyExtractor * | (item: Item) => string | | | | labelExtractor * | (item: Item) => string | | | | valueExtractor * | (item: Item) => string | | | | placeholder | string | 'Selecione uma opção' | | | title | string | | Título da folha de opções. Padrão: o placeholder. | | searchable | boolean | false | | | disabled | boolean | false | | | loading | boolean | false | | | error | boolean \| string | false | | | size | FieldSize | 'md' | | | style | StyleProp<ViewStyle> | | | | testID | string | | |

SearchablePicker

Seleção única com busca (sem acento e sem diferença de maiúsculas). Os itens têm o formato { text, value }, configurável por textKey/valueKey.

<SearchablePicker items={cities} selected={cityId} onChange={setCityId} modalTitle="Escolha a cidade" placeholder="Cidade" />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | items * | SearchablePickerItem[] | | | | selected | string \| number \| null | | Valor (propriedade valueKey) do item selecionado. | | onChange * | (selected: string \| number) => void | | | | modalTitle * | string | | | | keyExtractor | (item: SearchablePickerItem, index: number) => string | | | | placeholder | string | 'Selecione uma opção' | | | valueKey | string | 'value' | | | textKey | string | 'text' | | | searchPlaceholder | string | 'Buscar' | | | listTitle | string | | | | renderBottomContent | ReactNode | | | | loading | boolean | false | | | disabled | boolean | false | | | error | boolean \| string | false | | | size | FieldSize | 'md' | | | type | 'primary' \| 'secondary' | 'primary' | primary (campo padrão) ou secondary (campo pill maior). | | backgroundColor | string | | Obsoleto. O fundo vem do tema (surface_low). | | style | StyleProp<ViewStyle> | | | | testID | string | | |

MultiSelect

Seleção múltipla com busca e limite (ao atingir o máximo, substitui a seleção mais antiga).

<MultiSelect items={services} selectedItems={selected} onClose={setSelected} modalTitle="Serviços" maxSelectableItems={3} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | items * | MultiSelectItem[] | | | | onClose * | (selected: MultiSelectSelection) => void | | Chamado ao fechar a folha, com os itens selecionados (valor → texto). | | onChange | (selected: MultiSelectSelection) => void | | Chamado a cada alteração da seleção. | | modalTitle * | string | | | | keyExtractor | (item: MultiSelectItem, index: number) => string | | | | maxSelectableItems | number | | Ao atingir o máximo, a seleção mais antiga é substituída. | | placeholder | string | 'Selecione' | | | buttonTitle | string | 'Confirmar' | | | valueKey | string | 'value' | | | textKey | string | 'text' | | | searchPlaceholder | string | 'Buscar' | | | selectedItems | MultiSelectSelection | | | | disabled | boolean | false | | | error | boolean \| string | false | | | size | FieldSize | 'md' | | | style | StyleProp<ViewStyle> | | | | testID | string | | |

DateTimePicker

Data, hora ou data+hora:

  • iOS: folha com o picker inline; a data só é aplicada no "Confirmar".
  • Android: diálogos nativos; no modo datetime, abre a data e depois a hora.
<DateTimePicker date={date} onDateChange={setDate} placeholder="Data de vencimento" minimumDate={new Date()} />
<DateTimePicker mode="time" date={time} onDateChange={setTime} customFormat="HH'h'mm" />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | date | Date \| null | | Data selecionada. Vazio mostra o placeholder. | | onChange | (event: DateTimePickerEvent, date?: Date) => void | | Assinatura da v1: recebe o evento nativo e a data escolhida. | | onDateChange | (date: Date) => void | | Recebe apenas a data confirmada. | | mode | PickerMode | 'date' | | | placeholder | string | 'Selecione' | | | defaultDate | string \| Date | | Data exibida quando date está vazio. | | customFormat | string | | Formato com tokens dd MM MMM yyyy HH mm. O padrão depende do mode. | | formatValue | (date: Date) => string | | | | minimumDate | Date | | | | maximumDate | Date | | | | display | IOSDisplay | 'inline' | | | IOSHeaderTitle | string | 'Selecione uma data' | | | confirmText | string | 'Confirmar' | | | cancelText | string | 'Fechar' | | | locale | string | 'pt-BR' | | | disabled | boolean | false | | | error | boolean \| string | false | | | size | FieldSize | 'md' | | | containerStyle | StyleProp<ViewStyle> | | | | testID | string | | |

PhotoSlot

Espaço de foto: vazio (tracejado, para adicionar) ou preenchido (com legenda e botão de remover em vidro).

<PhotoSlot icon={CameraIcon} label="Frente do veículo" hint="Toque para fotografar" uri={photos.front} onAdd={takeFront} onOpen={preview} onRemove={removeFront} />
<PhotoSlot icon={CameraIcon} compact uri={photo} onAdd={take} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | icon * | IconComponent | | Ícone do slot vazio (ex.: CameraIcon). | | label | string | | | | hint | string | | | | uri | string | | URI da foto. Sem URI, mostra o slot vazio. | | compact | boolean | false | Versão quadrada pequena para grades. | | onAdd | () => void | | | | onOpen | () => void | | | | onRemove | () => void | | | | readable | boolean | false | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: false. | | style | StyleProp<ViewStyle> | | |


Listas e menus

ListItem

Linha com título, descrição e slots laterais.

<ListItem
  leftComponent={<Avatar name={client.name} size={40} />}
  title={client.name}
  description={client.document}
  rightComponent={<StatusPill tone="success">Ativo</StatusPill>}
  onPress={() => open(client)}
/>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | title | string | | | | description | string | | | | leftComponent | ReactNode | | | | rightComponent | ReactNode | | | | onPress | () => void | | | | divider | boolean | true | Divisória inferior. Padrão: true. | | titleNumberOfLines | number | 1 | | | descriptionNumberOfLines | number | 2 | | | containerStyle | StyleProp<ViewStyle> | | | | leftContentStyle | StyleProp<ViewStyle> | | | | rightContentStyle | StyleProp<ViewStyle> | | | | titleStyle | StyleProp<TextStyle> | | | | descriptionStyle | StyleProp<TextStyle> | | | | accessibilityLabel | string | | | | testID | string | | |

ListMenu, MenuListItem, MenuListSubitem e MenuSeparator

Menu lateral ou de configurações, com seções e itens expansíveis.

<ListMenu
  defaultActiveIndex={1}
  items={[
    { type: 'separator', text: 'Conta' },
    { type: 'menu-item', text: 'Perfil', icon: UserIcon, onPress: openProfile },
    { type: 'menu-item', text: 'Relatórios', icon: ChartBarIcon, subItems: [{ text: 'Mensal', onPress: openMonthly }] },
  ]}
/>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | text * | string | | | | type * | 'separator' \| 'menu-item' | | | | icon | IconComponent | | | | subItems | Pick<MenuItem, 'text' \| 'onPress'>[] | | | | onPress | () => void | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | title * | string | | | | icon | IconComponent | | | | iconColor | GrafitColorToken | 'foreground_medium' | | | onPress | () => void | | | | active | boolean | false | | | children | ReactNode | | Subitens (MenuListSubitem); o item vira um acordeão. | | defaultExpanded | boolean | false | | | containerStyle | StyleProp<ViewStyle> | | | | textStyle | StyleProp<TextStyle> | | | | testID | string | | |


Feedback e estados

Card

<Card title="Saldo disponível" icon={WalletIcon} rightContent={<Tag text="Novo" tone="success" />} onPress={openBalance}>
  <Text variant="display_sm">R$ 1.250,00</Text>
</Card>
<Card variant="filled" title="Sem borda" />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | title | string | | | | icon | IconComponent | | | | iconColor | GrafitColorToken | 'primary' | | | rightContent | ReactNode | | Conteúdo à direita do cabeçalho. | | onPress | () => void | | Torna o card inteiro clicável. | | variant | CardVariant | | outlined (padrão), filled ou elevated. Elevação vem das camadas de surface. | | mode | LegacyCardMode | | Obsoleto. Use variant: bordered → outlined, shadowed → elevated. | | style | StyleProp<ViewStyle> | | | | accessibilityLabel | string | | | | testID | string | | | | children | ReactNode | | |

Tag e StatusPill

Tag é um rótulo com ícone opcional; StatusPill é um status compacto com ponto colorido.

<Tag text="Combustível" icon={GasPumpIcon} tone="secondary" />
<StatusPill tone="warning">Aguardando aprovação</StatusPill>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | text | string | | | | icon | IconComponent | | | | tone | GrafitTone | 'primary' | Cor. Padrão: primary. | | variant | GrafitVariant | | Aparência. Padrão: soft. | | mode | TagShape | 'rounded' | Formato: rounded (pill, padrão) ou squared. | | light | boolean | true | Obsoleto. Use variant="solid" para a tag preenchida. | | containerStyle | StyleProp<ViewStyle> | | | | testID | string | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | children * | string | | | | tone | GrafitTone | 'neutral' | Cor do status. Padrão: neutral. | | style | StyleProp<ViewStyle> | | | | testID | string | | |

Notice, NoticeBar e Disclaimer

| Componente | Quando usar | |---|---| | Notice | Aviso com título e descrição, opcionalmente clicável (seta) | | NoticeBar | Mensagem curta de uma linha com botão de fechar | | Disclaimer | Bloco informativo com título, descrição e conteúdo livre |

<Notice tone="warning" title="Documento pendente" description="Envie a CNH para liberar o cartão." onPress={openDocs} />
<NoticeBar type="success" message="Cartão desbloqueado." onRightButtonClick={dismiss} />
<Disclaimer tone="neutral" title="Importante" description="O limite é renovado todo dia 1º." icon={InfoIcon} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | title * | string | | | | description | string | | | | tone | GrafitTone | 'primary' | Cor. Padrão: primary. | | icon | IconComponent | | | | onPress | () => void | | Torna o aviso clicável e mostra uma seta. | | style | StyleProp<ViewStyle> | | | | testID | string | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | message * | string | | | | type | NoticeType | 'information' | Preset de cor e ícone. Padrão: information. | | tone | GrafitTone | | Sobrescreve a cor do preset. | | variant | GrafitVariant | 'soft' | Aparência. Padrão: soft. | | icon | IconComponent | | | | showRightButton | boolean | true | | | rightButtonIcon | IconComponent | XIcon | | | onRightButtonClick | () => void | | | | rightButtonAccessibilityLabel | string | 'Fechar aviso' | | | style | StyleProp<ViewStyle> | | | | testID | string | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | title | string | | | | description | string | | | | icon | IconComponent | | | | tone | GrafitTone | | Cor. Padrão: neutral. | | variant | GrafitVariant | | Aparência. Padrão: soft. | | selectColor | LegacyColor | | Obsoleto. Use tone. | | stateView | LegacyStateView | | Obsoleto. Use variant. | | style | StyleProp<ViewStyle> | | | | testID | string | | | | children | ReactNode | | |

ProgressBar e PageProgressIndicator

<ProgressBar progress={72} label="Perfil completo" />       // fica success em 100%
<PageProgressIndicator numberOfPages={4} current={2} />     // fluxo em etapas

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | progress * | number | | Progresso de 0 a 100. | | size | GrafitSize | 'md' | | | color | GrafitColorToken | | Cor de preenchimento. Padrão: primary, e success ao completar. | | label | string | | | | showValue | boolean | true | Mostra o percentual. Padrão: true. | | style | StyleProp<ViewStyle> | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | numberOfPages * | number | | | | current | number | | Etapa atual, começando em 1. | | currentPage | number | | Obsoleto. Use current. | | style | StyleProp<ViewStyle> | | |

StepCard

Onboarding em passos, com paginação; o último passo chama onClose.

<StepCard steps={[{ title: 'Bem-vindo', description: '…' }, { title: 'Pronto', description: '…' }]} onClose={finish} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | steps * | StepCardStep[] | | | | onClose | () => void | | Chamado ao concluir o último passo. | | previousButtonText | string | 'Voltar' | | | nextButtonText | string | 'Próximo' | | | finishButtonText | string | 'Concluir' | | | style | StyleProp<ViewStyle> | | |

Timeline

<Timeline
  events={[
    { title: 'Pedido criado', description: '10/10 às 09:12', status: 'completed' },
    { title: 'Pagamento recusado', status: 'failed' },
    { title: 'Aguardando nova tentativa', status: 'pending' },
  ]}
/>

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | title * | string | | | | description | string | | | | status * | TimelineStatus | | |

Skeleton e SkeletonRow

Placeholder pulsante (easing.linear + duration.loop).

{loading ? [1, 2, 3].map(key => <SkeletonRow key={key} />) : items.map(renderItem)}
<Skeleton width="60%" height={24} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | width | DimensionValue | '100%' | Largura em pontos ou percentual. Padrão: 100%. | | height | number | | Altura. Padrão: spacing.x200. | | radius | number | | Raio. Padrão: radius.x100. | | style | StyleProp<ViewStyle> | | |

EmptyState, StateView e ErrorState

| Componente | Quando usar | |---|---| | EmptyState | Lista ou seção sem conteúdo (ícone ou ilustração, texto e ação) | | StateView | Estado ilustrado de tela cheia (emblema com anéis, ícones satélite e até 2 ações) | | ErrorState | StateView de erro; o texto por tipo de erro vem do app via resolveCopy |

<EmptyState icon={ReceiptIcon} title="Nenhum pedido" description="Seus pedidos aparecem aqui." buttonText="Fazer pedido" onButtonPress={create} />

<StateView
  icon={WifiSlashIcon}
  tone="warning"
  eyebrow="Offline"
  title="Sem conexão"
  description="Verifique sua internet."
  satellites={[CloudIcon, BellIcon]}
  primaryAction={{ text: 'Tentar novamente', onPress: retry }}
/>

<ErrorState error={error} resolveCopy={getErrorStateCopy} onRetry={refetch} />

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | icon | IconComponent | | | | iconTone | GrafitTone | 'neutral' | | | imageSource | ImageSourcePropType | | Ilustração no lugar do ícone. | | title | string | | | | description | string | | | | buttonText | string | | | | onButtonPress | () => void | | | | style | StyleProp<ViewStyle> | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | icon * | IconComponent | | | | title * | string | | | | tone | StateViewTone | 'primary' | | | eyebrow | string | | Texto curto acima do título (ex.: "Sem conexão"). | | description | string | | | | context | string | | Pílula de contexto abaixo da descrição (ex.: código do erro). | | satellites | IconComponent[] | [] | Até 3 ícones decorativos ao redor do emblema. | | primaryAction | StateViewAction | | | | secondaryAction | StateViewAction | | | | style | StyleProp<ViewStyle> | | |

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | error | unknown | | Erro original, repassado para resolveCopy. | | resolveCopy | (error: unknown) => ErrorStateCopy | | Converte o erro no texto da tela (ex.: o getErrorStateCopy do app). | | title | string | | Sobrescreve o título vindo da cópia. | | onRetry | () => void | | | | retryText | string | 'Tentar novamente' | | | style | StyleProp<ViewStyle> | | |

Toast e useToast

const { show, hide } = useToast();

show({ message: 'Pagamento aprovado', type: 'success' });
show({ message: 'Sem conexão', type: 'danger', buttonText: 'Tentar', onButtonPress: retry });
show({ message: 'Item removido', type: 'neutral', placement: 'bottom' });

O toast aparece no topo, abaixo da status bar. Para mudar a posição no app inteiro, use <ToastProvider placement="bottom">; o placement de cada show sobrescreve o do provider. Embaixo, ele fica acima da safe area e pode cobrir rodapés e tab bars. Com Liquid Glass, o toast usa sempre o vidro readable.

A duração padrão é de 50 ms por caractere, entre duration.ambient (1,5 s) e duration.toast (5 s). Mostrar outro toast reinicia o tempo. O leitor de tela anuncia a mensagem.

| Prop | Tipo | Padrão | Descrição | |---|---|---|---| | message * | string | | | | type | ToastType | | | | visible | boolean | | | | duration | number | | Tempo visível em ms. Padrão: 50ms por caractere, entre duration.ambient e duration.toast. | | buttonText | string | | | | onButtonPress | () => void | | | | glass | boolean | | Liquid Glass. Padrão: segue o GrafitProvider. | | placement | ToastPlacement | | Onde o toast aparece: top (abaixo da status bar) ou bottom (acima da safe area). Padrão: top. | | readable | boolean | | Vidro quase opaco para facilitar a leitura (ver Glass). Padrão: true. |

Utilitários

| Export | Uso | |---|---| | createGrafitTheme(options) | Tema fora do React | | resolveToneTokens(tone, variant) | Tokens de fundo/conteúdo da tabela de aparências | | useGlass(glass?) | { isGlass, isNativeGlass } para componentes próprios | | formatDate(date, pattern) | Datas pt-BR com tokens dd MM MMM MMMM yyyy HH mm ss; literais entre aspas simples | | getInitials(name) | Iniciais usadas pelo Avatar | | grafitThemes, grafitShared | Tokens crus (gerados a partir do DTCG) |

Dependências e versões duplicadas

  • Toda dependência nativa ou singleton é peerDependency. dependencies só tem JS puro (react-native-mask-input, react-native-currency-input).
  • O prepublishOnly roda scripts/check-dependencies.js, que bloqueia o publish se um módulo nativo ou singleton entrar em dependencies, direta ou transitivamente.
  • Os tipos publicados (.d.ts) não referenciam tipos privados do React Native, então funcionam do RN 0.78 ao 0.87.

Ao atualizar para a v2, remova os resolutions de react-native-svg, react-native-safe-area-context, react-native-gesture-handler, react-native-device-info e styled-components que existiam por causa da lib.

Desenvolvimento

Requer Node ≥ 22.11 (exigência do React Native 0.87 do app de exemplo).

yarn install
yarn typecheck     # tsc strict (lib + exemplo)
yarn lint
yarn test          # tema + render de todos os componentes em várias marcas/modos, com e sem vidro
yarn docs          # regenera as tabelas de props deste README a partir dos tipos
yarn tokens        # regenera src/theme/grafit/tokens.ts a partir de .claude/dtcg/dtcg
yarn check:peers   # garante que nada nativo/singleton vaze para dependencies
yarn verify        # todas as checagens acima (rode antes de publicar)
yarn prepare       # build (bob): lib/commonjs, lib/module, lib/typescript
yarn start | yarn ios | yarn android   # app de exemplo (roda dentro de example/)
  • lib/ é gerado no prepare e não é versionado.

  • O app de exemplo fica inteiro em example/ (App.tsx, android/, ios/, Metro e Babel) e usa o node_modules da raiz, sem instalação própria. No iOS, rode cd example/ios && bundle install && bundle exec pod install. Ao trocar a versão de uma dependência nativa nas devDependencies, atualize também example/package.json, que o autolinking lê.

  • Componente novo: crie a pasta com index.tsx + styles.ts, exporte em src/index.ts, adicione ao Showcase de src/__tests__/components.test.tsx e documente aqui com um marcador <!-- props:NomeProps -->.

  • Publicação no NPM

npm publish