@wordpress/media-fields 0.5.2-next.v.202602271551.0 → 0.5.2
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/build/media_thumbnail/view.cjs +13 -92
- package/build/media_thumbnail/view.cjs.map +3 -3
- package/build-module/media_thumbnail/view.mjs +14 -79
- package/build-module/media_thumbnail/view.mjs.map +2 -2
- package/build-style/style-rtl.css +0 -11
- package/build-style/style.css +0 -11
- package/build-types/attached_to/test/view.test.d.ts +2 -0
- package/build-types/attached_to/test/view.test.d.ts.map +1 -0
- package/build-types/media_thumbnail/view.d.ts +0 -10
- package/build-types/media_thumbnail/view.d.ts.map +1 -1
- package/package.json +14 -14
- package/src/media_thumbnail/style.scss +0 -21
- package/src/media_thumbnail/view.tsx +27 -122
- package/src/media_thumbnail/test/get-best-image-url.test.ts +0 -161
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,24 +15,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// packages/media-fields/src/media_thumbnail/view.tsx
|
|
31
21
|
var view_exports = {};
|
|
32
22
|
__export(view_exports, {
|
|
33
|
-
default: () => MediaThumbnailView
|
|
34
|
-
getBestImageUrl: () => getBestImageUrl
|
|
23
|
+
default: () => MediaThumbnailView
|
|
35
24
|
});
|
|
36
25
|
module.exports = __toCommonJS(view_exports);
|
|
37
|
-
var import_clsx = __toESM(require("clsx"));
|
|
38
26
|
var import_data = require("@wordpress/data");
|
|
39
27
|
var import_core_data = require("@wordpress/core-data");
|
|
40
28
|
var import_components = require("@wordpress/components");
|
|
@@ -42,34 +30,6 @@ var import_element = require("@wordpress/element");
|
|
|
42
30
|
var import_url = require("@wordpress/url");
|
|
43
31
|
var import_get_media_type_from_mime_type = require("../utils/get-media-type-from-mime-type.cjs");
|
|
44
32
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
45
|
-
function getBestImageUrl(featuredMedia, configSizes) {
|
|
46
|
-
const sizes = featuredMedia?.media_details?.sizes;
|
|
47
|
-
if (!sizes) {
|
|
48
|
-
return featuredMedia.source_url;
|
|
49
|
-
}
|
|
50
|
-
const sizeEntries = Object.values(sizes);
|
|
51
|
-
if (!sizeEntries.length) {
|
|
52
|
-
return featuredMedia.source_url;
|
|
53
|
-
}
|
|
54
|
-
const targetWidth = configSizes ? parseInt(configSizes, 10) : NaN;
|
|
55
|
-
if (!Number.isNaN(targetWidth)) {
|
|
56
|
-
const validEntries = sizeEntries.filter(
|
|
57
|
-
(s) => typeof s.width === "number" && !Number.isNaN(s.width)
|
|
58
|
-
);
|
|
59
|
-
if (!validEntries.length) {
|
|
60
|
-
return featuredMedia.source_url;
|
|
61
|
-
}
|
|
62
|
-
const sorted = [...validEntries].sort(
|
|
63
|
-
(a, b) => a.width - b.width
|
|
64
|
-
);
|
|
65
|
-
const match = sorted.find((s) => s.width >= targetWidth);
|
|
66
|
-
if (match) {
|
|
67
|
-
return match.source_url;
|
|
68
|
-
}
|
|
69
|
-
return sorted[sorted.length - 1].source_url;
|
|
70
|
-
}
|
|
71
|
-
return featuredMedia.source_url;
|
|
72
|
-
}
|
|
73
33
|
function FallbackView({
|
|
74
34
|
item,
|
|
75
35
|
filename
|
|
@@ -95,48 +55,6 @@ function FallbackView({
|
|
|
95
55
|
}
|
|
96
56
|
) });
|
|
97
57
|
}
|
|
98
|
-
function ImageView({
|
|
99
|
-
item,
|
|
100
|
-
configSizes,
|
|
101
|
-
onError
|
|
102
|
-
}) {
|
|
103
|
-
const imageUrl = getBestImageUrl(item, configSizes);
|
|
104
|
-
const imgRef = (0, import_element.useRef)(null);
|
|
105
|
-
const [loadingState, setLoadingState] = (0, import_element.useState)("loading");
|
|
106
|
-
(0, import_element.useLayoutEffect)(() => {
|
|
107
|
-
if (imgRef.current?.complete) {
|
|
108
|
-
setLoadingState("instant");
|
|
109
|
-
} else {
|
|
110
|
-
setLoadingState("loading");
|
|
111
|
-
}
|
|
112
|
-
}, [imageUrl]);
|
|
113
|
-
const handleLoad = () => {
|
|
114
|
-
if (loadingState === "loading") {
|
|
115
|
-
setLoadingState("loaded");
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
119
|
-
"div",
|
|
120
|
-
{
|
|
121
|
-
className: (0, import_clsx.default)("dataviews-media-field__media-thumbnail", {
|
|
122
|
-
"is-loading": loadingState === "loading",
|
|
123
|
-
"is-loaded": loadingState === "loaded"
|
|
124
|
-
}),
|
|
125
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
126
|
-
"img",
|
|
127
|
-
{
|
|
128
|
-
ref: imgRef,
|
|
129
|
-
className: "dataviews-media-field__media-thumbnail--image",
|
|
130
|
-
src: imageUrl,
|
|
131
|
-
alt: item.alt_text || item.title.raw,
|
|
132
|
-
onLoad: handleLoad,
|
|
133
|
-
onError,
|
|
134
|
-
loading: "lazy"
|
|
135
|
-
}
|
|
136
|
-
)
|
|
137
|
-
}
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
58
|
function MediaThumbnailView({
|
|
141
59
|
item,
|
|
142
60
|
config
|
|
@@ -163,17 +81,20 @@ function MediaThumbnailView({
|
|
|
163
81
|
if (imageError || (0, import_get_media_type_from_mime_type.getMediaTypeFromMimeType)(featuredMedia.mime_type).type !== "image") {
|
|
164
82
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FallbackView, { item: featuredMedia, filename: filename || "" });
|
|
165
83
|
}
|
|
166
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
167
|
-
|
|
84
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dataviews-media-field__media-thumbnail", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
85
|
+
"img",
|
|
168
86
|
{
|
|
169
|
-
|
|
170
|
-
|
|
87
|
+
className: "dataviews-media-field__media-thumbnail--image",
|
|
88
|
+
src: featuredMedia.source_url,
|
|
89
|
+
srcSet: featuredMedia?.media_details?.sizes ? Object.values(
|
|
90
|
+
featuredMedia.media_details.sizes
|
|
91
|
+
).map(
|
|
92
|
+
(size) => `${size.source_url} ${size.width}w`
|
|
93
|
+
).join(", ") : void 0,
|
|
94
|
+
sizes: config?.sizes || "100vw",
|
|
95
|
+
alt: featuredMedia.alt_text || featuredMedia.title.raw,
|
|
171
96
|
onError: () => setImageError(true)
|
|
172
97
|
}
|
|
173
|
-
);
|
|
98
|
+
) });
|
|
174
99
|
}
|
|
175
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
176
|
-
0 && (module.exports = {
|
|
177
|
-
getBestImageUrl
|
|
178
|
-
});
|
|
179
100
|
//# sourceMappingURL=view.cjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/media_thumbnail/view.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n *
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["VStack", "Truncate", "
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useSelect } from '@wordpress/data';\nimport { store as coreStore } from '@wordpress/core-data';\nimport {\n\t__experimentalTruncate as Truncate,\n\t__experimentalVStack as VStack,\n\tIcon,\n} from '@wordpress/components';\nimport { useState } from '@wordpress/element';\nimport type { Attachment } from '@wordpress/core-data';\nimport { getFilename } from '@wordpress/url';\nimport type { DataViewRenderFieldProps } from '@wordpress/dataviews';\n/**\n * Internal dependencies\n */\nimport { getMediaTypeFromMimeType } from '../utils/get-media-type-from-mime-type';\nimport type { MediaItem } from '../types';\n\nfunction FallbackView( {\n\titem,\n\tfilename,\n}: {\n\titem: MediaItem;\n\tfilename: string;\n} ) {\n\treturn (\n\t\t<div className=\"dataviews-media-field__media-thumbnail\">\n\t\t\t<VStack\n\t\t\t\tjustify=\"center\"\n\t\t\t\talignment=\"center\"\n\t\t\t\tclassName=\"dataviews-media-field__media-thumbnail__stack\"\n\t\t\t\tspacing={ 0 }\n\t\t\t>\n\t\t\t\t<Icon\n\t\t\t\t\tclassName=\"dataviews-media-field__media-thumbnail--icon\"\n\t\t\t\t\ticon={ getMediaTypeFromMimeType( item.mime_type ).icon }\n\t\t\t\t\tsize={ 24 }\n\t\t\t\t/>\n\t\t\t\t{ !! filename && (\n\t\t\t\t\t<div className=\"dataviews-media-field__media-thumbnail__filename\">\n\t\t\t\t\t\t<Truncate className=\"dataviews-media-field__media-thumbnail__filename__truncate\">\n\t\t\t\t\t\t\t{ filename }\n\t\t\t\t\t\t</Truncate>\n\t\t\t\t\t</div>\n\t\t\t\t) }\n\t\t\t</VStack>\n\t\t</div>\n\t);\n}\n\nexport default function MediaThumbnailView( {\n\titem,\n\tconfig,\n}: DataViewRenderFieldProps< MediaItem > ) {\n\tconst [ imageError, setImageError ] = useState( false );\n\n\tconst _featuredMedia = useSelect(\n\t\t( select ) => {\n\t\t\t// Avoid the network request if it's not needed. `featured_media` is\n\t\t\t// 0 for images and media without featured media.\n\t\t\tif ( ! item.featured_media ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn select( coreStore ).getEntityRecord< Attachment >(\n\t\t\t\t'postType',\n\t\t\t\t'attachment',\n\t\t\t\titem.featured_media\n\t\t\t);\n\t\t},\n\t\t[ item.featured_media ]\n\t);\n\tconst featuredMedia = item.featured_media ? _featuredMedia : item;\n\n\t// Fetching.\n\tif ( ! featuredMedia ) {\n\t\treturn null;\n\t}\n\n\tconst filename = getFilename( featuredMedia.source_url || '' );\n\n\t// Show fallback if image failed to load or if not an image type.\n\tif (\n\t\timageError ||\n\t\tgetMediaTypeFromMimeType( featuredMedia.mime_type ).type !== 'image'\n\t) {\n\t\treturn (\n\t\t\t<FallbackView item={ featuredMedia } filename={ filename || '' } />\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"dataviews-media-field__media-thumbnail\">\n\t\t\t<img\n\t\t\t\tclassName=\"dataviews-media-field__media-thumbnail--image\"\n\t\t\t\tsrc={ featuredMedia.source_url }\n\t\t\t\tsrcSet={\n\t\t\t\t\tfeaturedMedia?.media_details?.sizes\n\t\t\t\t\t\t? (\n\t\t\t\t\t\t\t\tObject.values(\n\t\t\t\t\t\t\t\t\tfeaturedMedia.media_details.sizes\n\t\t\t\t\t\t\t\t) as Array< {\n\t\t\t\t\t\t\t\t\tsource_url: string;\n\t\t\t\t\t\t\t\t\twidth: number;\n\t\t\t\t\t\t\t\t} >\n\t\t\t\t\t\t )\n\t\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\t\t( size ) =>\n\t\t\t\t\t\t\t\t\t\t`${ size.source_url } ${ size.width }w`\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.join( ', ' )\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tsizes={ config?.sizes || '100vw' }\n\t\t\t\talt={ featuredMedia.alt_text || featuredMedia.title.raw }\n\t\t\t\tonError={ () => setImageError( true ) }\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAA0B;AAC1B,uBAAmC;AACnC,wBAIO;AACP,qBAAyB;AAEzB,iBAA4B;AAK5B,2CAAyC;AAYtC;AATH,SAAS,aAAc;AAAA,EACtB;AAAA,EACA;AACD,GAGI;AACH,SACC,4CAAC,SAAI,WAAU,0CACd;AAAA,IAAC,kBAAAA;AAAA,IAAA;AAAA,MACA,SAAQ;AAAA,MACR,WAAU;AAAA,MACV,WAAU;AAAA,MACV,SAAU;AAAA,MAEV;AAAA;AAAA,UAAC;AAAA;AAAA,YACA,WAAU;AAAA,YACV,UAAO,+DAA0B,KAAK,SAAU,EAAE;AAAA,YAClD,MAAO;AAAA;AAAA,QACR;AAAA,QACE,CAAC,CAAE,YACJ,4CAAC,SAAI,WAAU,oDACd,sDAAC,kBAAAC,wBAAA,EAAS,WAAU,8DACjB,oBACH,GACD;AAAA;AAAA;AAAA,EAEF,GACD;AAEF;AAEe,SAAR,mBAAqC;AAAA,EAC3C;AAAA,EACA;AACD,GAA2C;AAC1C,QAAM,CAAE,YAAY,aAAc,QAAI,yBAAU,KAAM;AAEtD,QAAM,qBAAiB;AAAA,IACtB,CAAE,WAAY;AAGb,UAAK,CAAE,KAAK,gBAAiB;AAC5B;AAAA,MACD;AACA,aAAO,OAAQ,iBAAAC,KAAU,EAAE;AAAA,QAC1B;AAAA,QACA;AAAA,QACA,KAAK;AAAA,MACN;AAAA,IACD;AAAA,IACA,CAAE,KAAK,cAAe;AAAA,EACvB;AACA,QAAM,gBAAgB,KAAK,iBAAiB,iBAAiB;AAG7D,MAAK,CAAE,eAAgB;AACtB,WAAO;AAAA,EACR;AAEA,QAAM,eAAW,wBAAa,cAAc,cAAc,EAAG;AAG7D,MACC,kBACA,+DAA0B,cAAc,SAAU,EAAE,SAAS,SAC5D;AACD,WACC,4CAAC,gBAAa,MAAO,eAAgB,UAAW,YAAY,IAAK;AAAA,EAEnE;AAEA,SACC,4CAAC,SAAI,WAAU,0CACd;AAAA,IAAC;AAAA;AAAA,MACA,WAAU;AAAA,MACV,KAAM,cAAc;AAAA,MACpB,QACC,eAAe,eAAe,QAE3B,OAAO;AAAA,QACN,cAAc,cAAc;AAAA,MAC7B,EAKC;AAAA,QACA,CAAE,SACD,GAAI,KAAK,UAAW,IAAK,KAAK,KAAM;AAAA,MACtC,EACC,KAAM,IAAK,IACZ;AAAA,MAEJ,OAAQ,QAAQ,SAAS;AAAA,MACzB,KAAM,cAAc,YAAY,cAAc,MAAM;AAAA,MACpD,SAAU,MAAM,cAAe,IAAK;AAAA;AAAA,EACrC,GACD;AAEF;",
|
|
6
|
+
"names": ["VStack", "Truncate", "coreStore"]
|
|
7
7
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// packages/media-fields/src/media_thumbnail/view.tsx
|
|
2
|
-
import clsx from "clsx";
|
|
3
2
|
import { useSelect } from "@wordpress/data";
|
|
4
3
|
import { store as coreStore } from "@wordpress/core-data";
|
|
5
4
|
import {
|
|
@@ -7,38 +6,10 @@ import {
|
|
|
7
6
|
__experimentalVStack as VStack,
|
|
8
7
|
Icon
|
|
9
8
|
} from "@wordpress/components";
|
|
10
|
-
import { useState
|
|
9
|
+
import { useState } from "@wordpress/element";
|
|
11
10
|
import { getFilename } from "@wordpress/url";
|
|
12
11
|
import { getMediaTypeFromMimeType } from "../utils/get-media-type-from-mime-type.mjs";
|
|
13
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
-
function getBestImageUrl(featuredMedia, configSizes) {
|
|
15
|
-
const sizes = featuredMedia?.media_details?.sizes;
|
|
16
|
-
if (!sizes) {
|
|
17
|
-
return featuredMedia.source_url;
|
|
18
|
-
}
|
|
19
|
-
const sizeEntries = Object.values(sizes);
|
|
20
|
-
if (!sizeEntries.length) {
|
|
21
|
-
return featuredMedia.source_url;
|
|
22
|
-
}
|
|
23
|
-
const targetWidth = configSizes ? parseInt(configSizes, 10) : NaN;
|
|
24
|
-
if (!Number.isNaN(targetWidth)) {
|
|
25
|
-
const validEntries = sizeEntries.filter(
|
|
26
|
-
(s) => typeof s.width === "number" && !Number.isNaN(s.width)
|
|
27
|
-
);
|
|
28
|
-
if (!validEntries.length) {
|
|
29
|
-
return featuredMedia.source_url;
|
|
30
|
-
}
|
|
31
|
-
const sorted = [...validEntries].sort(
|
|
32
|
-
(a, b) => a.width - b.width
|
|
33
|
-
);
|
|
34
|
-
const match = sorted.find((s) => s.width >= targetWidth);
|
|
35
|
-
if (match) {
|
|
36
|
-
return match.source_url;
|
|
37
|
-
}
|
|
38
|
-
return sorted[sorted.length - 1].source_url;
|
|
39
|
-
}
|
|
40
|
-
return featuredMedia.source_url;
|
|
41
|
-
}
|
|
42
13
|
function FallbackView({
|
|
43
14
|
item,
|
|
44
15
|
filename
|
|
@@ -64,48 +35,6 @@ function FallbackView({
|
|
|
64
35
|
}
|
|
65
36
|
) });
|
|
66
37
|
}
|
|
67
|
-
function ImageView({
|
|
68
|
-
item,
|
|
69
|
-
configSizes,
|
|
70
|
-
onError
|
|
71
|
-
}) {
|
|
72
|
-
const imageUrl = getBestImageUrl(item, configSizes);
|
|
73
|
-
const imgRef = useRef(null);
|
|
74
|
-
const [loadingState, setLoadingState] = useState("loading");
|
|
75
|
-
useLayoutEffect(() => {
|
|
76
|
-
if (imgRef.current?.complete) {
|
|
77
|
-
setLoadingState("instant");
|
|
78
|
-
} else {
|
|
79
|
-
setLoadingState("loading");
|
|
80
|
-
}
|
|
81
|
-
}, [imageUrl]);
|
|
82
|
-
const handleLoad = () => {
|
|
83
|
-
if (loadingState === "loading") {
|
|
84
|
-
setLoadingState("loaded");
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
return /* @__PURE__ */ jsx(
|
|
88
|
-
"div",
|
|
89
|
-
{
|
|
90
|
-
className: clsx("dataviews-media-field__media-thumbnail", {
|
|
91
|
-
"is-loading": loadingState === "loading",
|
|
92
|
-
"is-loaded": loadingState === "loaded"
|
|
93
|
-
}),
|
|
94
|
-
children: /* @__PURE__ */ jsx(
|
|
95
|
-
"img",
|
|
96
|
-
{
|
|
97
|
-
ref: imgRef,
|
|
98
|
-
className: "dataviews-media-field__media-thumbnail--image",
|
|
99
|
-
src: imageUrl,
|
|
100
|
-
alt: item.alt_text || item.title.raw,
|
|
101
|
-
onLoad: handleLoad,
|
|
102
|
-
onError,
|
|
103
|
-
loading: "lazy"
|
|
104
|
-
}
|
|
105
|
-
)
|
|
106
|
-
}
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
38
|
function MediaThumbnailView({
|
|
110
39
|
item,
|
|
111
40
|
config
|
|
@@ -132,17 +61,23 @@ function MediaThumbnailView({
|
|
|
132
61
|
if (imageError || getMediaTypeFromMimeType(featuredMedia.mime_type).type !== "image") {
|
|
133
62
|
return /* @__PURE__ */ jsx(FallbackView, { item: featuredMedia, filename: filename || "" });
|
|
134
63
|
}
|
|
135
|
-
return /* @__PURE__ */ jsx(
|
|
136
|
-
|
|
64
|
+
return /* @__PURE__ */ jsx("div", { className: "dataviews-media-field__media-thumbnail", children: /* @__PURE__ */ jsx(
|
|
65
|
+
"img",
|
|
137
66
|
{
|
|
138
|
-
|
|
139
|
-
|
|
67
|
+
className: "dataviews-media-field__media-thumbnail--image",
|
|
68
|
+
src: featuredMedia.source_url,
|
|
69
|
+
srcSet: featuredMedia?.media_details?.sizes ? Object.values(
|
|
70
|
+
featuredMedia.media_details.sizes
|
|
71
|
+
).map(
|
|
72
|
+
(size) => `${size.source_url} ${size.width}w`
|
|
73
|
+
).join(", ") : void 0,
|
|
74
|
+
sizes: config?.sizes || "100vw",
|
|
75
|
+
alt: featuredMedia.alt_text || featuredMedia.title.raw,
|
|
140
76
|
onError: () => setImageError(true)
|
|
141
77
|
}
|
|
142
|
-
);
|
|
78
|
+
) });
|
|
143
79
|
}
|
|
144
80
|
export {
|
|
145
|
-
MediaThumbnailView as default
|
|
146
|
-
getBestImageUrl
|
|
81
|
+
MediaThumbnailView as default
|
|
147
82
|
};
|
|
148
83
|
//# sourceMappingURL=view.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/media_thumbnail/view.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n *
|
|
5
|
-
"mappings": ";AAGA,
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useSelect } from '@wordpress/data';\nimport { store as coreStore } from '@wordpress/core-data';\nimport {\n\t__experimentalTruncate as Truncate,\n\t__experimentalVStack as VStack,\n\tIcon,\n} from '@wordpress/components';\nimport { useState } from '@wordpress/element';\nimport type { Attachment } from '@wordpress/core-data';\nimport { getFilename } from '@wordpress/url';\nimport type { DataViewRenderFieldProps } from '@wordpress/dataviews';\n/**\n * Internal dependencies\n */\nimport { getMediaTypeFromMimeType } from '../utils/get-media-type-from-mime-type';\nimport type { MediaItem } from '../types';\n\nfunction FallbackView( {\n\titem,\n\tfilename,\n}: {\n\titem: MediaItem;\n\tfilename: string;\n} ) {\n\treturn (\n\t\t<div className=\"dataviews-media-field__media-thumbnail\">\n\t\t\t<VStack\n\t\t\t\tjustify=\"center\"\n\t\t\t\talignment=\"center\"\n\t\t\t\tclassName=\"dataviews-media-field__media-thumbnail__stack\"\n\t\t\t\tspacing={ 0 }\n\t\t\t>\n\t\t\t\t<Icon\n\t\t\t\t\tclassName=\"dataviews-media-field__media-thumbnail--icon\"\n\t\t\t\t\ticon={ getMediaTypeFromMimeType( item.mime_type ).icon }\n\t\t\t\t\tsize={ 24 }\n\t\t\t\t/>\n\t\t\t\t{ !! filename && (\n\t\t\t\t\t<div className=\"dataviews-media-field__media-thumbnail__filename\">\n\t\t\t\t\t\t<Truncate className=\"dataviews-media-field__media-thumbnail__filename__truncate\">\n\t\t\t\t\t\t\t{ filename }\n\t\t\t\t\t\t</Truncate>\n\t\t\t\t\t</div>\n\t\t\t\t) }\n\t\t\t</VStack>\n\t\t</div>\n\t);\n}\n\nexport default function MediaThumbnailView( {\n\titem,\n\tconfig,\n}: DataViewRenderFieldProps< MediaItem > ) {\n\tconst [ imageError, setImageError ] = useState( false );\n\n\tconst _featuredMedia = useSelect(\n\t\t( select ) => {\n\t\t\t// Avoid the network request if it's not needed. `featured_media` is\n\t\t\t// 0 for images and media without featured media.\n\t\t\tif ( ! item.featured_media ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn select( coreStore ).getEntityRecord< Attachment >(\n\t\t\t\t'postType',\n\t\t\t\t'attachment',\n\t\t\t\titem.featured_media\n\t\t\t);\n\t\t},\n\t\t[ item.featured_media ]\n\t);\n\tconst featuredMedia = item.featured_media ? _featuredMedia : item;\n\n\t// Fetching.\n\tif ( ! featuredMedia ) {\n\t\treturn null;\n\t}\n\n\tconst filename = getFilename( featuredMedia.source_url || '' );\n\n\t// Show fallback if image failed to load or if not an image type.\n\tif (\n\t\timageError ||\n\t\tgetMediaTypeFromMimeType( featuredMedia.mime_type ).type !== 'image'\n\t) {\n\t\treturn (\n\t\t\t<FallbackView item={ featuredMedia } filename={ filename || '' } />\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"dataviews-media-field__media-thumbnail\">\n\t\t\t<img\n\t\t\t\tclassName=\"dataviews-media-field__media-thumbnail--image\"\n\t\t\t\tsrc={ featuredMedia.source_url }\n\t\t\t\tsrcSet={\n\t\t\t\t\tfeaturedMedia?.media_details?.sizes\n\t\t\t\t\t\t? (\n\t\t\t\t\t\t\t\tObject.values(\n\t\t\t\t\t\t\t\t\tfeaturedMedia.media_details.sizes\n\t\t\t\t\t\t\t\t) as Array< {\n\t\t\t\t\t\t\t\t\tsource_url: string;\n\t\t\t\t\t\t\t\t\twidth: number;\n\t\t\t\t\t\t\t\t} >\n\t\t\t\t\t\t )\n\t\t\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t\t\t( size ) =>\n\t\t\t\t\t\t\t\t\t\t`${ size.source_url } ${ size.width }w`\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.join( ', ' )\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tsizes={ config?.sizes || '100vw' }\n\t\t\t\talt={ featuredMedia.alt_text || featuredMedia.title.raw }\n\t\t\t\tonError={ () => setImageError( true ) }\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],
|
|
5
|
+
"mappings": ";AAGA,SAAS,iBAAiB;AAC1B,SAAS,SAAS,iBAAiB;AACnC;AAAA,EACC,0BAA0B;AAAA,EAC1B,wBAAwB;AAAA,EACxB;AAAA,OACM;AACP,SAAS,gBAAgB;AAEzB,SAAS,mBAAmB;AAK5B,SAAS,gCAAgC;AAYtC,SAMC,KAND;AATH,SAAS,aAAc;AAAA,EACtB;AAAA,EACA;AACD,GAGI;AACH,SACC,oBAAC,SAAI,WAAU,0CACd;AAAA,IAAC;AAAA;AAAA,MACA,SAAQ;AAAA,MACR,WAAU;AAAA,MACV,WAAU;AAAA,MACV,SAAU;AAAA,MAEV;AAAA;AAAA,UAAC;AAAA;AAAA,YACA,WAAU;AAAA,YACV,MAAO,yBAA0B,KAAK,SAAU,EAAE;AAAA,YAClD,MAAO;AAAA;AAAA,QACR;AAAA,QACE,CAAC,CAAE,YACJ,oBAAC,SAAI,WAAU,oDACd,8BAAC,YAAS,WAAU,8DACjB,oBACH,GACD;AAAA;AAAA;AAAA,EAEF,GACD;AAEF;AAEe,SAAR,mBAAqC;AAAA,EAC3C;AAAA,EACA;AACD,GAA2C;AAC1C,QAAM,CAAE,YAAY,aAAc,IAAI,SAAU,KAAM;AAEtD,QAAM,iBAAiB;AAAA,IACtB,CAAE,WAAY;AAGb,UAAK,CAAE,KAAK,gBAAiB;AAC5B;AAAA,MACD;AACA,aAAO,OAAQ,SAAU,EAAE;AAAA,QAC1B;AAAA,QACA;AAAA,QACA,KAAK;AAAA,MACN;AAAA,IACD;AAAA,IACA,CAAE,KAAK,cAAe;AAAA,EACvB;AACA,QAAM,gBAAgB,KAAK,iBAAiB,iBAAiB;AAG7D,MAAK,CAAE,eAAgB;AACtB,WAAO;AAAA,EACR;AAEA,QAAM,WAAW,YAAa,cAAc,cAAc,EAAG;AAG7D,MACC,cACA,yBAA0B,cAAc,SAAU,EAAE,SAAS,SAC5D;AACD,WACC,oBAAC,gBAAa,MAAO,eAAgB,UAAW,YAAY,IAAK;AAAA,EAEnE;AAEA,SACC,oBAAC,SAAI,WAAU,0CACd;AAAA,IAAC;AAAA;AAAA,MACA,WAAU;AAAA,MACV,KAAM,cAAc;AAAA,MACpB,QACC,eAAe,eAAe,QAE3B,OAAO;AAAA,QACN,cAAc,cAAc;AAAA,MAC7B,EAKC;AAAA,QACA,CAAE,SACD,GAAI,KAAK,UAAW,IAAK,KAAK,KAAM;AAAA,MACtC,EACC,KAAM,IAAK,IACZ;AAAA,MAEJ,OAAQ,QAAQ,SAAS;AAAA,MACzB,KAAM,cAAc,YAAY,cAAc,MAAM;AAAA,MACpD,SAAU,MAAM,cAAe,IAAK;AAAA;AAAA,EACrC,GACD;AAEF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -137,17 +137,6 @@
|
|
|
137
137
|
position: relative;
|
|
138
138
|
height: 100%;
|
|
139
139
|
}
|
|
140
|
-
@media not (prefers-reduced-motion) {
|
|
141
|
-
.dataviews-media-field__media-thumbnail.is-loading img, .dataviews-media-field__media-thumbnail.is-loaded img {
|
|
142
|
-
transition: opacity 0.1s linear;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
.dataviews-media-field__media-thumbnail.is-loading img {
|
|
146
|
-
opacity: 0;
|
|
147
|
-
}
|
|
148
|
-
.dataviews-media-field__media-thumbnail.is-loaded img {
|
|
149
|
-
opacity: 1;
|
|
150
|
-
}
|
|
151
140
|
|
|
152
141
|
.dataviews-media-field__media-thumbnail--image {
|
|
153
142
|
display: block;
|
package/build-style/style.css
CHANGED
|
@@ -137,17 +137,6 @@
|
|
|
137
137
|
position: relative;
|
|
138
138
|
height: 100%;
|
|
139
139
|
}
|
|
140
|
-
@media not (prefers-reduced-motion) {
|
|
141
|
-
.dataviews-media-field__media-thumbnail.is-loading img, .dataviews-media-field__media-thumbnail.is-loaded img {
|
|
142
|
-
transition: opacity 0.1s linear;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
.dataviews-media-field__media-thumbnail.is-loading img {
|
|
146
|
-
opacity: 0;
|
|
147
|
-
}
|
|
148
|
-
.dataviews-media-field__media-thumbnail.is-loaded img {
|
|
149
|
-
opacity: 1;
|
|
150
|
-
}
|
|
151
140
|
|
|
152
141
|
.dataviews-media-field__media-thumbnail--image {
|
|
153
142
|
display: block;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.test.d.ts","sourceRoot":"","sources":["../../../src/attached_to/test/view.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
import type { Attachment } from '@wordpress/core-data';
|
|
2
1
|
import type { DataViewRenderFieldProps } from '@wordpress/dataviews';
|
|
3
2
|
import type { MediaItem } from '../types';
|
|
4
|
-
/**
|
|
5
|
-
* Given the available image sizes and a target display width, returns the URL
|
|
6
|
-
* of the smallest size whose width is >= the target. Falls back to the largest
|
|
7
|
-
* available size, or the original source_url.
|
|
8
|
-
*
|
|
9
|
-
* @param featuredMedia The media item with size details.
|
|
10
|
-
* @param configSizes The target display size string (e.g. '900px').
|
|
11
|
-
*/
|
|
12
|
-
export declare function getBestImageUrl(featuredMedia: Attachment | MediaItem, configSizes?: string): string;
|
|
13
3
|
export default function MediaThumbnailView({ item, config, }: DataViewRenderFieldProps<MediaItem>): import("react").JSX.Element | null;
|
|
14
4
|
//# sourceMappingURL=view.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/media_thumbnail/view.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/media_thumbnail/view.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAKrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAkC1C,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAE,EAC3C,IAAI,EACJ,MAAM,GACN,EAAE,wBAAwB,CAAE,SAAS,CAAE,sCAiEvC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/media-fields",
|
|
3
|
-
"version": "0.5.2
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Reusable field definitions for displaying and editing media attachment properties in WordPress.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -49,18 +49,18 @@
|
|
|
49
49
|
"src/**/*.scss"
|
|
50
50
|
],
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@wordpress/base-styles": "^6.16.1
|
|
53
|
-
"@wordpress/components": "^32.
|
|
54
|
-
"@wordpress/compose": "^7.40.1
|
|
55
|
-
"@wordpress/core-data": "^7.40.2
|
|
56
|
-
"@wordpress/data": "^10.40.1
|
|
57
|
-
"@wordpress/dataviews": "^12.
|
|
58
|
-
"@wordpress/date": "^5.40.1
|
|
59
|
-
"@wordpress/element": "^6.40.1
|
|
60
|
-
"@wordpress/i18n": "^6.13.1
|
|
61
|
-
"@wordpress/icons": "^11.7.1
|
|
62
|
-
"@wordpress/primitives": "^4.40.1
|
|
63
|
-
"@wordpress/url": "^4.40.1
|
|
52
|
+
"@wordpress/base-styles": "^6.16.1",
|
|
53
|
+
"@wordpress/components": "^32.2.1",
|
|
54
|
+
"@wordpress/compose": "^7.40.1",
|
|
55
|
+
"@wordpress/core-data": "^7.40.2",
|
|
56
|
+
"@wordpress/data": "^10.40.1",
|
|
57
|
+
"@wordpress/dataviews": "^12.0.1",
|
|
58
|
+
"@wordpress/date": "^5.40.1",
|
|
59
|
+
"@wordpress/element": "^6.40.1",
|
|
60
|
+
"@wordpress/i18n": "^6.13.1",
|
|
61
|
+
"@wordpress/icons": "^11.7.1",
|
|
62
|
+
"@wordpress/primitives": "^4.40.1",
|
|
63
|
+
"@wordpress/url": "^4.40.1",
|
|
64
64
|
"clsx": "2.1.1"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
@@ -73,5 +73,5 @@
|
|
|
73
73
|
"publishConfig": {
|
|
74
74
|
"access": "public"
|
|
75
75
|
},
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "adb6623c9f32490cfc73c7ac7f122578c1f10c65"
|
|
77
77
|
}
|
|
@@ -7,27 +7,6 @@
|
|
|
7
7
|
align-items: center;
|
|
8
8
|
position: relative;
|
|
9
9
|
height: 100%;
|
|
10
|
-
|
|
11
|
-
&.is-loading,
|
|
12
|
-
&.is-loaded {
|
|
13
|
-
img {
|
|
14
|
-
@media not (prefers-reduced-motion) {
|
|
15
|
-
transition: opacity 0.1s linear;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
&.is-loading {
|
|
21
|
-
img {
|
|
22
|
-
opacity: 0;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
&.is-loaded {
|
|
27
|
-
img {
|
|
28
|
-
opacity: 1;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
10
|
}
|
|
32
11
|
|
|
33
12
|
.dataviews-media-field__media-thumbnail--image {
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import clsx from 'clsx';
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
2
|
* WordPress dependencies
|
|
8
3
|
*/
|
|
@@ -13,7 +8,7 @@ import {
|
|
|
13
8
|
__experimentalVStack as VStack,
|
|
14
9
|
Icon,
|
|
15
10
|
} from '@wordpress/components';
|
|
16
|
-
import { useState
|
|
11
|
+
import { useState } from '@wordpress/element';
|
|
17
12
|
import type { Attachment } from '@wordpress/core-data';
|
|
18
13
|
import { getFilename } from '@wordpress/url';
|
|
19
14
|
import type { DataViewRenderFieldProps } from '@wordpress/dataviews';
|
|
@@ -23,59 +18,6 @@ import type { DataViewRenderFieldProps } from '@wordpress/dataviews';
|
|
|
23
18
|
import { getMediaTypeFromMimeType } from '../utils/get-media-type-from-mime-type';
|
|
24
19
|
import type { MediaItem } from '../types';
|
|
25
20
|
|
|
26
|
-
/**
|
|
27
|
-
* Given the available image sizes and a target display width, returns the URL
|
|
28
|
-
* of the smallest size whose width is >= the target. Falls back to the largest
|
|
29
|
-
* available size, or the original source_url.
|
|
30
|
-
*
|
|
31
|
-
* @param featuredMedia The media item with size details.
|
|
32
|
-
* @param configSizes The target display size string (e.g. '900px').
|
|
33
|
-
*/
|
|
34
|
-
export function getBestImageUrl(
|
|
35
|
-
featuredMedia: Attachment | MediaItem,
|
|
36
|
-
configSizes?: string
|
|
37
|
-
): string {
|
|
38
|
-
const sizes = featuredMedia?.media_details?.sizes;
|
|
39
|
-
if ( ! sizes ) {
|
|
40
|
-
return featuredMedia.source_url;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const sizeEntries = Object.values( sizes );
|
|
44
|
-
|
|
45
|
-
if ( ! sizeEntries.length ) {
|
|
46
|
-
return featuredMedia.source_url;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Parse target width from config.sizes (e.g. '900px' → 900).
|
|
50
|
-
const targetWidth = configSizes ? parseInt( configSizes, 10 ) : NaN;
|
|
51
|
-
|
|
52
|
-
if ( ! Number.isNaN( targetWidth ) ) {
|
|
53
|
-
// Filter to entries that have a valid numeric width.
|
|
54
|
-
const validEntries = sizeEntries.filter(
|
|
55
|
-
( s ) => typeof s.width === 'number' && ! Number.isNaN( s.width )
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
if ( ! validEntries.length ) {
|
|
59
|
-
return featuredMedia.source_url;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Sort ascending by width.
|
|
63
|
-
const sorted = [ ...validEntries ].sort(
|
|
64
|
-
( a, b ) => a.width - b.width
|
|
65
|
-
);
|
|
66
|
-
// Pick the smallest size that is >= target width.
|
|
67
|
-
const match = sorted.find( ( s ) => s.width >= targetWidth );
|
|
68
|
-
if ( match ) {
|
|
69
|
-
return match.source_url;
|
|
70
|
-
}
|
|
71
|
-
// No size large enough — use the largest available.
|
|
72
|
-
return sorted[ sorted.length - 1 ].source_url;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// If we can't parse the target, fall back to source_url.
|
|
76
|
-
return featuredMedia.source_url;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
21
|
function FallbackView( {
|
|
80
22
|
item,
|
|
81
23
|
filename,
|
|
@@ -108,64 +50,6 @@ function FallbackView( {
|
|
|
108
50
|
);
|
|
109
51
|
}
|
|
110
52
|
|
|
111
|
-
function ImageView( {
|
|
112
|
-
item,
|
|
113
|
-
configSizes,
|
|
114
|
-
onError,
|
|
115
|
-
}: {
|
|
116
|
-
item: Attachment | MediaItem;
|
|
117
|
-
configSizes?: string;
|
|
118
|
-
onError: () => void;
|
|
119
|
-
} ) {
|
|
120
|
-
const imageUrl = getBestImageUrl( item, configSizes );
|
|
121
|
-
|
|
122
|
-
/*
|
|
123
|
-
* Use three states to avoid fade-in animation for cached images:
|
|
124
|
-
* 'instant' = image already cached, 'loading' = waiting, 'loaded' = just finished.
|
|
125
|
-
*
|
|
126
|
-
* useLayoutEffect runs synchronously after DOM mutations but before paint,
|
|
127
|
-
* so we can check img.complete to detect disk-cached images and skip the
|
|
128
|
-
* fade-in animation entirely.
|
|
129
|
-
*/
|
|
130
|
-
const imgRef = useRef< HTMLImageElement >( null );
|
|
131
|
-
const [ loadingState, setLoadingState ] = useState<
|
|
132
|
-
'instant' | 'loading' | 'loaded'
|
|
133
|
-
>( 'loading' );
|
|
134
|
-
|
|
135
|
-
useLayoutEffect( () => {
|
|
136
|
-
if ( imgRef.current?.complete ) {
|
|
137
|
-
setLoadingState( 'instant' );
|
|
138
|
-
} else {
|
|
139
|
-
setLoadingState( 'loading' );
|
|
140
|
-
}
|
|
141
|
-
}, [ imageUrl ] );
|
|
142
|
-
|
|
143
|
-
const handleLoad = () => {
|
|
144
|
-
if ( loadingState === 'loading' ) {
|
|
145
|
-
setLoadingState( 'loaded' );
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
return (
|
|
150
|
-
<div
|
|
151
|
-
className={ clsx( 'dataviews-media-field__media-thumbnail', {
|
|
152
|
-
'is-loading': loadingState === 'loading',
|
|
153
|
-
'is-loaded': loadingState === 'loaded',
|
|
154
|
-
} ) }
|
|
155
|
-
>
|
|
156
|
-
<img
|
|
157
|
-
ref={ imgRef }
|
|
158
|
-
className="dataviews-media-field__media-thumbnail--image"
|
|
159
|
-
src={ imageUrl }
|
|
160
|
-
alt={ item.alt_text || item.title.raw }
|
|
161
|
-
onLoad={ handleLoad }
|
|
162
|
-
onError={ onError }
|
|
163
|
-
loading="lazy"
|
|
164
|
-
/>
|
|
165
|
-
</div>
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
53
|
export default function MediaThumbnailView( {
|
|
170
54
|
item,
|
|
171
55
|
config,
|
|
@@ -207,10 +91,31 @@ export default function MediaThumbnailView( {
|
|
|
207
91
|
}
|
|
208
92
|
|
|
209
93
|
return (
|
|
210
|
-
<
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
94
|
+
<div className="dataviews-media-field__media-thumbnail">
|
|
95
|
+
<img
|
|
96
|
+
className="dataviews-media-field__media-thumbnail--image"
|
|
97
|
+
src={ featuredMedia.source_url }
|
|
98
|
+
srcSet={
|
|
99
|
+
featuredMedia?.media_details?.sizes
|
|
100
|
+
? (
|
|
101
|
+
Object.values(
|
|
102
|
+
featuredMedia.media_details.sizes
|
|
103
|
+
) as Array< {
|
|
104
|
+
source_url: string;
|
|
105
|
+
width: number;
|
|
106
|
+
} >
|
|
107
|
+
)
|
|
108
|
+
.map(
|
|
109
|
+
( size ) =>
|
|
110
|
+
`${ size.source_url } ${ size.width }w`
|
|
111
|
+
)
|
|
112
|
+
.join( ', ' )
|
|
113
|
+
: undefined
|
|
114
|
+
}
|
|
115
|
+
sizes={ config?.sizes || '100vw' }
|
|
116
|
+
alt={ featuredMedia.alt_text || featuredMedia.title.raw }
|
|
117
|
+
onError={ () => setImageError( true ) }
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
215
120
|
);
|
|
216
121
|
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Internal dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { getBestImageUrl } from '../view';
|
|
5
|
-
|
|
6
|
-
type Media = Parameters< typeof getBestImageUrl >[ 0 ];
|
|
7
|
-
|
|
8
|
-
const baseMedia: Media = {
|
|
9
|
-
id: 1,
|
|
10
|
-
date: '2024-01-01T00:00:00',
|
|
11
|
-
date_gmt: '2024-01-01T00:00:00',
|
|
12
|
-
guid: {
|
|
13
|
-
raw: 'https://example.com/?attachment_id=1',
|
|
14
|
-
rendered: 'https://example.com/?attachment_id=1',
|
|
15
|
-
},
|
|
16
|
-
modified: '2024-01-01T00:00:00',
|
|
17
|
-
modified_gmt: '2024-01-01T00:00:00',
|
|
18
|
-
slug: 'test-image',
|
|
19
|
-
status: 'publish',
|
|
20
|
-
type: 'attachment',
|
|
21
|
-
link: 'https://example.com/test-image/',
|
|
22
|
-
title: { raw: 'Test Image', rendered: 'Test Image' },
|
|
23
|
-
author: 1,
|
|
24
|
-
featured_media: 0,
|
|
25
|
-
comment_status: 'open',
|
|
26
|
-
ping_status: 'closed',
|
|
27
|
-
template: '',
|
|
28
|
-
permalink_template: '',
|
|
29
|
-
generated_slug: 'test-image',
|
|
30
|
-
class_list: [ 'attachment' ],
|
|
31
|
-
caption: { raw: '', rendered: '' },
|
|
32
|
-
description: { raw: '', rendered: '' },
|
|
33
|
-
alt_text: 'A test image',
|
|
34
|
-
media_type: 'image',
|
|
35
|
-
mime_type: 'image/jpeg',
|
|
36
|
-
post: null,
|
|
37
|
-
source_url: 'https://example.com/original.jpg',
|
|
38
|
-
missing_image_sizes: [],
|
|
39
|
-
meta: {},
|
|
40
|
-
media_details: {
|
|
41
|
-
sizes: {
|
|
42
|
-
thumbnail: {
|
|
43
|
-
file: 'original-150x150.jpg',
|
|
44
|
-
width: 150,
|
|
45
|
-
height: 150,
|
|
46
|
-
mime_type: 'image/jpeg',
|
|
47
|
-
source_url: 'https://example.com/thumb.jpg',
|
|
48
|
-
},
|
|
49
|
-
medium: {
|
|
50
|
-
file: 'original-300x200.jpg',
|
|
51
|
-
width: 300,
|
|
52
|
-
height: 200,
|
|
53
|
-
mime_type: 'image/jpeg',
|
|
54
|
-
source_url: 'https://example.com/medium.jpg',
|
|
55
|
-
},
|
|
56
|
-
large: {
|
|
57
|
-
file: 'original-1024x683.jpg',
|
|
58
|
-
width: 1024,
|
|
59
|
-
height: 683,
|
|
60
|
-
mime_type: 'image/jpeg',
|
|
61
|
-
source_url: 'https://example.com/large.jpg',
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
describe( 'getBestImageUrl', () => {
|
|
68
|
-
describe( 'when media_details.sizes is unavailable', () => {
|
|
69
|
-
it( 'returns source_url when media_details has no sizes', () => {
|
|
70
|
-
const media = {
|
|
71
|
-
...baseMedia,
|
|
72
|
-
media_details: { sizes: {} },
|
|
73
|
-
};
|
|
74
|
-
expect( getBestImageUrl( media ) ).toBe( baseMedia.source_url );
|
|
75
|
-
} );
|
|
76
|
-
} );
|
|
77
|
-
|
|
78
|
-
describe( 'when configSizes is not provided or unparseable', () => {
|
|
79
|
-
it( 'returns source_url when configSizes is undefined', () => {
|
|
80
|
-
expect( getBestImageUrl( baseMedia ) ).toBe( baseMedia.source_url );
|
|
81
|
-
} );
|
|
82
|
-
|
|
83
|
-
it( 'returns source_url when configSizes is not a number', () => {
|
|
84
|
-
expect( getBestImageUrl( baseMedia, 'auto' ) ).toBe(
|
|
85
|
-
baseMedia.source_url
|
|
86
|
-
);
|
|
87
|
-
} );
|
|
88
|
-
} );
|
|
89
|
-
|
|
90
|
-
describe( 'size selection with a valid target width', () => {
|
|
91
|
-
it( 'picks the smallest size >= target width', () => {
|
|
92
|
-
expect( getBestImageUrl( baseMedia, '200px' ) ).toBe(
|
|
93
|
-
'https://example.com/medium.jpg'
|
|
94
|
-
);
|
|
95
|
-
} );
|
|
96
|
-
|
|
97
|
-
it( 'picks an exact match', () => {
|
|
98
|
-
expect( getBestImageUrl( baseMedia, '300px' ) ).toBe(
|
|
99
|
-
'https://example.com/medium.jpg'
|
|
100
|
-
);
|
|
101
|
-
} );
|
|
102
|
-
|
|
103
|
-
it( 'picks the smallest available size when target is very small', () => {
|
|
104
|
-
expect( getBestImageUrl( baseMedia, '50px' ) ).toBe(
|
|
105
|
-
'https://example.com/thumb.jpg'
|
|
106
|
-
);
|
|
107
|
-
} );
|
|
108
|
-
|
|
109
|
-
it( 'falls back to the largest size when target exceeds all sizes', () => {
|
|
110
|
-
expect( getBestImageUrl( baseMedia, '2000px' ) ).toBe(
|
|
111
|
-
'https://example.com/large.jpg'
|
|
112
|
-
);
|
|
113
|
-
} );
|
|
114
|
-
} );
|
|
115
|
-
|
|
116
|
-
// These tests deliberately omit required Size fields (width, height, etc.)
|
|
117
|
-
// to verify runtime defensiveness, so we cast via `unknown` to bypass TS.
|
|
118
|
-
describe( 'when size entries have missing or invalid widths', () => {
|
|
119
|
-
it( 'skips entries without a width and selects from valid ones', () => {
|
|
120
|
-
const media = {
|
|
121
|
-
...baseMedia,
|
|
122
|
-
media_details: {
|
|
123
|
-
sizes: {
|
|
124
|
-
broken: {
|
|
125
|
-
source_url: 'https://example.com/broken.jpg',
|
|
126
|
-
},
|
|
127
|
-
medium: {
|
|
128
|
-
file: 'original-300x200.jpg',
|
|
129
|
-
width: 300,
|
|
130
|
-
height: 200,
|
|
131
|
-
mime_type: 'image/jpeg',
|
|
132
|
-
source_url: 'https://example.com/medium.jpg',
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
} as unknown as Media;
|
|
137
|
-
expect( getBestImageUrl( media, '200px' ) ).toBe(
|
|
138
|
-
'https://example.com/medium.jpg'
|
|
139
|
-
);
|
|
140
|
-
} );
|
|
141
|
-
|
|
142
|
-
it( 'falls back to source_url when all entries lack a valid width', () => {
|
|
143
|
-
const media = {
|
|
144
|
-
...baseMedia,
|
|
145
|
-
media_details: {
|
|
146
|
-
sizes: {
|
|
147
|
-
broken: {
|
|
148
|
-
source_url: 'https://example.com/broken.jpg',
|
|
149
|
-
},
|
|
150
|
-
also_broken: {
|
|
151
|
-
source_url: 'https://example.com/also-broken.jpg',
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
} as unknown as Media;
|
|
156
|
-
expect( getBestImageUrl( media, '200px' ) ).toBe(
|
|
157
|
-
baseMedia.source_url
|
|
158
|
-
);
|
|
159
|
-
} );
|
|
160
|
-
} );
|
|
161
|
-
} );
|