···26263. Use the hooks to prefetch handles, blobs, or latest records when you want to control the render flow yourself.
27272828```tsx
2929-import { AtProtoProvider, BlueskyPost } from 'atproto-ui';
2929+import { AtProtoProvider, BlueskyPost } from "atproto-ui";
30303131export function App() {
3232- return (
3333- <AtProtoProvider>
3434- <BlueskyPost did="did:plc:example" rkey="3k2aexample" />
3535- {/* you can use handles in the components as well. */}
3636- <LeafletDocument did="nekomimi.pet" rkey="3m2seagm2222c" />
3737- </AtProtoProvider>
3838- );
3232+ return (
3333+ <AtProtoProvider>
3434+ <BlueskyPost did="did:plc:example" rkey="3k2aexample" />
3535+ {/* you can use handles in the components as well. */}
3636+ <LeafletDocument did="nekomimi.pet" rkey="3m2seagm2222c" />
3737+ </AtProtoProvider>
3838+ );
3939}
4040```
41414242### Available building blocks
43434444-| Component / Hook | What it does |
4545-| --- | --- |
4646-| `AtProtoProvider` | Configures PLC directory (defaults to `https://plc.directory`) and shares protocol clients via React context. |
4747-| `BlueskyProfile` | Renders a profile card for a DID/handle. Accepts `fallback`, `loadingIndicator`, `renderer`, and `colorScheme`. |
4848-| `BlueskyPost` / `BlueskyQuotePost` | Shows a single Bluesky post, with quotation support, custom renderer overrides, and the same loading/fallback knobs. |
4949-| `BlueskyPostList` | Lists the latest posts with built-in pagination (defaults: 5 per page, pagination controls on). |
5050-| `TangledString` | Renders a Tangled string (gist-like record) with optional renderer overrides. |
5151-| `LeafletDocument` | Displays long-form Leaflet documents with blocks, theme support, and renderer overrides. |
5252-| `useDidResolution`, `useLatestRecord`, `usePaginatedRecords`, … | Hook-level access to records if you want to own the markup or prefill components. |
4444+| Component / Hook | What it does |
4545+| --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
4646+| `AtProtoProvider` | Configures PLC directory (defaults to `https://plc.directory`) and shares protocol clients via React context. |
4747+| `BlueskyProfile` | Renders a profile card for a DID/handle. Accepts `fallback`, `loadingIndicator`, `renderer`, and `colorScheme`. |
4848+| `BlueskyPost` / `BlueskyQuotePost` | Shows a single Bluesky post, with quotation support, custom renderer overrides, and the same loading/fallback knobs. |
4949+| `BlueskyPostList` | Lists the latest posts with built-in pagination (defaults: 5 per page, pagination controls on). |
5050+| `TangledString` | Renders a Tangled string (gist-like record) with optional renderer overrides. |
5151+| `LeafletDocument` | Displays long-form Leaflet documents with blocks, theme support, and renderer overrides. |
5252+| `useDidResolution`, `useLatestRecord`, `usePaginatedRecords`, … | Hook-level access to records if you want to own the markup or prefill components. |
53535454All components accept a `colorScheme` of `'light' | 'dark' | 'system'` so they can blend into your design. They also accept `fallback` and `loadingIndicator` props to control what renders before or during network work, and most expose a `renderer` override when you need total control of the final markup.
5555···5858`useLatestRecord` gives you the most recent record for any collection along with its `rkey`. You can use that key to pre-populate components like `BlueskyPost`, `LeafletDocument`, or `TangledString`.
59596060```tsx
6161-import { useLatestRecord, BlueskyPost } from 'atproto-ui';
6262-import type { FeedPostRecord } from 'atproto-ui';
6161+import { useLatestRecord, BlueskyPost } from "atproto-ui";
6262+import type { FeedPostRecord } from "atproto-ui";
63636464const LatestBlueskyPost: React.FC<{ did: string }> = ({ did }) => {
6565- const { rkey, loading, error, empty } = useLatestRecord<FeedPostRecord>(did, 'app.bsky.feed.post');
6565+ const { rkey, loading, error, empty } = useLatestRecord<FeedPostRecord>(
6666+ did,
6767+ "app.bsky.feed.post",
6868+ );
66696767- if (loading) return <p>Fetching latest post…</p>;
6868- if (error) return <p>Could not load: {error.message}</p>;
6969- if (empty || !rkey) return <p>No posts yet.</p>;
7070+ if (loading) return <p>Fetching latest post…</p>;
7171+ if (error) return <p>Could not load: {error.message}</p>;
7272+ if (empty || !rkey) return <p>No posts yet.</p>;
70737171- return (
7272- <BlueskyPost
7373- did={did}
7474- rkey={rkey}
7575- colorScheme="system"
7676- />
7777- );
7474+ return <BlueskyPost did={did} rkey={rkey} colorScheme="system" />;
7875};
7976```
8077···82798380```tsx
8481const LatestLeafletDocument: React.FC<{ did: string }> = ({ did }) => {
8585- const { rkey } = useLatestRecord(did, 'pub.leaflet.document');
8686- return rkey ? <LeafletDocument did={did} rkey={rkey} colorScheme="light" /> : null;
8282+ const { rkey } = useLatestRecord(did, "pub.leaflet.document");
8383+ return rkey ? (
8484+ <LeafletDocument did={did} rkey={rkey} colorScheme="light" />
8585+ ) : null;
8786};
8887```
8988···9291The helpers let you stitch together custom experiences without reimplementing protocol plumbing. The example below pulls a creator’s latest post and renders a minimal summary:
93929493```tsx
9595-import { useLatestRecord, useColorScheme, AtProtoRecord } from 'atproto-ui';
9696-import type { FeedPostRecord } from 'atproto-ui';
9494+import { useLatestRecord, useColorScheme, AtProtoRecord } from "atproto-ui";
9595+import type { FeedPostRecord } from "atproto-ui";
97969897const LatestPostSummary: React.FC<{ did: string }> = ({ did }) => {
9999- const scheme = useColorScheme('system');
100100- const { rkey, loading, error } = useLatestRecord<FeedPostRecord>(did, 'app.bsky.feed.post');
9898+ const scheme = useColorScheme("system");
9999+ const { rkey, loading, error } = useLatestRecord<FeedPostRecord>(
100100+ did,
101101+ "app.bsky.feed.post",
102102+ );
101103102102- if (loading) return <span>Loading…</span>;
103103- if (error || !rkey) return <span>No post yet.</span>;
104104+ if (loading) return <span>Loading…</span>;
105105+ if (error || !rkey) return <span>No post yet.</span>;
104106105105- return (
106106- <AtProtoRecord<FeedPostRecord>
107107- did={did}
108108- collection="app.bsky.feed.post"
109109- rkey={rkey}
110110- renderer={({ record }) => (
111111- <article data-color-scheme={scheme}>
112112- <strong>{record?.text ?? 'Empty post'}</strong>
113113- </article>
114114- )}
115115- />
116116- );
107107+ return (
108108+ <AtProtoRecord<FeedPostRecord>
109109+ did={did}
110110+ collection="app.bsky.feed.post"
111111+ rkey={rkey}
112112+ renderer={({ record }) => (
113113+ <article data-color-scheme={scheme}>
114114+ <strong>{record?.text ?? "Empty post"}</strong>
115115+ </article>
116116+ )}
117117+ />
118118+ );
117119};
118120```
119121···133135- Expand renderer coverage (e.g., Grain.social photos).
134136- Expand documentation with TypeScript API references and theming guidelines.
135137136136-Contributions and ideas are welcome—feel free to open an issue or PR!138138+Contributions and ideas are welcome—feel free to open an issue or PR!
+36-32
lib/components/BlueskyIcon.tsx
···11-import React from 'react';
11+import React from "react";
2233/**
44 * Configuration for the `BlueskyIcon` component.
55 */
66export interface BlueskyIconProps {
77- /**
88- * Pixel dimensions applied to both the width and height of the SVG element.
99- * Defaults to `16`.
1010- */
1111- size?: number;
1212- /**
1313- * Hex, RGB, or any valid CSS color string used to fill the icon path.
1414- * Defaults to the standard Bluesky blue `#1185fe`.
1515- */
1616- color?: string;
1717- /**
1818- * Accessible title that will be exposed via `aria-label` for screen readers.
1919- * Defaults to `'Bluesky'`.
2020- */
2121- title?: string;
77+ /**
88+ * Pixel dimensions applied to both the width and height of the SVG element.
99+ * Defaults to `16`.
1010+ */
1111+ size?: number;
1212+ /**
1313+ * Hex, RGB, or any valid CSS color string used to fill the icon path.
1414+ * Defaults to the standard Bluesky blue `#1185fe`.
1515+ */
1616+ color?: string;
1717+ /**
1818+ * Accessible title that will be exposed via `aria-label` for screen readers.
1919+ * Defaults to `'Bluesky'`.
2020+ */
2121+ title?: string;
2222}
23232424/**
···2929 * @param title - Accessible label exposed via `aria-label`.
3030 * @returns A JSX `<svg>` element suitable for inline usage.
3131 */
3232-export const BlueskyIcon: React.FC<BlueskyIconProps> = ({ size = 16, color = '#1185fe', title = 'Bluesky' }) => (
3333- <svg
3434- xmlns="http://www.w3.org/2000/svg"
3535- width={size}
3636- height={size}
3737- viewBox="0 0 16 16"
3838- role="img"
3939- aria-label={title}
4040- focusable="false"
4141- style={{ display: 'block' }}
4242- >
4343- <path
4444- fill={color}
4545- d="M3.468 1.948C5.303 3.325 7.276 6.118 8 7.616c.725-1.498 2.698-4.29 4.532-5.668C13.855.955 16 .186 16 2.632c0 .489-.28 4.105-.444 4.692-.572 2.04-2.653 2.561-4.504 2.246 3.236.551 4.06 2.375 2.281 4.2-3.376 3.464-4.852-.87-5.23-1.98-.07-.204-.103-.3-.103-.218 0-.081-.033.014-.102.218-.379 1.11-1.855 5.444-5.231 1.98-1.778-1.825-.955-3.65 2.28-4.2-1.85.315-3.932-.205-4.503-2.246C.28 6.737 0 3.12 0 2.632 0 .186 2.145.955 3.468 1.948"
4646- />
4747- </svg>
3232+export const BlueskyIcon: React.FC<BlueskyIconProps> = ({
3333+ size = 16,
3434+ color = "#1185fe",
3535+ title = "Bluesky",
3636+}) => (
3737+ <svg
3838+ xmlns="http://www.w3.org/2000/svg"
3939+ width={size}
4040+ height={size}
4141+ viewBox="0 0 16 16"
4242+ role="img"
4343+ aria-label={title}
4444+ focusable="false"
4545+ style={{ display: "block" }}
4646+ >
4747+ <path
4848+ fill={color}
4949+ d="M3.468 1.948C5.303 3.325 7.276 6.118 8 7.616c.725-1.498 2.698-4.29 4.532-5.668C13.855.955 16 .186 16 2.632c0 .489-.28 4.105-.444 4.692-.572 2.04-2.653 2.561-4.504 2.246 3.236.551 4.06 2.375 2.281 4.2-3.376 3.464-4.852-.87-5.23-1.98-.07-.204-.103-.3-.103-.218 0-.081-.033.014-.102.218-.379 1.11-1.855 5.444-5.231 1.98-1.778-1.825-.955-3.65 2.28-4.2-1.85.315-3.932-.205-4.503-2.246C.28 6.737 0 3.12 0 2.632 0 .186 2.145.955 3.468 1.948"
5050+ />
5151+ </svg>
4852);
49535054export default BlueskyIcon;
+176-134
lib/components/BlueskyPost.tsx
···11-import React, { useMemo } from 'react';
22-import { AtProtoRecord } from '../core/AtProtoRecord';
33-import { BlueskyPostRenderer } from '../renderers/BlueskyPostRenderer';
44-import type { FeedPostRecord, ProfileRecord } from '../types/bluesky';
55-import { useDidResolution } from '../hooks/useDidResolution';
66-import { useAtProtoRecord } from '../hooks/useAtProtoRecord';
77-import { useBlob } from '../hooks/useBlob';
88-import { BLUESKY_PROFILE_COLLECTION } from './BlueskyProfile';
99-import { getAvatarCid } from '../utils/profile';
1010-import { formatDidForLabel } from '../utils/at-uri';
11+import React, { useMemo } from "react";
22+import { AtProtoRecord } from "../core/AtProtoRecord";
33+import { BlueskyPostRenderer } from "../renderers/BlueskyPostRenderer";
44+import type { FeedPostRecord, ProfileRecord } from "../types/bluesky";
55+import { useDidResolution } from "../hooks/useDidResolution";
66+import { useAtProtoRecord } from "../hooks/useAtProtoRecord";
77+import { useBlob } from "../hooks/useBlob";
88+import { BLUESKY_PROFILE_COLLECTION } from "./BlueskyProfile";
99+import { getAvatarCid } from "../utils/profile";
1010+import { formatDidForLabel } from "../utils/at-uri";
11111212/**
1313 * Props for rendering a single Bluesky post with optional customization hooks.
1414 */
1515export interface BlueskyPostProps {
1616- /**
1717- * Decentralized identifier for the repository that owns the post.
1818- */
1919- did: string;
2020- /**
2121- * Record key identifying the specific post within the collection.
2222- */
2323- rkey: string;
2424- /**
2525- * Custom renderer component that receives resolved post data and status flags.
2626- */
2727- renderer?: React.ComponentType<BlueskyPostRendererInjectedProps>;
2828- /**
2929- * React node shown while the post query has not yet produced data or an error.
3030- */
3131- fallback?: React.ReactNode;
3232- /**
3333- * React node displayed while the post fetch is actively loading.
3434- */
3535- loadingIndicator?: React.ReactNode;
3636- /**
3737- * Preferred color scheme to pass through to renderers.
3838- */
3939- colorScheme?: 'light' | 'dark' | 'system';
4040- /**
4141- * Whether the default renderer should show the Bluesky icon.
4242- * Defaults to `true`.
4343- */
4444- showIcon?: boolean;
4545- /**
4646- * Placement strategy for the icon when it is rendered.
4747- * Defaults to `'timestamp'`.
4848- */
4949- iconPlacement?: 'cardBottomRight' | 'timestamp' | 'linkInline';
1616+ /**
1717+ * Decentralized identifier for the repository that owns the post.
1818+ */
1919+ did: string;
2020+ /**
2121+ * Record key identifying the specific post within the collection.
2222+ */
2323+ rkey: string;
2424+ /**
2525+ * Custom renderer component that receives resolved post data and status flags.
2626+ */
2727+ renderer?: React.ComponentType<BlueskyPostRendererInjectedProps>;
2828+ /**
2929+ * React node shown while the post query has not yet produced data or an error.
3030+ */
3131+ fallback?: React.ReactNode;
3232+ /**
3333+ * React node displayed while the post fetch is actively loading.
3434+ */
3535+ loadingIndicator?: React.ReactNode;
3636+ /**
3737+ * Preferred color scheme to pass through to renderers.
3838+ */
3939+ colorScheme?: "light" | "dark" | "system";
4040+ /**
4141+ * Whether the default renderer should show the Bluesky icon.
4242+ * Defaults to `true`.
4343+ */
4444+ showIcon?: boolean;
4545+ /**
4646+ * Placement strategy for the icon when it is rendered.
4747+ * Defaults to `'timestamp'`.
4848+ */
4949+ iconPlacement?: "cardBottomRight" | "timestamp" | "linkInline";
5050}
51515252/**
5353 * Values injected by `BlueskyPost` into a downstream renderer component.
5454 */
5555export type BlueskyPostRendererInjectedProps = {
5656- /**
5757- * Resolved record payload for the post.
5858- */
5959- record: FeedPostRecord;
6060- /**
6161- * `true` while network operations are in-flight.
6262- */
6363- loading: boolean;
6464- /**
6565- * Error encountered during loading, if any.
6666- */
6767- error?: Error;
6868- /**
6969- * The author's public handle derived from the DID.
7070- */
7171- authorHandle: string;
7272- /**
7373- * The DID that owns the post record.
7474- */
7575- authorDid: string;
7676- /**
7777- * Resolved URL for the author's avatar blob, if available.
7878- */
7979- avatarUrl?: string;
8080- /**
8181- * Preferred color scheme bubbled down to children.
8282- */
8383- colorScheme?: 'light' | 'dark' | 'system';
8484- /**
8585- * Placement strategy for the Bluesky icon.
8686- */
8787- iconPlacement?: 'cardBottomRight' | 'timestamp' | 'linkInline';
8888- /**
8989- * Controls whether the icon should render at all.
9090- */
9191- showIcon?: boolean;
9292- /**
9393- * Fully qualified AT URI of the post, when resolvable.
9494- */
9595- atUri?: string;
9696- /**
9797- * Optional override for the rendered embed contents.
9898- */
9999- embed?: React.ReactNode;
5656+ /**
5757+ * Resolved record payload for the post.
5858+ */
5959+ record: FeedPostRecord;
6060+ /**
6161+ * `true` while network operations are in-flight.
6262+ */
6363+ loading: boolean;
6464+ /**
6565+ * Error encountered during loading, if any.
6666+ */
6767+ error?: Error;
6868+ /**
6969+ * The author's public handle derived from the DID.
7070+ */
7171+ authorHandle: string;
7272+ /**
7373+ * The DID that owns the post record.
7474+ */
7575+ authorDid: string;
7676+ /**
7777+ * Resolved URL for the author's avatar blob, if available.
7878+ */
7979+ avatarUrl?: string;
8080+ /**
8181+ * Preferred color scheme bubbled down to children.
8282+ */
8383+ colorScheme?: "light" | "dark" | "system";
8484+ /**
8585+ * Placement strategy for the Bluesky icon.
8686+ */
8787+ iconPlacement?: "cardBottomRight" | "timestamp" | "linkInline";
8888+ /**
8989+ * Controls whether the icon should render at all.
9090+ */
9191+ showIcon?: boolean;
9292+ /**
9393+ * Fully qualified AT URI of the post, when resolvable.
9494+ */
9595+ atUri?: string;
9696+ /**
9797+ * Optional override for the rendered embed contents.
9898+ */
9999+ embed?: React.ReactNode;
100100};
101101102102/** NSID for the canonical Bluesky feed post collection. */
103103-export const BLUESKY_POST_COLLECTION = 'app.bsky.feed.post';
103103+export const BLUESKY_POST_COLLECTION = "app.bsky.feed.post";
104104105105/**
106106 * Fetches a Bluesky feed post, resolves metadata such as author handle and avatar,
···116116 * @param iconPlacement - Determines where the icon is positioned in the rendered post. Defaults to `'timestamp'`.
117117 * @returns A component that renders loading/fallback states and the resolved post.
118118 */
119119-export const BlueskyPost: React.FC<BlueskyPostProps> = ({ did: handleOrDid, rkey, renderer, fallback, loadingIndicator, colorScheme, showIcon = true, iconPlacement = 'timestamp' }) => {
120120- const { did: resolvedDid, handle, loading: resolvingIdentity, error: resolutionError } = useDidResolution(handleOrDid);
121121- const repoIdentifier = resolvedDid ?? handleOrDid;
122122- const { record: profile } = useAtProtoRecord<ProfileRecord>({ did: repoIdentifier, collection: BLUESKY_PROFILE_COLLECTION, rkey: 'self' });
123123- const avatarCid = getAvatarCid(profile);
119119+export const BlueskyPost: React.FC<BlueskyPostProps> = ({
120120+ did: handleOrDid,
121121+ rkey,
122122+ renderer,
123123+ fallback,
124124+ loadingIndicator,
125125+ colorScheme,
126126+ showIcon = true,
127127+ iconPlacement = "timestamp",
128128+}) => {
129129+ const {
130130+ did: resolvedDid,
131131+ handle,
132132+ loading: resolvingIdentity,
133133+ error: resolutionError,
134134+ } = useDidResolution(handleOrDid);
135135+ const repoIdentifier = resolvedDid ?? handleOrDid;
136136+ const { record: profile } = useAtProtoRecord<ProfileRecord>({
137137+ did: repoIdentifier,
138138+ collection: BLUESKY_PROFILE_COLLECTION,
139139+ rkey: "self",
140140+ });
141141+ const avatarCid = getAvatarCid(profile);
124142125125- const Comp: React.ComponentType<BlueskyPostRendererInjectedProps> = renderer ?? ((props) => <BlueskyPostRenderer {...props} />);
143143+ const Comp: React.ComponentType<BlueskyPostRendererInjectedProps> = useMemo(
144144+ () => renderer ?? ((props) => <BlueskyPostRenderer {...props} />),
145145+ [renderer]
146146+ );
126147127127- const displayHandle = handle ?? (handleOrDid.startsWith('did:') ? undefined : handleOrDid);
128128- const authorHandle = displayHandle ?? formatDidForLabel(resolvedDid ?? handleOrDid);
129129- const atUri = resolvedDid ? `at://${resolvedDid}/${BLUESKY_POST_COLLECTION}/${rkey}` : undefined;
148148+ const displayHandle =
149149+ handle ?? (handleOrDid.startsWith("did:") ? undefined : handleOrDid);
150150+ const authorHandle =
151151+ displayHandle ?? formatDidForLabel(resolvedDid ?? handleOrDid);
152152+ const atUri = resolvedDid
153153+ ? `at://${resolvedDid}/${BLUESKY_POST_COLLECTION}/${rkey}`
154154+ : undefined;
130155131131- const Wrapped = useMemo(() => {
132132- const WrappedComponent: React.FC<{ record: FeedPostRecord; loading: boolean; error?: Error }> = (props) => {
133133- const { url: avatarUrl } = useBlob(repoIdentifier, avatarCid);
134134- return (
135135- <Comp
136136- {...props}
137137- authorHandle={authorHandle}
138138- authorDid={repoIdentifier}
139139- avatarUrl={avatarUrl}
140140- colorScheme={colorScheme}
141141- iconPlacement={iconPlacement}
142142- showIcon={showIcon}
143143- atUri={atUri}
144144- />
145145- );
146146- };
147147- WrappedComponent.displayName = 'BlueskyPostWrappedRenderer';
148148- return WrappedComponent;
149149- }, [Comp, repoIdentifier, avatarCid, authorHandle, colorScheme, iconPlacement, showIcon, atUri]);
156156+ const Wrapped = useMemo(() => {
157157+ const WrappedComponent: React.FC<{
158158+ record: FeedPostRecord;
159159+ loading: boolean;
160160+ error?: Error;
161161+ }> = (props) => {
162162+ const { url: avatarUrl } = useBlob(repoIdentifier, avatarCid);
163163+ return (
164164+ <Comp
165165+ {...props}
166166+ authorHandle={authorHandle}
167167+ authorDid={repoIdentifier}
168168+ avatarUrl={avatarUrl}
169169+ colorScheme={colorScheme}
170170+ iconPlacement={iconPlacement}
171171+ showIcon={showIcon}
172172+ atUri={atUri}
173173+ />
174174+ );
175175+ };
176176+ WrappedComponent.displayName = "BlueskyPostWrappedRenderer";
177177+ return WrappedComponent;
178178+ }, [
179179+ Comp,
180180+ repoIdentifier,
181181+ avatarCid,
182182+ authorHandle,
183183+ colorScheme,
184184+ iconPlacement,
185185+ showIcon,
186186+ atUri,
187187+ ]);
150188151151- if (!displayHandle && resolvingIdentity) {
152152- return <div style={{ padding: 8 }}>Resolving handle…</div>;
153153- }
154154- if (!displayHandle && resolutionError) {
155155- return <div style={{ padding: 8, color: 'crimson' }}>Could not resolve handle.</div>;
156156- }
189189+ if (!displayHandle && resolvingIdentity) {
190190+ return <div style={{ padding: 8 }}>Resolving handle…</div>;
191191+ }
192192+ if (!displayHandle && resolutionError) {
193193+ return (
194194+ <div style={{ padding: 8, color: "crimson" }}>
195195+ Could not resolve handle.
196196+ </div>
197197+ );
198198+ }
157199158158- return (
159159- <AtProtoRecord<FeedPostRecord>
160160- did={repoIdentifier}
161161- collection={BLUESKY_POST_COLLECTION}
162162- rkey={rkey}
163163- renderer={Wrapped}
164164- fallback={fallback}
165165- loadingIndicator={loadingIndicator}
166166- />
167167- );
200200+ return (
201201+ <AtProtoRecord<FeedPostRecord>
202202+ did={repoIdentifier}
203203+ collection={BLUESKY_POST_COLLECTION}
204204+ rkey={rkey}
205205+ renderer={Wrapped}
206206+ fallback={fallback}
207207+ loadingIndicator={loadingIndicator}
208208+ />
209209+ );
168210};
169211170170-export default BlueskyPost;212212+export default BlueskyPost;
···11// Master exporter for the AT React component library.
2233// Providers & core primitives
44-export * from './providers/AtProtoProvider';
55-export * from './core/AtProtoRecord';
44+export * from "./providers/AtProtoProvider";
55+export * from "./core/AtProtoRecord";
6677// Components
88-export * from './components/BlueskyIcon';
99-export * from './components/BlueskyPost';
1010-export * from './components/BlueskyPostList';
1111-export * from './components/BlueskyProfile';
1212-export * from './components/BlueskyQuotePost';
1313-export * from './components/ColorSchemeToggle';
1414-export * from './components/LeafletDocument';
1515-export * from './components/TangledString';
88+export * from "./components/BlueskyIcon";
99+export * from "./components/BlueskyPost";
1010+export * from "./components/BlueskyPostList";
1111+export * from "./components/BlueskyProfile";
1212+export * from "./components/BlueskyQuotePost";
1313+export * from "./components/ColorSchemeToggle";
1414+export * from "./components/LeafletDocument";
1515+export * from "./components/TangledString";
16161717// Hooks
1818-export * from './hooks/useAtProtoRecord';
1919-export * from './hooks/useBlob';
2020-export * from './hooks/useBlueskyProfile';
2121-export * from './hooks/useColorScheme';
2222-export * from './hooks/useDidResolution';
2323-export * from './hooks/useLatestRecord';
2424-export * from './hooks/usePaginatedRecords';
2525-export * from './hooks/usePdsEndpoint';
1818+export * from "./hooks/useAtProtoRecord";
1919+export * from "./hooks/useBlob";
2020+export * from "./hooks/useBlueskyProfile";
2121+export * from "./hooks/useColorScheme";
2222+export * from "./hooks/useDidResolution";
2323+export * from "./hooks/useLatestRecord";
2424+export * from "./hooks/usePaginatedRecords";
2525+export * from "./hooks/usePdsEndpoint";
26262727// Renderers
2828-export * from './renderers/BlueskyPostRenderer';
2929-export * from './renderers/BlueskyProfileRenderer';
3030-export * from './renderers/LeafletDocumentRenderer';
3131-export * from './renderers/TangledStringRenderer';
2828+export * from "./renderers/BlueskyPostRenderer";
2929+export * from "./renderers/BlueskyProfileRenderer";
3030+export * from "./renderers/LeafletDocumentRenderer";
3131+export * from "./renderers/TangledStringRenderer";
32323333// Types
3434-export * from './types/bluesky';
3535-export * from './types/leaflet';
3434+export * from "./types/bluesky";
3535+export * from "./types/leaflet";
36363737// Utilities
3838-export * from './utils/at-uri';
3939-export * from './utils/atproto-client';
4040-export * from './utils/profile';
3838+export * from "./utils/at-uri";
3939+export * from "./utils/atproto-client";
4040+export * from "./utils/profile";
···11// Re-export precise lexicon types from @atcute/bluesky instead of redefining.
22-import type { AppBskyFeedPost, AppBskyActorProfile } from '@atcute/bluesky';
22+import type { AppBskyFeedPost, AppBskyActorProfile } from "@atcute/bluesky";
3344// The atcute lexicon modules expose Main interface for record input shapes.
55export type FeedPostRecord = AppBskyFeedPost.Main;