@cdr-kit/forms/Components/StorageProviderPicker

StorageProviderPicker

Admin-side chip-pill picker for the storage backend that routes encrypted form submissions. Real brand marks for Supabase / IPFS / Cloudflare, cdr-kit-authored shapes for the rest. Not for respondent UIs.
import { StorageProviderPicker } from "@cdr-kit/forms"

Live preview

mock kit

Storage backend

Pinata

Hosted IPFS pinning. Free signup. Simplest setup — one JWT env var.

createPinataStorage({ jwt: process.env.PINATA_JWT! })
import { StorageProviderPicker } from "@cdr-kit/forms";
import { useState } from "react";

export function StorageSetup() {
const [provider, setProvider] = useState("pinata");
return <StorageProviderPicker value={provider} onChange={setProvider} />;
}

A horizontal chip-pill row over a brand-colored detail card. Click any provider to see its name, description, and the exact @cdr-kit/core factory call that builds the matching adapter.

Where to use it

This component is an admin/setup affordance. Render it in your dashboard, an onboarding wizard, or a settings page — wherever you decide which backend your platform stores form submissions in. Do not render it on the public form your respondents fill out: they should never see (or pick) the storage backend.

The picker's value (a StorageProviderId) maps 1:1 to one of the 8 Create*Storage factories shipped by @cdr-kit/core. Your server route reads it (typically from your DB, where you persist the choice) and constructs the matching adapter:

ts
// app/api/respond/route.ts
import { storeFormSubmission } from "@cdr-kit/forms/server";
import {
createPinataStorage,
createSupabaseStorage,
createS3Storage,
// ... etc
} from "@cdr-kit/core";
import type { StorageProviderId } from "@cdr-kit/forms";

const choice = await db.getPlatformStorageProvider() as StorageProviderId;
const storage =
choice === "pinata"   ? createPinataStorage({ jwt: process.env.PINATA_JWT! }) :
choice === "supabase" ? createSupabaseStorage({ supabaseUrl: ..., key: ..., bucket: "cdr" }) :
choice === "s3"       ? createS3Storage({ bucket: ..., region: ..., accessKeyId: ..., secretAccessKey: ... }) :
/* ... */              null;

const { vaultId, cid } = await storeFormSubmission(fields, {
privateKey: process.env.PLATFORM_WALLET_PRIVATE_KEY as `0x${string}`,
storage,
});

Props

PropTypeDefaultDescription
valueStorageProviderId | undefinedCurrently-selected provider id. Pass undefined for "none chosen".
onChangerequired(id: StorageProviderId) => voidFires when the user clicks a chip.
includereadonly StorageProviderId[]Restrict + order the visible providers. Default: all 8.
headingReactNode | null"Storage backend"Visible eyebrow heading above the chips. Pass null to hide.
showDetailbooleantrueShow the brand-colored detail card under the chips for the selected provider. Set false for a compact toolbar-only mode.
classNamestringForwarded to the root container.
styleCSSPropertiesForwarded inline style.

The StorageProviderId union

PropTypeDefaultDescription
pinataStorageProviderIdHosted IPFS pinning. Brand mark by cdr-kit (red).
supabaseStorageProviderIdPostgres + Object Storage. Real CC0 brand mark (green).
storachaStorageProviderIdUCAN pinning / Filecoin. cdr-kit mark (amber).
ipfsStorageProviderIdSelf-hosted Kubo / generic. Real CC0 brand mark (teal).
s3StorageProviderIdAWS S3 / Cloudflare R2 / S3-compatible. cdr-kit bucket mark (orange).
heliaStorageProviderIdBrowser-embedded IPFS via @helia/unixfs. cdr-kit mark (green).
gatewayStorageProviderIdRead-only IPFS gateway. cdr-kit mark (violet).
memoryStorageProviderIdIn-process for tests + CI. cdr-kit mark (slate).

Subset + ordering

If your platform only supports a couple of backends, pass include to constrain — the picker honours the order of the array:

tsx
<StorageProviderPicker
value={value}
onChange={onChange}
include={["pinata", "supabase", "s3"]}
/>

Hide the detail card

For a compact toolbar mode, set showDetail={false}:

tsx
<StorageProviderPicker value={value} onChange={onChange} showDetail={false} />