feat(packages): resolve the poster from the store, not from markup - #2010
feat(packages): resolve the poster from the store, not from markup#2010decepulis wants to merge 2 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📦 Bundle Size Report🎨 @videojs/html
Small changes (15, ≤ 300 B)
Presets (7)
Media (13)
Players (5)
Skins (30)
UI Components (40)
⚛️ @videojs/react — 24 small size changes
Presets (7)
Media (12)
Skins (27)
UI Components (34)
🧩 @videojs/core — 1 small size change
Entries (76)
🏷️ @videojs/element — no changesEntries (2)
📦 @videojs/store — no changesEntries (3)
🔧 @videojs/utils — no changesEntries (13)
📦 @videojs/jsx — no changesEntries (3)
📦 @videojs/media — no changesEntries (15)
📦 @videojs/spf — no changesEntries (5)
ℹ️ How to interpretEach entry is independently bundled, minified, and brotli-compressed. Initial size includes its static import graph; lazy dynamic chunks are reported separately. Entries are not additive because their dependency graphs overlap. Preset rows represent realistic combined bundles. Changes of 300 B or less across initial, lazy, and total size are collapsed, not discarded. Run |
ea57f4e to
1211fed
Compare
b875d68 to
0c81705
Compare
1211fed to
a7e5054
Compare
0c81705 to
e807ada
Compare
The poster URL was configured in markup — an `<img slot="poster">` in HTML, a `poster` prop on the React skin. That left content configuration in the skin's hands, made it unreachable from a hand-authored layout, and left the store's resolved `poster` with no reader at all. The URL now comes from the metadata feature, so a packaged skin, an ejected one, and a layout you wrote yourself all inherit the same resolution chain. Rendering an image is what that requires, so each binding renders one — as a default, not a takeover: - React renders the `<img>` it always did. `src` fills in from the store when you do not pass one; every other image attribute is untouched, and `render` receives the resolved `src` so it can reach `next/image`. - HTML owns an `<img part="img">` in a shadow root, beside the slot. Supply an image and the owned one is hidden and its `src` removed — an image that is not rendered still downloads. `data-loaded` moves to the host, because a selector cannot reach past `::part()` to read an attribute. The skins style three images: the owned part, one slotted through a skin, and one inlined by an ejected skin. That third selector fixes a pre-existing bug where an ejected Tailwind skin rendered the poster unpositioned. Refs #1798
Rewrite the poster reference around the image the component renders: how to supply your own, how to reach the owned one as a part, and what `data-loaded` is for. Move the poster URL onto the provider in the demos, the home page, and the skin examples. Refs #1798
a7e5054 to
09b3a5e
Compare
e807ada to
dcaa7e6
Compare
|
Closing in favour of #2039, which takes the compound-image route: What carried over from here: the store-resolved poster on the metadata feature, What #2039 does differently: no owned image, so no The Generated by Claude Code |
Stacked on #2009. Closes #1798.
The problem
The poster was configured in markup: an
imgcarryingslot="poster"in HTML, aposterprop on the React skin. That put content configuration in the skin's hands, made it unreachable from a hand-authored layout, and left the store's resolvedposter— user, media, user default — with no reader.The change
Before, in HTML:
After:
<video-player poster="poster.jpg"> <video-skin> <video src="video.mp4" playsinline></video> </video-skin> </video-player>Before, in React:
After:
PosterCorecomposesplaybackandmetadata, so the chain is written and tested once and every consumer inherits it: a packaged skin, an ejected one, a layout you wrote yourself.BaseVideoSkinPropsis gone — the video skins take the same three props the audio ones always did.Rendering an image without taking it away
internal/design/ui/poster.mdtreats author control of the image as the point of the component, and that still holds. The store supplies a default, it doesn't take over.React's
Posterstays theimgit was.srcfills in from the store when none is passed; every other image attribute is untouched.It also gains
alt=""— it had noaltat all, so screen readers announced the URL.HTML is the harder half, because
media-posternever rendered an image; it positioned one you supplied. It now owns animgcarryingpart="img"in a shadow root, beside a slot, the same shapemedia-thumbnailalready uses. Fill the slot and the owned image steps aside:Hiding it isn't enough on its own: an image that isn't rendered still downloads, which is not hypothetical now that Mux and Vimeo donate posters. The
srcis withheld too.Why
assignedElements({ flatten: true })A skin forwards its own
slotcarryingname="poster"into the element, and that empty slot is itself an assigned node — so counting assigned nodes finds one whether or not you supplied anything. Verified in Chromium:Same reason the owned image sits beside the slot rather than inside it as fallback content: fallback renders only when nothing is assigned, and inside a skin something always is.
Why
data-loadedmoved to the hostA selector can't reach past
::part()to read an attribute.media-poster:not([data-loaded])::part(img)is expressible;::part(img):not([data-loaded])is not. Skins reach the owned image as a part and leave yours alone, which is what held the blur-up sequence together before.Fixes that fall out
::slotted(img), butsite/scripts/ejected-skins/html.tsinlines a literalimgwhere the slot used to be, which::slottednever matches. All three variants — part, slotted, descendant — are emitted now..media-default-skin > img. It's the explicit.media-posternow, matching the.media-poster-placeholderits sibling uses.Testing
Suites green per package: core 1411, react 406, html 311, media 539, utils 419, skins 4, site 530.
pnpm typecheckreports only the 24 pre-existingpackages/storetest errors;check:workspaceandastro checkclean.New coverage:
PosterCoreresolving the URL; the element rendering it, stepping aside for a slotted image without fetching its own, taking back over when that image is removed, and reporting load on the host; and the React side filling insrc, preferring one passed to it, defaultingalt, and handing the resolvedsrcto arenderoverride.Verified in Chromium across both skins and both stylings: the store-resolved poster paints over the poster placeholder, a slotted image replaces it with the owned one hidden and unfetched, and Tailwind compiles the
[&::part(img)]variants that reach it.🤖 Generated with Claude Code
https://claude.ai/code/session_019fBNWkGLWPzsP4QK6w7u2L