diff --git a/dist/index.js b/dist/index.js index 2c18cc8..40e7a86 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,2 +1,2 @@ /*! For license information please see index.js.LICENSE.txt */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["@humanmade/block-editor-components"]=t():e["@humanmade/block-editor-components"]=t()}(self,(()=>(()=>{var e={184:(e,t)=>{var n;!function(){"use strict";var o={}.hasOwnProperty;function r(){for(var e=[],t=0;t{"use strict";var o=n(414);function r(){}function l(){}l.resetWarningCache=r,e.exports=function(){function e(e,t,n,r,l,i){if(i!==o){var a=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw a.name="Invariant Violation",a}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:l,resetWarningCache:r};return n.PropTypes=n,n}},697:(e,t,n)=>{e.exports=n(703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"}},t={};function n(o){var r=t[o];if(void 0!==r)return r.exports;var l=t[o]={exports:{}};return e[o](l,l.exports,n),l.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};return(()=>{"use strict";n.r(o),n.d(o,{ConditionalComponent:()=>r,FetchAllTermSelectControl:()=>m,FileControls:()=>b,GenericServerSideEdit:()=>h,ImageControl:()=>B,InnerBlockSlider:()=>L,LinkToolbar:()=>F,PlainTextWithLimit:()=>j,PostTitleControl:()=>$,PostTypeCheck:()=>q,RichTextWithLimit:()=>H,createOptionFromPost:()=>le,createOptionFromTerm:()=>ie,createOptionsFromPosts:()=>ae,createOptionsFromPostsWithHierarchy:()=>ce,createOptionsFromTerms:()=>se,createOptionsFromTermsWithHierarchy:()=>ue,findBlockByName:()=>Z,findInvalidBlock:()=>ee,findInvalidBlocks:()=>te,findValidBlock:()=>ne,findValidBlocks:()=>oe,getImageDataForSize:()=>v,useActiveBlockStyle:()=>V,useBlockStyles:()=>G,useDisallowedBlocks:()=>Q,useMeta:()=>Y,useRenderAppenderWithBlockLimit:()=>J,useSelectBlock:()=>K,useSetAttribute:()=>X,withActiveVariation:()=>de});const e=window.wp.element,t=window.React;function r(t){const{children:n=null,ComponentFalse:o=(()=>null),ComponentTrue:r=(()=>n),predicate:l,...i}=t,a=l(i)?r:o;return(0,e.createElement)(a,{...i})}const l=window.wp.apiFetch;var i=n.n(l);const a=window.wp.components,c=window.wp.data,s=window.wp.i18n,u=window.wp.url,d={label:"",value:""},p={disabled:!0,label:(0,s.__)("No items found!","block-editor-components"),value:""};const m=function(n){const{defaultOption:o=d,fallbackOption:r=p,taxonomy:l,...m}=n,[f,b]=(0,t.useState)(),[k,g]=(0,t.useState)(),h=(0,c.useSelect)((e=>e("core").getTaxonomy(l)?.rest_base),[l]);return(0,t.useEffect)((()=>{h&&(async()=>{try{const e=await i()({path:(0,u.addQueryArgs)(`/wp/v2/${h}`,{_fields:"id,name",context:"view",per_page:-1})});if(!e?.length)return void g(r?[r]:[]);g([...o?[o]:[],...se(e)])}catch(t){var e;b(null!==(e=t.message)&&void 0!==e?e:(0,s.__)("Unknown error.","block-editor-components"))}})()}),[h,o,r]),f?(0,e.createElement)(a.Notice,{isDismissible:!1,status:"error"},(0,e.createElement)("p",null,f)):k?(0,e.createElement)(a.SelectControl,{...m,options:k}):(0,e.createElement)(a.Spinner,null)},f=window.wp.blockEditor;function b(t){const{value:n,onChange:o,...r}=t;return(0,e.createElement)(f.MediaUploadCheck,null,(0,e.createElement)(f.MediaUpload,{title:(0,s.__)("Select or Upload File","block-editor-components"),...r,multiple:!1,render:({open:t})=>(0,e.createElement)(a.ToolbarGroup,null,(0,e.createElement)(a.ToolbarButton,{icon:"admin-links",label:n?(0,s.__)("Edit file","block-editor-components"):(0,s.__)("Select file","block-editor-components"),onClick:t}),n&&(0,e.createElement)(a.ToolbarButton,{icon:"editor-unlink",label:(0,s.__)("Deselect file","block-editor-components"),onClick:()=>o(null)})),value:n,onSelect:o}))}const k=window.wp.serverSideRender;var g=n.n(k);const h=function({attributes:t,context:n,name:o}){return(0,e.createElement)("div",{...(0,f.useBlockProps)()},(0,e.createElement)(a.Disabled,null,(0,e.createElement)(g(),{attributes:t,block:o,EmptyResponsePlaceholder:()=>(0,e.createElement)("div",{className:`wp-block-${o.replace("/","-")}`},o," ",(0,s.__)("Block rendered as empty.")),urlQueryArgs:"object"==typeof n&&Object.hasOwn(n,"postId")?{post_id:n.postId}:{}})))};function v(e,t){var n;const o=null!==(n=e?.sizes)&&void 0!==n?n:e?.media_details?.sizes,r=o?.[t];return r?{src:r.url||r.source_url,width:r.width,height:r.height}:null}const y=["image"],S=(0,s.__)("Select Image","block-editor-components"),E=(0,s.__)("Select Image","block-editor-components"),w=(0,s.__)("Remove image","block-editor-components"),_=(0,s.__)("Replace Image","block-editor-components");function B(t){const{buttonText:n=S,className:o,help:r,id:l,label:i,modalTitle:s=E,removeButtonText:u=w,replaceButtonText:d=_,size:p,value:m,onChange:b}=t,k=(0,c.useSelect)((e=>{const t=e("core").getMedia(m,{context:"view"});return t?t.alt_text:""}),[m]),g=(0,c.useSelect)((e=>{const t=e("core").getMedia(m,{context:"view"});if(t){if(p){const e=v(t,p);if(e)return e.src}return t.source_url}}),[p,m]);return(0,e.createElement)(a.BaseControl,{className:o,help:r,id:l,label:i},(0,e.createElement)(f.MediaUploadCheck,null,(0,e.createElement)(f.MediaUpload,{allowedTypes:y,render:({open:t})=>(0,e.createElement)("div",null,m?g?(0,e.createElement)(a.Button,{isLink:!0,onClick:t},(0,e.createElement)("img",{alt:k,src:g})):(0,e.createElement)(a.Spinner,null):null,(0,e.createElement)(a.Button,{isSecondary:!0,onClick:t},m?d:n)),title:s,onSelect:b})),(0,e.createElement)("br",null),m?(0,e.createElement)(a.Button,{isDestructive:!0,isLink:!0,onClick:()=>b(null)},u):null)}var T=n(697),C=n.n(T);const x=window.wp.blocks;function P({className:n,allowedBlocks:o,template:r,currentItemIndex:l,parentBlockId:i,renderAppender:a,captureToolbars:c}){const s=(0,t.useRef)(),u=(0,f.useInnerBlocksProps)({id:`inner-block-display-single-${i}`,className:n},{__experimentalCaptureToolbars:c,allowedBlocks:o,orientation:"horizontal",renderAppender:a,template:r,templateLock:!1});return(0,t.useEffect)((()=>{s.current&&(s.current.innerHTML=`#inner-block-display-single-${i} > *:not(:nth-child(${l+1}) ) { display: none; }`)}),[l,s,i]),(0,e.createElement)(e.Fragment,null,(0,e.createElement)("style",{ref:s}),(0,e.createElement)("div",{...u}))}P.defaultProps={currentItemIndex:0,renderAppender:!1,captureToolbars:!0},P.propTypes={parentBlockId:C().string.isRequired,allowedBlocks:C().arrayOf(C().string).isRequired,template:C().array,className:C().string,currentItemIndex:C().number,renderAppender:C().oneOfType([C().bool,C().element])};const I=P;var R=n(184),O=n.n(R);function N({totalPages:t,currentPage:n,setCurrentPage:o,prevEnabled:r,nextEnabled:l,addSlide:i=(()=>{}),addSlideEnabled:c=!1}){return(0,e.createElement)("div",{className:"inner-block-slider__navigation"},(0,e.createElement)(a.IconButton,{disabled:!r,icon:"arrow-left-alt2",isSecondary:!0,isSmall:!0,onClick:()=>{r&&o(n-1)}}),[...Array(t).keys()].map((t=>(0,e.createElement)(a.Button,{key:t+1,"aria-label":`Slide ${t+1}`,className:O()("components-button","is-not-small",{"is-primary":n===t+1,"is-secondary":n!==t+1}),type:"button",onClick:()=>{o(t+1)}},t+1))),(0,e.createElement)(a.IconButton,{disabled:!l,icon:"arrow-right-alt2",isSecondary:!0,isSmall:!0,onClick:()=>{l&&o(n+1)}}),(0,e.createElement)(a.IconButton,{disabled:!c,icon:"plus-alt2",isSecondary:!0,isSmall:!0,onClick:()=>i()}))}N.propTypes={totalPages:C().number.isRequired,currentPage:C().number.isRequired,setCurrentPage:C().func.isRequired,prevEnabled:C().bool.isRequired,nextEnabled:C().bool.isRequired,addSlide:C().func,addSlideEnabled:C().bool};const A=N,M=({parentBlockId:n,allowedBlock:o,template:r,slideLimit:l})=>{const i=r||[[o]],a=(0,c.useSelect)((e=>e("core/block-editor").getBlock(n).innerBlocks)),[s,u]=(0,t.useState)(0),d=(0,t.useRef)(a.length),{insertBlock:p}=(0,c.useDispatch)("core/block-editor");return(0,t.useEffect)((()=>{(a.length>d.current||a.lengtha.length)&&u(a.length-1),d.current=a.length}),[a.length,s,d]),(0,e.createElement)("div",{className:"inner-block-slider"},(0,e.createElement)(I,{allowedBlocks:[o],className:"slides",currentItemIndex:s,parentBlockId:n,template:i}),(0,e.createElement)(A,{addSlide:()=>{const e=(0,x.createBlock)(o);p(e,void 0,n)},addSlideEnabled:a.length1,setCurrentPage:e=>u(e-1),totalPages:a.length}))};M.defaultProps={slideLimit:10,template:null},M.propTypes={parentBlockId:C().string.isRequired,allowedBlock:C().string.isRequired,template:C().array};const L=M;function F(n){const{onChange:o,opensInNewTab:r,url:l}=n,[i,c]=(0,t.useState)(!1),u=(0,t.useMemo)((()=>[{icon:"admin-links",title:(0,s.__)("Link","block-editor-components"),isActive:l?.length>0,onClick:()=>c(!i)}]),[c,i,l]),d=(0,t.useMemo)((()=>({url:l,opensInNewTab:r})),[r,l]);return(0,e.createElement)(e.Fragment,null,(0,e.createElement)(a.ToolbarGroup,{controls:u}),i&&(0,e.createElement)(a.Popover,null,(0,e.createElement)(f.__experimentalLinkControl,{forceIsEditingLink:i,opensInNewTab:r,value:d,onChange:o})))}function j(n){const{className:o,limit:r=0,onChange:l,...i}=n,[a,c]=(0,t.useState)(r&&n.value?.length>r);return(0,e.createElement)(f.PlainText,{className:`${o} limit-text ${a?"invalid":""}`.trim(),onChange:e=>{r&&e.length>r?a||c(!0):(a&&c(!1),l(e))},...i})}const D=/[\r\n]+/g;function $(n){const{editPost:o}=(0,c.useDispatch)("core/editor"),r=(0,c.useSelect)((e=>e("core/editor").getEditedPostAttribute("title")),[]),l=(0,t.useCallback)((e=>o({title:e.replace(D," ")})),[o]);return(0,e.createElement)(f.RichText,{...n,allowedFormats:[],value:r,onChange:l})}function q(e){var t;const{postType:n}=e;return(0,c.useSelect)((e=>e("core/editor").getCurrentPostType()),[])===n?e.children:null!==(t=e.fallback)&&void 0!==t?t:null}const U=window.wp.dom,W=e=>{const t=document.createRange();t.selectNodeContents(e),t.collapse(!1);const n=window.getSelection();n.removeAllRanges(),n.addRange(t)};function H(n){const{className:o,limit:r=0,onChange:l,...i}=n,a=(0,t.useRef)(),[c,s]=(0,t.useState)(r&&n.value?.length>r),[u,d]=(0,t.useState)(!1);return(0,e.createElement)(f.RichText,{ref:a,className:`${o} limit-text ${c?"invalid":""}`.trim(),onChange:e=>{if(r&&(0,U.__unstableStripHTML)(e).length>r)return d(!1),a.current.innerHTML=n.value,W(a.current),void(c||s(!0));u&&c&&s(!1),d(!0),l(e)},...i})}const z=/^is-style-/;function V(e){const{blockName:n,className:o}=(0,c.useSelect)((t=>{var n,o;const r=t("core/block-editor").getBlock(e);return{blockName:null!==(n=r?.name)&&void 0!==n?n:"",className:null!==(o=r?.attributes?.className)&&void 0!==o?o:""}}),[e]),{blockStyles:r,defaultStyle:l}=G(n),i=(0,t.useMemo)((()=>r.map((({name:e})=>e))),[r]),a=(0,t.useMemo)((()=>function(e=""){return e.trim().replace(/\s+/," ").split(" ").map((e=>z.test(e)?e.replace(z,""):"")).filter(Boolean)}(o)),[o]);return(0,t.useMemo)((()=>{var e;return null!==(e=a.find((e=>i.includes(e))))&&void 0!==e?e:l}),[i,a,l])}function G(e){const n=(0,c.useSelect)((t=>t("core/blocks").getBlockStyles(e)),[e]);return(0,t.useMemo)((()=>{var e;return{blockStyles:n,defaultStyle:null!==(e=n.find((({isDefault:e})=>e))?.name)&&void 0!==e?e:""}}),[n])}function Q(e){return(0,t.useMemo)((()=>{const t=(0,x.getBlockTypes)();return t?.length?t.filter((({name:t,parent:n})=>!n&&!e.includes(t))).map((({name:e})=>e)):[]}),[e])}function Y(e,n){var o;const{editPost:r}=(0,c.useDispatch)("core/editor"),l=(0,c.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta"))),i=(0,t.useCallback)((t=>r({meta:{[e]:t}})),[r,e]);return[null!==(o=l?.[e])&&void 0!==o?o:n,i]}function J(e,t,n){return(0,c.useSelect)((o=>{const{innerBlocks:r}=o("core/block-editor").getBlock(e);return r?.length{const n=document.getElementById(`block-${t}`);n&&(e(t),setTimeout((()=>n.scrollIntoView({behavior:"smooth"})),200))}),[e])}function X(e,n,o){return(0,t.useCallback)(((t=o)=>n({[e]:t})),[e,o,n])}function Z(e){const{getBlocks:t}=(0,c.select)("core/block-editor");return t().find((({name:t})=>t===e))}function ee(e,t){return e.find((e=>!t(e)))}function te(e,t){return e.filter((e=>!t(e)))}function ne(e,t){return e.find((e=>t(e)))}function oe(e,t){return e.filter((e=>t(e)))}const re=window.wp.htmlEntities;function le(e,t=""){const{id:n,title:o}=e;return{label:t+(0,re.decodeEntities)(o.rendered||(0,s.sprintf)((0,s.__)("#%d (no title)","block-editor-components"),n)),value:n}}function ie(e,t=""){const{id:n,name:o}=e;return{label:t+(0,re.decodeEntities)(o||(0,s.sprintf)((0,s.__)("#%d (no name)","block-editor-components"),n)),value:n}}function ae(e){return e.map((e=>le(e)))}function ce(e,t="\u2014 ",n=0){return e.map((({children:e=[],...o})=>[le(o,t.repeat(n)),...ce(e,t,n+1)])).flat()}function se(e){return e.map((e=>ie(e)))}function ue(e,t="\u2014 ",n=0){return e.map((({children:e=[],...o})=>[ie(o,t.repeat(n)),...ue(e,t,n+1)])).flat()}function de(e,...t){if(e.variations?.length){const n=function(e){return(t,n)=>e.every((e=>t[e]===n[e]))}(t);e.variations=e.variations.map((e=>(e.isActive=n,e)))}return e}})(),o})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["@humanmade/block-editor-components"]=t():e["@humanmade/block-editor-components"]=t()}(self,(()=>(()=>{var e={184:(e,t)=>{var n;!function(){"use strict";var o={}.hasOwnProperty;function r(){for(var e=[],t=0;t{"use strict";var o=n(414);function r(){}function l(){}l.resetWarningCache=r,e.exports=function(){function e(e,t,n,r,l,a){if(a!==o){var i=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw i.name="Invariant Violation",i}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:l,resetWarningCache:r};return n.PropTypes=n,n}},697:(e,t,n)=>{e.exports=n(703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"}},t={};function n(o){var r=t[o];if(void 0!==r)return r.exports;var l=t[o]={exports:{}};return e[o](l,l.exports,n),l.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};return(()=>{"use strict";n.r(o),n.d(o,{ConditionalComponent:()=>r,FetchAllTermSelectControl:()=>p,FileControls:()=>f,GenericServerSideEdit:()=>y,ImageControl:()=>T,InnerBlockSlider:()=>A,LinkToolbar:()=>L,PlainTextWithLimit:()=>j,PostPickerButton:()=>J,PostPickerModal:()=>Q,PostPickerToolbarButton:()=>Y,PostTitleControl:()=>D,PostTypeCheck:()=>$,RichTextWithLimit:()=>z,TermSelector:()=>H,createOptionFromPost:()=>de,createOptionFromTerm:()=>me,createOptionsFromPosts:()=>pe,createOptionsFromPostsWithHierarchy:()=>be,createOptionsFromTerms:()=>fe,createOptionsFromTermsWithHierarchy:()=>ge,findBlockByName:()=>le,findInvalidBlock:()=>ae,findInvalidBlocks:()=>ie,findValidBlock:()=>ce,findValidBlocks:()=>se,getImageDataForSize:()=>h,useActiveBlockStyle:()=>X,useBlockStyles:()=>Z,useDisallowedBlocks:()=>ee,useMeta:()=>te,useRenderAppenderWithBlockLimit:()=>ne,useSelectBlock:()=>oe,useSetAttribute:()=>re,withActiveVariation:()=>ke});const e=window.wp.element,t=window.React;function r(t){const{children:n=null,ComponentFalse:o=(()=>null),ComponentTrue:r=(()=>n),predicate:l,...a}=t,i=l(a)?r:o;return(0,e.createElement)(i,{...a})}const l=window.wp.apiFetch;var a=n.n(l);const i=window.wp.components,c=window.wp.data,s=window.wp.i18n,u=window.wp.url,d={label:"",value:""},m={disabled:!0,label:(0,s.__)("No items found!","block-editor-components"),value:""};const p=function(n){const{defaultOption:o=d,fallbackOption:r=m,taxonomy:l,...p}=n,[b,f]=(0,t.useState)(),[g,k]=(0,t.useState)(),y=(0,c.useSelect)((e=>e("core").getTaxonomy(l)?.rest_base),[l]);return(0,t.useEffect)((()=>{y&&(async()=>{try{const e=await a()({path:(0,u.addQueryArgs)(`/wp/v2/${y}`,{_fields:"id,name",context:"view",per_page:-1})});if(!e?.length)return void k(r?[r]:[]);k([...o?[o]:[],...fe(e)])}catch(t){var e;f(null!==(e=t.message)&&void 0!==e?e:(0,s.__)("Unknown error.","block-editor-components"))}})()}),[y,o,r]),b?(0,e.createElement)(i.Notice,{isDismissible:!1,status:"error"},(0,e.createElement)("p",null,b)):g?(0,e.createElement)(i.SelectControl,{...p,options:g}):(0,e.createElement)(i.Spinner,null)},b=window.wp.blockEditor;function f(t){const{value:n,onChange:o,...r}=t;return(0,e.createElement)(b.MediaUploadCheck,null,(0,e.createElement)(b.MediaUpload,{title:(0,s.__)("Select or Upload File","block-editor-components"),...r,multiple:!1,render:({open:t})=>(0,e.createElement)(i.ToolbarGroup,null,(0,e.createElement)(i.ToolbarButton,{icon:"admin-links",label:n?(0,s.__)("Edit file","block-editor-components"):(0,s.__)("Select file","block-editor-components"),onClick:t}),n&&(0,e.createElement)(i.ToolbarButton,{icon:"editor-unlink",label:(0,s.__)("Deselect file","block-editor-components"),onClick:()=>o(null)})),value:n,onSelect:o}))}const g=window.wp.serverSideRender;var k=n.n(g);const y=function({attributes:t,context:n,name:o}){return(0,e.createElement)("div",{...(0,b.useBlockProps)()},(0,e.createElement)(i.Disabled,null,(0,e.createElement)(k(),{attributes:t,block:o,EmptyResponsePlaceholder:()=>(0,e.createElement)("div",{className:`wp-block-${o.replace("/","-")}`},o," ",(0,s.__)("Block rendered as empty.")),urlQueryArgs:"object"==typeof n&&Object.hasOwn(n,"postId")?{post_id:n.postId}:{}})))};function h(e,t){var n;const o=null!==(n=e?.sizes)&&void 0!==n?n:e?.media_details?.sizes,r=o?.[t];return r?{src:r.url||r.source_url,width:r.width,height:r.height}:null}const v=["image"],E=(0,s.__)("Select Image","block-editor-components"),S=(0,s.__)("Select Image","block-editor-components"),_=(0,s.__)("Remove image","block-editor-components"),w=(0,s.__)("Replace Image","block-editor-components");function T(t){const{buttonText:n=E,className:o,help:r,id:l,label:a,modalTitle:s=S,removeButtonText:u=_,replaceButtonText:d=w,size:m,value:p,onChange:f}=t,g=(0,c.useSelect)((e=>{const t=e("core").getMedia(p,{context:"view"});return t?t.alt_text:""}),[p]),k=(0,c.useSelect)((e=>{const t=e("core").getMedia(p,{context:"view"});if(t){if(m){const e=h(t,m);if(e)return e.src}return t.source_url}}),[m,p]);return(0,e.createElement)(i.BaseControl,{className:o,help:r,id:l,label:a},(0,e.createElement)(b.MediaUploadCheck,null,(0,e.createElement)(b.MediaUpload,{allowedTypes:v,render:({open:t})=>(0,e.createElement)("div",null,p?k?(0,e.createElement)(i.Button,{isLink:!0,onClick:t},(0,e.createElement)("img",{alt:g,src:k})):(0,e.createElement)(i.Spinner,null):null,(0,e.createElement)(i.Button,{isSecondary:!0,onClick:t},p?d:n)),title:s,onSelect:f})),(0,e.createElement)("br",null),p?(0,e.createElement)(i.Button,{isDestructive:!0,isLink:!0,onClick:()=>f(null)},u):null)}var C=n(697),B=n.n(C);const x=window.wp.blocks;function P({className:n,allowedBlocks:o,template:r,currentItemIndex:l,parentBlockId:a,renderAppender:i,captureToolbars:c}){const s=(0,t.useRef)(),u=(0,b.useInnerBlocksProps)({id:`inner-block-display-single-${a}`,className:n},{__experimentalCaptureToolbars:c,allowedBlocks:o,orientation:"horizontal",renderAppender:i,template:r,templateLock:!1});return(0,t.useEffect)((()=>{s.current&&(s.current.innerHTML=`#inner-block-display-single-${a} > *:not(:nth-child(${l+1}) ) { display: none; }`)}),[l,s,a]),(0,e.createElement)(e.Fragment,null,(0,e.createElement)("style",{ref:s}),(0,e.createElement)("div",{...u}))}P.defaultProps={currentItemIndex:0,renderAppender:!1,captureToolbars:!0},P.propTypes={parentBlockId:B().string.isRequired,allowedBlocks:B().arrayOf(B().string).isRequired,template:B().array,className:B().string,currentItemIndex:B().number,renderAppender:B().oneOfType([B().bool,B().element])};const I=P;var R=n(184),O=n.n(R);function N({totalPages:t,currentPage:n,setCurrentPage:o,prevEnabled:r,nextEnabled:l,addSlide:a=(()=>{}),addSlideEnabled:c=!1}){return(0,e.createElement)("div",{className:"inner-block-slider__navigation"},(0,e.createElement)(i.IconButton,{disabled:!r,icon:"arrow-left-alt2",isSecondary:!0,isSmall:!0,onClick:()=>{r&&o(n-1)}}),[...Array(t).keys()].map((t=>(0,e.createElement)(i.Button,{key:t+1,"aria-label":`Slide ${t+1}`,className:O()("components-button","is-not-small",{"is-primary":n===t+1,"is-secondary":n!==t+1}),type:"button",onClick:()=>{o(t+1)}},t+1))),(0,e.createElement)(i.IconButton,{disabled:!l,icon:"arrow-right-alt2",isSecondary:!0,isSmall:!0,onClick:()=>{l&&o(n+1)}}),(0,e.createElement)(i.IconButton,{disabled:!c,icon:"plus-alt2",isSecondary:!0,isSmall:!0,onClick:()=>a()}))}N.propTypes={totalPages:B().number.isRequired,currentPage:B().number.isRequired,setCurrentPage:B().func.isRequired,prevEnabled:B().bool.isRequired,nextEnabled:B().bool.isRequired,addSlide:B().func,addSlideEnabled:B().bool};const M=N,F=({parentBlockId:n,allowedBlock:o,template:r,slideLimit:l})=>{const a=r||[[o]],i=(0,c.useSelect)((e=>e("core/block-editor").getBlock(n).innerBlocks)),[s,u]=(0,t.useState)(0),d=(0,t.useRef)(i.length),{insertBlock:m}=(0,c.useDispatch)("core/block-editor");return(0,t.useEffect)((()=>{(i.length>d.current||i.lengthi.length)&&u(i.length-1),d.current=i.length}),[i.length,s,d]),(0,e.createElement)("div",{className:"inner-block-slider"},(0,e.createElement)(I,{allowedBlocks:[o],className:"slides",currentItemIndex:s,parentBlockId:n,template:a}),(0,e.createElement)(M,{addSlide:()=>{const e=(0,x.createBlock)(o);m(e,void 0,n)},addSlideEnabled:i.length1,setCurrentPage:e=>u(e-1),totalPages:i.length}))};F.defaultProps={slideLimit:10,template:null},F.propTypes={parentBlockId:B().string.isRequired,allowedBlock:B().string.isRequired,template:B().array};const A=F;function L(n){const{onChange:o,opensInNewTab:r,url:l}=n,[a,c]=(0,t.useState)(!1),u=(0,t.useMemo)((()=>[{icon:"admin-links",title:(0,s.__)("Link","block-editor-components"),isActive:l?.length>0,onClick:()=>c(!a)}]),[c,a,l]),d=(0,t.useMemo)((()=>({url:l,opensInNewTab:r})),[r,l]);return(0,e.createElement)(e.Fragment,null,(0,e.createElement)(i.ToolbarGroup,{controls:u}),a&&(0,e.createElement)(i.Popover,null,(0,e.createElement)(b.__experimentalLinkControl,{forceIsEditingLink:a,opensInNewTab:r,value:d,onChange:o})))}function j(n){const{className:o,limit:r=0,onChange:l,...a}=n,[i,c]=(0,t.useState)(r&&n.value?.length>r);return(0,e.createElement)(b.PlainText,{className:`${o} limit-text ${i?"invalid":""}`.trim(),onChange:e=>{r&&e.length>r?i||c(!0):(i&&c(!1),l(e))},...a})}const q=/[\r\n]+/g;function D(n){const{editPost:o}=(0,c.useDispatch)("core/editor"),r=(0,c.useSelect)((e=>e("core/editor").getEditedPostAttribute("title")),[]),l=(0,t.useCallback)((e=>o({title:e.replace(q," ")})),[o]);return(0,e.createElement)(b.RichText,{...n,allowedFormats:[],value:r,onChange:l})}function $(e){var t;const{postType:n}=e;return(0,c.useSelect)((e=>e("core/editor").getCurrentPostType()),[])===n?e.children:null!==(t=e.fallback)&&void 0!==t?t:null}const W=window.wp.dom,U=e=>{const t=document.createRange();t.selectNodeContents(e),t.collapse(!1);const n=window.getSelection();n.removeAllRanges(),n.addRange(t)};function z(n){const{className:o,limit:r=0,onChange:l,...a}=n,i=(0,t.useRef)(),[c,s]=(0,t.useState)(r&&n.value?.length>r),[u,d]=(0,t.useState)(!1);return(0,e.createElement)(b.RichText,{ref:i,className:`${o} limit-text ${c?"invalid":""}`.trim(),onChange:e=>{if(r&&(0,W.__unstableStripHTML)(e).length>r)return d(!1),i.current.innerHTML=n.value,U(i.current),void(c||s(!0));u&&c&&s(!1),d(!0),l(e)},...a})}const H=function(t){const{taxonomy:n,value:o=[],onChange:r}=t,l=(0,c.useSelect)((e=>e("core").getTaxonomy(n)),[n]),{taxonomyTermsById:a,taxonomyTermsByTitle:u}=(0,c.useSelect)((e=>{var t;const o=null!==(t=e("core").getEntityRecords("taxonomy",n,{per_page:100}))&&void 0!==t?t:[],r=function(e){return e?e.reduce(((e,t)=>(e[t.id]=t.name,e)),{}):[]}(o),l=function(e){return e?e.reduce(((e,t)=>(e[t.name]=t.id,e)),{}):[]}(o);return{taxonomyTermsById:r,taxonomyTermsByTitle:l}}),[n]),d=o.map((e=>a[e])).filter(Boolean);return(0,e.createElement)(i.FormTokenField,{label:(0,s.sprintf)((0,s.__)("Filter by %s","block-editor-components"),l?l.labels.singular_name:""),suggestions:Object.values(a),value:d,onChange:e=>{r(e.map((e=>u[e])))}})};function V(t){const{postType:n,queryArgs:o,onChange:r,values:l=[],isSortable:a=!1}=t,u=(0,c.useSelect)((e=>{var t;return null!==(t=e("core").getEntityRecords("postType",n,o))&&void 0!==t?t:[]}),[n,o]),d=(0,c.useSelect)((e=>e("core/data").isResolving("core","getEntityRecords",["postType",n,o])));return(0,e.createElement)("div",{style:{marginTop:-24,paddingTop:24,paddingLeft:4,marginLeft:-4}},d&&(0,e.createElement)(i.Spinner,null)||u.length<1&&(0,e.createElement)(i.Notice,{isDismissible:!1},(0,s.__)("No results found","block-editor-components"))||u.map((t=>(0,e.createElement)("div",{style:{display:"grid",gridTemplateColumns:"1fr auto",marginRight:-2,paddingRight:2}},(0,e.createElement)(i.CheckboxControl,{key:t.id,checked:l.includes(t.id),label:t.title?.rendered||(0,s.__)("(No title)","block-editor-components"),onChange:e=>{r(e?[...l,t.id]:l.filter((e=>e!==t.id)))}}),a&&(0,e.createElement)(i.ButtonGroup,null,(0,e.createElement)(i.Button,{icon:"arrow-up-alt2",iconSize:12,isSmall:!0,label:(0,s.__)("Move up","block-editor-components"),variant:"secondary",onClick:()=>(e=>{const t=l.indexOf(e);-1!==t&&0!==t&&r([...l.slice(0,t-1),l[t],l[t-1],...l.slice(t+1)])})(t.id)}),(0,e.createElement)(i.Button,{icon:"arrow-down-alt2",iconSize:12,isSmall:!0,label:(0,s.__)("Move down","block-editor-components"),variant:"secondary",onClick:()=>(e=>{const t=l.indexOf(e);-1!==t&&t!==l.length-1&&r([...l.slice(0,t),l[t+1],l[t],...l.slice(t+2)])})(t.id)}))))))}function G(n){const{postType:o,onChange:r,values:l,taxonomies:a}=n,[u,d]=(0,e.useState)(""),m=(0,c.useSelect)((e=>a.map((t=>e("core").getTaxonomy(t)))),[a]),[p,b]=(0,e.useState)([]),f=(0,t.useCallback)(((e,t)=>{const n=m.find((t=>t&&t.slug===e));n&&b({...p,[`${n.rest_base}`]:t})}),[p,m]);(0,t.useEffect)((()=>{m.forEach((e=>{e&&!p[e.rest_base]&&f(e.rest_base,[])}))}),[m,f,p]);const g={search:u||void 0,per_page:30,...p};return(0,e.createElement)(i.Flex,{align:"flex-start",style:{gap:24}},(0,e.createElement)(i.FlexItem,{style:{width:"35%"}},(0,e.createElement)(i.SearchControl,{label:(0,s.__)("Search Posts","block-editor-components"),style:{marginBottom:24},value:u,onChange:e=>d(e)}),a.map((t=>{const n=m.find((e=>e&&e.slug===t));return n?(0,e.createElement)(H,{taxonomy:t,value:p[n.rest_base],onChange:e=>f(t,e)}):null}))),(0,e.createElement)(i.FlexItem,{style:{width:"65%"}},(0,e.createElement)(V,{postType:o,queryArgs:g,values:l,onChange:r})))}function Q(t){const{title:n,postType:o="post",taxonomies:r=[],values:l=[],onChange:a,setModalOpen:c}=t;return(0,e.createElement)(i.Modal,{style:{width:"800px",maxWidth:"100%"},title:n,onRequestClose:()=>c(!1)},(0,e.createElement)("div",{style:{marginTop:-16}},(0,e.createElement)(i.TabPanel,{tabs:[{name:"browse",title:(0,s.__)("Browse Posts","block-editor-components"),content:()=>(0,e.createElement)(e.Fragment,null,"Foo")},{name:"selection",title:(0,s.__)("Current Selection","block-editor-components")}]},(t=>(0,e.createElement)("div",{style:{marginTop:"calc( var(--wp-admin-border-width-focus) * -1 )",borderStyle:"none",borderTop:"var( --wp-admin-border-width-focus ) solid #ddd",paddingTop:24}},"browse"===t.name&&(0,e.createElement)(G,{postType:o,taxonomies:r,values:l,onChange:a}),"selection"===t.name&&(0,e.createElement)(V,{isSortable:!0,postType:o,queryArgs:{include:l,orderby:"include",per_page:l.length},values:l,onChange:a}))))))}function Y(t){const{title:n=(0,s.__)("Select posts","block-editor-components"),icon:o="edit"}=t,[r,l]=(0,e.useState)(!1);return(0,e.createElement)(e.Fragment,null,(0,e.createElement)(i.ToolbarButton,{icon:o,label:n,onClick:()=>l(!0)},n),r&&(0,e.createElement)(Q,{...t,setModalOpen:l,title:n}))}function J(t){const{title:n=(0,s.__)("Select posts","block-editor-components")}=t,[o,r]=(0,e.useState)(!1);return(0,e.createElement)(e.Fragment,null,(0,e.createElement)(i.Button,{variant:"primary",onClick:()=>r(!0)},n),o&&(0,e.createElement)(Q,{...t,setModalOpen:r,title:n}))}const K=/^is-style-/;function X(e){const{blockName:n,className:o}=(0,c.useSelect)((t=>{var n,o;const r=t("core/block-editor").getBlock(e);return{blockName:null!==(n=r?.name)&&void 0!==n?n:"",className:null!==(o=r?.attributes?.className)&&void 0!==o?o:""}}),[e]),{blockStyles:r,defaultStyle:l}=Z(n),a=(0,t.useMemo)((()=>r.map((({name:e})=>e))),[r]),i=(0,t.useMemo)((()=>function(e=""){return e.trim().replace(/\s+/," ").split(" ").map((e=>K.test(e)?e.replace(K,""):"")).filter(Boolean)}(o)),[o]);return(0,t.useMemo)((()=>{var e;return null!==(e=i.find((e=>a.includes(e))))&&void 0!==e?e:l}),[a,i,l])}function Z(e){const n=(0,c.useSelect)((t=>t("core/blocks").getBlockStyles(e)),[e]);return(0,t.useMemo)((()=>{var e;return{blockStyles:n,defaultStyle:null!==(e=n.find((({isDefault:e})=>e))?.name)&&void 0!==e?e:""}}),[n])}function ee(e){return(0,t.useMemo)((()=>{const t=(0,x.getBlockTypes)();return t?.length?t.filter((({name:t,parent:n})=>!n&&!e.includes(t))).map((({name:e})=>e)):[]}),[e])}function te(e,n){var o;const{editPost:r}=(0,c.useDispatch)("core/editor"),l=(0,c.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta"))),a=(0,t.useCallback)((t=>r({meta:{[e]:t}})),[r,e]);return[null!==(o=l?.[e])&&void 0!==o?o:n,a]}function ne(e,t,n){return(0,c.useSelect)((o=>{const{innerBlocks:r}=o("core/block-editor").getBlock(e);return r?.length{const n=document.getElementById(`block-${t}`);n&&(e(t),setTimeout((()=>n.scrollIntoView({behavior:"smooth"})),200))}),[e])}function re(e,n,o){return(0,t.useCallback)(((t=o)=>n({[e]:t})),[e,o,n])}function le(e){const{getBlocks:t}=(0,c.select)("core/block-editor");return t().find((({name:t})=>t===e))}function ae(e,t){return e.find((e=>!t(e)))}function ie(e,t){return e.filter((e=>!t(e)))}function ce(e,t){return e.find((e=>t(e)))}function se(e,t){return e.filter((e=>t(e)))}const ue=window.wp.htmlEntities;function de(e,t=""){const{id:n,title:o}=e;return{label:t+(0,ue.decodeEntities)(o.rendered||(0,s.sprintf)((0,s.__)("#%d (no title)","block-editor-components"),n)),value:n}}function me(e,t=""){const{id:n,name:o}=e;return{label:t+(0,ue.decodeEntities)(o||(0,s.sprintf)((0,s.__)("#%d (no name)","block-editor-components"),n)),value:n}}function pe(e){return e.map((e=>de(e)))}function be(e,t="\u2014 ",n=0){return e.map((({children:e=[],...o})=>[de(o,t.repeat(n)),...be(e,t,n+1)])).flat()}function fe(e){return e.map((e=>me(e)))}function ge(e,t="\u2014 ",n=0){return e.map((({children:e=[],...o})=>[me(o,t.repeat(n)),...ge(e,t,n+1)])).flat()}function ke(e,...t){if(e.variations?.length){const n=function(e){return(t,n)=>e.every((e=>t[e]===n[e]))}(t);e.variations=e.variations.map((e=>(e.isActive=n,e)))}return e}})(),o})())); \ No newline at end of file diff --git a/src/components/PostPicker/README.md b/src/components/PostPicker/README.md new file mode 100644 index 0000000..ab7ae3f --- /dev/null +++ b/src/components/PostPicker/README.md @@ -0,0 +1,81 @@ +# PostPicker + +There are several `PostPicker` controls. + +* `PostPickerButton` A simple button. +* `PostPickerToolbarButton` A button for use within `BlockControls` toolbar. +* `PostPickerModal` The actual modal interface, that can be integrated into your own UI. + +## `PostPickerButton` + +```jsx +import { PostPickerButton } from '@humanmade/block-editor-components'; + +... + + setAttributes( { postIds: newValue } ) } + values={ attributes.postIds || [] } +/> +``` + +### Props + +The `LinkToolbar` component does not have any custom props other than `opensInNewTab`, `value` and `onChange`, which are all passed on as is to the nested [`LinkControl`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-editor/src/components/link-control/index.js) component. + +#### `values` + +The saved values. Array of post IDs. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `Array` | yes | `undefined` | + + +#### `onChange` + +The callback to use for handling changing the selected posts. `onChange` will receive an array of post IDs. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `Function` | yes | `undefined` | + +#### `title` + +The title, used by button and modal title. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `String` | no | `Select Posts` + +#### `postType` + +Post type to select from. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `String` | no | `post` + +#### `taxonomies` + +Taxonomies that results can be filtered by. Array of taxonomy slugs. e.g. `[ 'category', 'post_tag' ]`. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `Array` | no | `[]` + + +## Post Picker Toolbar Button + +There is also a `PostPickerToolbarButton` component available if you import it directly from the source file, which is intended for use within the BlockControls. It supports all the same props as the PostPicker component, with the addition of an `icon`. + +## props + +#### `icon` + +Button icon. Passed through to `ToolbarButton`, refer to the documentation of that component for more info. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `string` | no | `edit` diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js new file mode 100644 index 0000000..14e0b8a --- /dev/null +++ b/src/components/PostPicker/index.js @@ -0,0 +1,385 @@ +import React, { ReactNode, useCallback, useEffect } from 'react'; + +import { + Button, + ButtonGroup, + ToolbarButton, + TabPanel, + CheckboxControl, + Flex, + FlexItem, + Modal, + Notice, + SearchControl, + Spinner, +} from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { useState } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +import TermSelector from '../TermSelector'; + +/** + * List of selectable posts + * + * @param {object} props Component props + * @returns {ReactNode} Component + */ +function PostList( props ) { + const { + postType, + queryArgs, + onChange, + values = [], + isSortable = false, + } = props; + + const queriedPosts = useSelect( ( select ) => { + return select( 'core' ).getEntityRecords( 'postType', postType, queryArgs ) ?? []; + }, [ postType, queryArgs ] ); + + const isResolving = useSelect( ( select ) => { + return select( 'core/data' ).isResolving( 'core', 'getEntityRecords', [ 'postType', postType, queryArgs ] ); + } ); + + const reorderUp = ( postId ) => { + const index = values.indexOf( postId ); + + // Item not found or already at the first position + if ( index === -1 || index === 0 ) { + return; + } + + onChange( [ + ...values.slice( 0, index - 1 ), + values[ index ], + values[ index - 1 ], + ...values.slice( index + 1 ), + ] ); + }; + + const reorderDown = ( postId ) => { + const index = values.indexOf( postId ); + + // Item not found or already at the last position + if ( index === -1 || index === values.length - 1 ) { + return; + } + + onChange( [ + ...values.slice( 0, index ), + values[ index + 1 ], + values[ index ], + ...values.slice( index + 2 ), + ] ); + }; + + return ( +
+ { + ( isResolving && ) + || ( queriedPosts.length < 1 && + + { __( 'No results found', 'block-editor-components' ) } + + ) + || ( + queriedPosts.map( post => ( +
+ { + if ( checked ) { + onChange( [ ...values, post.id ] ); + } else { + onChange( values.filter( value => ( value !== post.id ) ) ); + } + } } + /> + { isSortable && ( + +
+ ) ) + ) + } +
+ ); +} + +/** + * Post Picker Browse Post Panel. + * + * @param {object} props Component props. + * @returns {ReactNode} Component. + */ +function BrowsePanel( props ) { + const { + postType, + onChange, + values, + taxonomies, + } = props; + + const [ search, setSearch ] = useState( '' ); + + const taxObjects = useSelect( select => { + return taxonomies.map( taxonomy => select( 'core' ).getTaxonomy( taxonomy ) ); + }, [ taxonomies ] ); + + const [ taxQueries, setTaxQueries ] = useState( [] ); + + /** + * Helper function to update tax query for a taxonomy. + * + * Sets correct property value of rest_base. + * Merges the new data with existing data. + * + * @param {*} taxonomy Taxonomy. + * @param {*} newTerms New terms. + */ + const updateTaxQueryState = useCallback( ( taxonomy, newTerms ) => { + const taxObject = taxObjects.find( t => t && t.slug === taxonomy ); + + if ( taxObject ) { + setTaxQueries( { + ...taxQueries, + [`${taxObject.rest_base}`]: newTerms, + } ); + } + }, [ taxQueries, taxObjects ] ); + + // Ensure initial tax query state is set. + // Use effect to account for delay loading tax objects. + useEffect( () => { + taxObjects.forEach( taxObject => { + if ( taxObject && ! taxQueries[ taxObject.rest_base ] ) { + updateTaxQueryState( taxObject.rest_base, [] ); + } + } ); + }, [ taxObjects, updateTaxQueryState, taxQueries ] ); + + const queryArgs = { + search: search || undefined, // When empty, set as undefined to omit query var from API request. + per_page: 30, + ...taxQueries, + }; + + return ( + + + setSearch( text ) } + /> + { taxonomies.map( taxonomy => { + const taxObject = taxObjects.find( t => t && t.slug === taxonomy ); + + return taxObject ? ( + updateTaxQueryState( taxonomy, terms ) } + /> + ) : null; + } ) } + + + + + + ); +} + +/** + * Post Picker Modal Component. + * + * @param {object} props Props. + * @returns {ReactNode} Component + */ +export function PostPickerModal( props ) { + const { + title, + postType = 'post', + taxonomies = [], + values = [], + onChange, + setModalOpen, + } = props; + + return ( + setModalOpen( false ) } + > +
+ ( + <>Foo + ), + }, + { + name: 'selection', + title: __( 'Current Selection', 'block-editor-components' ), + }, + ] } + > + { tabPanel => ( +
+ { tabPanel.name === 'browse' && ( + + ) } + + { tabPanel.name === 'selection' && ( + + ) } +
+ ) } +
+
+
+ ); +} + +/** + * Post picker toolbar button. + * + * @param {object} props Props. + * @returns {ReactNode} Component + */ +export function PostPickerToolbarButton( props ) { + const { + title = __( 'Select posts', 'block-editor-components' ), + icon = 'edit', + } = props; + + const [ modalOpen, setModalOpen ] = useState( false ); + + return ( + <> + setModalOpen( true ) } + > + { title } + + { modalOpen && ( + + ) } + + ); +} + +/** + * Component allowing the selection of one or more posts + * + * @param {object} props Component props + * @returns {ReactNode} Component + */ +export function PostPickerButton( props ) { + const { + title = __( 'Select posts', 'block-editor-components' ), + } = props; + + const [ modalOpen, setModalOpen ] = useState( false ); + + return ( + <> + + { modalOpen && ( + + ) } + + ); +} diff --git a/src/components/TermSelector/index.js b/src/components/TermSelector/index.js new file mode 100644 index 0000000..6993ecd --- /dev/null +++ b/src/components/TermSelector/index.js @@ -0,0 +1,80 @@ +import React, { ReactNode } from 'react'; + +import { FormTokenField } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { __, sprintf } from '@wordpress/i18n'; + +/** + * Generate a list of term IDs, keyed by title. + * + * @param {object[]} termObjects array of terms, returned from getEntityRecords. + * @returns {Array} array of term IDs, keyed by title. + */ +function generateTitleToIdMap( termObjects ) { + + if ( ! termObjects ) { + return []; + } + + return termObjects.reduce( ( accumulator, currentTerm ) => { + accumulator[currentTerm.name] = currentTerm.id; + return accumulator; + }, {} ); + +} + +/** + * Generate a list of term titles, keyed by id. + * + * @param {object[]} termObjects array of terms, returned from getEntityRecords. + * @returns {Array} array of term titles, keyed by id. + */ +function generateIdToTitleMap( termObjects ) { + + if ( ! termObjects ) { + return []; + } + + return termObjects.reduce( ( accumulator, currentTerm ) => { + accumulator[currentTerm.id] = currentTerm.name; + return accumulator; + }, {} ); +} + +/** + * Form token field to select one or more terms. + * + * @param {object} props Component props + * @returns {ReactNode} Component + */ +function TermSelector( props ) { + const { taxonomy, value = [], onChange } = props; + + const taxObject = useSelect( select => { + return select( 'core' ).getTaxonomy( taxonomy ); + }, [ taxonomy ] ); + + const { taxonomyTermsById, taxonomyTermsByTitle } = useSelect( ( select ) => { + const termObjects = select( 'core' ).getEntityRecords( 'taxonomy', taxonomy, { per_page: 100 } ) ?? []; + const taxonomyTermsById = generateIdToTitleMap( termObjects ); + const taxonomyTermsByTitle = generateTitleToIdMap( termObjects ); + + return { + taxonomyTermsById, + taxonomyTermsByTitle, + }; + }, [ taxonomy ] ); + + const selectedTerms = value.map( id => taxonomyTermsById[id] ).filter( Boolean ); + + return ( { + onChange( terms.map( term => taxonomyTermsByTitle[term] ) ); + } } + /> ); +} + +export default TermSelector; diff --git a/src/index.js b/src/index.js index a8bb58f..6350054 100644 --- a/src/index.js +++ b/src/index.js @@ -9,6 +9,12 @@ export { default as PlainTextWithLimit } from './components/PlainTextWithLimit'; export { default as PostTitleControl } from './components/PostTitleControl'; export { default as PostTypeCheck } from './components/PostTypeCheck'; export { default as RichTextWithLimit } from './components/RichTextWithLimit'; +export { default as TermSelector } from './components/TermSelector'; +export { + PostPickerButton, + PostPickerToolbarButton, + PostPickerModal, +} from './components/PostPicker'; export { default as useActiveBlockStyle } from './hooks/useActiveBlockStyle'; export { default as useBlockStyles } from './hooks/useBlockStyles';