@airdraft/content
v0.1.6
Published
Airdraft framework-agnostic content rendering utilities — URL resolution, Markdown parsing, relation helpers
Readme
@airdraft/content
Framework-agnostic pure functions for resolving and parsing Airdraft CMS content. No React required — safe to use in server actions, API routes, generateMetadata, middleware, or any non-React context.
Installation
npm install @airdraft/contentMedia / Image
import {
resolveMediaUrl,
resolveMediaUrls,
resolveImageDimensions,
} from '@airdraft/content'resolveMediaUrl(fieldName, data)
Resolves a single media or image field to a URL string.
Resolution chain (first truthy wins):
data["{field}_media"].url— managed media object URLdata["{field}_url"]— raw URL stored alongside the keydata["{field}"]as string — raw storage key, prefixed with/if relative
const url = resolveMediaUrl('cover', entry.data)
// → 'https://cdn.example.com/covers/my-post.jpg' | undefinedUseful for <meta property="og:image">, next/image src, or any place you need the URL value rather than a rendered element.
resolveMediaUrls(fieldName, data)
Resolves a media field with multiple: true to an array of URLs.
Resolution chain:
data["{field}_medias"]— injectedMediaItem[]→ extracts.urlfrom eachdata["{field}_urls"]— injectedstring[]data["{field}"]— rawstring[]or JSON-encodedstring[]
const urls = resolveMediaUrls('gallery', entry.data)
// → ['https://...', 'https://...']resolveImageDimensions(fieldName, data)
Reads width and height from the {field}_media sidecar object. Returns undefined when the media object is absent or has no dimension data.
const dims = resolveImageDimensions('cover', entry.data)
// → { width: 1200, height: 630 } | undefinedCombine with resolveMediaUrl to pass explicit dimensions to next/image and avoid layout shift:
const url = resolveMediaUrl('cover', entry.data)
const dims = resolveImageDimensions('cover', entry.data)
// In a Next.js page / generateMetadata:
return {
openGraph: { images: [{ url, ...dims }] },
}
// Or in a component:
<Image src={url} alt="cover" width={dims?.width ?? 800} height={dims?.height ?? 450} />resolveImageUrl (alias)
Legacy alias for resolveMediaUrl. Prefer resolveMediaUrl for new media-typed fields.
Body / Rich-text
import { parseMarkdown, parseText } from '@airdraft/content'parseMarkdown(text)
Parses a Markdown string to an HTML string via marked. Safe for use with dangerouslySetInnerHTML — content is CMS-authored, not user-supplied.
const html = parseMarkdown(entry.data.body)
// → '<h1>Hello</h1><p>World</p>'parseText(text)
Splits a plain text field into paragraphs (split on \n\n). Returns string[]. Useful when you want to render paragraphs manually without dangerouslySetInnerHTML.
const paragraphs = parseText(entry.data.excerpt)
// → ['First paragraph.', 'Second paragraph.']Relations
import { resolveRelation, resolveRelations } from '@airdraft/content'resolveRelation(fieldName, data)
Resolves the display label for a single relation field. Handles both expanded entry objects (returned when expand=true) and raw slug strings.
Label priority: name → title → label → slug.
const label = resolveRelation('author', entry.data)
// → 'Jane Doe' | 'jane-doe' | nullresolveRelations(fieldName, data)
Same as resolveRelation but for relations (multi-relation) fields. Returns string[].
const labels = resolveRelations('authors', entry.data)
// → ['Jane Doe', 'John Smith']Notes
- All functions are synchronous and have no side effects.
resolveImageUrl/resolveMediaUrl/resolveMediaUrlsare used internally by@airdraft/react-contentfield components. Call them directly when you need the resolved value in logic rather than in JSX.parseMarkdownusesmarkedunder the hood. To customise rendering (syntax highlighting, custom link targets, etc.) use therenderprop on<BodyField>from@airdraft/react-contentinstead.
Changelog
See CHANGELOG.md.
