@wordpress/media-fields 0.13.1 → 0.13.2-next.v.202606191442.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/filename/view.tsx"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useMemo } from '@wordpress/element';\nimport { getFilename } from '@wordpress/url';\nimport type { DataViewRenderFieldProps } from '@wordpress/dataviews';\n// eslint-disable-next-line @wordpress/use-recommended-components -- `Tooltip` is not yet on the recommended `@wordpress/ui` allow-list; landing as a migration step ahead of the wider rollout.\nimport { Tooltip } from '@wordpress/ui';\n\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// The full filename is always in the DOM, so assistive tech gets it\n\t// regardless. The Tooltip aids mouse users where the cell visually clips\n\t// (DataViews layouts); in a non-truncating context like the DataForm the\n\t// name wraps in full, making it redundant but harmless.\n\treturn (\n\t\t<Tooltip.Root>\n\t\t\t<Tooltip.Trigger\n\t\t\t\trender={\n\t\t\t\t\t<span className=\"dataviews-media-field__filename\">\n\t\t\t\t\t\t{ fileName }\n\t\t\t\t\t</span>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<Tooltip.Popup>{ fileName }</Tooltip.Popup>\n\t\t</Tooltip.Root>\n\t);\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAAwB;AACxB,iBAA4B;AAG5B,gBAAwB;AA0BrB;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;AAMA,SACC,6CAAC,kBAAQ,MAAR,EACA;AAAA;AAAA,MAAC,kBAAQ;AAAA,MAAR;AAAA,QACA,QACC,4CAAC,UAAK,WAAU,mCACb,oBACH;AAAA;AAAA,IAEF;AAAA,IACA,4CAAC,kBAAQ,OAAR,EAAgB,oBAAU;AAAA,KAC5B;AAEF;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useMemo } from '@wordpress/element';\nimport { getFilename } from '@wordpress/url';\nimport type { DataViewRenderFieldProps } from '@wordpress/dataviews';\nimport { Tooltip } from '@wordpress/ui';\n\n/**\n * Internal dependencies\n */\nimport type { MediaItem } from '../types';\n\n// Proxy threshold for \"long enough that the cell will visually truncate\" —\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// The full filename is always in the DOM, so assistive tech gets it\n\t// regardless. The Tooltip aids mouse users where the cell visually clips\n\t// (DataViews layouts); in a non-truncating context like the DataForm the\n\t// name wraps in full, making it redundant but harmless.\n\treturn (\n\t\t<Tooltip.Root>\n\t\t\t<Tooltip.Trigger\n\t\t\t\trender={\n\t\t\t\t\t<span className=\"dataviews-media-field__filename\">\n\t\t\t\t\t\t{ fileName }\n\t\t\t\t\t</span>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<Tooltip.Popup>{ fileName }</Tooltip.Popup>\n\t\t</Tooltip.Root>\n\t);\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAAwB;AACxB,iBAA4B;AAE5B,gBAAwB;AA0BrB;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;AAMA,SACC,6CAAC,kBAAQ,MAAR,EACA;AAAA;AAAA,MAAC,kBAAQ;AAAA,MAAR;AAAA,QACA,QACC,4CAAC,UAAK,WAAU,mCACb,oBACH;AAAA;AAAA,IAEF;AAAA,IACA,4CAAC,kBAAQ,OAAR,EAAgB,oBAAU;AAAA,KAC5B;AAEF;",
6
6
  "names": []
7
7
  }
@@ -30,7 +30,7 @@ var mediaDimensionsField = {
30
30
  label: (0, import_i18n.__)("Dimensions"),
31
31
  getValue: ({ item }) => item?.media_details?.width && item?.media_details?.height ? (0, import_i18n.sprintf)(
32
32
  // translators: 1: Width. 2: Height.
33
- (0, import_i18n._x)("%1$s \xD7 %2$s", "image dimensions"),
33
+ (0, import_i18n._x)("%1$s × %2$s", "image dimensions"),
34
34
  item?.media_details?.width?.toString(),
35
35
  item?.media_details?.height?.toString()
36
36
  ) : "",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/media_dimensions/index.ts"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, _x, sprintf } from '@wordpress/i18n';\nimport type { Attachment, Updatable } from '@wordpress/core-data';\nimport type { Field } from '@wordpress/dataviews';\n\nconst mediaDimensionsField: Partial< Field< Updatable< Attachment > > > = {\n\tid: 'media_dimensions',\n\ttype: 'text',\n\tlabel: __( 'Dimensions' ),\n\tgetValue: ( { item } ) =>\n\t\titem?.media_details?.width && item?.media_details?.height\n\t\t\t? sprintf(\n\t\t\t\t\t// translators: 1: Width. 2: Height.\n\t\t\t\t\t_x( '%1$s \u00D7 %2$s', 'image dimensions' ),\n\t\t\t\t\titem?.media_details?.width?.toString(),\n\t\t\t\t\titem?.media_details?.height?.toString()\n\t\t\t )\n\t\t\t: '',\n\tisVisible: ( item ) => {\n\t\treturn !! ( item?.media_details?.width && item?.media_details?.height );\n\t},\n\tenableSorting: false,\n\tfilterBy: false,\n\treadOnly: true,\n};\n\nexport default mediaDimensionsField;\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAgC;AAIhC,IAAM,uBAAoE;AAAA,EACzE,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,WAAO,gBAAI,YAAa;AAAA,EACxB,UAAU,CAAE,EAAE,KAAK,MAClB,MAAM,eAAe,SAAS,MAAM,eAAe,aAChD;AAAA;AAAA,QAEA,gBAAI,kBAAe,kBAAmB;AAAA,IACtC,MAAM,eAAe,OAAO,SAAS;AAAA,IACrC,MAAM,eAAe,QAAQ,SAAS;AAAA,EACtC,IACA;AAAA,EACJ,WAAW,CAAE,SAAU;AACtB,WAAO,CAAC,EAAI,MAAM,eAAe,SAAS,MAAM,eAAe;AAAA,EAChE;AAAA,EACA,eAAe;AAAA,EACf,UAAU;AAAA,EACV,UAAU;AACX;AAEA,IAAO,2BAAQ;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, _x, sprintf } from '@wordpress/i18n';\nimport type { Attachment, Updatable } from '@wordpress/core-data';\nimport type { Field } from '@wordpress/dataviews';\n\nconst mediaDimensionsField: Partial< Field< Updatable< Attachment > > > = {\n\tid: 'media_dimensions',\n\ttype: 'text',\n\tlabel: __( 'Dimensions' ),\n\tgetValue: ( { item } ) =>\n\t\titem?.media_details?.width && item?.media_details?.height\n\t\t\t? sprintf(\n\t\t\t\t\t// translators: 1: Width. 2: Height.\n\t\t\t\t\t_x( '%1$s × %2$s', 'image dimensions' ),\n\t\t\t\t\titem?.media_details?.width?.toString(),\n\t\t\t\t\titem?.media_details?.height?.toString()\n\t\t\t )\n\t\t\t: '',\n\tisVisible: ( item ) => {\n\t\treturn !! ( item?.media_details?.width && item?.media_details?.height );\n\t},\n\tenableSorting: false,\n\tfilterBy: false,\n\treadOnly: true,\n};\n\nexport default mediaDimensionsField;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAgC;AAIhC,IAAM,uBAAoE;AAAA,EACzE,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,WAAO,gBAAI,YAAa;AAAA,EACxB,UAAU,CAAE,EAAE,KAAK,MAClB,MAAM,eAAe,SAAS,MAAM,eAAe,aAChD;AAAA;AAAA,QAEA,gBAAI,eAAe,kBAAmB;AAAA,IACtC,MAAM,eAAe,OAAO,SAAS;AAAA,IACrC,MAAM,eAAe,QAAQ,SAAS;AAAA,EACtC,IACA;AAAA,EACJ,WAAW,CAAE,SAAU;AACtB,WAAO,CAAC,EAAI,MAAM,eAAe,SAAS,MAAM,eAAe;AAAA,EAChE;AAAA,EACA,eAAe;AAAA,EACf,UAAU;AAAA,EACV,UAAU;AACX;AAEA,IAAO,2BAAQ;",
6
6
  "names": []
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 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"],
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' 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 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
5
  "mappings": "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",
6
6
  "names": ["VStack", "WCIcon", "Truncate", "clsx", "coreStore"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/filename/view.tsx"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useMemo } from '@wordpress/element';\nimport { getFilename } from '@wordpress/url';\nimport type { DataViewRenderFieldProps } from '@wordpress/dataviews';\n// eslint-disable-next-line @wordpress/use-recommended-components -- `Tooltip` is not yet on the recommended `@wordpress/ui` allow-list; landing as a migration step ahead of the wider rollout.\nimport { Tooltip } from '@wordpress/ui';\n\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// The full filename is always in the DOM, so assistive tech gets it\n\t// regardless. The Tooltip aids mouse users where the cell visually clips\n\t// (DataViews layouts); in a non-truncating context like the DataForm the\n\t// name wraps in full, making it redundant but harmless.\n\treturn (\n\t\t<Tooltip.Root>\n\t\t\t<Tooltip.Trigger\n\t\t\t\trender={\n\t\t\t\t\t<span className=\"dataviews-media-field__filename\">\n\t\t\t\t\t\t{ fileName }\n\t\t\t\t\t</span>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<Tooltip.Popup>{ fileName }</Tooltip.Popup>\n\t\t</Tooltip.Root>\n\t);\n}\n"],
5
- "mappings": ";AAGA,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAG5B,SAAS,eAAe;AA0BrB,cAWD,YAXC;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;AAMA,SACC,qBAAC,QAAQ,MAAR,EACA;AAAA;AAAA,MAAC,QAAQ;AAAA,MAAR;AAAA,QACA,QACC,oBAAC,UAAK,WAAU,mCACb,oBACH;AAAA;AAAA,IAEF;AAAA,IACA,oBAAC,QAAQ,OAAR,EAAgB,oBAAU;AAAA,KAC5B;AAEF;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useMemo } from '@wordpress/element';\nimport { getFilename } from '@wordpress/url';\nimport type { DataViewRenderFieldProps } from '@wordpress/dataviews';\nimport { Tooltip } from '@wordpress/ui';\n\n/**\n * Internal dependencies\n */\nimport type { MediaItem } from '../types';\n\n// Proxy threshold for \"long enough that the cell will visually truncate\" —\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// The full filename is always in the DOM, so assistive tech gets it\n\t// regardless. The Tooltip aids mouse users where the cell visually clips\n\t// (DataViews layouts); in a non-truncating context like the DataForm the\n\t// name wraps in full, making it redundant but harmless.\n\treturn (\n\t\t<Tooltip.Root>\n\t\t\t<Tooltip.Trigger\n\t\t\t\trender={\n\t\t\t\t\t<span className=\"dataviews-media-field__filename\">\n\t\t\t\t\t\t{ fileName }\n\t\t\t\t\t</span>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<Tooltip.Popup>{ fileName }</Tooltip.Popup>\n\t\t</Tooltip.Root>\n\t);\n}\n"],
5
+ "mappings": ";AAGA,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAE5B,SAAS,eAAe;AA0BrB,cAWD,YAXC;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;AAMA,SACC,qBAAC,QAAQ,MAAR,EACA;AAAA;AAAA,MAAC,QAAQ;AAAA,MAAR;AAAA,QACA,QACC,oBAAC,UAAK,WAAU,mCACb,oBACH;AAAA;AAAA,IAEF;AAAA,IACA,oBAAC,QAAQ,OAAR,EAAgB,oBAAU;AAAA,KAC5B;AAEF;",
6
6
  "names": []
7
7
  }
@@ -6,7 +6,7 @@ var mediaDimensionsField = {
6
6
  label: __("Dimensions"),
7
7
  getValue: ({ item }) => item?.media_details?.width && item?.media_details?.height ? sprintf(
8
8
  // translators: 1: Width. 2: Height.
9
- _x("%1$s \xD7 %2$s", "image dimensions"),
9
+ _x("%1$s × %2$s", "image dimensions"),
10
10
  item?.media_details?.width?.toString(),
11
11
  item?.media_details?.height?.toString()
12
12
  ) : "",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/media_dimensions/index.ts"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, _x, sprintf } from '@wordpress/i18n';\nimport type { Attachment, Updatable } from '@wordpress/core-data';\nimport type { Field } from '@wordpress/dataviews';\n\nconst mediaDimensionsField: Partial< Field< Updatable< Attachment > > > = {\n\tid: 'media_dimensions',\n\ttype: 'text',\n\tlabel: __( 'Dimensions' ),\n\tgetValue: ( { item } ) =>\n\t\titem?.media_details?.width && item?.media_details?.height\n\t\t\t? sprintf(\n\t\t\t\t\t// translators: 1: Width. 2: Height.\n\t\t\t\t\t_x( '%1$s \u00D7 %2$s', 'image dimensions' ),\n\t\t\t\t\titem?.media_details?.width?.toString(),\n\t\t\t\t\titem?.media_details?.height?.toString()\n\t\t\t )\n\t\t\t: '',\n\tisVisible: ( item ) => {\n\t\treturn !! ( item?.media_details?.width && item?.media_details?.height );\n\t},\n\tenableSorting: false,\n\tfilterBy: false,\n\treadOnly: true,\n};\n\nexport default mediaDimensionsField;\n"],
5
- "mappings": ";AAGA,SAAS,IAAI,IAAI,eAAe;AAIhC,IAAM,uBAAoE;AAAA,EACzE,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,OAAO,GAAI,YAAa;AAAA,EACxB,UAAU,CAAE,EAAE,KAAK,MAClB,MAAM,eAAe,SAAS,MAAM,eAAe,SAChD;AAAA;AAAA,IAEA,GAAI,kBAAe,kBAAmB;AAAA,IACtC,MAAM,eAAe,OAAO,SAAS;AAAA,IACrC,MAAM,eAAe,QAAQ,SAAS;AAAA,EACtC,IACA;AAAA,EACJ,WAAW,CAAE,SAAU;AACtB,WAAO,CAAC,EAAI,MAAM,eAAe,SAAS,MAAM,eAAe;AAAA,EAChE;AAAA,EACA,eAAe;AAAA,EACf,UAAU;AAAA,EACV,UAAU;AACX;AAEA,IAAO,2BAAQ;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, _x, sprintf } from '@wordpress/i18n';\nimport type { Attachment, Updatable } from '@wordpress/core-data';\nimport type { Field } from '@wordpress/dataviews';\n\nconst mediaDimensionsField: Partial< Field< Updatable< Attachment > > > = {\n\tid: 'media_dimensions',\n\ttype: 'text',\n\tlabel: __( 'Dimensions' ),\n\tgetValue: ( { item } ) =>\n\t\titem?.media_details?.width && item?.media_details?.height\n\t\t\t? sprintf(\n\t\t\t\t\t// translators: 1: Width. 2: Height.\n\t\t\t\t\t_x( '%1$s × %2$s', 'image dimensions' ),\n\t\t\t\t\titem?.media_details?.width?.toString(),\n\t\t\t\t\titem?.media_details?.height?.toString()\n\t\t\t )\n\t\t\t: '',\n\tisVisible: ( item ) => {\n\t\treturn !! ( item?.media_details?.width && item?.media_details?.height );\n\t},\n\tenableSorting: false,\n\tfilterBy: false,\n\treadOnly: true,\n};\n\nexport default mediaDimensionsField;\n"],
5
+ "mappings": ";AAGA,SAAS,IAAI,IAAI,eAAe;AAIhC,IAAM,uBAAoE;AAAA,EACzE,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,OAAO,GAAI,YAAa;AAAA,EACxB,UAAU,CAAE,EAAE,KAAK,MAClB,MAAM,eAAe,SAAS,MAAM,eAAe,SAChD;AAAA;AAAA,IAEA,GAAI,eAAe,kBAAmB;AAAA,IACtC,MAAM,eAAe,OAAO,SAAS;AAAA,IACrC,MAAM,eAAe,QAAQ,SAAS;AAAA,EACtC,IACA;AAAA,EACJ,WAAW,CAAE,SAAU;AACtB,WAAO,CAAC,EAAI,MAAM,eAAe,SAAS,MAAM,eAAe;AAAA,EAChE;AAAA,EACA,eAAe;AAAA,EACf,UAAU;AAAA,EACV,UAAU;AACX;AAEA,IAAO,2BAAQ;",
6
6
  "names": []
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 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"],
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' 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 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
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/filename/view.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAIrE;;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,oCAkCvC"}
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/filename/view.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGrE;;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,oCAkCvC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/media-fields",
3
- "version": "0.13.1",
3
+ "version": "0.13.2-next.v.202606191442.0+17fe7db8a",
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",
@@ -48,20 +48,19 @@
48
48
  "src/**/*.scss"
49
49
  ],
50
50
  "dependencies": {
51
- "@types/react": "^18.3.27",
52
- "@wordpress/base-styles": "^10.0.1",
53
- "@wordpress/components": "^35.0.1",
54
- "@wordpress/compose": "^8.1.1",
55
- "@wordpress/core-data": "^7.48.1",
56
- "@wordpress/data": "^10.48.1",
57
- "@wordpress/dataviews": "^16.0.1",
58
- "@wordpress/date": "^5.48.1",
59
- "@wordpress/element": "^8.0.1",
60
- "@wordpress/i18n": "^6.21.1",
61
- "@wordpress/icons": "^14.0.1",
62
- "@wordpress/primitives": "^4.48.1",
63
- "@wordpress/ui": "^0.15.1",
64
- "@wordpress/url": "^4.48.1",
51
+ "@wordpress/base-styles": "^10.0.2-next.v.202606191442.0+17fe7db8a",
52
+ "@wordpress/components": "^35.1.1-next.v.202606191442.0+17fe7db8a",
53
+ "@wordpress/compose": "^8.1.2-next.v.202606191442.0+17fe7db8a",
54
+ "@wordpress/core-data": "^7.48.2-next.v.202606191442.0+17fe7db8a",
55
+ "@wordpress/data": "^10.48.2-next.v.202606191442.0+17fe7db8a",
56
+ "@wordpress/dataviews": "^17.0.1-next.v.202606191442.0+17fe7db8a",
57
+ "@wordpress/date": "^5.48.2-next.v.202606191442.0+17fe7db8a",
58
+ "@wordpress/element": "^8.0.2-next.v.202606191442.0+17fe7db8a",
59
+ "@wordpress/i18n": "^6.21.2-next.v.202606191442.0+17fe7db8a",
60
+ "@wordpress/icons": "^14.0.2-next.v.202606191442.0+17fe7db8a",
61
+ "@wordpress/primitives": "^4.48.2-next.v.202606191442.0+17fe7db8a",
62
+ "@wordpress/ui": "^0.16.1-next.v.202606191442.0+17fe7db8a",
63
+ "@wordpress/url": "^4.48.2-next.v.202606191442.0+17fe7db8a",
65
64
  "clsx": "^2.1.1"
66
65
  },
67
66
  "devDependencies": {
@@ -71,10 +70,16 @@
71
70
  "@types/jest": "^29.5.14"
72
71
  },
73
72
  "peerDependencies": {
73
+ "@types/react": "^18.3.27",
74
74
  "react": "^18.0.0"
75
75
  },
76
+ "peerDependenciesMeta": {
77
+ "@types/react": {
78
+ "optional": true
79
+ }
80
+ },
76
81
  "publishConfig": {
77
82
  "access": "public"
78
83
  },
79
- "gitHead": "99df7432c5c7cb83ba41146fd1f57f3c19004305"
84
+ "gitHead": "1b6a19222df5a88f161880b5789efb3171d8f425"
80
85
  }
@@ -4,7 +4,6 @@
4
4
  import { useMemo } from '@wordpress/element';
5
5
  import { getFilename } from '@wordpress/url';
6
6
  import type { DataViewRenderFieldProps } from '@wordpress/dataviews';
7
- // eslint-disable-next-line @wordpress/use-recommended-components -- `Tooltip` is not yet on the recommended `@wordpress/ui` allow-list; landing as a migration step ahead of the wider rollout.
8
7
  import { Tooltip } from '@wordpress/ui';
9
8
 
10
9
  /**