-
Notifications
You must be signed in to change notification settings - Fork 10
feat: add WpMediaUpload field type for WordPress Media Library #84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
be38ddd
0178186
7c86dd3
e676113
324cf2a
2726132
7a13371
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| import type { Meta, StoryObj } from '@storybook/react'; | ||
| import { fn } from 'storybook/test'; | ||
| import { useState } from 'react'; | ||
| import { WpMediaUpload, WpMediaUploadMultiple } from './WpMediaUpload'; | ||
|
|
||
| // ── Mock wp.media for Storybook (not available outside WordPress) ───────────── | ||
|
|
||
| const SAMPLE_IMAGE = 'https://placehold.co/400x400/e2e8f0/475569?text=Logo'; | ||
| const SAMPLE_IMAGES = [ | ||
| 'https://placehold.co/400x400/e2e8f0/475569?text=Image+1', | ||
| 'https://placehold.co/400x400/dbeafe/1d4ed8?text=Image+2', | ||
| 'https://placehold.co/400x400/dcfce7/15803d?text=Image+3', | ||
| ]; | ||
|
|
||
| function mockWpMedia( multiple = false ) { | ||
| ( window as any ).wp = { | ||
| media: ( _options: object ) => { | ||
| let selectCb: (() => void) | null = null; | ||
| const urls = multiple ? SAMPLE_IMAGES.slice( 0, 2 ) : [ SAMPLE_IMAGE ]; | ||
| return { | ||
| on: ( event: string, cb: () => void ) => { | ||
| if ( event === 'select' ) selectCb = cb; | ||
| }, | ||
| once: ( event: string, cb: () => void ) => { | ||
| if ( event === 'select' ) selectCb = cb; | ||
| }, | ||
| open: () => { | ||
| // Simulate async media selection | ||
| setTimeout( () => selectCb?.(), 300 ); | ||
| }, | ||
| state: () => ( { | ||
| get: ( key: string ) => { | ||
| if ( key !== 'selection' ) return null; | ||
| if ( multiple ) { | ||
| const items = urls.map( ( url ) => ( { toJSON: () => ( { url } ) } ) ); | ||
| return { | ||
| map: ( fn: ( a: any ) => any ) => items.map( fn ), | ||
|
Check warning on line 37 in src/components/wordpress/WpMediaUpload.stories.tsx
|
||
| each: ( fn: ( a: any ) => void ) => items.forEach( fn ), | ||
| pop: () => items.pop(), | ||
| }; | ||
| } | ||
| const item = { toJSON: () => ( { url: urls[0] } ) }; | ||
| return { | ||
| map: ( fn: ( a: any ) => any ) => [ item ].map( fn ), | ||
| each: ( fn: ( a: any ) => void ) => [ item ].forEach( fn ), | ||
| first: () => item, | ||
| pop: () => item.toJSON(), | ||
| }; | ||
| }, | ||
| } ), | ||
| }; | ||
| }, | ||
| }; | ||
| } | ||
|
|
||
| // ── Single ──────────────────────────────────────────────────────────────────── | ||
|
|
||
| const SingleMeta = { | ||
| title: 'WordPress/WpMediaUpload', | ||
| component: WpMediaUpload, | ||
| parameters: { layout: 'centered' }, | ||
| tags: ['autodocs'], | ||
| args: { | ||
| onChange: fn(), | ||
| }, | ||
| argTypes: { | ||
| value: { control: 'text' }, | ||
| btnText: { control: 'text' }, | ||
| disabled: { control: 'boolean' }, | ||
| }, | ||
| decorators: [ | ||
| ( Story: any ) => { | ||
| mockWpMedia( false ); | ||
| return <Story />; | ||
| }, | ||
| ], | ||
| } satisfies Meta<typeof WpMediaUpload>; | ||
|
|
||
| export default SingleMeta; | ||
|
|
||
| type SingleStory = StoryObj<typeof SingleMeta>; | ||
|
|
||
| export const Empty: SingleStory = { | ||
| args: { | ||
| btnText: 'Upload Logo', | ||
| }, | ||
| }; | ||
|
|
||
| export const WithPreview: SingleStory = { | ||
| args: { | ||
| value: SAMPLE_IMAGE, | ||
| btnText: 'Upload Logo', | ||
| }, | ||
| }; | ||
|
|
||
| export const Disabled: SingleStory = { | ||
| args: { | ||
| value: SAMPLE_IMAGE, | ||
| btnText: 'Upload Logo', | ||
| disabled: true, | ||
| }, | ||
| }; | ||
|
|
||
| /** Interactive — click "Upload Image" to simulate a media library selection. */ | ||
| export const Interactive: SingleStory = { | ||
| render: ( args ) => { | ||
| const [ value, setValue ] = useState( args.value ?? '' ); | ||
|
Check failure on line 107 in src/components/wordpress/WpMediaUpload.stories.tsx
|
||
| return <WpMediaUpload { ...args } value={ value } onChange={ setValue } />; | ||
| }, | ||
| args: {}, | ||
| }; | ||
|
|
||
| // ── Multiple ────────────────────────────────────────────────────────────────── | ||
|
|
||
| export const Multiple: StoryObj<typeof WpMediaUploadMultiple> = { | ||
| render: () => { | ||
| const [ values, setValues ] = useState<string[]>( [] ); | ||
|
Check failure on line 117 in src/components/wordpress/WpMediaUpload.stories.tsx
|
||
| mockWpMedia( true ); | ||
| return ( | ||
| <WpMediaUploadMultiple | ||
| value={ values } | ||
| onChange={ setValues } | ||
| btnText="Add Images" | ||
| /> | ||
| ); | ||
| }, | ||
| }; | ||
|
|
||
| export const MultipleWithExisting: StoryObj<typeof WpMediaUploadMultiple> = { | ||
| render: () => { | ||
| const [ values, setValues ] = useState<string[]>( SAMPLE_IMAGES ); | ||
|
Check failure on line 131 in src/components/wordpress/WpMediaUpload.stories.tsx
|
||
| mockWpMedia( true ); | ||
| return ( | ||
| <WpMediaUploadMultiple | ||
| value={ values } | ||
| onChange={ setValues } | ||
| btnText="Add Images" | ||
| /> | ||
| ); | ||
| }, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,144 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import React from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Upload, X } from 'lucide-react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { cn } from '@/lib/utils'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Button } from '@/components/ui/button'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import wpMedia from '@/lib/WpMedia'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ─── Single ─────────────────────────────────────────────────────────────────── | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface WpMediaUploadProps { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onChange: ( url: string ) => void; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| btnText?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled?: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function WpMediaUpload( { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onChange, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| btnText = 'Upload Image', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: WpMediaUploadProps ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleUpload = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wpMedia( ( file ) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const url = Array.isArray( file ) ? ( file[0]?.url ?? '' ) : ( file as { url: string } ).url; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onChange( url ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className={ cn( 'flex flex-col items-end gap-2', className ) }> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { value && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="relative inline-flex"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <img | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| src={ value } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alt="" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className="h-16 w-16 rounded-md border border-border bg-muted object-contain p-1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="button" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled={ disabled } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title="Remove" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={ () => onChange( '' ) } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className="absolute -right-2 -top-2 flex h-4 w-4 items-center justify-center rounded-full bg-destructive text-white hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <X size={ 10 } strokeWidth={ 3 } /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="button" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| variant="outline" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size="sm" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled={ disabled } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={ handleUpload } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className="gap-1.5" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Upload size={ 14 } /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { value ? 'Change' : btnText } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ─── Multiple ───────────────────────────────────────────────────────────────── | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export interface WpMediaUploadMultipleProps { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value?: string[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onChange: ( urls: string[] ) => void; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| btnText?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled?: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function WpMediaUploadMultiple( { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value = [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onChange, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| btnText = 'Add Images', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: WpMediaUploadMultipleProps ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleUpload = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // @ts-expect-error wp.media is not defined in the global scope | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const frame = wp.media( { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: 'Select Images', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| button: { text: 'Add' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| multiple: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| frame.once( 'select', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const selection = frame.state().get( 'selection' ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const newUrls: string[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selection.each( ( attachment: { toJSON: () => { url: string } } ) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| newUrls.push( attachment.toJSON().url ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onChange( [ ...value, ...newUrls ] ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| frame.open(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const remove = ( index: number ) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onChange( value.filter( ( _, i ) => i !== index ) ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className={ cn( 'flex flex-col items-end gap-2', className ) }> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { value.length > 0 && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex flex-wrap justify-end gap-2"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { value.map( ( url, i ) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div key={ i } className="relative inline-flex"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <img | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| src={ url } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alt="" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className="h-14 w-14 rounded-md border border-border bg-muted object-contain p-1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="button" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled={ disabled } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title="Remove" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={ () => remove( i ) } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className="absolute -right-1.5 -top-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-destructive text-white hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <X size={ 10 } strokeWidth={ 3 } /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) ) } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+111
to
+128
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using array index as React key when items can be removed. Using 🔧 Proposed fix- { value.map( ( url, i ) => (
- <div key={ i } className="relative inline-flex">
+ { value.map( ( url ) => (
+ <div key={ url } className="relative inline-flex">
<img
src={ url }
alt=""
className="h-14 w-14 rounded-md border border-border bg-muted object-contain p-1"
/>
<button
type="button"
disabled={ disabled }
title="Remove"
- onClick={ () => remove( i ) }
+ onClick={ () => onChange( value.filter( ( v ) => v !== url ) ) }
className="absolute -right-1.5 -top-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-destructive text-white hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50"
>
<X size={ 10 } strokeWidth={ 3 } />
</button>
</div>
) ) }Note: If duplicate URLs are valid, consider using 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="button" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| variant="outline" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size="sm" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled={ disabled } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={ handleUpload } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className="gap-1.5" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Upload size={ 14 } /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { btnText } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: getdokan/plugin-ui
Length of output: 306
🏁 Script executed:
Repository: getdokan/plugin-ui
Length of output: 4760
Align mock
selection.pop()return shape between single and multiple modesLine 39 returns an item object (with
toJSONmethod) in multiple mode, while line 47 returns a plain serialized object in single mode. Though the current consumers inWpMedia.tsandWpMediaUpload.tsxonly usemap()andeach(), this inconsistency can cause regressions if future code callspop()expecting a model object with atoJSONmethod. Normalize both modes to return item objects consistently.🤖 Prompt for AI Agents