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

@infloapi/react-social

v0.1.0

Published

React components for the Inflo social graph — connections, groups, and the CirclesPickerDialog

Readme

@infloapi/react-social

React components for the Inflo social graph layer — connection discovery, group browsing, and the shareable CirclesPickerDialog.

This package is the UI counterpart to the @infloapi/node SDK's connections and groups resources, and complements @infloapp/share-react (which handles CLP content sharing) by covering the social graph selection step that always precedes a share.


Installation

npm install @infloapi/react-social

Peer dependencies:

npm install react react-dom

Quick start

1. Wrap your app with ConnectionsProvider

ConnectionsProvider accepts two async adapter functions — fetchConnections and fetchGroups — so you can route calls through your own server proxy (recommended) or call Inflo directly.

import { ConnectionsProvider } from "@infloapi/react-social";

function App() {
  return (
    <ConnectionsProvider
      fetchConnections={async (opts) => {
        // IMPORTANT: always forward limit and offset so the provider can
        // paginate through all connections when has_more is true.
        const params = new URLSearchParams();
        if (opts?.limit  !== undefined) params.set("limit",  String(opts.limit));
        if (opts?.offset !== undefined) params.set("offset", String(opts.offset));
        const res = await fetch(`/api/social/connections?${params}`);
        return res.json();
        // Expected shape: { connections: ConnectionItem[], total: number, has_more: boolean }
      }}
      fetchGroups={async () => {
        const res = await fetch("/api/social/groups");
        return res.json();
        // Expected shape: { groups: GroupItem[] }
        // total and has_more are optional and ignored if absent.
      }}
    >
      <YourApp />
    </ConnectionsProvider>
  );
}

The provider:

  • Loads the full connection list on mount (search filters it client-side, with no extra network request).
  • Loads groups on mount.
  • Exposes everything to child components via context.

Why client-side search? Inflo's GET /api/v1/users/me/connections endpoint does not support a q or search parameter. The provider caches all connections and filters them in-memory when the user types — this is instant and requires no additional requests.

2. Use hooks inside the provider

import { useConnections, useGroups } from "@infloapi/react-social";

function ConnectionsList() {
  const { connections, loading, error, search } = useConnections();
  const { groups } = useGroups();

  if (loading) return <p>Loading…</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <>
      <input
        placeholder="Search…"
        onChange={(e) => search(e.target.value)}
      />
      {/* connections is already filtered by the current search query */}
      <ul>
        {connections.map((c) => (
          <li key={c.uid ?? c.inflo_user_id}>{c.display_name}</li>
        ))}
      </ul>
    </>
  );
}

3. Open the CirclesPickerDialog

import { useState } from "react";
import { CirclesPickerDialog } from "@infloapi/react-social";
import type { CirclesSelection } from "@infloapi/react-social";

function ShareButton({ alreadySharedUids }: { alreadySharedUids: string[] }) {
  const [open, setOpen] = useState(false);

  function handleSelect(selection: CirclesSelection) {
    console.log("Selected UIDs:", selection.connections);
    console.log("Selected group IDs:", selection.groups);
    // → call your share API here
  }

  return (
    <>
      <button onClick={() => setOpen(true)}>Share…</button>

      <CirclesPickerDialog
        open={open}
        onOpenChange={setOpen}
        onSelect={handleSelect}
        maxConnections={10}
        disabledUids={alreadySharedUids}
        title="Share with circles"
      />
    </>
  );
}

CirclesPickerDialog features:

  • Instant client-side search — filters the locally-loaded connection list as the user types; no extra network request.
  • Groups section — shown above connections when there's no active search query.
  • Multi-select — each row is checkable; a checkmark appears on selected items.
  • Already-connected indicator — UIDs in disabledUids render with a "Connected" badge and cannot be selected.
  • Connection limit — pass maxConnections to cap individual connection picks (does not limit group selection).
  • Keyboard / accessibilityEscape closes the dialog; role="dialog" and aria-selected attributes included.

Components

ConnectionCard

Renders an Inflo user row: avatar, display name, username, optional status badge, and a checkmark when selected.

import { ConnectionCard } from "@infloapi/react-social";

<ConnectionCard
  connection={conn}
  status="connected"        // "connected" | "pending" | "not_connected"
  selected={isSelected}
  disabled={false}
  onClick={(c) => toggleUid(c.uid)}
  theme={{ primaryColor: "#7c3aed" }}
/>

InvitationStatusBadge

Renders an invitation status as a colour-coded pill.

| Status | Colour | |-------------|--------| | pending | Yellow | | accepted | Green | | declined | Red | | cancelled | Grey | | expired | Grey |

import { InvitationStatusBadge } from "@infloapi/react-social";

<InvitationStatusBadge status={invitation.status} />

Theming

Every component accepts a theme prop for inline style-based overrides — no extra CSS required.

const theme = {
  primaryColor: "#7c3aed",       // accent / selected state
  primaryForeground: "#ffffff",  // text on primary button
  dialogBackground: "#1e1e2e",   // dialog background
  border: "#3f3f5c",
  mutedText: "#a0a0c0",
  radius: "12px",
  fontFamily: "'Inter', sans-serif",
};

<CirclesPickerDialog theme={theme} ... />

Wiring fetch adapters to your server proxy

The adapter functions should call your backend, which in turn calls Inflo using a server-side token. Never expose Inflo API keys or PATs to the browser.

Browser → /api/social/connections → Your server → Inflo /api/v1/users/me/connections
Browser → /api/social/groups      → Your server → Inflo /api/v1/groups

A minimal Next.js example using @infloapi/node:

// pages/api/social/connections.ts
import { InfloClient } from "@infloapi/node";

const inflo = new InfloClient({ pat: process.env.INFLO_PAT! });

export default async function handler(req, res) {
  // Forward limit + offset so ConnectionsProvider can paginate all pages.
  const limit  = Number(req.query.limit  ?? 200);
  const offset = Number(req.query.offset ?? 0);

  const result = await inflo.connections.list({
    userToken: req.headers["x-user-token"] as string,
    limit,
    offset,
  });
  res.json(result);
  // returns { connections: [...], total, has_more }
}
// pages/api/social/groups.ts
export default async function handler(req, res) {
  const result = await fetch(
    "https://infloapp.com/api/v1/groups",
    { headers: { Authorization: `Bearer ${process.env.INFLO_PAT}` } },
  );
  const data = await result.json();
  res.json(data);
  // returns { groups: [...] }
}

API reference

ConnectionsProvider props

| Prop | Type | Description | |------|------|-------------| | fetchConnections | FetchConnectionsFn | Async adapter. Returns { connections, total, has_more }. Called on mount and on refresh. | | fetchGroups | FetchGroupsFn | Async adapter. Returns { groups }. Called on mount and on refreshGroups. | | children | ReactNode | — |

useConnections() return value

| Key | Type | Description | |-----|------|-------------| | connections | ConnectionItem[] | Client-side filtered list matching the current searchQuery. | | loading | boolean | true during initial fetch or refresh. | | error | Error \| null | Last fetch error. | | refresh | () => Promise<void> | Re-fetch all connections from the server. | | search | (query: string) => void | Update the search query (client-side filter, no network call). | | searchQuery | string | Current search query string. | | total | number | Total count from the server. |

useGroups() return value

| Key | Type | Description | |-----|------|-------------| | groups | GroupItem[] | Loaded groups. | | loading | boolean | true during fetch. | | error | Error \| null | Last fetch error. | | refresh | () => Promise<void> | Re-fetch groups. |

CirclesPickerDialog props

| Prop | Type | Default | Description | |------|------|---------|-------------| | open | boolean | — | Controls dialog visibility. | | onOpenChange | (open: boolean) => void | — | Called on close request. | | onSelect | (selection: CirclesSelection) => void | — | Called on confirm. | | maxConnections | number | undefined | Cap on selectable connections. | | disabledUids | string[] | [] | UIDs shown as "already connected". | | title | string | "Share with circles" | Dialog title. | | theme | SocialTheme | {} | Visual overrides. |


Related packages

| Package | Purpose | |---------|---------| | @infloapi/react | React auth layer — InfloProvider, AuthGuard, PKCE SSO. Required before users have a valid token to pass to your server proxy. | | @infloapi/node | Node.js SDK — implement the fetchConnections / fetchGroups adapter on your server using inflo.connections.list(). |

License

MIT © Inflo