Files
bsky-social-app/src/components/hooks/useRichText.ts
T
Samuel Newman b1a4e1cd16 flip types/bsky sources to #/lexicons, add chat client and strict hook contracts
Phase 3 task 2: types/bsky sibling modules (post/profile/starterPack) now
source from generated #/lexicons with interim dual-world widening aliases
(TODO(phase4) markers). SessionBundle gains a chatClient proxied to
did:web:api.bsky.chat#bsky_chat via useChatClient(). usePdsClient() and
useChatClient() no longer fall back to the public appview when logged out -
they return a client that throws NotAuthenticatedError before any network
I/O; useMaybePdsClient()/useMaybeChatClient() cover logged-out-aware
callers. RichText pilot: useRichText.ts on @bsky.app/sdk/richtext with
detectFacets(pdsClient); RichText.tsx display sink accepts both worlds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 18:07:26 +03:00

42 lines
1.4 KiB
TypeScript

import {useEffect, useState} from 'react'
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {usePdsClient} from '#/state/session'
export function useRichText(text: string): [RichTextAPI, boolean] {
const [prevText, setPrevText] = useState(text)
const [rawRT, setRawRT] = useState(() => new RichTextAPI({text}))
const [resolvedRT, setResolvedRT] = useState<RichTextAPI | null>(null)
/*
* Facet detection resolves handles via `com.atproto.identity.resolveHandle`,
* which the account (PDS) client serves. We standardize on the account client
* where a session is in scope (design section B). Logged out, this is the
* throwing client; `detectFacets` will reject, and the raw (unresolved)
* RichText is returned in the meantime.
*/
const client = usePdsClient()
if (text !== prevText) {
setPrevText(text)
setRawRT(new RichTextAPI({text}))
setResolvedRT(null)
// This will queue an immediate re-render
}
useEffect(() => {
let ignore = false
async function resolveRTFacets() {
// new each time
const resolvedRT = new RichTextAPI({text})
await resolvedRT.detectFacets(client)
if (!ignore) {
setResolvedRT(resolvedRT)
}
}
resolveRTFacets()
return () => {
ignore = true
}
}, [text, client])
const isResolving = resolvedRT === null
return [resolvedRT ?? rawRT, isResolving]
}