Images — @sonordev/site-kit/images
Sonor-managed image slots with dev-mode editing, focal point support, and image picker.
Usage
import { ManagedImage } from '@sonordev/site-kit/images'
export default function HeroSection() {
return (
<ManagedImage
slotId="hero-background"
alt="Hero background"
width={1920}
height={1080}
objectFit="cover"
fallback="/images/default-hero.jpg"
/>
)
}Props
interface ManagedImageProps {
slotId: string // Unique slot identifier (e.g., 'hero-background')
pagePath?: string // Page-specific slots (defaults to current path)
alt?: string // Fallback alt text
className?: string
width?: number | string
height?: number | string
objectFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'
fallback?: string // Fallback image URL when slot is empty
placeholder?: React.ReactNode // Custom placeholder component
onLoad?: () => void
onError?: (error: Error) => void
priority?: boolean // Eager loading (Next.js Image priority)
style?: React.CSSProperties
forceDevMode?: boolean // Enable dev picker outside localhost
}Dev Mode
Dev mode is on when NODE_ENV is development, on localhost / 127.0.0.1, on any host with ?sonor_dev=true in the URL, or with forceDevMode:
- Click any
ManagedImageto open the image picker modal - Browse files by folder, search, upload new images
- Set alt text and focal point
- Shows slot ID in empty states for debugging
Focal Point
When an image has focal_point_x / focal_point_y set in Sonor, the component auto-calculates object-position so the focal area stays visible during cropping.
API Functions
import { fetchManagedImage, uploadImage, assignImageToSlot } from '@sonordev/site-kit/images'
const image = await fetchManagedImage(slotId, pagePath)
const uploaded = await uploadImage(file, { folder: 'heroes', category: 'background' })
await assignImageToSlot(slotId, uploaded.id, pagePath)Favicon
import { ManagedFavicon } from '@sonordev/site-kit/images'
// In layout <head>:
<ManagedFavicon /> // Fetches Sonor logo as favicon link tags