Skip to content

refactor: Extend PayloadMediaProps with HTML media element attributes#439

Merged
ainsleyclark merged 3 commits intomainfrom
claude/update-payload-types-L8Woy
Mar 17, 2026
Merged

refactor: Extend PayloadMediaProps with HTML media element attributes#439
ainsleyclark merged 3 commits intomainfrom
claude/update-payload-types-L8Woy

Conversation

@ainsleyclark
Copy link
Contributor

Summary

Enhanced the PayloadMediaProps type to support a broader range of HTML media element attributes by intersecting with native HTML attribute types for video, image, and picture elements. Also updated the Media type to allow null values for the alt property.

Key Changes

  • Added imports for HTMLVideoAttributes, HTMLImgAttributes, and HTMLPictureAttributes from svelte/elements
  • Extended PayloadMediaProps to intersect with HTMLVideoAttributes, HTMLImgAttributes, and HTMLPictureAttributes in addition to the existing HTMLAttributes<HTMLElement>
  • Updated the Media.alt property type from string | undefined to string | null for more explicit null handling

Implementation Details

These changes allow the PayloadMediaProps type to properly support attributes specific to video, img, and picture HTML elements, providing better type safety and IDE autocomplete when using media components with these native HTML attributes. The alt property change aligns with how Payload CMS handles optional string fields that can be explicitly set to null.

https://claude.ai/code/session_01JsPYAtAnEtvcMbfWA1tEyz

claude added 2 commits March 17, 2026 08:57
…ompatibility

- Make Media.alt nullable (string | null) to match Payload-generated types
- Extend PayloadMediaProps with HTMLVideoAttributes, HTMLImgAttributes, and
  HTMLPictureAttributes so video props (autoplay, muted, loop, playsinline,
  controls, preload) and img/picture props (srcset, sizes, decoding) can be
  spread onto the rendered element

https://claude.ai/code/session_01JsPYAtAnEtvcMbfWA1tEyz
@claude

This comment has been minimized.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b49991343e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

>;

export type PayloadMediaProps = HTMLAttributes<HTMLElement> & {
export type PayloadMediaProps = HTMLAttributes<HTMLElement> & HTMLVideoAttributes & HTMLImgAttributes & HTMLPictureAttributes & {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove unsupported img attrs from public props

Adding HTMLImgAttributes to PayloadMediaProps makes callers believe image-specific props (for example decoding, fetchpriority, referrerpolicy) will be forwarded, but in the normal image path restProps is spread onto <picture> while the inner <img> does not receive ...restProps (PayloadMedia.svelte non-SVG branch). This means those newly-accepted props are silently ignored for most images, which is a behavioural regression introduced by this type change.

Useful? React with 👍 / 👎.

@claude
Copy link

claude bot commented Mar 17, 2026

Review summary

  • Overall score: 7/10
  • Critical issues: 0
  • Warnings: 2
  • Suggestions: 1
  • Recommendation: ⚠️ Approve with comments

Small, focused change that addresses a real gap. The alt nullable fix is correct and the intent to pass element-specific props is sound. Two type-safety concerns worth addressing before merging.

Critical issues 🔴

None

Warnings 🟡

1. Type intersection may produce never for conflicting properties

Intersecting HTMLVideoAttributes & HTMLImgAttributes & HTMLPictureAttributes means the resulting type must simultaneously satisfy all three. Properties shared across those interfaces but with incompatible types will resolve to never, silently breaking callers at compile time. For example, crossorigin is typed as string | null | undefined in HTMLVideoAttributes but as HTMLCrossorigin | undefined in HTMLImgAttributes — the intersection narrows it further and can catch callers off-guard.

Since the component conditionally renders one element type at a time (isVideo / isImage), a union or overload approach more accurately models the one-of semantics and avoids this narrowing problem.

Suggested alternative
export type PayloadMediaBaseProps = {
  data: Media;
  loading?: 'lazy' | 'eager' | undefined;
  className?: string;
  breakpointBuffer?: number;
  maxWidth?: number | undefined;
  onload?: (event: Event) => void;
};

export type PayloadMediaProps =
  | (PayloadMediaBaseProps & HTMLVideoAttributes)
  | (PayloadMediaBaseProps & HTMLImgAttributes)
  | (PayloadMediaBaseProps & HTMLPictureAttributes);

This correctly models "one of these three element types" and avoids the intersection narrowing issue.

2. HTMLAttributes<HTMLElement> is now redundant

HTMLVideoAttributes, HTMLImgAttributes, and HTMLPictureAttributes all extend HTMLAttributes<HTMLElement> internally, so the explicit HTMLAttributes<HTMLElement> & at the start of the intersection is a no-op. It should be removed to avoid confusion.

Suggestions 🟢

1. restProps is not spread on the inner <img> inside <picture>

Pre-existing, but worth noting: in PayloadMedia.svelte (line 97), {...restProps} is spread onto <picture> but not the inner <img> (lines 105–112). This means ARIA attributes, data-* attributes, and any HTMLImgAttributes passed by the consumer are silently dropped for non-SVG images. The SVG path (line 94) correctly spreads onto <img>. This PR increases the likelihood that consumers will pass img-specific attributes (e.g. decoding, fetchpriority) that never reach the element.

@codecov
Copy link

codecov bot commented Mar 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.26%. Comparing base (7f6b060) to head (0e61aae).
⚠️ Report is 524 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #439      +/-   ##
==========================================
+ Coverage   64.59%   70.26%   +5.67%     
==========================================
  Files         154      187      +33     
  Lines        6064     7439    +1375     
==========================================
+ Hits         3917     5227    +1310     
+ Misses       2064     2012      -52     
- Partials       83      200     +117     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ainsleyclark ainsleyclark merged commit 818860f into main Mar 17, 2026
8 checks passed
@ainsleyclark ainsleyclark deleted the claude/update-payload-types-L8Woy branch March 17, 2026 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants