@wordpress/media-editor 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +788 -0
- package/README.md +121 -0
- package/build/components/media-editor-provider/index.cjs +59 -0
- package/build/components/media-editor-provider/index.cjs.map +7 -0
- package/build/components/media-form/index.cjs +71 -0
- package/build/components/media-form/index.cjs.map +7 -0
- package/build/components/media-preview/index.cjs +119 -0
- package/build/components/media-preview/index.cjs.map +7 -0
- package/build/index.cjs +47 -0
- package/build/index.cjs.map +7 -0
- package/build/utils/get-media-type.cjs +45 -0
- package/build/utils/get-media-type.cjs.map +7 -0
- package/build/utils/index.cjs +31 -0
- package/build/utils/index.cjs.map +7 -0
- package/build-module/components/media-editor-provider/index.mjs +33 -0
- package/build-module/components/media-editor-provider/index.mjs.map +7 -0
- package/build-module/components/media-form/index.mjs +50 -0
- package/build-module/components/media-form/index.mjs.map +7 -0
- package/build-module/components/media-preview/index.mjs +98 -0
- package/build-module/components/media-preview/index.mjs.map +7 -0
- package/build-module/index.mjs +10 -0
- package/build-module/index.mjs.map +7 -0
- package/build-module/utils/get-media-type.mjs +20 -0
- package/build-module/utils/get-media-type.mjs.map +7 -0
- package/build-module/utils/index.mjs +6 -0
- package/build-module/utils/index.mjs.map +7 -0
- package/build-style/style-rtl.css +127 -0
- package/build-style/style.css +127 -0
- package/build-types/components/media-editor-provider/index.d.ts +62 -0
- package/build-types/components/media-editor-provider/index.d.ts.map +1 -0
- package/build-types/components/media-form/index.d.ts +22 -0
- package/build-types/components/media-form/index.d.ts.map +1 -0
- package/build-types/components/media-preview/index.d.ts +15 -0
- package/build-types/components/media-preview/index.d.ts.map +1 -0
- package/build-types/index.d.ts +8 -0
- package/build-types/index.d.ts.map +1 -0
- package/build-types/utils/get-media-type.d.ts +14 -0
- package/build-types/utils/get-media-type.d.ts.map +1 -0
- package/build-types/utils/index.d.ts +3 -0
- package/build-types/utils/index.d.ts.map +1 -0
- package/package.json +57 -0
- package/src/components/media-editor-provider/index.tsx +90 -0
- package/src/components/media-form/index.tsx +87 -0
- package/src/components/media-preview/index.tsx +154 -0
- package/src/components/media-preview/style.scss +89 -0
- package/src/index.ts +15 -0
- package/src/style.scss +2 -0
- package/src/utils/get-media-type.ts +29 -0
- package/src/utils/index.ts +2 -0
- package/tsconfig.json +13 -0
- package/tsconfig.tsbuildinfo +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wordpress/media-editor",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Media editor components for WordPress.",
|
|
5
|
+
"author": "The WordPress Contributors",
|
|
6
|
+
"license": "GPL-2.0-or-later",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"wordpress",
|
|
9
|
+
"gutenberg",
|
|
10
|
+
"media",
|
|
11
|
+
"editor",
|
|
12
|
+
"attachment"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/packages/media-editor/README.md",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/WordPress/gutenberg.git",
|
|
18
|
+
"directory": "packages/media-editor"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/WordPress/gutenberg/issues"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18.12.0",
|
|
25
|
+
"npm": ">=8.19.2"
|
|
26
|
+
},
|
|
27
|
+
"main": "build/index.cjs",
|
|
28
|
+
"module": "build-module/index.mjs",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./build-types/index.d.ts",
|
|
32
|
+
"import": "./build-module/index.mjs",
|
|
33
|
+
"require": "./build/index.cjs"
|
|
34
|
+
},
|
|
35
|
+
"./package.json": "./package.json"
|
|
36
|
+
},
|
|
37
|
+
"react-native": "src/index",
|
|
38
|
+
"types": "build-types",
|
|
39
|
+
"sideEffects": [
|
|
40
|
+
"build-style/**",
|
|
41
|
+
"src/**/*.scss"
|
|
42
|
+
],
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@babel/runtime": "^7.16.0",
|
|
45
|
+
"@wordpress/components": "^32.1.0",
|
|
46
|
+
"@wordpress/dataviews": "^11.3.0",
|
|
47
|
+
"@wordpress/element": "^6.39.0",
|
|
48
|
+
"@wordpress/i18n": "^6.12.0"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"react": "^18.0.0"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
},
|
|
56
|
+
"gitHead": "eee1cfb1472f11183e40fb77465a5f13145df7ad"
|
|
57
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { createContext, useContext } from '@wordpress/element';
|
|
5
|
+
import type { Field } from '@wordpress/dataviews';
|
|
6
|
+
import type { ReactNode } from 'react';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Media object from WordPress REST API.
|
|
10
|
+
*/
|
|
11
|
+
export interface Media {
|
|
12
|
+
id?: number;
|
|
13
|
+
source_url?: string;
|
|
14
|
+
mime_type?: string;
|
|
15
|
+
alt_text?: string;
|
|
16
|
+
title?: string | { rendered?: string; raw?: string };
|
|
17
|
+
caption?: string | { rendered?: string; raw?: string };
|
|
18
|
+
description?: string | { rendered?: string; raw?: string };
|
|
19
|
+
[ key: string ]: any;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Context value for MediaEditor.
|
|
24
|
+
*/
|
|
25
|
+
export interface MediaEditorContextValue {
|
|
26
|
+
media?: Media;
|
|
27
|
+
onChange?: ( updates: Partial< Media > ) => void;
|
|
28
|
+
fields: Field< Media >[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Props for MediaEditorProvider.
|
|
33
|
+
*/
|
|
34
|
+
export interface MediaEditorProviderProps {
|
|
35
|
+
/** The media object to edit. */
|
|
36
|
+
value?: Media;
|
|
37
|
+
/**
|
|
38
|
+
* Callback when media is updated.
|
|
39
|
+
*
|
|
40
|
+
* Optional - if not provided, the MediaEditor can be used in a read-only mode,
|
|
41
|
+
* useful for preview-only scenarios.
|
|
42
|
+
*/
|
|
43
|
+
onChange?: ( updates: Partial< Media > ) => void;
|
|
44
|
+
/** Configuration settings for the media editor. */
|
|
45
|
+
settings?: {
|
|
46
|
+
fields?: Field< Media >[];
|
|
47
|
+
};
|
|
48
|
+
/** Child components. */
|
|
49
|
+
children: ReactNode;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const MediaEditorContext = createContext< MediaEditorContextValue | undefined >(
|
|
53
|
+
undefined
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
export function MediaEditorProvider( {
|
|
57
|
+
value,
|
|
58
|
+
onChange,
|
|
59
|
+
settings = {},
|
|
60
|
+
children,
|
|
61
|
+
}: MediaEditorProviderProps ) {
|
|
62
|
+
const contextValue: MediaEditorContextValue = {
|
|
63
|
+
media: value,
|
|
64
|
+
onChange,
|
|
65
|
+
fields: settings.fields || [],
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<MediaEditorContext.Provider value={ contextValue }>
|
|
70
|
+
{ children }
|
|
71
|
+
</MediaEditorContext.Provider>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Hook to access the MediaEditor context.
|
|
77
|
+
*
|
|
78
|
+
* Must be used within a MediaEditorProvider component.
|
|
79
|
+
*
|
|
80
|
+
* @return MediaEditorContextValue value with media, onChange, and fields, etc.
|
|
81
|
+
*/
|
|
82
|
+
export function useMediaEditorContext(): MediaEditorContextValue {
|
|
83
|
+
const context = useContext( MediaEditorContext );
|
|
84
|
+
if ( ! context ) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
'useMediaEditorContext must be used within MediaEditorProvider'
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return context;
|
|
90
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { DataForm } from '@wordpress/dataviews';
|
|
5
|
+
import type { Form, Field } from '@wordpress/dataviews';
|
|
6
|
+
import { Spinner, __experimentalVStack as VStack } from '@wordpress/components';
|
|
7
|
+
import type { ReactNode } from 'react';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
import { useMediaEditorContext } from '../media-editor-provider';
|
|
13
|
+
import type { Media } from '../media-editor-provider';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Props for MediaForm component.
|
|
17
|
+
*/
|
|
18
|
+
export interface MediaFormProps {
|
|
19
|
+
form?: Form;
|
|
20
|
+
header?: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* MediaForm component for editing media metadata.
|
|
25
|
+
*
|
|
26
|
+
* Renders a DataForm with fields for editing media properties like
|
|
27
|
+
* title, alt text, caption, description, etc.
|
|
28
|
+
*
|
|
29
|
+
* @param props - Component props.
|
|
30
|
+
* @param props.form - Optional form configuration.
|
|
31
|
+
* @param props.header - Optional header content to display above the form.
|
|
32
|
+
* @return The MediaForm component.
|
|
33
|
+
*/
|
|
34
|
+
export default function MediaForm( {
|
|
35
|
+
form: formOverrides,
|
|
36
|
+
header,
|
|
37
|
+
}: MediaFormProps ) {
|
|
38
|
+
const { media, fields, onChange } = useMediaEditorContext();
|
|
39
|
+
|
|
40
|
+
if ( ! media || ! onChange ) {
|
|
41
|
+
return (
|
|
42
|
+
<div className="media-editor-form media-editor-form--loading">
|
|
43
|
+
<Spinner />
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Default form structure with panel layout
|
|
49
|
+
const defaultForm: Form = {
|
|
50
|
+
layout: {
|
|
51
|
+
type: 'panel',
|
|
52
|
+
},
|
|
53
|
+
fields: fields.map( ( field: Field< Media > ) => {
|
|
54
|
+
// Use regular layout for main editable fields
|
|
55
|
+
if (
|
|
56
|
+
[ 'title', 'alt_text', 'caption', 'description' ].includes(
|
|
57
|
+
field.id
|
|
58
|
+
)
|
|
59
|
+
) {
|
|
60
|
+
return {
|
|
61
|
+
id: field.id,
|
|
62
|
+
layout: {
|
|
63
|
+
type: 'regular',
|
|
64
|
+
labelPosition: 'top',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return field.id;
|
|
69
|
+
} ),
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const form = formOverrides || defaultForm;
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div className="media-editor-form">
|
|
76
|
+
<VStack spacing={ 4 }>
|
|
77
|
+
{ header }
|
|
78
|
+
<DataForm
|
|
79
|
+
data={ media }
|
|
80
|
+
fields={ fields }
|
|
81
|
+
form={ form }
|
|
82
|
+
onChange={ onChange }
|
|
83
|
+
/>
|
|
84
|
+
</VStack>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { Spinner } from '@wordpress/components';
|
|
5
|
+
import { useState } from '@wordpress/element';
|
|
6
|
+
import { __ } from '@wordpress/i18n';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
import { useMediaEditorContext } from '../media-editor-provider';
|
|
12
|
+
import { getMediaTypeFromMimeType } from '../../utils';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Props for MediaPreview component.
|
|
16
|
+
*/
|
|
17
|
+
export interface MediaPreviewProps {
|
|
18
|
+
[ key: string ]: any; // TODO: Define specific props as needed, this will likely be for click handlers, accessibility attributes, etc.
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Props for MediaPreviewContent component.
|
|
23
|
+
*/
|
|
24
|
+
interface MediaPreviewContentProps {
|
|
25
|
+
mediaType: { type: string };
|
|
26
|
+
mediaUrl: string;
|
|
27
|
+
altText?: string;
|
|
28
|
+
displayTitle?: string;
|
|
29
|
+
mimeType?: string;
|
|
30
|
+
onLoad: () => void;
|
|
31
|
+
onError: () => void;
|
|
32
|
+
loadingState: 'loading' | 'loaded' | 'error';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function MediaPreviewContent( {
|
|
36
|
+
mediaType,
|
|
37
|
+
mediaUrl,
|
|
38
|
+
altText,
|
|
39
|
+
displayTitle,
|
|
40
|
+
mimeType,
|
|
41
|
+
onLoad,
|
|
42
|
+
onError,
|
|
43
|
+
loadingState,
|
|
44
|
+
}: MediaPreviewContentProps ) {
|
|
45
|
+
switch ( mediaType.type ) {
|
|
46
|
+
case 'image':
|
|
47
|
+
return (
|
|
48
|
+
<img
|
|
49
|
+
className={ loadingState === 'loaded' ? 'loaded' : '' }
|
|
50
|
+
src={ mediaUrl }
|
|
51
|
+
alt={ altText || '' }
|
|
52
|
+
onLoad={ onLoad }
|
|
53
|
+
onError={ onError }
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
case 'video':
|
|
57
|
+
return (
|
|
58
|
+
<video src={ mediaUrl } controls onError={ onError }>
|
|
59
|
+
{ displayTitle }
|
|
60
|
+
</video>
|
|
61
|
+
);
|
|
62
|
+
case 'audio':
|
|
63
|
+
return (
|
|
64
|
+
<audio src={ mediaUrl } controls onError={ onError }>
|
|
65
|
+
{ displayTitle }
|
|
66
|
+
</audio>
|
|
67
|
+
);
|
|
68
|
+
default:
|
|
69
|
+
return (
|
|
70
|
+
<div className="media-editor-preview__file-info">
|
|
71
|
+
<p className="media-editor-preview__file-name">
|
|
72
|
+
{ displayTitle }
|
|
73
|
+
</p>
|
|
74
|
+
<p className="media-editor-preview__mime-type">
|
|
75
|
+
{ mimeType }
|
|
76
|
+
</p>
|
|
77
|
+
<a
|
|
78
|
+
href={ mediaUrl }
|
|
79
|
+
target="_blank"
|
|
80
|
+
rel="noopener noreferrer"
|
|
81
|
+
className="media-editor-preview__download-link"
|
|
82
|
+
>
|
|
83
|
+
{ __( 'View file' ) }
|
|
84
|
+
</a>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* MediaPreview component displays the media file in the editor canvas.
|
|
92
|
+
* Supports images, videos, audio files, and generic file displays.
|
|
93
|
+
*
|
|
94
|
+
* @param props - Component props including click handlers and accessibility attributes.
|
|
95
|
+
* @return The MediaPreview component.
|
|
96
|
+
*/
|
|
97
|
+
export default function MediaPreview( props: MediaPreviewProps ) {
|
|
98
|
+
const [ loadingState, setLoadingState ] = useState<
|
|
99
|
+
'loading' | 'loaded' | 'error'
|
|
100
|
+
>( 'loading' );
|
|
101
|
+
const { media } = useMediaEditorContext();
|
|
102
|
+
|
|
103
|
+
const {
|
|
104
|
+
source_url: mediaUrl,
|
|
105
|
+
mime_type: mimeType,
|
|
106
|
+
alt_text: altText,
|
|
107
|
+
title,
|
|
108
|
+
} = media || {};
|
|
109
|
+
|
|
110
|
+
const mediaType = getMediaTypeFromMimeType( mimeType );
|
|
111
|
+
|
|
112
|
+
if ( ! mediaUrl ) {
|
|
113
|
+
return (
|
|
114
|
+
<div className="media-editor-preview media-editor-preview--empty">
|
|
115
|
+
<p>{ __( 'No media file available.' ) }</p>
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if ( loadingState === 'error' ) {
|
|
121
|
+
return (
|
|
122
|
+
<div className="media-editor-preview media-editor-preview--error">
|
|
123
|
+
<p>{ __( 'Failed to load media file.' ) }</p>
|
|
124
|
+
<p className="media-editor-preview__url">{ mediaUrl }</p>
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const displayTitle =
|
|
130
|
+
typeof title === 'string' ? title : title?.rendered || title?.raw;
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<div
|
|
134
|
+
{ ...props }
|
|
135
|
+
className={ `media-editor-preview media-editor-preview--${ mediaType.type }` }
|
|
136
|
+
>
|
|
137
|
+
{ mediaType.type === 'image' && loadingState === 'loading' && (
|
|
138
|
+
<div className="media-editor-preview__spinner">
|
|
139
|
+
<Spinner />
|
|
140
|
+
</div>
|
|
141
|
+
) }
|
|
142
|
+
<MediaPreviewContent
|
|
143
|
+
mediaType={ mediaType }
|
|
144
|
+
mediaUrl={ mediaUrl }
|
|
145
|
+
altText={ altText }
|
|
146
|
+
displayTitle={ displayTitle }
|
|
147
|
+
mimeType={ mimeType }
|
|
148
|
+
onLoad={ () => setLoadingState( 'loaded' ) }
|
|
149
|
+
onError={ () => setLoadingState( 'error' ) }
|
|
150
|
+
loadingState={ loadingState }
|
|
151
|
+
/>
|
|
152
|
+
</div>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
@use "@wordpress/base-styles/animations" as *;
|
|
2
|
+
@use "@wordpress/base-styles/colors" as *;
|
|
3
|
+
@use "@wordpress/base-styles/variables" as *;
|
|
4
|
+
|
|
5
|
+
.media-editor-preview {
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
display: flex;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
align-items: center;
|
|
10
|
+
min-height: 100%;
|
|
11
|
+
padding: $grid-unit-40;
|
|
12
|
+
position: relative;
|
|
13
|
+
|
|
14
|
+
&__spinner {
|
|
15
|
+
position: absolute;
|
|
16
|
+
top: 50%;
|
|
17
|
+
left: 50%;
|
|
18
|
+
transform: translate(-50%, -50%);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
&--loading {
|
|
22
|
+
width: 100%;
|
|
23
|
+
height: 100%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&--image img {
|
|
27
|
+
max-width: 100%;
|
|
28
|
+
max-height: 100%;
|
|
29
|
+
object-fit: contain;
|
|
30
|
+
width: auto;
|
|
31
|
+
height: auto;
|
|
32
|
+
opacity: 0;
|
|
33
|
+
|
|
34
|
+
&.loaded {
|
|
35
|
+
@include animation__fade-in();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&--video video {
|
|
40
|
+
max-width: 100%;
|
|
41
|
+
max-height: 100%;
|
|
42
|
+
object-fit: contain;
|
|
43
|
+
width: auto;
|
|
44
|
+
height: auto;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&--audio audio {
|
|
48
|
+
max-width: 100%;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
&--file {
|
|
52
|
+
text-align: center;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&__file-info {
|
|
56
|
+
background: $gray-100;
|
|
57
|
+
padding: $grid-unit-30;
|
|
58
|
+
border-radius: 2px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__file-name {
|
|
62
|
+
font-weight: 600;
|
|
63
|
+
margin-bottom: $grid-unit-10;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&__mime-type {
|
|
67
|
+
color: $gray-700;
|
|
68
|
+
font-size: 0.9em;
|
|
69
|
+
margin-bottom: $grid-unit-20;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&__download-link {
|
|
73
|
+
display: inline-block;
|
|
74
|
+
margin-top: $grid-unit-10;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
&--error,
|
|
78
|
+
&--empty {
|
|
79
|
+
color: $gray-700;
|
|
80
|
+
text-align: center;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&__url {
|
|
84
|
+
font-size: 0.9em;
|
|
85
|
+
color: $gray-600;
|
|
86
|
+
word-break: break-all;
|
|
87
|
+
margin-top: $grid-unit-10;
|
|
88
|
+
}
|
|
89
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Components
|
|
2
|
+
export { MediaEditorProvider } from './components/media-editor-provider';
|
|
3
|
+
export { default as MediaPreview } from './components/media-preview';
|
|
4
|
+
export { default as MediaForm } from './components/media-form';
|
|
5
|
+
|
|
6
|
+
// Types
|
|
7
|
+
export type {
|
|
8
|
+
Media,
|
|
9
|
+
MediaEditorProviderProps,
|
|
10
|
+
} from './components/media-editor-provider';
|
|
11
|
+
export type { MediaPreviewProps } from './components/media-preview';
|
|
12
|
+
export type { MediaFormProps } from './components/media-form';
|
|
13
|
+
|
|
14
|
+
// Re-export commonly used dataviews types for convenience
|
|
15
|
+
export type { Field, Form } from '@wordpress/dataviews';
|
package/src/style.scss
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media type result.
|
|
3
|
+
*/
|
|
4
|
+
export interface MediaType {
|
|
5
|
+
type: 'image' | 'video' | 'audio' | 'application';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Determines the media type from a MIME type string.
|
|
10
|
+
*
|
|
11
|
+
* @param mimeType - The MIME type to check.
|
|
12
|
+
* @return Object with type property ('image', 'video', 'audio', or 'application').
|
|
13
|
+
*/
|
|
14
|
+
export function getMediaTypeFromMimeType( mimeType?: string ): MediaType {
|
|
15
|
+
if ( ! mimeType ) {
|
|
16
|
+
return { type: 'application' };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if ( mimeType.startsWith( 'image/' ) ) {
|
|
20
|
+
return { type: 'image' };
|
|
21
|
+
}
|
|
22
|
+
if ( mimeType.startsWith( 'video/' ) ) {
|
|
23
|
+
return { type: 'video' };
|
|
24
|
+
}
|
|
25
|
+
if ( mimeType.startsWith( 'audio/' ) ) {
|
|
26
|
+
return { type: 'audio' };
|
|
27
|
+
}
|
|
28
|
+
return { type: 'application' };
|
|
29
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig.json",
|
|
3
|
+
"extends": "../../tsconfig.base.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"types": [ "gutenberg-env" ]
|
|
6
|
+
},
|
|
7
|
+
"references": [
|
|
8
|
+
{ "path": "../components" },
|
|
9
|
+
{ "path": "../dataviews" },
|
|
10
|
+
{ "path": "../element" },
|
|
11
|
+
{ "path": "../i18n" }
|
|
12
|
+
]
|
|
13
|
+
}
|