@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
8 lines (7 loc) • 22.6 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../src/components/media-categories/index.js"],
"sourcesContent": ["/**\n * The `editor` settings here need to be in sync with the corresponding ones in `editor` package.\n * See `packages/editor/src/components/media-categories/index.js`.\n *\n * In the future we could consider creating an Openvese package that can be used in both `editor` and `site-editor`.\n * The rest of the settings would still need to be in sync though.\n */\nimport { __, sprintf, _x } from '@wordpress/i18n';\nimport { dispatch, resolveSelect, select, subscribe } from '@wordpress/data';\nimport { decodeEntities } from '@wordpress/html-entities';\nimport { store as coreStore } from '@wordpress/core-data';\n\n/** @typedef {import('@wordpress/block-editor').InserterMediaRequest} InserterMediaRequest */\n/** @typedef {import('@wordpress/block-editor').InserterMediaItem} InserterMediaItem */\n/** @typedef {import('@wordpress/block-editor').InserterMediaCategory} InserterMediaCategory */\n\nconst getExternalLink = ( url, text ) =>\n\t`<a ${ getExternalLinkAttributes( url ) }>${ text }</a>`;\n\nconst getExternalLinkAttributes = ( url ) =>\n\t`href=\"${ url }\" target=\"_blank\" rel=\"noopener\"`;\n\nconst getOpenverseLicense = ( license, licenseVersion ) => {\n\tlet licenseName = license.trim();\n\t// PDM has no abbreviation\n\tif ( license !== 'pdm' ) {\n\t\tlicenseName = license.toUpperCase().replace( 'SAMPLING', 'Sampling' );\n\t}\n\t// If version is known, append version to the name.\n\t// The license has to have a version to be valid. Only\n\t// PDM (public domain mark) doesn't have a version.\n\tif ( licenseVersion ) {\n\t\tlicenseName += ` ${ licenseVersion }`;\n\t}\n\t// For licenses other than public-domain marks, prepend 'CC' to the name.\n\tif ( ! [ 'pdm', 'cc0' ].includes( license ) ) {\n\t\tlicenseName = `CC ${ licenseName }`;\n\t}\n\treturn licenseName;\n};\n\nconst getOpenverseCaption = ( item ) => {\n\tconst {\n\t\ttitle,\n\t\tforeign_landing_url: foreignLandingUrl,\n\t\tcreator,\n\t\tcreator_url: creatorUrl,\n\t\tlicense,\n\t\tlicense_version: licenseVersion,\n\t\tlicense_url: licenseUrl,\n\t} = item;\n\tconst fullLicense = getOpenverseLicense( license, licenseVersion );\n\tconst _creator = decodeEntities( creator );\n\tlet _caption;\n\tif ( _creator ) {\n\t\t_caption = title\n\t\t\t? sprintf(\n\t\t\t\t\t// translators: %1s: Title of a media work from Openverse; %2$s: Name of the work's creator; %3s: Work's licence e.g: \"CC0 1.0\".\n\t\t\t\t\t_x( '\"%1$s\" by %2$s/ %3$s', 'caption' ),\n\t\t\t\t\tgetExternalLink(\n\t\t\t\t\t\tforeignLandingUrl,\n\t\t\t\t\t\tdecodeEntities( title )\n\t\t\t\t\t),\n\t\t\t\t\tcreatorUrl\n\t\t\t\t\t\t? getExternalLink( creatorUrl, _creator )\n\t\t\t\t\t\t: _creator,\n\t\t\t\t\tlicenseUrl\n\t\t\t\t\t\t? getExternalLink(\n\t\t\t\t\t\t\t\t`${ licenseUrl }?ref=openverse`,\n\t\t\t\t\t\t\t\tfullLicense\n\t\t\t\t\t\t )\n\t\t\t\t\t\t: fullLicense\n\t\t\t )\n\t\t\t: sprintf(\n\t\t\t\t\t// translators: %1s: Link attributes for a given Openverse media work; %2s: Name of the work's creator; %3s: Works's licence e.g: \"CC0 1.0\".\n\t\t\t\t\t_x( '<a %1$s>Work</a> by %2$s/ %3$s', 'caption' ),\n\t\t\t\t\tgetExternalLinkAttributes( foreignLandingUrl ),\n\t\t\t\t\tcreatorUrl\n\t\t\t\t\t\t? getExternalLink( creatorUrl, _creator )\n\t\t\t\t\t\t: _creator,\n\t\t\t\t\tlicenseUrl\n\t\t\t\t\t\t? getExternalLink(\n\t\t\t\t\t\t\t\t`${ licenseUrl }?ref=openverse`,\n\t\t\t\t\t\t\t\tfullLicense\n\t\t\t\t\t\t )\n\t\t\t\t\t\t: fullLicense\n\t\t\t );\n\t} else {\n\t\t_caption = title\n\t\t\t? sprintf(\n\t\t\t\t\t// translators: %1s: Title of a media work from Openverse; %2s: Work's licence e.g: \"CC0 1.0\".\n\t\t\t\t\t_x( '\"%1$s\"/ %2$s', 'caption' ),\n\t\t\t\t\tgetExternalLink(\n\t\t\t\t\t\tforeignLandingUrl,\n\t\t\t\t\t\tdecodeEntities( title )\n\t\t\t\t\t),\n\t\t\t\t\tlicenseUrl\n\t\t\t\t\t\t? getExternalLink(\n\t\t\t\t\t\t\t\t`${ licenseUrl }?ref=openverse`,\n\t\t\t\t\t\t\t\tfullLicense\n\t\t\t\t\t\t )\n\t\t\t\t\t\t: fullLicense\n\t\t\t )\n\t\t\t: sprintf(\n\t\t\t\t\t// translators: %1s: Link attributes for a given Openverse media work; %2s: Works's licence e.g: \"CC0 1.0\".\n\t\t\t\t\t_x( '<a %1$s>Work</a>/ %2$s', 'caption' ),\n\t\t\t\t\tgetExternalLinkAttributes( foreignLandingUrl ),\n\t\t\t\t\tlicenseUrl\n\t\t\t\t\t\t? getExternalLink(\n\t\t\t\t\t\t\t\t`${ licenseUrl }?ref=openverse`,\n\t\t\t\t\t\t\t\tfullLicense\n\t\t\t\t\t\t )\n\t\t\t\t\t\t: fullLicense\n\t\t\t );\n\t}\n\treturn _caption.replace( /\\s{2}/g, ' ' );\n};\n\nconst getCoreMediaQuery = ( query = {} ) => ( {\n\t...query,\n\torderBy: !! query?.search ? 'relevance' : 'date',\n} );\n\nconst coreMediaFetch = async ( query = {} ) => {\n\t// Use the same final query for the records fetch and the totals selectors so\n\t// their cached query key matches and the totals resolve to this exact request.\n\tconst finalQuery = getCoreMediaQuery( query );\n\tconst records = await resolveSelect( coreStore ).getEntityRecords(\n\t\t'postType',\n\t\t'attachment',\n\t\tfinalQuery\n\t);\n\t// Totals are read synchronously after resolution — the `getEntityRecords`\n\t// resolver captures them from the `X-WP-Total` / `X-WP-TotalPages` response\n\t// headers, and `resolveSelect().getEntityRecords()` only returns the records.\n\tconst totalItems = select( coreStore ).getEntityRecordsTotalItems(\n\t\t'postType',\n\t\t'attachment',\n\t\tfinalQuery\n\t);\n\tconst totalPages = select( coreStore ).getEntityRecordsTotalPages(\n\t\t'postType',\n\t\t'attachment',\n\t\tfinalQuery\n\t);\n\treturn {\n\t\tmediaItems: records.map( ( record ) => ( {\n\t\t\t...record,\n\t\t\talt: record.alt_text,\n\t\t\turl: record.source_url,\n\t\t\tpreviewUrl: record.media_details?.sizes?.medium?.source_url,\n\t\t\tcaption: record.caption?.raw,\n\t\t} ) ),\n\t\ttotalItems,\n\t\ttotalPages,\n\t};\n};\n\nconst getAttachedImagesQuery = ( postId, query = {} ) => ( {\n\t...query,\n\tmedia_type: 'image',\n\tparent: postId,\n} );\n\nconst normalizePostId = ( postId ) => {\n\tconst parsedPostId = typeof postId === 'number' ? postId : Number( postId );\n\n\treturn Number.isInteger( parsedPostId ) && parsedPostId > 0\n\t\t? parsedPostId\n\t\t: undefined;\n};\n\nconst saveAttachmentParent = ( attachmentId, postId ) =>\n\t// `throwOnError` so a failed REST write rejects (rather than being silently\n\t// swallowed), letting the attach/detach handlers surface an error notice\n\t// instead of a false success.\n\tdispatch( coreStore ).saveEntityRecord(\n\t\t'postType',\n\t\t'attachment',\n\t\t{\n\t\t\tid: attachmentId,\n\t\t\tpost: postId,\n\t\t},\n\t\t{ throwOnError: true }\n\t);\n\n// A selected media item's coarse type is exposed differently by each picker.\n// The classic media modal puts the media type directly on `type` (e.g. 'image').\n// The DataViews-driven modal passes REST attachment records, where `type` is the\n// *post* type ('attachment') and the media type lives in `media_type`\n// ('image'|'file') / `mime_type`. So the REST fields must be read first, with\n// `type` as the classic-modal fallback — otherwise a REST image reads as\n// 'attachment' and gets gated out.\nconst getMediaItemType = ( mediaItem ) =>\n\tmediaItem?.media_type ||\n\tmediaItem?.mime_type?.split( '/' )[ 0 ] ||\n\tmediaItem?.type;\n\n// The picker's \"Upload files\" tab accepts any file type, so the selection can\n// include non-images. Gate to images only: a non-image would be reparented to\n// the post but never appear in the image-filtered grid, and would wrongly count\n// toward the \"images attached\" notice.\nconst getImageAttachmentIds = ( mediaItems ) => [\n\t...new Set(\n\t\t( Array.isArray( mediaItems ) ? mediaItems : [ mediaItems ] )\n\t\t\t.filter(\n\t\t\t\t( mediaItem ) => getMediaItemType( mediaItem ) === 'image'\n\t\t\t)\n\t\t\t.map( ( mediaItem ) => mediaItem?.id )\n\t\t\t.filter( Boolean )\n\t),\n];\n\nconst invalidateAttachedImagesQueries = ( postId, query = {} ) => {\n\tconst { invalidateResolution } = dispatch( coreStore );\n\t// Invalidate the resolution backing the visible grid so it refetches after\n\t// an attach/detach and reflects the updated set of attached images. The tab\n\t// is always shown (via `emptyMessage`), so there's no separate visibility\n\t// probe to invalidate.\n\tinvalidateResolution( 'getEntityRecords', [\n\t\t'postType',\n\t\t'attachment',\n\t\tgetCoreMediaQuery( getAttachedImagesQuery( postId, query ) ),\n\t] );\n};\n\n// The inserter panel fetches imperatively into local state, so it can't react to\n// attachment cache invalidation on its own. Calls `onChange` on the resolved ->\n// unresolved edge of the resolution the grid reads, i.e. when that cache is\n// invalidated. `args` must match what `coreMediaFetch` resolves byte-for-byte,\n// since `invalidateResolution` keys on deep argument equality.\nconst subscribeToMediaInvalidation = ( args, onChange ) => {\n\tconst isResolved = () =>\n\t\tselect( coreStore ).hasFinishedResolution( 'getEntityRecords', args );\n\tlet wasResolved = isResolved();\n\t// Scoped to `coreStore` so the listener only runs on core-data changes.\n\treturn subscribe( () => {\n\t\tconst nowResolved = isResolved();\n\t\tif ( wasResolved && ! nowResolved ) {\n\t\t\tonChange();\n\t\t}\n\t\twasResolved = nowResolved;\n\t}, coreStore );\n};\n\n// Builds a core-data-backed category from a single `getQuery` mapper, so `fetch`\n// and `subscribe` can't drift apart on the resolution args. `coreMediaFetch`\n// applies `getCoreMediaQuery` internally, so `subscribe` mirrors it. External\n// sources (e.g. Openverse) don't use this and simply omit `subscribe`.\nconst createCoreMediaCategory = ( { getQuery, ...category } ) => ( {\n\t...category,\n\tasync fetch( query = {} ) {\n\t\treturn coreMediaFetch( getQuery( query ) );\n\t},\n\tsubscribe( onChange, query = {} ) {\n\t\treturn subscribeToMediaInvalidation(\n\t\t\t[\n\t\t\t\t'postType',\n\t\t\t\t'attachment',\n\t\t\t\tgetCoreMediaQuery( getQuery( query ) ),\n\t\t\t],\n\t\t\tonChange\n\t\t);\n\t},\n} );\n\n/**\n * Builds the \"Attachments\" media category for a given post. It behaves like\n * any other inserter media source (e.g. Openverse): it appears in the tab list\n * and renders through the shared media panel. In addition to `fetch`, it exposes\n * optional `attach`/`detach`/`invalidate` capabilities that the shared panel\n * picks up to offer an \"Attach images\" button and a per-item \"Detach from post\"\n * action in the same dropdown Openverse uses for \"Report image\". It also exposes\n * `subscribe`, so the panel can refetch when the attachment cache is invalidated\n * elsewhere (e.g. a media modal closing after an upload).\n *\n * @param {number} postId The current post id.\n * @param {string|null} [typeLabel] The post type's singular label to use in copy (e.g. \"Page\"),\n * or null to fall back to the generic \"post\".\n * @return {InserterMediaCategory} The Attachments media category.\n */\nconst getAttachedImagesCategory = ( postId, typeLabel ) =>\n\tcreateCoreMediaCategory( {\n\t\tname: 'attached-images',\n\t\tlabels: {\n\t\t\tname: __( 'Attached images' ),\n\t\t\tsearch_items: __( 'Search attachments' ),\n\t\t},\n\t\tmediaType: 'image',\n\t\tgetQuery: ( query ) => getAttachedImagesQuery( postId, query ),\n\t\t// The post type's singular label (e.g. \"Page\"), threaded through so the\n\t\t// shared panel can word its attach/detach copy for the current post type.\n\t\tpostTypeLabel: typeLabel,\n\t\t// Empty-state message. Providing this also keeps the source in the tab\n\t\t// list when it has no items, so it stays discoverable and the first\n\t\t// image can be attached even with none yet.\n\t\temptyMessage: typeLabel\n\t\t\t? sprintf(\n\t\t\t\t\t// translators: %s: Name of the post type e.g: \"Page\".\n\t\t\t\t\t__( 'No images attached to this %s.' ),\n\t\t\t\t\ttypeLabel\n\t\t\t )\n\t\t\t: __( 'No images attached to this post.' ),\n\t\tasync attach( mediaItems ) {\n\t\t\tconst attachmentIds = getImageAttachmentIds( mediaItems );\n\n\t\t\tawait Promise.all(\n\t\t\t\tattachmentIds.map( ( attachmentId ) =>\n\t\t\t\t\tsaveAttachmentParent( attachmentId, postId )\n\t\t\t\t)\n\t\t\t);\n\n\t\t\treturn attachmentIds.length;\n\t\t},\n\t\tasync detach( mediaItem ) {\n\t\t\tawait saveAttachmentParent( mediaItem.id, 0 );\n\t\t},\n\t\tinvalidate( query = {} ) {\n\t\t\tinvalidateAttachedImagesQueries( postId, query );\n\t\t},\n\t} );\n\n/** @type {InserterMediaCategory[]} */\nconst inserterMediaCategories = [\n\tcreateCoreMediaCategory( {\n\t\tname: 'images',\n\t\tlabels: {\n\t\t\tname: __( 'Images' ),\n\t\t\tsearch_items: __( 'Search images' ),\n\t\t},\n\t\tmediaType: 'image',\n\t\tgetQuery: ( query ) => ( { ...query, media_type: 'image' } ),\n\t} ),\n\tcreateCoreMediaCategory( {\n\t\tname: 'videos',\n\t\tlabels: {\n\t\t\tname: __( 'Videos' ),\n\t\t\tsearch_items: __( 'Search videos' ),\n\t\t},\n\t\tmediaType: 'video',\n\t\tgetQuery: ( query ) => ( { ...query, media_type: 'video' } ),\n\t} ),\n\tcreateCoreMediaCategory( {\n\t\tname: 'audio',\n\t\tlabels: {\n\t\t\tname: __( 'Audio' ),\n\t\t\tsearch_items: __( 'Search audio' ),\n\t\t},\n\t\tmediaType: 'audio',\n\t\tgetQuery: ( query ) => ( { ...query, media_type: 'audio' } ),\n\t} ),\n\t{\n\t\tname: 'openverse',\n\t\tlabels: {\n\t\t\tname: __( 'Openverse' ),\n\t\t\tsearch_items: __( 'Search Openverse' ),\n\t\t},\n\t\tmediaType: 'image',\n\t\tasync fetch( query = {} ) {\n\t\t\tconst defaultArgs = {\n\t\t\t\tmature: false,\n\t\t\t\texcluded_source: 'flickr,inaturalist,wikimedia',\n\t\t\t\tlicense: 'pdm,cc0',\n\t\t\t};\n\t\t\tconst finalQuery = { ...query, ...defaultArgs };\n\t\t\tconst mapFromInserterMediaRequest = {\n\t\t\t\tper_page: 'page_size',\n\t\t\t\tsearch: 'q',\n\t\t\t};\n\t\t\tconst url = new URL( 'https://api.openverse.org/v1/images/' );\n\t\t\tObject.entries( finalQuery ).forEach( ( [ key, value ] ) => {\n\t\t\t\tconst queryKey = mapFromInserterMediaRequest[ key ] || key;\n\t\t\t\turl.searchParams.set( queryKey, value );\n\t\t\t} );\n\t\t\tconst response = await window.fetch( url, {\n\t\t\t\theaders: {\n\t\t\t\t\t'User-Agent': 'WordPress/inserter-media-fetch',\n\t\t\t\t},\n\t\t\t} );\n\t\t\tconst jsonResponse = await response.json();\n\t\t\tconst results = jsonResponse.results;\n\t\t\t// This external source returns a plain array, so it renders without a\n\t\t\t// pager (the shared panel treats a non-object result as a single\n\t\t\t// page). To paginate it later, return the same\n\t\t\t// `{ mediaItems, totalItems, totalPages }` shape the core sources use,\n\t\t\t// mapping `jsonResponse.result_count` -> `totalItems` and\n\t\t\t// `jsonResponse.page_count` -> `totalPages` (Openverse already accepts\n\t\t\t// a `page` query arg, which passes straight through above).\n\t\t\treturn results.map( ( result ) => ( {\n\t\t\t\t...result,\n\t\t\t\t// This is a temp solution for better titles, until Openverse API\n\t\t\t\t// completes the cleaning up of some titles of their upstream data.\n\t\t\t\ttitle: result.title?.toLowerCase().startsWith( 'file:' )\n\t\t\t\t\t? result.title.slice( 5 )\n\t\t\t\t\t: result.title,\n\t\t\t\tsourceId: result.id,\n\t\t\t\tid: undefined,\n\t\t\t\tcaption: getOpenverseCaption( result ),\n\t\t\t\tpreviewUrl: result.thumbnail,\n\t\t\t} ) );\n\t\t},\n\t\tgetReportUrl: ( { sourceId } ) =>\n\t\t\t`https://wordpress.org/openverse/image/${ sourceId }/report/`,\n\t\tisExternalResource: true,\n\t},\n];\n\n/**\n * Returns the inserter media categories for a given post. The \"Attachments\"\n * category is prepended only when editing real, front-end-rendered content\n * (posts, pages, public custom post types). It is omitted for synced patterns,\n * navigation menus and templates, which aren't the entity that actually gets\n * rendered, so attaching media to them is meaningless.\n *\n * @param {number|string} postId The current post id.\n * @param {string} [viewablePostTypeLabel] Singular label of the post type, set only when it is front-end viewable (post, page, public CPT).\n * @return {InserterMediaCategory[]} The inserter media categories.\n */\nexport default function getInserterMediaCategories(\n\tpostId,\n\tviewablePostTypeLabel\n) {\n\tconst currentPostId = normalizePostId( postId );\n\n\t// A falsy label means either a non-viewable post type (synced pattern,\n\t// navigation, template) or that the record hasn't resolved yet — in both\n\t// cases the category is omitted. A numeric id is also required since it\n\t// backs the attachment `parent` query.\n\tif ( ! currentPostId || ! viewablePostTypeLabel ) {\n\t\treturn inserterMediaCategories;\n\t}\n\n\treturn [\n\t\tgetAttachedImagesCategory( currentPostId, viewablePostTypeLabel ),\n\t\t...inserterMediaCategories,\n\t];\n}\n"],
"mappings": ";AAOA,SAAS,IAAI,SAAS,UAAU;AAChC,SAAS,UAAU,eAAe,QAAQ,iBAAiB;AAC3D,SAAS,sBAAsB;AAC/B,SAAS,SAAS,iBAAiB;AAMnC,IAAM,kBAAkB,CAAE,KAAK,SAC9B,MAAO,0BAA2B,GAAI,CAAE,IAAK,IAAK;AAEnD,IAAM,4BAA4B,CAAE,QACnC,SAAU,GAAI;AAEf,IAAM,sBAAsB,CAAE,SAAS,mBAAoB;AAC1D,MAAI,cAAc,QAAQ,KAAK;AAE/B,MAAK,YAAY,OAAQ;AACxB,kBAAc,QAAQ,YAAY,EAAE,QAAS,YAAY,UAAW;AAAA,EACrE;AAIA,MAAK,gBAAiB;AACrB,mBAAe,IAAK,cAAe;AAAA,EACpC;AAEA,MAAK,CAAE,CAAE,OAAO,KAAM,EAAE,SAAU,OAAQ,GAAI;AAC7C,kBAAc,MAAO,WAAY;AAAA,EAClC;AACA,SAAO;AACR;AAEA,IAAM,sBAAsB,CAAE,SAAU;AACvC,QAAM;AAAA,IACL;AAAA,IACA,qBAAqB;AAAA,IACrB;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACd,IAAI;AACJ,QAAM,cAAc,oBAAqB,SAAS,cAAe;AACjE,QAAM,WAAW,eAAgB,OAAQ;AACzC,MAAI;AACJ,MAAK,UAAW;AACf,eAAW,QACR;AAAA;AAAA,MAEA,GAAI,wBAAwB,SAAU;AAAA,MACtC;AAAA,QACC;AAAA,QACA,eAAgB,KAAM;AAAA,MACvB;AAAA,MACA,aACG,gBAAiB,YAAY,QAAS,IACtC;AAAA,MACH,aACG;AAAA,QACA,GAAI,UAAW;AAAA,QACf;AAAA,MACA,IACA;AAAA,IACH,IACA;AAAA;AAAA,MAEA,GAAI,kCAAkC,SAAU;AAAA,MAChD,0BAA2B,iBAAkB;AAAA,MAC7C,aACG,gBAAiB,YAAY,QAAS,IACtC;AAAA,MACH,aACG;AAAA,QACA,GAAI,UAAW;AAAA,QACf;AAAA,MACA,IACA;AAAA,IACH;AAAA,EACJ,OAAO;AACN,eAAW,QACR;AAAA;AAAA,MAEA,GAAI,gBAAgB,SAAU;AAAA,MAC9B;AAAA,QACC;AAAA,QACA,eAAgB,KAAM;AAAA,MACvB;AAAA,MACA,aACG;AAAA,QACA,GAAI,UAAW;AAAA,QACf;AAAA,MACA,IACA;AAAA,IACH,IACA;AAAA;AAAA,MAEA,GAAI,0BAA0B,SAAU;AAAA,MACxC,0BAA2B,iBAAkB;AAAA,MAC7C,aACG;AAAA,QACA,GAAI,UAAW;AAAA,QACf;AAAA,MACA,IACA;AAAA,IACH;AAAA,EACJ;AACA,SAAO,SAAS,QAAS,UAAU,GAAI;AACxC;AAEA,IAAM,oBAAoB,CAAE,QAAQ,CAAC,OAAS;AAAA,EAC7C,GAAG;AAAA,EACH,SAAS,CAAC,CAAE,OAAO,SAAS,cAAc;AAC3C;AAEA,IAAM,iBAAiB,OAAQ,QAAQ,CAAC,MAAO;AAG9C,QAAM,aAAa,kBAAmB,KAAM;AAC5C,QAAM,UAAU,MAAM,cAAe,SAAU,EAAE;AAAA,IAChD;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAIA,QAAM,aAAa,OAAQ,SAAU,EAAE;AAAA,IACtC;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACA,QAAM,aAAa,OAAQ,SAAU,EAAE;AAAA,IACtC;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACA,SAAO;AAAA,IACN,YAAY,QAAQ,IAAK,CAAE,YAAc;AAAA,MACxC,GAAG;AAAA,MACH,KAAK,OAAO;AAAA,MACZ,KAAK,OAAO;AAAA,MACZ,YAAY,OAAO,eAAe,OAAO,QAAQ;AAAA,MACjD,SAAS,OAAO,SAAS;AAAA,IAC1B,EAAI;AAAA,IACJ;AAAA,IACA;AAAA,EACD;AACD;AAEA,IAAM,yBAAyB,CAAE,QAAQ,QAAQ,CAAC,OAAS;AAAA,EAC1D,GAAG;AAAA,EACH,YAAY;AAAA,EACZ,QAAQ;AACT;AAEA,IAAM,kBAAkB,CAAE,WAAY;AACrC,QAAM,eAAe,OAAO,WAAW,WAAW,SAAS,OAAQ,MAAO;AAE1E,SAAO,OAAO,UAAW,YAAa,KAAK,eAAe,IACvD,eACA;AACJ;AAEA,IAAM,uBAAuB,CAAE,cAAc;AAAA;AAAA;AAAA;AAAA,EAI5C,SAAU,SAAU,EAAE;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,MACC,IAAI;AAAA,MACJ,MAAM;AAAA,IACP;AAAA,IACA,EAAE,cAAc,KAAK;AAAA,EACtB;AAAA;AASD,IAAM,mBAAmB,CAAE,cAC1B,WAAW,cACX,WAAW,WAAW,MAAO,GAAI,EAAG,CAAE,KACtC,WAAW;AAMZ,IAAM,wBAAwB,CAAE,eAAgB;AAAA,EAC/C,GAAG,IAAI;AAAA,KACJ,MAAM,QAAS,UAAW,IAAI,aAAa,CAAE,UAAW,GACxD;AAAA,MACA,CAAE,cAAe,iBAAkB,SAAU,MAAM;AAAA,IACpD,EACC,IAAK,CAAE,cAAe,WAAW,EAAG,EACpC,OAAQ,OAAQ;AAAA,EACnB;AACD;AAEA,IAAM,kCAAkC,CAAE,QAAQ,QAAQ,CAAC,MAAO;AACjE,QAAM,EAAE,qBAAqB,IAAI,SAAU,SAAU;AAKrD,uBAAsB,oBAAoB;AAAA,IACzC;AAAA,IACA;AAAA,IACA,kBAAmB,uBAAwB,QAAQ,KAAM,CAAE;AAAA,EAC5D,CAAE;AACH;AAOA,IAAM,+BAA+B,CAAE,MAAM,aAAc;AAC1D,QAAM,aAAa,MAClB,OAAQ,SAAU,EAAE,sBAAuB,oBAAoB,IAAK;AACrE,MAAI,cAAc,WAAW;AAE7B,SAAO,UAAW,MAAM;AACvB,UAAM,cAAc,WAAW;AAC/B,QAAK,eAAe,CAAE,aAAc;AACnC,eAAS;AAAA,IACV;AACA,kBAAc;AAAA,EACf,GAAG,SAAU;AACd;AAMA,IAAM,0BAA0B,CAAE,EAAE,UAAU,GAAG,SAAS,OAAS;AAAA,EAClE,GAAG;AAAA,EACH,MAAM,MAAO,QAAQ,CAAC,GAAI;AACzB,WAAO,eAAgB,SAAU,KAAM,CAAE;AAAA,EAC1C;AAAA,EACA,UAAW,UAAU,QAAQ,CAAC,GAAI;AACjC,WAAO;AAAA,MACN;AAAA,QACC;AAAA,QACA;AAAA,QACA,kBAAmB,SAAU,KAAM,CAAE;AAAA,MACtC;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACD;AAiBA,IAAM,4BAA4B,CAAE,QAAQ,cAC3C,wBAAyB;AAAA,EACxB,MAAM;AAAA,EACN,QAAQ;AAAA,IACP,MAAM,GAAI,iBAAkB;AAAA,IAC5B,cAAc,GAAI,oBAAqB;AAAA,EACxC;AAAA,EACA,WAAW;AAAA,EACX,UAAU,CAAE,UAAW,uBAAwB,QAAQ,KAAM;AAAA;AAAA;AAAA,EAG7D,eAAe;AAAA;AAAA;AAAA;AAAA,EAIf,cAAc,YACX;AAAA;AAAA,IAEA,GAAI,gCAAiC;AAAA,IACrC;AAAA,EACA,IACA,GAAI,kCAAmC;AAAA,EAC1C,MAAM,OAAQ,YAAa;AAC1B,UAAM,gBAAgB,sBAAuB,UAAW;AAExD,UAAM,QAAQ;AAAA,MACb,cAAc;AAAA,QAAK,CAAE,iBACpB,qBAAsB,cAAc,MAAO;AAAA,MAC5C;AAAA,IACD;AAEA,WAAO,cAAc;AAAA,EACtB;AAAA,EACA,MAAM,OAAQ,WAAY;AACzB,UAAM,qBAAsB,UAAU,IAAI,CAAE;AAAA,EAC7C;AAAA,EACA,WAAY,QAAQ,CAAC,GAAI;AACxB,oCAAiC,QAAQ,KAAM;AAAA,EAChD;AACD,CAAE;AAGH,IAAM,0BAA0B;AAAA,EAC/B,wBAAyB;AAAA,IACxB,MAAM;AAAA,IACN,QAAQ;AAAA,MACP,MAAM,GAAI,QAAS;AAAA,MACnB,cAAc,GAAI,eAAgB;AAAA,IACnC;AAAA,IACA,WAAW;AAAA,IACX,UAAU,CAAE,WAAa,EAAE,GAAG,OAAO,YAAY,QAAQ;AAAA,EAC1D,CAAE;AAAA,EACF,wBAAyB;AAAA,IACxB,MAAM;AAAA,IACN,QAAQ;AAAA,MACP,MAAM,GAAI,QAAS;AAAA,MACnB,cAAc,GAAI,eAAgB;AAAA,IACnC;AAAA,IACA,WAAW;AAAA,IACX,UAAU,CAAE,WAAa,EAAE,GAAG,OAAO,YAAY,QAAQ;AAAA,EAC1D,CAAE;AAAA,EACF,wBAAyB;AAAA,IACxB,MAAM;AAAA,IACN,QAAQ;AAAA,MACP,MAAM,GAAI,OAAQ;AAAA,MAClB,cAAc,GAAI,cAAe;AAAA,IAClC;AAAA,IACA,WAAW;AAAA,IACX,UAAU,CAAE,WAAa,EAAE,GAAG,OAAO,YAAY,QAAQ;AAAA,EAC1D,CAAE;AAAA,EACF;AAAA,IACC,MAAM;AAAA,IACN,QAAQ;AAAA,MACP,MAAM,GAAI,WAAY;AAAA,MACtB,cAAc,GAAI,kBAAmB;AAAA,IACtC;AAAA,IACA,WAAW;AAAA,IACX,MAAM,MAAO,QAAQ,CAAC,GAAI;AACzB,YAAM,cAAc;AAAA,QACnB,QAAQ;AAAA,QACR,iBAAiB;AAAA,QACjB,SAAS;AAAA,MACV;AACA,YAAM,aAAa,EAAE,GAAG,OAAO,GAAG,YAAY;AAC9C,YAAM,8BAA8B;AAAA,QACnC,UAAU;AAAA,QACV,QAAQ;AAAA,MACT;AACA,YAAM,MAAM,IAAI,IAAK,sCAAuC;AAC5D,aAAO,QAAS,UAAW,EAAE,QAAS,CAAE,CAAE,KAAK,KAAM,MAAO;AAC3D,cAAM,WAAW,4BAA6B,GAAI,KAAK;AACvD,YAAI,aAAa,IAAK,UAAU,KAAM;AAAA,MACvC,CAAE;AACF,YAAM,WAAW,MAAM,OAAO,MAAO,KAAK;AAAA,QACzC,SAAS;AAAA,UACR,cAAc;AAAA,QACf;AAAA,MACD,CAAE;AACF,YAAM,eAAe,MAAM,SAAS,KAAK;AACzC,YAAM,UAAU,aAAa;AAQ7B,aAAO,QAAQ,IAAK,CAAE,YAAc;AAAA,QACnC,GAAG;AAAA;AAAA;AAAA,QAGH,OAAO,OAAO,OAAO,YAAY,EAAE,WAAY,OAAQ,IACpD,OAAO,MAAM,MAAO,CAAE,IACtB,OAAO;AAAA,QACV,UAAU,OAAO;AAAA,QACjB,IAAI;AAAA,QACJ,SAAS,oBAAqB,MAAO;AAAA,QACrC,YAAY,OAAO;AAAA,MACpB,EAAI;AAAA,IACL;AAAA,IACA,cAAc,CAAE,EAAE,SAAS,MAC1B,yCAA0C,QAAS;AAAA,IACpD,oBAAoB;AAAA,EACrB;AACD;AAae,SAAR,2BACN,QACA,uBACC;AACD,QAAM,gBAAgB,gBAAiB,MAAO;AAM9C,MAAK,CAAE,iBAAiB,CAAE,uBAAwB;AACjD,WAAO;AAAA,EACR;AAEA,SAAO;AAAA,IACN,0BAA2B,eAAe,qBAAsB;AAAA,IAChE,GAAG;AAAA,EACJ;AACD;",
"names": []
}