A React component library for rendering common AT Protocol records for applications such as Bluesky and Leaflet.
1import React from "react"; 2import { AtProtoRecord } from "../core/AtProtoRecord"; 3import { TangledStringRenderer } from "../renderers/TangledStringRenderer"; 4import type { TangledStringRecord } from "../types/tangled"; 5import { useAtProto } from "../providers/AtProtoProvider"; 6 7/** 8 * Props for rendering Tangled String records. 9 */ 10export interface TangledStringProps { 11 /** DID of the repository that stores the string record. */ 12 did: string; 13 /** Record key within the `sh.tangled.string` collection. */ 14 rkey: string; 15 /** Prefetched Tangled String record. When provided, skips fetching from the network. */ 16 record?: TangledStringRecord; 17 /** Optional renderer override for custom presentation. */ 18 renderer?: React.ComponentType<TangledStringRendererInjectedProps>; 19 /** Fallback node displayed before loading begins. */ 20 fallback?: React.ReactNode; 21 /** Indicator node shown while data is loading. */ 22 loadingIndicator?: React.ReactNode; 23 /** Preferred color scheme for theming. */ 24 colorScheme?: "light" | "dark" | "system"; 25} 26 27/** 28 * Values injected into custom Tangled String renderer implementations. 29 */ 30export type TangledStringRendererInjectedProps = { 31 /** Loaded Tangled String record value. */ 32 record: TangledStringRecord; 33 /** Indicates whether the record is currently loading. */ 34 loading: boolean; 35 /** Fetch error, if any. */ 36 error?: Error; 37 /** Preferred color scheme for downstream components. */ 38 colorScheme?: "light" | "dark" | "system"; 39 /** DID associated with the record. */ 40 did: string; 41 /** Record key for the string. */ 42 rkey: string; 43 /** Canonical external URL for linking to the string. */ 44 canonicalUrl: string; 45}; 46 47/** NSID for Tangled String records. */ 48export const TANGLED_COLLECTION = "sh.tangled.string"; 49 50/** 51 * Resolves a Tangled String record and renders it with optional overrides while computing a canonical link. 52 * 53 * @param did - DID whose Tangled String should be fetched. 54 * @param rkey - Record key within the Tangled String collection. 55 * @param renderer - Optional component override that will receive injected props. 56 * @param fallback - Node rendered before the first load begins. 57 * @param loadingIndicator - Node rendered while the Tangled String is loading. 58 * @param colorScheme - Preferred color scheme for theming the renderer. 59 * @returns A JSX subtree representing the Tangled String record with loading states handled. 60 */ 61export const TangledString: React.FC<TangledStringProps> = React.memo(({ 62 did, 63 rkey, 64 record, 65 renderer, 66 fallback, 67 loadingIndicator, 68 colorScheme, 69}) => { 70 const { tangledBaseUrl } = useAtProto(); 71 const Comp: React.ComponentType<TangledStringRendererInjectedProps> = 72 renderer ?? ((props) => <TangledStringRenderer {...props} />); 73 const Wrapped: React.FC<{ 74 record: TangledStringRecord; 75 loading: boolean; 76 error?: Error; 77 }> = (props) => ( 78 <Comp 79 {...props} 80 colorScheme={colorScheme} 81 did={did} 82 rkey={rkey} 83 canonicalUrl={`${tangledBaseUrl}/strings/${did}/${encodeURIComponent(rkey)}`} 84 /> 85 ); 86 87 if (record !== undefined) { 88 return ( 89 <AtProtoRecord<TangledStringRecord> 90 record={record} 91 renderer={Wrapped} 92 fallback={fallback} 93 loadingIndicator={loadingIndicator} 94 /> 95 ); 96 } 97 98 return ( 99 <AtProtoRecord<TangledStringRecord> 100 did={did} 101 collection={TANGLED_COLLECTION} 102 rkey={rkey} 103 renderer={Wrapped} 104 fallback={fallback} 105 loadingIndicator={loadingIndicator} 106 /> 107 ); 108}); 109 110export default TangledString;