- ImageBlock/ImageStylePanel: SizeControl width(absorbs old maxWidth
presets)/height, AspectRatioControl + OBJECT_FIT grid + FocalPointGrid for
CSS framing crop (aspect-ratio/object-fit/object-position on the <img>).
Exported <img> always gets loading="lazy" decoding="async", plus width/
height attrs when the style has a plain px length (pxAttr helper).
- VideoBlock/MediaStylePanel: Video URL text input replaced with
AssetPicker(mediaType="video") writing videoUrl (paste-URL still handles
YouTube/Vimeo, upload/browse handle files). Added SizeControl(width) +
AspectRatioControl so the video frame honors real size/aspect instead of
a hardcoded 16:9 (padding-bottom hack replaced with CSS aspect-ratio).
New optional `poster` prop (image AssetPicker) + preload="metadata" on
file-type <video>.
- Gallery: surfaced the existing-but-unexposed `columns` and `lightbox`
props with panel controls.
- All 5 owned components (ImageBlock, VideoBlock, Gallery, ContentSlider,
MapEmbed): added margin/padding (per-side)/border/box-shadow/opacity style
defaults + AnimationControl/VisibilityControl-backed animation/
animationDelay/hideOnDesktop/hideOnTablet/hideOnMobile props. New shared
mediaBoxModel.tsx (package-local, not shared.tsx) DRYs the box-model +
border/effects + animation/visibility panel sections across
ImageStylePanel and MediaStylePanel.
- Tests: extended *.toHtml.test.ts for all 5 components (crop/perf attrs,
video size/aspect/poster/preload, gallery columns/lightbox, box-model
style emission, craft.props presence) + new MediaStylePanel.video.test.tsx
verifying the AssetPicker wiring writes videoUrl/poster and the video-only
size controls are gated on videoUrl. 694 tests green, tsc + vite build
clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>