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

@rocapine/community-ui

v0.1.0

Published

Drop-in React Native screens and components (feed, thread, profile, moderation) for @rocapine/community-core.

Readme

@rocapine/community-ui

Themable, ready-to-mount React Native screens and components for the Community SDK: feed, thread, profile, profile edit, notification inbox, composer, poll block, rules/report sheets. Navigation is by callback props (onOpenProfile(userId), onOpenThread(postId), ...) — this package has no dependency on expo-router or react-navigation; you mount its screens inside your own router.

npm install @rocapine/community-ui

Peer dependencies (beyond @rocapine/community-core's own): react-native >=0.74.0, react-native-reanimated >=3.16.0, expo-image >=1.10.0, expo-haptics >=13.0.0, expo-image-picker >=15.0.0, phosphor-react-native >=2.0.0. phosphor-react-native is an optional peer (peerDependenciesMeta) — skip it if you pass a complete icons set to CommunityUIProvider (see Icons below); the default icon set only requires it once a default icon actually renders.

Provider

import { CommunityUIProvider } from "@rocapine/community-ui";

<CommunityUIProvider
  theme={{ colors: { accent: "#6C4DF6" } }}
  translations={{ locale: "es-ES", overrides: { "rules.accept": "Estoy de acuerdo" } }}
>
  {/* your screens */}
</CommunityUIProvider>;

CommunityUIProvider must sit inside @rocapine/community-core's CommunityProvider (see the root README's quickstart). theme and translations are both optional — omit either to get the neutral defaults.

Theming

theme is a DeepPartial<CommunityTheme>, merged over defaultTheme via mergeTheme (exported, in case you want to build a theme object outside the provider). useCommunityTheme() reads the resolved theme in your own components; useThemedStyles(factory) memoizes a StyleSheet.create(...) against theme identity (avoids rebuilding style objects on every render).

CommunityTheme shape:

type CommunityTheme = {
  colors: {
    background: string;
    surface: string;
    surfaceMuted: string;
    border: string;
    borderStrong: string;
    hairline: string;
    textPrimary: string;
    textSecondary: string;
    textMuted: string;
    textFaint: string;
    textInverse: string;
    accent: string;
    accentSoft: string;
    danger: string;
    success: string;
    like: string;
    official: string;
    pinned: string;
  };
  fonts: {
    regular: string | undefined;
    medium: string | undefined;
    bold: string | undefined;
    serifBold: string | undefined;
    serifBoldItalic: string | undefined;
  };
  radius: { sm: number; md: number; lg: number; pill: number };
  spacing: (n: number) => number; // default: n * 4
  shadow: {
    shadowColor: string;
    shadowOpacity: number;
    shadowRadius: number;
    shadowOffset: { width: number; height: number };
    elevation: number;
  };
};

The default theme is a neutral placeholder palette (accent: "#4C6FFF", system fonts) — no app branding. like/official/pinned default to accent too but are separate tokens so you can diverge them.

i18n

Framework-free, no i18next. 9 built-in locales ship as plain objects: en, es-ES, es-419, fr, de, it, pl, pt-PT, pt-BR (all exported by name, e.g. import { en, esES, es419, fr, de, it, pl, ptPT, ptBR } from "@rocapine/community-ui").

<CommunityUIProvider translations={{ locale: "pt-BR", overrides: { "rules.accept": "..." } }}>

Lookup order for a key: overridescatalog[locale] (exact match) → catalog[baseLocale] (base-language match — a locale not shipped verbatim falls back to its language family's designated base: es/any other es-* region falls back to es-ES, pt/any other pt-* region falls back to pt-PT, and any other language's regional variant, e.g. it-CH, falls back to its bare-language catalog, e.g. it) → catalog.en → the key itself (never a blank string). A numeric params.count selects <key>.one / <key>.other (through the same fallback chain) before falling back to the bare key — e.g. t("feed.newPosts", { count: 3 }). Interpolation uses {name}-style placeholders, not i18next's {{name}}.

Topic labels: a topic's display label resolves through the key topics.<id> — the id you gave it in CommunityConfig.topics. Built-in ids (news, general, question, ...) already have translations in every shipped locale; any topic id you invent needs its own topics.<yourId> override in every locale you support, since it won't exist in the built-in catalogs.

The COMMUNITY_REACTION_PUSH_TEXT caveat: the reaction module's push copy (server-side, in the notify-reaction Edge Function) is built-in and localized per recipient for the common "one reactor" case across all 7 locales. The COMMUNITY_REACTION_PUSH_TEXT secret (see docs/backend-runbook.md) overrides that template — but it is a single string, not a per-locale map: setting it replaces the built-in copy for every recipient locale at once with the one string you set (with {name} substituted). If you set this secret, pick wording that reads acceptably in translation, or don't set it and rely on the neutral built-in copy. The "and N others" multi-reactor phrasing always comes from the built-in per-locale table regardless — there is no secret for it.

Icons

Not every app uses phosphor-react-native, so the icon set is injectable — phosphor-react-native is an optional peer (see above), not a hard dependency. Every icon this package renders is looked up by a semantic role name (CommunityIconName: like, comment, reaction, menu, back, close, send, bell, search, officialSeal, pin, announcement, checkmark, poll, add, warning), never by a phosphor glyph name.

import { CommunityUIProvider, type CommunityIconSet } from "@rocapine/community-ui";
import { Feather } from "@expo/vector-icons";

// Bring your own icon library — map each role to a component that accepts
// { size?, color?, weight?: "regular" | "fill" | "bold" }.
const icons: Partial<CommunityIconSet> = {
  like: ({ size, color }) => <Feather name="heart" size={size} color={color} />,
  comment: ({ size, color }) => <Feather name="message-circle" size={size} color={color} />,
  menu: ({ size, color }) => <Feather name="more-horizontal" size={size} color={color} />,
  // ...the rest fall back to the built-in phosphor-backed defaults
};

<CommunityUIProvider icons={icons}>{/* your screens */}</CommunityUIProvider>;

Unset names fall back to defaultIcons (exported, phosphor-backed). Supply every CommunityIconName and you never need phosphor-react-native installed at all — the default set only requires it lazily, inside a default icon's own render, so it throws a clear error (naming the fix: install phosphor-react-native, or pass a complete icons set to CommunityUIProvider) only if a default icon actually renders without it. Read the merged set yourself with useCommunityIcons() (e.g. to build your own slot content) — it returns the full CommunityIconSet (defaults merged with your icons override), not just what you passed.

Slots

Render-prop customization points that receive the SDK's own default node so you can wrap, replace, or ignore it:

  • CommunityPost's renderPostFooter?: (post: FeedPost, defaults: ReactNode) => ReactNode and renderReactionButton?: (post: FeedPost, defaultButton: ReactNode) => ReactNode — passed through from CommunityFeedScreen's own slots prop (PostSlots). renderReactionButton is how you swap the generic reaction button for something app-specific (e.g. a themed prayer/support sheet) while keeping everything else about the post card unchanged.
  • NotificationInboxScreen's renderInboxRow?: (item: InboxItem, defaults: ReactNode | null) => ReactNode — called for every row; defaults is a built-in row for a recognized kind (like/comment/reaction/official_post) or null for an app-defined custom kind the SDK doesn't know how to render itself (e.g. a support_reply notification your own backend inserts).

Screens

| Screen | Key props | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | CommunityFeedScreen | onOpenProfile(userId), onOpenInbox?(), header?: ReactNode, slots?: PostSlots | | ThreadSheet | postId: string \| null, onClose(), onOpenProfile(userId) — self-contained sheet, render it once and drive it by postId | | ProfileScreen | userId: string, onOpenThread(postId), onBack?() | | ProfileEditSheet | visible: boolean, onClose() | | NotificationInboxScreen | onOpenPost(postId), renderInboxRow? (see Slots above) |

Plus standalone components you can use directly: CommunityPost, PollBlock, NoticeCard, ComposerCard, RulesSheet, ReportSheet, and the package's own CommunitySheet primitive (no host sheet library needed).

See examples/expo-app/App.tsx for a complete, working wiring of CommunityFeedScreen + ProfileScreen + NotificationInboxScreen + ThreadSheet behind a simple useState-driven router.