refactor(packages)!: replace button availability with disabled and hidden state - #1474
Conversation
✅ Deploy Preview for vjs10-site ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📦 Bundle Size Report🎨 @videojs/html — no changesPresets (7)
Media (12)
Players (5)
Skins (30)
UI Components (39)
Sizes are marginal over the root entry point. ⚛️ @videojs/react — no changesPresets (7)
Media (11)
Skins (27)
UI Components (33)
Sizes are marginal over the root entry point. 🧩 @videojs/core — no changesEntries (73)
🏷️ @videojs/element — no changesEntries (2)
📦 @videojs/store — no changesEntries (3)
🔧 @videojs/utils — no changesEntries (12)
📦 @videojs/media — no changesEntries (14)
📦 @videojs/spf — no changesEntries (5)
ℹ️ How to interpretJS sizes are initial static graph totals (minified + brotli). Lazy dynamic chunks are shown separately when present.
Run |
8bcff00 to
d5c1de0
Compare
7debc81 to
3f57e8a
Compare
9e5f8b8 to
4fe11f7
Compare
…dden state Cast, fullscreen, and pip buttons now expose `disabled` (non-interactive) and `hidden` (unsupported) state derived from `availability` and the `disabled` prop, instead of relying on the raw availability enum at the attribute layer. - `getAttrs` returns `aria-disabled` from state and the native HTML `hidden` attribute when the feature is unsupported. New `data-disabled` and `data-hidden` data attribute mappings ride along. - `toggle` short-circuits on `state.disabled` and otherwise awaits the underlying media call directly, propagating errors to the caller instead of swallowing them. - `MediaButtonElement` and `createMediaButton` now wrap the activation in try/catch with a `__DEV__` console.error and rethrow so callers see the original failure. - React buttons pass `isSupported: (s) => !s.hidden` so unsupported features render `null` rather than a hidden `<button>`. Aligns with the WAI-ARIA APG toolbar pattern (focusable disabled controls) documented in `internal/design/ui/disabled-hidden.md`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace `data-[availability=...]:hidden` with `data-[disabled]` styling classes to match the new disabled/hidden button state model. Hidden buttons use the native HTML hidden attribute; disabled buttons get reduced opacity and grayscale via data-disabled. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PiP is unsupported on WebKit so the button receives the `hidden` attribute and is removed from the layout. Only assert `data-availability` when the pip button is visible. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tons Update the fullscreen and pip button reference pages plus the features concept page to describe the new `disabled`/`hidden` state model: HTML `hidden` for unsupported environments (or `null` in React) and `data-disabled` for non-interactive styling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the two pre-existing fields alongside the newly added disabled/hidden so the component reference table renders complete descriptions for every cast button state property. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The skin's `display: flex` (and `grid` on the icon variant) outranks the
user-agent `[hidden] { display: none }` rule on specificity, so feature
buttons stayed visible when the cast/fullscreen/pip cores set the native
`hidden` attribute.
Add a `&[hidden] { display: none }` rule under the high-specificity
skin selector in both default and minimal CSS, and a `[&[hidden]]:hidden`
class in the Tailwind variants so the same override works for the
Tailwind-compiled skins.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…omponent override Move the native `hidden` attribute override from the button component into the skin reset so any authored template that sets `[hidden]` stays hidden, not just media buttons. Use the doubled `[hidden][hidden]` selector under the skin root to outrank component-level `display: flex/grid` declarations. The Tailwind root composition gets the equivalent `[&_[hidden][hidden]]:hidden` class. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The captions button previously relied on the now-removed `data-availability="unavailable"` skin rule to hide itself when no caption tracks were present. Extend the same `disabled`/`hidden` model already applied to cast/fullscreen/pip buttons so it stays hidden in that state without depending on availability-specific CSS. - Add `disabled` and `hidden` to `CaptionsButtonState`, derived from the `disabled` prop and whether any caption/subtitle tracks exist. - `getAttrs` returns `aria-disabled` from state and the native HTML `hidden` attribute when no tracks are available. - `toggle` short-circuits on `state.disabled`. - `data-disabled` and `data-hidden` data attribute mappings ride along. - React captions button passes `isSupported: (s) => !s.hidden` so it renders `null` when no tracks are present. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously unavailable buttons used `display: none`, which masked the
`:active { scale: 0.98 }` rule. Now that `[data-disabled]` keeps the
button visible but non-interactive, guard the press animation with
`:not([disabled]):not([data-disabled])` (and the Tailwind equivalent
`not-disabled:not-data-disabled:active:*`) so disabled buttons no
longer give misleading press feedback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7ad1ccb to
f7097b2
Compare
|
|
||
| async toggle(state: MediaRemotePlaybackState): Promise<void> { | ||
| if (this.#props.disabled) return; | ||
| async toggle(media: MediaRemotePlaybackState): Promise<void> { |
There was a problem hiding this comment.
question: is it state or media - the type looks like a state? Ideally they should match?
There was a problem hiding this comment.
I'll have to follow-up and look into how state was modelled for AirPlay.
| /** Non-interactive but still focusable (mirrors `aria-disabled`). */ | ||
| disabled: boolean; | ||
| /** Whether the button is hidden until AirPlay is available. */ | ||
| hidden: boolean; |
There was a problem hiding this comment.
nit(non-blocking): we seem to repeat this a lot, is it worth having it in a shared/common button type perhaps? Same for the data attributes.
There was a problem hiding this comment.
Right now for the state and mainly data attrs we're intentionally repetitive to simplify the API extraction. It keeps it simple and easy to review/read per component. Leaving it for now but happy to revisit.
Replace the
availableboolean on buttons withdisabledandhiddenstates that follow standard ARIA patterns —aria-disabledfor non-interactive controls and HTMLhiddenfor unsupported features.Note
High Risk
Wide breaking API and UX change across core, HTML, React, and skins (including Cast state rename and when controls appear), affecting accessibility, toolbars, and integrators who styled
data-availability.Overview
Breaking change: toolbar media buttons now expose derived
disabledandhiddenstate (plusdata-disabled/data-hidden) instead of relying on skins or consumer CSS to hide controls viadata-availability.Non-interactive controls use
aria-disabledfrom core state (including when a feature isn’t ready), while useless controls are removed with the nativehiddenattribute on HTML custom elements andnullin React via a newisSupportedhook oncreateMediaButton. Rawdata-availabilityis still exposed for styling and debugging.Per-control rules differ: PiP, fullscreen, AirPlay, and captions hide until
available; Cast hides only whenunsupportedbut stays visible andaria-disabledwhen supported with no device.CastButtonstate renamescastState→connection.togglepaths recompute disabled state before acting; Cast/fullscreen/PiP can propagate media API errors while HTML/React UI layers catch async rejections in dev.Skins drop availability-based
display: noneand[disabled]styling in favor ofaria-disabled. Docs, demos, e2e (e.g. PiP on WebKit), and an internal disabled/hidden design note are updated to match.Reviewed by Cursor Bugbot for commit fa204b0. Bugbot is set up for automated code reviews on this repo. Configure here.