@wordpress/media-fields 0.11.0 → 0.12.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/build/author/view.cjs.map +3 -3
- package/build/filename/view.cjs +4 -1
- package/build/filename/view.cjs.map +3 -3
- package/build/media_thumbnail/view.cjs.map +3 -3
- package/build-module/author/view.mjs +5 -2
- package/build-module/author/view.mjs.map +2 -2
- package/build-module/filename/view.mjs +6 -6
- package/build-module/filename/view.mjs.map +2 -2
- package/build-module/media_thumbnail/view.mjs +2 -2
- package/build-module/media_thumbnail/view.mjs.map +2 -2
- package/build-style/style-rtl.css +9 -0
- package/build-style/style.css +9 -0
- package/build-types/author/view.d.ts.map +1 -1
- package/build-types/filename/view.d.ts.map +1 -1
- package/package.json +15 -15
- package/src/author/view.tsx +5 -2
- package/src/filename/style.scss +14 -0
- package/src/filename/test/view.test.tsx +30 -9
- package/src/filename/view.tsx +22 -13
- package/src/media_thumbnail/view.tsx +2 -2
- package/src/style.scss +1 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/author/view.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\nimport { useState, useCallback, useEffect } from '@wordpress/element';\nimport { commentAuthorAvatar as authorIcon } from '@wordpress/icons';\nimport {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAiB;AAKjB,kBAAmB;AACnB,qBAAiD;AACjD,mBAAkD;AAClD,
|
|
6
|
-
"names": ["HStack", "clsx", "authorIcon"]
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\nimport { useState, useCallback, useEffect } from '@wordpress/element';\nimport { commentAuthorAvatar as authorIcon } from '@wordpress/icons';\nimport {\n\t__experimentalHStack as HStack,\n\tIcon as WCIcon,\n} from '@wordpress/components';\nimport type { DataViewRenderFieldProps } from '@wordpress/dataviews';\n\n/**\n * Internal dependencies\n */\nimport type { MediaItem } from '../types';\n\nexport default function AuthorView( {\n\titem,\n}: DataViewRenderFieldProps< MediaItem > ) {\n\tconst author = item?._embedded?.author?.[ 0 ];\n\tconst text = author?.name;\n\tconst imageUrl = author?.avatar_urls?.[ 48 ];\n\n\t/*\n\t * Use three states to avoid fade-in animation for cached images:\n\t * 'instant' = image already cached, 'loading' = waiting, 'loaded' = just finished.\n\t */\n\tconst [ loadingState, setLoadingState ] = useState<\n\t\t'instant' | 'loading' | 'loaded'\n\t>( 'loading' );\n\n\tuseEffect( () => {\n\t\tsetLoadingState( 'loading' );\n\t}, [ imageUrl ] );\n\n\tconst imgRef = useCallback( ( img: HTMLImageElement | null ) => {\n\t\tif ( img?.complete ) {\n\t\t\tsetLoadingState( 'instant' );\n\t\t}\n\t}, [] );\n\n\tconst handleLoad = () => {\n\t\tif ( loadingState === 'loading' ) {\n\t\t\tsetLoadingState( 'loaded' );\n\t\t}\n\t};\n\n\treturn (\n\t\t<HStack alignment=\"left\" spacing={ 0 }>\n\t\t\t{ !! imageUrl && (\n\t\t\t\t<div\n\t\t\t\t\tclassName={ clsx( 'media-author-field__avatar', {\n\t\t\t\t\t\t'is-loading': loadingState === 'loading',\n\t\t\t\t\t\t'is-loaded': loadingState === 'loaded',\n\t\t\t\t\t} ) }\n\t\t\t\t>\n\t\t\t\t\t<img\n\t\t\t\t\t\tref={ imgRef }\n\t\t\t\t\t\tonLoad={ handleLoad }\n\t\t\t\t\t\talt={ __( 'Author avatar' ) }\n\t\t\t\t\t\tsrc={ imageUrl }\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t) }\n\t\t\t{ ! imageUrl && (\n\t\t\t\t<div className=\"media-author-field__icon\">\n\t\t\t\t\t<WCIcon icon={ authorIcon } />\n\t\t\t\t</div>\n\t\t\t) }\n\t\t\t<span className=\"media-author-field__name\">{ text }</span>\n\t\t</HStack>\n\t);\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAiB;AAKjB,kBAAmB;AACnB,qBAAiD;AACjD,mBAAkD;AAClD,wBAGO;AAwCL;AAhCa,SAAR,WAA6B;AAAA,EACnC;AACD,GAA2C;AAC1C,QAAM,SAAS,MAAM,WAAW,SAAU,CAAE;AAC5C,QAAM,OAAO,QAAQ;AACrB,QAAM,WAAW,QAAQ,cAAe,EAAG;AAM3C,QAAM,CAAE,cAAc,eAAgB,QAAI,yBAEvC,SAAU;AAEb,gCAAW,MAAM;AAChB,oBAAiB,SAAU;AAAA,EAC5B,GAAG,CAAE,QAAS,CAAE;AAEhB,QAAM,aAAS,4BAAa,CAAE,QAAkC;AAC/D,QAAK,KAAK,UAAW;AACpB,sBAAiB,SAAU;AAAA,IAC5B;AAAA,EACD,GAAG,CAAC,CAAE;AAEN,QAAM,aAAa,MAAM;AACxB,QAAK,iBAAiB,WAAY;AACjC,sBAAiB,QAAS;AAAA,IAC3B;AAAA,EACD;AAEA,SACC,6CAAC,kBAAAA,sBAAA,EAAO,WAAU,QAAO,SAAU,GAChC;AAAA,KAAC,CAAE,YACJ;AAAA,MAAC;AAAA;AAAA,QACA,eAAY,YAAAC,SAAM,8BAA8B;AAAA,UAC/C,cAAc,iBAAiB;AAAA,UAC/B,aAAa,iBAAiB;AAAA,QAC/B,CAAE;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACA,KAAM;AAAA,YACN,QAAS;AAAA,YACT,SAAM,gBAAI,eAAgB;AAAA,YAC1B,KAAM;AAAA;AAAA,QACP;AAAA;AAAA,IACD;AAAA,IAEC,CAAE,YACH,4CAAC,SAAI,WAAU,4BACd,sDAAC,kBAAAC,MAAA,EAAO,MAAO,aAAAC,qBAAa,GAC7B;AAAA,IAED,4CAAC,UAAK,WAAU,4BAA6B,gBAAM;AAAA,KACpD;AAEF;",
|
|
6
|
+
"names": ["HStack", "clsx", "WCIcon", "authorIcon"]
|
|
7
7
|
}
|
package/build/filename/view.cjs
CHANGED
|
@@ -38,6 +38,9 @@ function FileNameView({
|
|
|
38
38
|
if (!fileName) {
|
|
39
39
|
return "";
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
if (fileName.length <= TRUNCATE_LENGTH) {
|
|
42
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dataviews-media-field__filename", children: fileName });
|
|
43
|
+
}
|
|
44
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Tooltip, { text: fileName, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dataviews-media-field__filename", tabIndex: -1, children: fileName }) });
|
|
42
45
|
}
|
|
43
46
|
//# sourceMappingURL=view.cjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/filename/view.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,
|
|
6
|
-
"names": ["
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { Tooltip as WCTooltip } from '@wordpress/components';\nimport { useMemo } from '@wordpress/element';\nimport { getFilename } from '@wordpress/url';\nimport type { DataViewRenderFieldProps } from '@wordpress/dataviews';\n/**\n * Internal dependencies\n */\nimport type { MediaItem } from '../types';\n\n// Proxy threshold for \"long enough that the cell will visually truncate\" \u2014\n// used to decide whether to wrap the filename in a Tooltip showing the full\n// name on hover. Visual truncation itself is handled in CSS.\nconst TRUNCATE_LENGTH = 15;\n\nexport default function FileNameView( {\n\titem,\n}: DataViewRenderFieldProps< MediaItem > ) {\n\tconst fileName = useMemo(\n\t\t() => ( item?.source_url ? getFilename( item.source_url ) : null ),\n\t\t[ item?.source_url ]\n\t);\n\n\tif ( ! fileName ) {\n\t\treturn '';\n\t}\n\n\tif ( fileName.length <= TRUNCATE_LENGTH ) {\n\t\treturn (\n\t\t\t<span className=\"dataviews-media-field__filename\">\n\t\t\t\t{ fileName }\n\t\t\t</span>\n\t\t);\n\t}\n\n\t// `tabIndex={-1}` keeps the Tooltip anchor out of the keyboard tab order:\n\t// Ariakit's `useFocusable` (via TooltipAnchor) preserves an explicit\n\t// `tabIndex` on non-natively-focusable elements rather than defaulting it\n\t// to `0`. Hover-only reveal is intentional \u2014 the full filename text is\n\t// already in the DOM for assistive technology reading the row.\n\treturn (\n\t\t<WCTooltip text={ fileName }>\n\t\t\t<span className=\"dataviews-media-field__filename\" tabIndex={ -1 }>\n\t\t\t\t{ fileName }\n\t\t\t</span>\n\t\t</WCTooltip>\n\t);\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,wBAAqC;AACrC,qBAAwB;AACxB,iBAA4B;AA0BzB;AAhBH,IAAM,kBAAkB;AAET,SAAR,aAA+B;AAAA,EACrC;AACD,GAA2C;AAC1C,QAAM,eAAW;AAAA,IAChB,MAAQ,MAAM,iBAAa,wBAAa,KAAK,UAAW,IAAI;AAAA,IAC5D,CAAE,MAAM,UAAW;AAAA,EACpB;AAEA,MAAK,CAAE,UAAW;AACjB,WAAO;AAAA,EACR;AAEA,MAAK,SAAS,UAAU,iBAAkB;AACzC,WACC,4CAAC,UAAK,WAAU,mCACb,oBACH;AAAA,EAEF;AAOA,SACC,4CAAC,kBAAAA,SAAA,EAAU,MAAO,UACjB,sDAAC,UAAK,WAAU,mCAAkC,UAAW,IAC1D,oBACH,GACD;AAEF;",
|
|
6
|
+
"names": ["WCTooltip"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/media_thumbnail/view.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\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, useRef, useLayoutEffect } 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\n/**\n * Given the available image sizes and a target display width, returns the URL\n * of the smallest size whose width is >= the target. Falls back to the largest\n * available size, or the original source_url.\n *\n * @param featuredMedia The media item with size details.\n * @param configSizes The target display size string (e.g. '900px').\n */\nexport function getBestImageUrl(\n\tfeaturedMedia: Attachment | MediaItem,\n\tconfigSizes?: string\n): string {\n\tconst sizes = featuredMedia?.media_details?.sizes;\n\tif ( ! sizes ) {\n\t\treturn featuredMedia.source_url;\n\t}\n\n\tconst sizeEntries = Object.values( sizes );\n\n\tif ( ! sizeEntries.length ) {\n\t\treturn featuredMedia.source_url;\n\t}\n\n\t// Parse target width from config.sizes (e.g. '900px' \u2192 900).\n\tconst targetWidth = configSizes ? parseInt( configSizes, 10 ) : NaN;\n\n\tif ( ! Number.isNaN( targetWidth ) ) {\n\t\t// Filter to entries that have a valid numeric width.\n\t\tconst validEntries = sizeEntries.filter(\n\t\t\t( s ) => typeof s.width === 'number' && ! Number.isNaN( s.width )\n\t\t);\n\n\t\tif ( ! validEntries.length ) {\n\t\t\treturn featuredMedia.source_url;\n\t\t}\n\n\t\t// Sort ascending by width.\n\t\tconst sorted = [ ...validEntries ].sort(\n\t\t\t( a, b ) => a.width - b.width\n\t\t);\n\t\t// Pick the smallest size that is >= target width.\n\t\tconst match = sorted.find( ( s ) => s.width >= targetWidth );\n\t\tif ( match ) {\n\t\t\treturn match.source_url;\n\t\t}\n\t\t// No size large enough \u2014 use the largest available.\n\t\treturn sorted[ sorted.length - 1 ].source_url;\n\t}\n\n\t// If we can't parse the target, fall back to source_url.\n\treturn featuredMedia.source_url;\n}\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<
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["VStack", "Truncate", "clsx", "coreStore"]
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\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 as WCIcon,\n} from '@wordpress/components';\nimport { useState, useRef, useLayoutEffect } 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\n/**\n * Given the available image sizes and a target display width, returns the URL\n * of the smallest size whose width is >= the target. Falls back to the largest\n * available size, or the original source_url.\n *\n * @param featuredMedia The media item with size details.\n * @param configSizes The target display size string (e.g. '900px').\n */\nexport function getBestImageUrl(\n\tfeaturedMedia: Attachment | MediaItem,\n\tconfigSizes?: string\n): string {\n\tconst sizes = featuredMedia?.media_details?.sizes;\n\tif ( ! sizes ) {\n\t\treturn featuredMedia.source_url;\n\t}\n\n\tconst sizeEntries = Object.values( sizes );\n\n\tif ( ! sizeEntries.length ) {\n\t\treturn featuredMedia.source_url;\n\t}\n\n\t// Parse target width from config.sizes (e.g. '900px' \u2192 900).\n\tconst targetWidth = configSizes ? parseInt( configSizes, 10 ) : NaN;\n\n\tif ( ! Number.isNaN( targetWidth ) ) {\n\t\t// Filter to entries that have a valid numeric width.\n\t\tconst validEntries = sizeEntries.filter(\n\t\t\t( s ) => typeof s.width === 'number' && ! Number.isNaN( s.width )\n\t\t);\n\n\t\tif ( ! validEntries.length ) {\n\t\t\treturn featuredMedia.source_url;\n\t\t}\n\n\t\t// Sort ascending by width.\n\t\tconst sorted = [ ...validEntries ].sort(\n\t\t\t( a, b ) => a.width - b.width\n\t\t);\n\t\t// Pick the smallest size that is >= target width.\n\t\tconst match = sorted.find( ( s ) => s.width >= targetWidth );\n\t\tif ( match ) {\n\t\t\treturn match.source_url;\n\t\t}\n\t\t// No size large enough \u2014 use the largest available.\n\t\treturn sorted[ sorted.length - 1 ].source_url;\n\t}\n\n\t// If we can't parse the target, fall back to source_url.\n\treturn featuredMedia.source_url;\n}\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<WCIcon\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\nfunction ImageView( {\n\titem,\n\tconfigSizes,\n\tonError,\n}: {\n\titem: Attachment | MediaItem;\n\tconfigSizes?: string;\n\tonError: () => void;\n} ) {\n\tconst imageUrl = getBestImageUrl( item, configSizes );\n\n\t/*\n\t * Use three states to avoid fade-in animation for cached images:\n\t * 'instant' = image already cached, 'loading' = waiting, 'loaded' = just finished.\n\t *\n\t * useLayoutEffect runs synchronously after DOM mutations but before paint,\n\t * so we can check img.complete to detect disk-cached images and skip the\n\t * fade-in animation entirely.\n\t */\n\tconst imgRef = useRef< HTMLImageElement >( null );\n\tconst [ loadingState, setLoadingState ] = useState<\n\t\t'instant' | 'loading' | 'loaded'\n\t>( 'loading' );\n\n\tuseLayoutEffect( () => {\n\t\tif ( imgRef.current?.complete ) {\n\t\t\tsetLoadingState( 'instant' );\n\t\t} else {\n\t\t\tsetLoadingState( 'loading' );\n\t\t}\n\t}, [ imageUrl ] );\n\n\tconst handleLoad = () => {\n\t\tif ( loadingState === 'loading' ) {\n\t\t\tsetLoadingState( 'loaded' );\n\t\t}\n\t};\n\n\treturn (\n\t\t<div\n\t\t\tclassName={ clsx( 'dataviews-media-field__media-thumbnail', {\n\t\t\t\t'is-loading': loadingState === 'loading',\n\t\t\t\t'is-loaded': loadingState === 'loaded',\n\t\t\t} ) }\n\t\t>\n\t\t\t<img\n\t\t\t\tref={ imgRef }\n\t\t\t\tclassName=\"dataviews-media-field__media-thumbnail--image\"\n\t\t\t\tsrc={ imageUrl }\n\t\t\t\talt={ item.alt_text || item.title.raw }\n\t\t\t\tonLoad={ handleLoad }\n\t\t\t\tonError={ onError }\n\t\t\t\tloading=\"lazy\"\n\t\t\t/>\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<ImageView\n\t\t\titem={ featuredMedia }\n\t\t\tconfigSizes={ config?.sizes }\n\t\t\tonError={ () => setImageError( true ) }\n\t\t/>\n\t);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["VStack", "WCIcon", "Truncate", "clsx", "coreStore"]
|
|
7
7
|
}
|
|
@@ -3,7 +3,10 @@ import clsx from "clsx";
|
|
|
3
3
|
import { __ } from "@wordpress/i18n";
|
|
4
4
|
import { useState, useCallback, useEffect } from "@wordpress/element";
|
|
5
5
|
import { commentAuthorAvatar as authorIcon } from "@wordpress/icons";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
__experimentalHStack as HStack,
|
|
8
|
+
Icon as WCIcon
|
|
9
|
+
} from "@wordpress/components";
|
|
7
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
11
|
function AuthorView({
|
|
9
12
|
item
|
|
@@ -44,7 +47,7 @@ function AuthorView({
|
|
|
44
47
|
)
|
|
45
48
|
}
|
|
46
49
|
),
|
|
47
|
-
!imageUrl && /* @__PURE__ */ jsx("div", { className: "media-author-field__icon", children: /* @__PURE__ */ jsx(
|
|
50
|
+
!imageUrl && /* @__PURE__ */ jsx("div", { className: "media-author-field__icon", children: /* @__PURE__ */ jsx(WCIcon, { icon: authorIcon }) }),
|
|
48
51
|
/* @__PURE__ */ jsx("span", { className: "media-author-field__name", children: text })
|
|
49
52
|
] });
|
|
50
53
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/author/view.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\nimport { useState, useCallback, useEffect } from '@wordpress/element';\nimport { commentAuthorAvatar as authorIcon } from '@wordpress/icons';\nimport {
|
|
5
|
-
"mappings": ";AAGA,OAAO,UAAU;AAKjB,SAAS,UAAU;AACnB,SAAS,UAAU,aAAa,iBAAiB;AACjD,SAAS,uBAAuB,kBAAkB;AAClD,
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport { __ } from '@wordpress/i18n';\nimport { useState, useCallback, useEffect } from '@wordpress/element';\nimport { commentAuthorAvatar as authorIcon } from '@wordpress/icons';\nimport {\n\t__experimentalHStack as HStack,\n\tIcon as WCIcon,\n} from '@wordpress/components';\nimport type { DataViewRenderFieldProps } from '@wordpress/dataviews';\n\n/**\n * Internal dependencies\n */\nimport type { MediaItem } from '../types';\n\nexport default function AuthorView( {\n\titem,\n}: DataViewRenderFieldProps< MediaItem > ) {\n\tconst author = item?._embedded?.author?.[ 0 ];\n\tconst text = author?.name;\n\tconst imageUrl = author?.avatar_urls?.[ 48 ];\n\n\t/*\n\t * Use three states to avoid fade-in animation for cached images:\n\t * 'instant' = image already cached, 'loading' = waiting, 'loaded' = just finished.\n\t */\n\tconst [ loadingState, setLoadingState ] = useState<\n\t\t'instant' | 'loading' | 'loaded'\n\t>( 'loading' );\n\n\tuseEffect( () => {\n\t\tsetLoadingState( 'loading' );\n\t}, [ imageUrl ] );\n\n\tconst imgRef = useCallback( ( img: HTMLImageElement | null ) => {\n\t\tif ( img?.complete ) {\n\t\t\tsetLoadingState( 'instant' );\n\t\t}\n\t}, [] );\n\n\tconst handleLoad = () => {\n\t\tif ( loadingState === 'loading' ) {\n\t\t\tsetLoadingState( 'loaded' );\n\t\t}\n\t};\n\n\treturn (\n\t\t<HStack alignment=\"left\" spacing={ 0 }>\n\t\t\t{ !! imageUrl && (\n\t\t\t\t<div\n\t\t\t\t\tclassName={ clsx( 'media-author-field__avatar', {\n\t\t\t\t\t\t'is-loading': loadingState === 'loading',\n\t\t\t\t\t\t'is-loaded': loadingState === 'loaded',\n\t\t\t\t\t} ) }\n\t\t\t\t>\n\t\t\t\t\t<img\n\t\t\t\t\t\tref={ imgRef }\n\t\t\t\t\t\tonLoad={ handleLoad }\n\t\t\t\t\t\talt={ __( 'Author avatar' ) }\n\t\t\t\t\t\tsrc={ imageUrl }\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t) }\n\t\t\t{ ! imageUrl && (\n\t\t\t\t<div className=\"media-author-field__icon\">\n\t\t\t\t\t<WCIcon icon={ authorIcon } />\n\t\t\t\t</div>\n\t\t\t) }\n\t\t\t<span className=\"media-author-field__name\">{ text }</span>\n\t\t</HStack>\n\t);\n}\n"],
|
|
5
|
+
"mappings": ";AAGA,OAAO,UAAU;AAKjB,SAAS,UAAU;AACnB,SAAS,UAAU,aAAa,iBAAiB;AACjD,SAAS,uBAAuB,kBAAkB;AAClD;AAAA,EACC,wBAAwB;AAAA,EACxB,QAAQ;AAAA,OACF;AAwCL,SAQG,KARH;AAhCa,SAAR,WAA6B;AAAA,EACnC;AACD,GAA2C;AAC1C,QAAM,SAAS,MAAM,WAAW,SAAU,CAAE;AAC5C,QAAM,OAAO,QAAQ;AACrB,QAAM,WAAW,QAAQ,cAAe,EAAG;AAM3C,QAAM,CAAE,cAAc,eAAgB,IAAI,SAEvC,SAAU;AAEb,YAAW,MAAM;AAChB,oBAAiB,SAAU;AAAA,EAC5B,GAAG,CAAE,QAAS,CAAE;AAEhB,QAAM,SAAS,YAAa,CAAE,QAAkC;AAC/D,QAAK,KAAK,UAAW;AACpB,sBAAiB,SAAU;AAAA,IAC5B;AAAA,EACD,GAAG,CAAC,CAAE;AAEN,QAAM,aAAa,MAAM;AACxB,QAAK,iBAAiB,WAAY;AACjC,sBAAiB,QAAS;AAAA,IAC3B;AAAA,EACD;AAEA,SACC,qBAAC,UAAO,WAAU,QAAO,SAAU,GAChC;AAAA,KAAC,CAAE,YACJ;AAAA,MAAC;AAAA;AAAA,QACA,WAAY,KAAM,8BAA8B;AAAA,UAC/C,cAAc,iBAAiB;AAAA,UAC/B,aAAa,iBAAiB;AAAA,QAC/B,CAAE;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACA,KAAM;AAAA,YACN,QAAS;AAAA,YACT,KAAM,GAAI,eAAgB;AAAA,YAC1B,KAAM;AAAA;AAAA,QACP;AAAA;AAAA,IACD;AAAA,IAEC,CAAE,YACH,oBAAC,SAAI,WAAU,4BACd,8BAAC,UAAO,MAAO,YAAa,GAC7B;AAAA,IAED,oBAAC,UAAK,WAAU,4BAA6B,gBAAM;AAAA,KACpD;AAEF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
// packages/media-fields/src/filename/view.tsx
|
|
2
|
-
import {
|
|
3
|
-
Tooltip,
|
|
4
|
-
__experimentalTruncate as Truncate
|
|
5
|
-
} from "@wordpress/components";
|
|
2
|
+
import { Tooltip as WCTooltip } from "@wordpress/components";
|
|
6
3
|
import { useMemo } from "@wordpress/element";
|
|
7
4
|
import { getFilename } from "@wordpress/url";
|
|
8
|
-
import {
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
6
|
var TRUNCATE_LENGTH = 15;
|
|
10
7
|
function FileNameView({
|
|
11
8
|
item
|
|
@@ -17,7 +14,10 @@ function FileNameView({
|
|
|
17
14
|
if (!fileName) {
|
|
18
15
|
return "";
|
|
19
16
|
}
|
|
20
|
-
|
|
17
|
+
if (fileName.length <= TRUNCATE_LENGTH) {
|
|
18
|
+
return /* @__PURE__ */ jsx("span", { className: "dataviews-media-field__filename", children: fileName });
|
|
19
|
+
}
|
|
20
|
+
return /* @__PURE__ */ jsx(WCTooltip, { text: fileName, children: /* @__PURE__ */ jsx("span", { className: "dataviews-media-field__filename", tabIndex: -1, children: fileName }) });
|
|
21
21
|
}
|
|
22
22
|
export {
|
|
23
23
|
FileNameView as default
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/filename/view.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {
|
|
5
|
-
"mappings": ";AAGA
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { Tooltip as WCTooltip } from '@wordpress/components';\nimport { useMemo } from '@wordpress/element';\nimport { getFilename } from '@wordpress/url';\nimport type { DataViewRenderFieldProps } from '@wordpress/dataviews';\n/**\n * Internal dependencies\n */\nimport type { MediaItem } from '../types';\n\n// Proxy threshold for \"long enough that the cell will visually truncate\" \u2014\n// used to decide whether to wrap the filename in a Tooltip showing the full\n// name on hover. Visual truncation itself is handled in CSS.\nconst TRUNCATE_LENGTH = 15;\n\nexport default function FileNameView( {\n\titem,\n}: DataViewRenderFieldProps< MediaItem > ) {\n\tconst fileName = useMemo(\n\t\t() => ( item?.source_url ? getFilename( item.source_url ) : null ),\n\t\t[ item?.source_url ]\n\t);\n\n\tif ( ! fileName ) {\n\t\treturn '';\n\t}\n\n\tif ( fileName.length <= TRUNCATE_LENGTH ) {\n\t\treturn (\n\t\t\t<span className=\"dataviews-media-field__filename\">\n\t\t\t\t{ fileName }\n\t\t\t</span>\n\t\t);\n\t}\n\n\t// `tabIndex={-1}` keeps the Tooltip anchor out of the keyboard tab order:\n\t// Ariakit's `useFocusable` (via TooltipAnchor) preserves an explicit\n\t// `tabIndex` on non-natively-focusable elements rather than defaulting it\n\t// to `0`. Hover-only reveal is intentional \u2014 the full filename text is\n\t// already in the DOM for assistive technology reading the row.\n\treturn (\n\t\t<WCTooltip text={ fileName }>\n\t\t\t<span className=\"dataviews-media-field__filename\" tabIndex={ -1 }>\n\t\t\t\t{ fileName }\n\t\t\t</span>\n\t\t</WCTooltip>\n\t);\n}\n"],
|
|
5
|
+
"mappings": ";AAGA,SAAS,WAAW,iBAAiB;AACrC,SAAS,eAAe;AACxB,SAAS,mBAAmB;AA0BzB;AAhBH,IAAM,kBAAkB;AAET,SAAR,aAA+B;AAAA,EACrC;AACD,GAA2C;AAC1C,QAAM,WAAW;AAAA,IAChB,MAAQ,MAAM,aAAa,YAAa,KAAK,UAAW,IAAI;AAAA,IAC5D,CAAE,MAAM,UAAW;AAAA,EACpB;AAEA,MAAK,CAAE,UAAW;AACjB,WAAO;AAAA,EACR;AAEA,MAAK,SAAS,UAAU,iBAAkB;AACzC,WACC,oBAAC,UAAK,WAAU,mCACb,oBACH;AAAA,EAEF;AAOA,SACC,oBAAC,aAAU,MAAO,UACjB,8BAAC,UAAK,WAAU,mCAAkC,UAAW,IAC1D,oBACH,GACD;AAEF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -5,7 +5,7 @@ import { store as coreStore } from "@wordpress/core-data";
|
|
|
5
5
|
import {
|
|
6
6
|
__experimentalTruncate as Truncate,
|
|
7
7
|
__experimentalVStack as VStack,
|
|
8
|
-
Icon
|
|
8
|
+
Icon as WCIcon
|
|
9
9
|
} from "@wordpress/components";
|
|
10
10
|
import { useState, useRef, useLayoutEffect } from "@wordpress/element";
|
|
11
11
|
import { getFilename } from "@wordpress/url";
|
|
@@ -52,7 +52,7 @@ function FallbackView({
|
|
|
52
52
|
spacing: 0,
|
|
53
53
|
children: [
|
|
54
54
|
/* @__PURE__ */ jsx(
|
|
55
|
-
|
|
55
|
+
WCIcon,
|
|
56
56
|
{
|
|
57
57
|
className: "dataviews-media-field__media-thumbnail--icon",
|
|
58
58
|
icon: getMediaTypeFromMimeType(item.mime_type).icon,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/media_thumbnail/view.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\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, useRef, useLayoutEffect } 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\n/**\n * Given the available image sizes and a target display width, returns the URL\n * of the smallest size whose width is >= the target. Falls back to the largest\n * available size, or the original source_url.\n *\n * @param featuredMedia The media item with size details.\n * @param configSizes The target display size string (e.g. '900px').\n */\nexport function getBestImageUrl(\n\tfeaturedMedia: Attachment | MediaItem,\n\tconfigSizes?: string\n): string {\n\tconst sizes = featuredMedia?.media_details?.sizes;\n\tif ( ! sizes ) {\n\t\treturn featuredMedia.source_url;\n\t}\n\n\tconst sizeEntries = Object.values( sizes );\n\n\tif ( ! sizeEntries.length ) {\n\t\treturn featuredMedia.source_url;\n\t}\n\n\t// Parse target width from config.sizes (e.g. '900px' \u2192 900).\n\tconst targetWidth = configSizes ? parseInt( configSizes, 10 ) : NaN;\n\n\tif ( ! Number.isNaN( targetWidth ) ) {\n\t\t// Filter to entries that have a valid numeric width.\n\t\tconst validEntries = sizeEntries.filter(\n\t\t\t( s ) => typeof s.width === 'number' && ! Number.isNaN( s.width )\n\t\t);\n\n\t\tif ( ! validEntries.length ) {\n\t\t\treturn featuredMedia.source_url;\n\t\t}\n\n\t\t// Sort ascending by width.\n\t\tconst sorted = [ ...validEntries ].sort(\n\t\t\t( a, b ) => a.width - b.width\n\t\t);\n\t\t// Pick the smallest size that is >= target width.\n\t\tconst match = sorted.find( ( s ) => s.width >= targetWidth );\n\t\tif ( match ) {\n\t\t\treturn match.source_url;\n\t\t}\n\t\t// No size large enough \u2014 use the largest available.\n\t\treturn sorted[ sorted.length - 1 ].source_url;\n\t}\n\n\t// If we can't parse the target, fall back to source_url.\n\treturn featuredMedia.source_url;\n}\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<
|
|
5
|
-
"mappings": ";AAGA,OAAO,UAAU;AAKjB,SAAS,iBAAiB;AAC1B,SAAS,SAAS,iBAAiB;AACnC;AAAA,EACC,0BAA0B;AAAA,EAC1B,wBAAwB;AAAA,EACxB;AAAA,
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\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 as WCIcon,\n} from '@wordpress/components';\nimport { useState, useRef, useLayoutEffect } 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\n/**\n * Given the available image sizes and a target display width, returns the URL\n * of the smallest size whose width is >= the target. Falls back to the largest\n * available size, or the original source_url.\n *\n * @param featuredMedia The media item with size details.\n * @param configSizes The target display size string (e.g. '900px').\n */\nexport function getBestImageUrl(\n\tfeaturedMedia: Attachment | MediaItem,\n\tconfigSizes?: string\n): string {\n\tconst sizes = featuredMedia?.media_details?.sizes;\n\tif ( ! sizes ) {\n\t\treturn featuredMedia.source_url;\n\t}\n\n\tconst sizeEntries = Object.values( sizes );\n\n\tif ( ! sizeEntries.length ) {\n\t\treturn featuredMedia.source_url;\n\t}\n\n\t// Parse target width from config.sizes (e.g. '900px' \u2192 900).\n\tconst targetWidth = configSizes ? parseInt( configSizes, 10 ) : NaN;\n\n\tif ( ! Number.isNaN( targetWidth ) ) {\n\t\t// Filter to entries that have a valid numeric width.\n\t\tconst validEntries = sizeEntries.filter(\n\t\t\t( s ) => typeof s.width === 'number' && ! Number.isNaN( s.width )\n\t\t);\n\n\t\tif ( ! validEntries.length ) {\n\t\t\treturn featuredMedia.source_url;\n\t\t}\n\n\t\t// Sort ascending by width.\n\t\tconst sorted = [ ...validEntries ].sort(\n\t\t\t( a, b ) => a.width - b.width\n\t\t);\n\t\t// Pick the smallest size that is >= target width.\n\t\tconst match = sorted.find( ( s ) => s.width >= targetWidth );\n\t\tif ( match ) {\n\t\t\treturn match.source_url;\n\t\t}\n\t\t// No size large enough \u2014 use the largest available.\n\t\treturn sorted[ sorted.length - 1 ].source_url;\n\t}\n\n\t// If we can't parse the target, fall back to source_url.\n\treturn featuredMedia.source_url;\n}\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<WCIcon\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\nfunction ImageView( {\n\titem,\n\tconfigSizes,\n\tonError,\n}: {\n\titem: Attachment | MediaItem;\n\tconfigSizes?: string;\n\tonError: () => void;\n} ) {\n\tconst imageUrl = getBestImageUrl( item, configSizes );\n\n\t/*\n\t * Use three states to avoid fade-in animation for cached images:\n\t * 'instant' = image already cached, 'loading' = waiting, 'loaded' = just finished.\n\t *\n\t * useLayoutEffect runs synchronously after DOM mutations but before paint,\n\t * so we can check img.complete to detect disk-cached images and skip the\n\t * fade-in animation entirely.\n\t */\n\tconst imgRef = useRef< HTMLImageElement >( null );\n\tconst [ loadingState, setLoadingState ] = useState<\n\t\t'instant' | 'loading' | 'loaded'\n\t>( 'loading' );\n\n\tuseLayoutEffect( () => {\n\t\tif ( imgRef.current?.complete ) {\n\t\t\tsetLoadingState( 'instant' );\n\t\t} else {\n\t\t\tsetLoadingState( 'loading' );\n\t\t}\n\t}, [ imageUrl ] );\n\n\tconst handleLoad = () => {\n\t\tif ( loadingState === 'loading' ) {\n\t\t\tsetLoadingState( 'loaded' );\n\t\t}\n\t};\n\n\treturn (\n\t\t<div\n\t\t\tclassName={ clsx( 'dataviews-media-field__media-thumbnail', {\n\t\t\t\t'is-loading': loadingState === 'loading',\n\t\t\t\t'is-loaded': loadingState === 'loaded',\n\t\t\t} ) }\n\t\t>\n\t\t\t<img\n\t\t\t\tref={ imgRef }\n\t\t\t\tclassName=\"dataviews-media-field__media-thumbnail--image\"\n\t\t\t\tsrc={ imageUrl }\n\t\t\t\talt={ item.alt_text || item.title.raw }\n\t\t\t\tonLoad={ handleLoad }\n\t\t\t\tonError={ onError }\n\t\t\t\tloading=\"lazy\"\n\t\t\t/>\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<ImageView\n\t\t\titem={ featuredMedia }\n\t\t\tconfigSizes={ config?.sizes }\n\t\t\tonError={ () => setImageError( true ) }\n\t\t/>\n\t);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -131,6 +131,15 @@
|
|
|
131
131
|
overflow: hidden;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
.dataviews-media-field__filename {
|
|
135
|
+
display: inline-block;
|
|
136
|
+
max-inline-size: 15ch;
|
|
137
|
+
overflow: hidden;
|
|
138
|
+
text-overflow: ellipsis;
|
|
139
|
+
white-space: nowrap;
|
|
140
|
+
vertical-align: top;
|
|
141
|
+
}
|
|
142
|
+
|
|
134
143
|
.dataviews-media-field__media-thumbnail {
|
|
135
144
|
display: flex;
|
|
136
145
|
align-items: center;
|
package/build-style/style.css
CHANGED
|
@@ -131,6 +131,15 @@
|
|
|
131
131
|
overflow: hidden;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
.dataviews-media-field__filename {
|
|
135
|
+
display: inline-block;
|
|
136
|
+
max-inline-size: 15ch;
|
|
137
|
+
overflow: hidden;
|
|
138
|
+
text-overflow: ellipsis;
|
|
139
|
+
white-space: nowrap;
|
|
140
|
+
vertical-align: top;
|
|
141
|
+
}
|
|
142
|
+
|
|
134
143
|
.dataviews-media-field__media-thumbnail {
|
|
135
144
|
display: flex;
|
|
136
145
|
align-items: center;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/author/view.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/author/view.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAErE;;GAEG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,MAAM,CAAC,OAAO,UAAU,UAAU,CAAE,EACnC,IAAI,EACJ,EAAE,wBAAwB,CAAE,SAAS,CAAE,+BAsDvC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/filename/view.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/filename/view.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACrE;;GAEG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAO1C,MAAM,CAAC,OAAO,UAAU,YAAY,CAAE,EACrC,IAAI,EACJ,EAAE,wBAAwB,CAAE,SAAS,CAAE,oCA8BvC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/media-fields",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
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": "^
|
|
53
|
-
"@wordpress/components": "^
|
|
54
|
-
"@wordpress/compose": "^
|
|
55
|
-
"@wordpress/core-data": "^7.
|
|
56
|
-
"@wordpress/data": "^10.
|
|
57
|
-
"@wordpress/dataviews": "^
|
|
58
|
-
"@wordpress/date": "^5.
|
|
59
|
-
"@wordpress/element": "^
|
|
60
|
-
"@wordpress/i18n": "^6.
|
|
61
|
-
"@wordpress/icons": "^13.
|
|
62
|
-
"@wordpress/primitives": "^4.
|
|
63
|
-
"@wordpress/url": "^4.
|
|
52
|
+
"@wordpress/base-styles": "^9.0.0",
|
|
53
|
+
"@wordpress/components": "^34.0.0",
|
|
54
|
+
"@wordpress/compose": "^8.0.0",
|
|
55
|
+
"@wordpress/core-data": "^7.47.0",
|
|
56
|
+
"@wordpress/data": "^10.47.0",
|
|
57
|
+
"@wordpress/dataviews": "^15.0.0",
|
|
58
|
+
"@wordpress/date": "^5.47.0",
|
|
59
|
+
"@wordpress/element": "^7.0.0",
|
|
60
|
+
"@wordpress/i18n": "^6.20.0",
|
|
61
|
+
"@wordpress/icons": "^13.2.0",
|
|
62
|
+
"@wordpress/primitives": "^4.47.0",
|
|
63
|
+
"@wordpress/url": "^4.47.0",
|
|
64
64
|
"clsx": "2.1.1"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
@@ -68,10 +68,10 @@
|
|
|
68
68
|
"@types/jest": "^29.5.14"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
|
-
"react": "^
|
|
71
|
+
"react": "^19.2.4"
|
|
72
72
|
},
|
|
73
73
|
"publishConfig": {
|
|
74
74
|
"access": "public"
|
|
75
75
|
},
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "d653c5fd6161571a0c2ebde28553d6e25624eacc"
|
|
77
77
|
}
|
package/src/author/view.tsx
CHANGED
|
@@ -9,7 +9,10 @@ import clsx from 'clsx';
|
|
|
9
9
|
import { __ } from '@wordpress/i18n';
|
|
10
10
|
import { useState, useCallback, useEffect } from '@wordpress/element';
|
|
11
11
|
import { commentAuthorAvatar as authorIcon } from '@wordpress/icons';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
__experimentalHStack as HStack,
|
|
14
|
+
Icon as WCIcon,
|
|
15
|
+
} from '@wordpress/components';
|
|
13
16
|
import type { DataViewRenderFieldProps } from '@wordpress/dataviews';
|
|
14
17
|
|
|
15
18
|
/**
|
|
@@ -67,7 +70,7 @@ export default function AuthorView( {
|
|
|
67
70
|
) }
|
|
68
71
|
{ ! imageUrl && (
|
|
69
72
|
<div className="media-author-field__icon">
|
|
70
|
-
<
|
|
73
|
+
<WCIcon icon={ authorIcon } />
|
|
71
74
|
</div>
|
|
72
75
|
) }
|
|
73
76
|
<span className="media-author-field__name">{ text }</span>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// CSS-based truncation (rather than `__experimentalTruncate`) so the full
|
|
2
|
+
// filename stays in the DOM — keeps it available to assistive technology
|
|
3
|
+
// reading the row, and lets the cell respond to column width changes.
|
|
4
|
+
.dataviews-media-field__filename {
|
|
5
|
+
display: inline-block;
|
|
6
|
+
max-inline-size: 15ch;
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
text-overflow: ellipsis;
|
|
9
|
+
white-space: nowrap;
|
|
10
|
+
// Snap to the top of the line box so the cell aligns correctly in the
|
|
11
|
+
// DataViews Grid layout — without this the inline-block sits on the
|
|
12
|
+
// baseline and pushes the row out of alignment.
|
|
13
|
+
vertical-align: top;
|
|
14
|
+
}
|
|
@@ -17,7 +17,7 @@ import type { MediaItem } from '../../types';
|
|
|
17
17
|
|
|
18
18
|
describe( 'FileNameView', () => {
|
|
19
19
|
describe( 'filename rendering', () => {
|
|
20
|
-
it( 'renders short filename
|
|
20
|
+
it( 'renders short filename without a tooltip anchor or tabindex', () => {
|
|
21
21
|
const item: Partial< MediaItem > = {
|
|
22
22
|
source_url: 'https://example.com/uploads/12345678901.jpg', // exactly 15 chars
|
|
23
23
|
};
|
|
@@ -29,11 +29,12 @@ describe( 'FileNameView', () => {
|
|
|
29
29
|
/>
|
|
30
30
|
);
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
expect(
|
|
32
|
+
const rendered = screen.getByText( '12345678901.jpg' );
|
|
33
|
+
expect( rendered ).toHaveClass( 'dataviews-media-field__filename' );
|
|
34
|
+
expect( rendered ).not.toHaveAttribute( 'tabindex' );
|
|
34
35
|
} );
|
|
35
36
|
|
|
36
|
-
it( 'renders long filename
|
|
37
|
+
it( 'renders long filename inside a Tooltip and exposes the full name in the DOM', () => {
|
|
37
38
|
const longFilename =
|
|
38
39
|
'very-long-filename-that-exceeds-fifteen-characters.jpg';
|
|
39
40
|
const item: Partial< MediaItem > = {
|
|
@@ -47,11 +48,31 @@ describe( 'FileNameView', () => {
|
|
|
47
48
|
/>
|
|
48
49
|
);
|
|
49
50
|
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
).
|
|
51
|
+
// CSS handles the visual ellipsis; the DOM text remains the full
|
|
52
|
+
// filename so assistive technology reading the row gets the
|
|
53
|
+
// complete name, and the Tooltip exposes it on mouse hover.
|
|
54
|
+
const rendered = screen.getByText( longFilename );
|
|
55
|
+
expect( rendered ).toHaveClass( 'dataviews-media-field__filename' );
|
|
56
|
+
} );
|
|
57
|
+
|
|
58
|
+
it( 'does not add a tab stop for truncated filenames', () => {
|
|
59
|
+
const longFilename =
|
|
60
|
+
'very-long-filename-that-exceeds-fifteen-characters.jpg';
|
|
61
|
+
const item: Partial< MediaItem > = {
|
|
62
|
+
source_url: `https://example.com/uploads/${ longFilename }`,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
render(
|
|
66
|
+
<FileNameView
|
|
67
|
+
item={ item as MediaItem }
|
|
68
|
+
field={ filenameField as NormalizedField< MediaItem > }
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
expect( screen.getByText( longFilename ) ).toHaveAttribute(
|
|
73
|
+
'tabindex',
|
|
74
|
+
'-1'
|
|
75
|
+
);
|
|
55
76
|
} );
|
|
56
77
|
} );
|
|
57
78
|
|
package/src/filename/view.tsx
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
Tooltip,
|
|
6
|
-
__experimentalTruncate as Truncate,
|
|
7
|
-
} from '@wordpress/components';
|
|
4
|
+
import { Tooltip as WCTooltip } from '@wordpress/components';
|
|
8
5
|
import { useMemo } from '@wordpress/element';
|
|
9
6
|
import { getFilename } from '@wordpress/url';
|
|
10
7
|
import type { DataViewRenderFieldProps } from '@wordpress/dataviews';
|
|
@@ -13,8 +10,9 @@ import type { DataViewRenderFieldProps } from '@wordpress/dataviews';
|
|
|
13
10
|
*/
|
|
14
11
|
import type { MediaItem } from '../types';
|
|
15
12
|
|
|
16
|
-
//
|
|
17
|
-
//
|
|
13
|
+
// Proxy threshold for "long enough that the cell will visually truncate" —
|
|
14
|
+
// used to decide whether to wrap the filename in a Tooltip showing the full
|
|
15
|
+
// name on hover. Visual truncation itself is handled in CSS.
|
|
18
16
|
const TRUNCATE_LENGTH = 15;
|
|
19
17
|
|
|
20
18
|
export default function FileNameView( {
|
|
@@ -29,13 +27,24 @@ export default function FileNameView( {
|
|
|
29
27
|
return '';
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<
|
|
30
|
+
if ( fileName.length <= TRUNCATE_LENGTH ) {
|
|
31
|
+
return (
|
|
32
|
+
<span className="dataviews-media-field__filename">
|
|
35
33
|
{ fileName }
|
|
36
|
-
</
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
</span>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// `tabIndex={-1}` keeps the Tooltip anchor out of the keyboard tab order:
|
|
39
|
+
// Ariakit's `useFocusable` (via TooltipAnchor) preserves an explicit
|
|
40
|
+
// `tabIndex` on non-natively-focusable elements rather than defaulting it
|
|
41
|
+
// to `0`. Hover-only reveal is intentional — the full filename text is
|
|
42
|
+
// already in the DOM for assistive technology reading the row.
|
|
43
|
+
return (
|
|
44
|
+
<WCTooltip text={ fileName }>
|
|
45
|
+
<span className="dataviews-media-field__filename" tabIndex={ -1 }>
|
|
46
|
+
{ fileName }
|
|
47
|
+
</span>
|
|
48
|
+
</WCTooltip>
|
|
40
49
|
);
|
|
41
50
|
}
|
|
@@ -11,7 +11,7 @@ import { store as coreStore } from '@wordpress/core-data';
|
|
|
11
11
|
import {
|
|
12
12
|
__experimentalTruncate as Truncate,
|
|
13
13
|
__experimentalVStack as VStack,
|
|
14
|
-
Icon,
|
|
14
|
+
Icon as WCIcon,
|
|
15
15
|
} from '@wordpress/components';
|
|
16
16
|
import { useState, useRef, useLayoutEffect } from '@wordpress/element';
|
|
17
17
|
import type { Attachment } from '@wordpress/core-data';
|
|
@@ -91,7 +91,7 @@ function FallbackView( {
|
|
|
91
91
|
className="dataviews-media-field__media-thumbnail__stack"
|
|
92
92
|
spacing={ 0 }
|
|
93
93
|
>
|
|
94
|
-
<
|
|
94
|
+
<WCIcon
|
|
95
95
|
className="dataviews-media-field__media-thumbnail--icon"
|
|
96
96
|
icon={ getMediaTypeFromMimeType( item.mime_type ).icon }
|
|
97
97
|
size={ 24 }
|
package/src/style.scss
CHANGED