A React component library for rendering common AT Protocol records for applications such as Bluesky and Leaflet.
1import React from "react"; 2import { useAtProtoRecord } from "../hooks/useAtProtoRecord"; 3 4interface AtProtoRecordRenderProps<T> { 5 renderer?: React.ComponentType<{ 6 record: T; 7 loading: boolean; 8 error?: Error; 9 }>; 10 fallback?: React.ReactNode; 11 loadingIndicator?: React.ReactNode; 12} 13 14type AtProtoRecordFetchProps<T> = AtProtoRecordRenderProps<T> & { 15 did: string; 16 collection: string; 17 rkey: string; 18 record?: undefined; 19}; 20 21type AtProtoRecordProvidedRecordProps<T> = AtProtoRecordRenderProps<T> & { 22 record: T; 23 did?: string; 24 collection?: string; 25 rkey?: string; 26}; 27 28export type AtProtoRecordProps<T = unknown> = 29 | AtProtoRecordFetchProps<T> 30 | AtProtoRecordProvidedRecordProps<T>; 31 32export function AtProtoRecord<T = unknown>(props: AtProtoRecordProps<T>) { 33 const { 34 renderer: Renderer, 35 fallback = null, 36 loadingIndicator = "Loading…", 37 } = props; 38 const hasProvidedRecord = "record" in props; 39 const providedRecord = hasProvidedRecord ? props.record : undefined; 40 41 const { 42 record: fetchedRecord, 43 error, 44 loading, 45 } = useAtProtoRecord<T>({ 46 did: hasProvidedRecord ? undefined : props.did, 47 collection: hasProvidedRecord ? undefined : props.collection, 48 rkey: hasProvidedRecord ? undefined : props.rkey, 49 }); 50 51 const record = providedRecord ?? fetchedRecord; 52 const isLoading = loading && !providedRecord; 53 54 if (error && !record) return <>{fallback}</>; 55 if (!record) return <>{isLoading ? loadingIndicator : fallback}</>; 56 if (Renderer) 57 return <Renderer record={record} loading={isLoading} error={error} />; 58 return ( 59 <pre 60 style={{ 61 fontSize: 12, 62 padding: 8, 63 background: "#f5f5f5", 64 overflow: "auto", 65 }} 66 > 67 {JSON.stringify(record, null, 2)} 68 </pre> 69 ); 70}