UNPKG

@wordpress/server-side-render

Version:

The component used with WordPress to server-side render a preview of dynamic blocks to display in the editor.

8 lines (7 loc) 7.56 kB
{ "version": 3, "sources": ["../src/hook.js"], "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { debounce } from '@wordpress/compose';\nimport { useEffect, useState, useRef } from '@wordpress/element';\nimport apiFetch from '@wordpress/api-fetch';\nimport { addQueryArgs } from '@wordpress/url';\nimport { __experimentalSanitizeBlockAttributes } from '@wordpress/blocks';\n\nexport function rendererPath( block, attributes = null, urlQueryArgs = {} ) {\n\treturn addQueryArgs( `/wp/v2/block-renderer/${ block }`, {\n\t\tcontext: 'edit',\n\t\t...( null !== attributes ? { attributes } : {} ),\n\t\t...urlQueryArgs,\n\t} );\n}\n\nexport function removeBlockSupportAttributes( attributes ) {\n\tconst {\n\t\tbackgroundColor,\n\t\tborderColor,\n\t\tfontFamily,\n\t\tfontSize,\n\t\tgradient,\n\t\ttextColor,\n\t\tclassName,\n\t\t...restAttributes\n\t} = attributes;\n\n\tconst {\n\t\tborder,\n\t\tcolor,\n\t\telements,\n\t\tshadow,\n\t\tspacing,\n\t\ttypography,\n\t\t...restStyles\n\t} = attributes?.style || {};\n\n\treturn {\n\t\t...restAttributes,\n\t\tstyle: restStyles,\n\t};\n}\n\n/**\n * @typedef {Object} ServerSideRenderResponse\n * @property {string} status - The current request status: 'idle', 'loading', 'success', or 'error'.\n * @property {string} [content] - The rendered block content (available when status is 'success').\n * @property {string} [error] - The error message (available when status is 'error').\n */\n\n/**\n * A hook for server-side rendering a preview of dynamic blocks to display in the editor.\n *\n * Handles fetching server-rendered previews for blocks, managing loading states,\n * and automatically debouncing requests to prevent excessive API calls. It supports both\n * GET and POST requests, with POST requests used for larger attribute payloads.\n *\n * @example\n * Basic usage:\n *\n * ```jsx\n * import { RawHTML } from '@wordpress/element';\n * import { useServerSideRender } from '@wordpress/server-side-render';\n *\n * function MyServerSideRender( { attributes, block } ) {\n * const { content, status, error } = useServerSideRender( {\n * attributes,\n * block,\n * } );\n *\n * if ( status === 'loading' ) {\n * return <div>Loading...</div>;\n * }\n *\n * if ( status === 'error' ) {\n * return <div>Error: { error }</div>;\n * }\n *\n * return <RawHTML>{ content }</RawHTML>;\n * }\n * ```\n *\n * @param {Object} args The hook configuration object.\n * @param {Object} args.attributes The block attributes to be sent to the server for rendering.\n * @param {string} args.block The identifier of the block to be serverside rendered. Example: 'core/archives'.\n * @param {boolean} [args.skipBlockSupportAttributes=false] Whether to remove block support attributes before sending.\n * @param {string} [args.httpMethod='GET'] The HTTP method to use ('GET' or 'POST'). Default is 'GET'.\n * @param {Object} [args.urlQueryArgs] Additional query arguments to append to the request URL.\n *\n * @return {ServerSideRenderResponse} The server-side render response object.\n */\nexport function useServerSideRender( args ) {\n\tconst [ response, setResponse ] = useState( { status: 'idle' } );\n\tconst shouldDebounceRef = useRef( false );\n\n\tconst {\n\t\tattributes,\n\t\tblock,\n\t\tskipBlockSupportAttributes = false,\n\t\thttpMethod = 'GET',\n\t\turlQueryArgs,\n\t} = args;\n\n\tlet sanitizedAttributes =\n\t\tattributes &&\n\t\t__experimentalSanitizeBlockAttributes( block, attributes );\n\n\tif ( skipBlockSupportAttributes ) {\n\t\tsanitizedAttributes =\n\t\t\tremoveBlockSupportAttributes( sanitizedAttributes );\n\t}\n\n\t// If httpMethod is 'POST', send the attributes in the request body instead of the URL.\n\t// This allows sending a larger attributes object than in a GET request, where the attributes are in the URL.\n\tconst isPostRequest = 'POST' === httpMethod;\n\tconst urlAttributes = isPostRequest ? null : sanitizedAttributes;\n\tconst path = rendererPath( block, urlAttributes, urlQueryArgs );\n\tconst body = isPostRequest\n\t\t? JSON.stringify( { attributes: sanitizedAttributes ?? null } )\n\t\t: undefined;\n\n\tuseEffect( () => {\n\t\tconst controller = new AbortController();\n\t\tconst debouncedFetch = debounce(\n\t\t\tfunction () {\n\t\t\t\t{\n\t\t\t\t\tsetResponse( { status: 'loading' } );\n\n\t\t\t\t\tapiFetch( {\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tmethod: isPostRequest ? 'POST' : 'GET',\n\t\t\t\t\t\tbody,\n\t\t\t\t\t\theaders: isPostRequest\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t: {},\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t} )\n\t\t\t\t\t\t.then( ( res ) => {\n\t\t\t\t\t\t\tsetResponse( {\n\t\t\t\t\t\t\t\tstatus: 'success',\n\t\t\t\t\t\t\t\tcontent: res ? res.rendered : '',\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.catch( ( error ) => {\n\t\t\t\t\t\t\t// The request was aborted, do not update the response.\n\t\t\t\t\t\t\tif ( error.name === 'AbortError' ) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tsetResponse( {\n\t\t\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\t\t\terror: error.message,\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.finally( () => {\n\t\t\t\t\t\t\t// Debounce requests after first fetch.\n\t\t\t\t\t\t\tshouldDebounceRef.current = true;\n\t\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t},\n\t\t\tshouldDebounceRef.current ? 500 : 0\n\t\t);\n\n\t\tdebouncedFetch();\n\n\t\treturn () => {\n\t\t\tcontroller.abort();\n\t\t\tdebouncedFetch.cancel();\n\t\t};\n\t}, [ path, isPostRequest, body ] );\n\n\treturn response;\n}\n"], "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAAyB;AACzB,qBAA4C;AAC5C,uBAAqB;AACrB,iBAA6B;AAC7B,oBAAsD;AAE/C,SAAS,aAAc,OAAO,aAAa,MAAM,eAAe,CAAC,GAAI;AAC3E,aAAO,yBAAc,yBAA0B,KAAM,IAAI;AAAA,IACxD,SAAS;AAAA,IACT,GAAK,SAAS,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IAC7C,GAAG;AAAA,EACJ,CAAE;AACH;AAEO,SAAS,6BAA8B,YAAa;AAC1D,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACJ,IAAI;AAEJ,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACJ,IAAI,YAAY,SAAS,CAAC;AAE1B,SAAO;AAAA,IACN,GAAG;AAAA,IACH,OAAO;AAAA,EACR;AACD;AAkDO,SAAS,oBAAqB,MAAO;AAC3C,QAAM,CAAE,UAAU,WAAY,QAAI,yBAAU,EAAE,QAAQ,OAAO,CAAE;AAC/D,QAAM,wBAAoB,uBAAQ,KAAM;AAExC,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA,6BAA6B;AAAA,IAC7B,aAAa;AAAA,IACb;AAAA,EACD,IAAI;AAEJ,MAAI,sBACH,kBACA,qDAAuC,OAAO,UAAW;AAE1D,MAAK,4BAA6B;AACjC,0BACC,6BAA8B,mBAAoB;AAAA,EACpD;AAIA,QAAM,gBAAgB,WAAW;AACjC,QAAM,gBAAgB,gBAAgB,OAAO;AAC7C,QAAM,OAAO,aAAc,OAAO,eAAe,YAAa;AAC9D,QAAM,OAAO,gBACV,KAAK,UAAW,EAAE,YAAY,uBAAuB,KAAK,CAAE,IAC5D;AAEH,gCAAW,MAAM;AAChB,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,qBAAiB;AAAA,MACtB,WAAY;AACX;AACC,sBAAa,EAAE,QAAQ,UAAU,CAAE;AAEnC,+BAAAA,SAAU;AAAA,YACT;AAAA,YACA,QAAQ,gBAAgB,SAAS;AAAA,YACjC;AAAA,YACA,SAAS,gBACN;AAAA,cACA,gBAAgB;AAAA,YAChB,IACA,CAAC;AAAA,YACJ,QAAQ,WAAW;AAAA,UACpB,CAAE,EACA,KAAM,CAAE,QAAS;AACjB,wBAAa;AAAA,cACZ,QAAQ;AAAA,cACR,SAAS,MAAM,IAAI,WAAW;AAAA,YAC/B,CAAE;AAAA,UACH,CAAE,EACD,MAAO,CAAE,UAAW;AAEpB,gBAAK,MAAM,SAAS,cAAe;AAClC;AAAA,YACD;AAEA,wBAAa;AAAA,cACZ,QAAQ;AAAA,cACR,OAAO,MAAM;AAAA,YACd,CAAE;AAAA,UACH,CAAE,EACD,QAAS,MAAM;AAEf,8BAAkB,UAAU;AAAA,UAC7B,CAAE;AAAA,QACJ;AAAA,MACD;AAAA,MACA,kBAAkB,UAAU,MAAM;AAAA,IACnC;AAEA,mBAAe;AAEf,WAAO,MAAM;AACZ,iBAAW,MAAM;AACjB,qBAAe,OAAO;AAAA,IACvB;AAAA,EACD,GAAG,CAAE,MAAM,eAAe,IAAK,CAAE;AAEjC,SAAO;AACR;", "names": ["apiFetch"] }