UNPKG

@ws-ui/craftjs-layers

Version:

A Photoshop-like layers panel for your page editor

86 lines (82 loc) 14.3 kB
import{useCollector as e,wrapConnectorHooks as t,RenderIndicator as n,useMethods as r,ROOT_NODE as a}from"@ws-ui/craftjs-utils";import*as o from"react";import i,{createContext as d,useContext as s,useMemo as l,useState as c,useLayoutEffect as p,useRef as u,useEffect as v,useCallback as g}from"react";import{useEditor as h,ROOT_NODE as m,DerivedCoreEventHandlers as f,useEventHandler as y}from"@ws-ui/craftjs-core";import x from"styled-components";import b from"react-contenteditable";const E=i.createContext({}),w=d({});function O(t){const{store:n}=s(w),r=e(n,t);return l((()=>({store:n,...r})),[n,r])}function C(e){const{id:n,depth:r,connectors:a}=s(E),{actions:o,...i}=O((t=>n&&t.layers[n]&&e&&e(t.layers[n]))),{children:d}=h(((e,t)=>({children:e.nodes[n]&&t.node(n).descendants()}))),c=l((()=>({toggleLayer:()=>o.toggleLayer(n),setExpandedState:e=>o.setExpandedState(n,e)})),[o,n]),p=l((()=>t({layer:e=>a.layer(e,n),drag:e=>a.drag(e,n),layerHeader:e=>a.layerHeader(e,n)})),[a,n]);return{id:n,depth:r,children:d,actions:c,connectors:p,...i}}const L=()=>{const{id:e,depth:t,children:n,expanded:r}=C((e=>({expanded:e.expanded}))),{data:a,shouldBeExpanded:o}=h(((t,n)=>{const r=n.getEvent("selected").first();return{data:t.nodes[e]&&t.nodes[e].data,shouldBeExpanded:r&&n.node(r).ancestors(!0).includes(e)}})),{actions:{registerLayer:d,toggleLayer:s},renderLayer:l,expandRootOnLoad:g}=O((e=>({renderLayer:e.options.renderLayer,expandRootOnLoad:e.options.expandRootOnLoad}))),[f,y]=c(!1);p((()=>{d(e),y(!0)}),[d,e]);const x=u(r);x.current=r;const b=u(g&&e===m);return v((()=>{!x.current&&o&&s(e)}),[s,e,o]),v((()=>{b.current&&s(e)}),[s,e]),a&&f?i.createElement("div",{className:`craft-layer-node ${e}`},i.createElement(l,{},n&&r?n.map((e=>i.createElement(P,{key:e,id:e,depth:t+1}))):null)):null},j=d(null),P=({id:e,depth:n})=>{const r=s(j),{store:a}=s(w);u(a).current=a;const o=l((()=>r.createConnectorsUsage()),[r]),d=l((()=>t(o.connectors)),[o]);v((()=>(o.register(),()=>{o.cleanup()})),[o]);const{exists:c}=h((t=>({exists:!!t.nodes[e]})));return c?i.createElement(E.Provider,{value:{id:e,depth:n,connectors:d}},i.createElement(L,null)):null},D=e=>({setLayerEvent:(t,n)=>{if(null!==n&&!e.layers[n])return;const r=e.events[t];r&&n!==r&&(e.layers[r].event[t]=!1),n?(e.layers[n].event[t]=!0,e.events[t]=n):e.events[t]=null},registerLayer:t=>{e.layers[t]||(e.layers[t]={dom:null,headingDom:null,expanded:!1,id:t,event:{selected:!1,hovered:!1}})},setDOM:(t,n)=>{e.layers[t]={...e.layers[t],...n.dom?{dom:n.dom}:{},...n.headingDom?{headingDom:n.headingDom}:{}}},toggleLayer:t=>{e.layers[t].expanded=!e.layers[t].expanded},setExpandedState:(t,n)=>{e.layers[t].expanded=n},setIndicator:t=>{e.events.indicator=t}});function N(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function k(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?N(Object(n),!0).forEach((function(t){H(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):N(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function H(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,"string");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class $ extends f{getLayer(e){return this.options.layerStore.getState().layers[e]}handlers(){const e=this.derived.options.store,{layerStore:t}=this.options;return{layer:(n,r)=>{t.actions.setDOM(r,{dom:n});const a=this.inherit((e=>{e.select(n,r),e.hover(n,r),e.drag(n,r)})),o=this.addCraftEventListener(n,"mouseover",(e=>{e.craft.stopPropagation(),t.actions.setLayerEvent("hovered",r)})),i=this.addCraftEventListener(n,"drop",(e=>{t.actions.setIndicator(null)})),d=this.addCraftEventListener(n,"dragover",(n=>{n.craft.stopPropagation(),n.preventDefault();const{indicator:r,currentCanvasHovered:a}=$.events;if(a&&r){var o;const i=null===(o=this.getLayer(a.id))||void 0===o?void 0:o.getBoundingClientRect();if(n.clientY>((null==i?void 0:i.top)||0)+10&&n.clientY<((null==i?void 0:i.bottom)||0)-10){const n=a.data.nodes[a.data.nodes.length-1];if(!n)return void($.events.indicator=k(k({},r),{},{placement:k(k({},r.placement),{},{index:0,where:"before",parent:a}),onCanvas:!0}));$.events.indicator=k(k({},r),{},{placement:{currentNode:e.query.node(n).get(),index:a.data.nodes.length,where:"after",parent:a},onCanvas:!0}),t.actions.setIndicator($.events.indicator)}}})),s=this.addCraftEventListener(n,"dragenter",(n=>{n.craft.stopPropagation(),n.preventDefault();const a=$.draggedElement;if(!a)return;const o=e.query.getDropPlaceholder(a,r,{x:n.clientX,y:n.clientY},(e=>{const t=this.getLayer(e.id);return t&&t.dom}));if(o){const{placement:{parent:r}}=o;let a;try{var i,d;a=null===(i=this.getLayer(r.id))||void 0===i||null===(d=i.headingDom)||void 0===d?void 0:d.getBoundingClientRect()}catch(n){}if($.events.currentCanvasHovered=null,e.query.node(r.id).isCanvas()&&r.data.parent){const t=e.query.node(r.data.parent).get();var s,l,c,p;e.query.node(t.id).isCanvas()&&($.events.currentCanvasHovered=r,(n.clientY>((null===(s=a)||void 0===s?void 0:s.bottom)||0)-10&&!this.getLayer(r.id).expanded||n.clientY<((null===(l=a)||void 0===l?void 0:l.top)||0)+10)&&(o.placement.parent=t,o.placement.currentNode=r,o.placement.index=t.data.nodes?t.data.nodes.indexOf(r.id):0,n.clientY>((null===(c=a)||void 0===c?void 0:c.bottom)||0)-10&&!this.getLayer(r.id).expanded?o.placement.where="after":n.clientY<((null===(p=a)||void 0===p?void 0:p.top)||0)+10&&(o.placement.where="before")))}$.events.indicator=k(k({},o),{},{onCanvas:!1}),t.actions.setIndicator($.events.indicator)}}));return()=>{a(),o(),d(),s(),i()}},layerHeader:(e,n)=>{t.actions.setDOM(n,{headingDom:e})},drag:(n,r)=>{n.setAttribute("draggable","true");const a=this.addCraftEventListener(n,"dragstart",(e=>{e.craft.stopPropagation(),$.draggedElement=r})),o=this.addCraftEventListener(n,"dragend",(n=>{n.craft.stopPropagation();const r=$.events;if(r.indicator&&!r.indicator.error){const{placement:t}=r.indicator,{parent:n,index:a,where:o}=t,{id:i}=n;e.actions.move($.draggedElement,i,a+("after"===o?1:0))}$.draggedElement=null,$.events.indicator=null,t.actions.setIndicator(null)}));return()=>{n.removeAttribute("draggable"),a(),o(),t.actions.setIndicator(null)}}}}}H($,"draggedElement",void 0),H($,"events",{indicator:null,currentCanvasHovered:null});const S=({children:e})=>{const{layers:t,events:r}=O((e=>e)),{query:a}=h((e=>({enabled:e.options.enabled}))),{indicator:o}=a.getOptions();let d;try{d=(()=>{const{indicator:e}=r;if(e){const{placement:{where:n,parent:r,currentNode:a},error:i}=e,d=a?a.id:r.id;let s;const l=i?o.error:o.success;if(e.onCanvas&&null!=t[r.id].dom){const e=t[r.id]?.dom?.getBoundingClientRect(),n=t[r.id]?.headingDom?.getBoundingClientRect();return{top:n?.top,left:e?.left,width:e?.width,height:n?.height,background:"transparent",borderWidth:"1px",borderColor:l}}{if(!t[d]&&null==t[d].headingDom)return;const e=t[d]?.headingDom?.getBoundingClientRect(),r=t[d]?.dom?.getBoundingClientRect();return s="after"!==n&&a?r?.top:r?.top+r?.height,{top:s,left:e?.left,width:r.width+r?.left-e?.left,height:2,borderWidth:0,background:l}}}})()}catch(e){}return i.createElement("div",null,r.indicator?i.createElement(n,{style:d}):null,e)},B=({children:e})=>{const{store:t}=O(),n=y(),r=l((()=>n.derive($,{layerStore:t})),[n,t]);return i.createElement(j.Provider,{value:r},i.createElement(S,null),e)},M=()=>{const{id:e}=C(),{displayName:t,actions:n}=h((t=>({displayName:t.nodes[e]&&t.nodes[e].data.custom.displayName?t.nodes[e].data.custom.displayName:t.nodes[e].data.displayName,hidden:t.nodes[e]&&t.nodes[e].data.hidden}))),[r,a]=c(!1),o=u(null),d=g((e=>{o.current&&!o.current.contains(e.target)&&a(!1)}),[]);return v((()=>()=>{window.removeEventListener("click",d)}),[d]),i.createElement(b,{html:t,disabled:!r,ref:e=>{e&&(o.current=e.el.current,window.removeEventListener("click",d),window.addEventListener("click",d))},onChange:t=>{n.setCustom(e,(e=>e.displayName=t.target.value))},tagName:"h2",onDoubleClick:()=>{r||a(!0)}})};var R;function z(){return z=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},z.apply(this,arguments)}var Y,_,q=function(e){return o.createElement("svg",z({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 10 6"},e),R||(R=o.createElement("path",{d:"M9.99 1.01A1 1 0 0 0 8.283.303L5 3.586 1.717.303A1 1 0 1 0 .303 1.717l3.99 3.98a1 1 0 0 0 1.414 0l3.99-3.98a.997.997 0 0 0 .293-.707Z"})))};function I(){return I=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},I.apply(this,arguments)}var A,T,V=function(e){return o.createElement("svg",I({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",width:16,height:16},e),Y||(Y=o.createElement("path",{fill:"none",d:"M0 0h24v24H0z"})),_||(_=o.createElement("path",{d:"M1.181 12C2.121 6.88 6.608 3 12 3c5.392 0 9.878 3.88 10.819 9-.94 5.12-5.427 9-10.819 9-5.392 0-9.878-3.88-10.819-9zM12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10zm0-2a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"})))};function Z(){return Z=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},Z.apply(this,arguments)}var W=function(e){return o.createElement("svg",Z({xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 18 18"},e),A||(A=o.createElement("path",{className:"linked_svg__a",d:"M16.5 9h-1a.5.5 0 0 0-.5.5V15H3V3h5.5a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-7a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5h15a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.5-.5Z"})),T||(T=o.createElement("path",{className:"linked_svg__a",d:"M16.75 1h-5.373a.4.4 0 0 0-.377.4.392.392 0 0 0 .117.28l1.893 1.895-3.52 3.521a.5.5 0 0 0 0 .707l.706.708a.5.5 0 0 0 .708 0l3.521-3.521 1.893 1.892A.39.39 0 0 0 16.6 7a.4.4 0 0 0 .4-.377V1.25a.25.25 0 0 0-.25-.25Z"})))};const U=x.div` display: flex; flex-direction: row; align-items: center; padding: 4px 10px; background: ${e=>e.selected?"#2680eb":"transparent"}; color: ${e=>e.selected?"#fff":"inherit"}; svg { fill: ${e=>e.selected?"#fff":"#808184"}; margin-top: 2px; } .inner { flex: 1; > div { padding: 0px; flex: 1; display: flex; margin-left: ${e=>10*e.depth}px; align-items: center; div.layer-name { flex: 1; h2 { font-size: 15px; line-height: 26px; } } } } `,X=x.a` width: 8px; height: 8px; display: flex; align-items: center; justify-content: center; transform-origin: center; transition: 0.4s cubic-bezier(0.19, 1, 0.22, 1); transform: rotate(${e=>e.expanded?180:0}deg); opacity: 0.7; cursor: pointer; `,F=x.a` width: 14px; height: 14px; margin-right: 10px; position: relative; transition: 0.4s cubic-bezier(0.19, 1, 0.22, 1); cursor: pointer; svg { width: 100%; height: 100%; object-fit: contain; opacity: ${e=>e.isHidden?.2:1}; } &:after { content: ' '; width: 2px; height: ${e=>e.isHidden?100:0}%; position: absolute; left: 2px; top: 3px; background: ${e=>e.selected?"#fff":"#808184"}; transform: rotate(-45deg); transition: 0.4s cubic-bezier(0.19, 1, 0.22, 1); transform-origin: 0% 0%; opacity: ${e=>e.isHidden?.4:1}; } `,G=x.div` margin-left: -22px; margin-right: 10px; svg { width: 12px; height: 12px; } `,J=()=>{const{id:e,depth:t,expanded:n,children:r,connectors:{drag:a,layerHeader:o},actions:{toggleLayer:d}}=C((e=>({expanded:e.expanded}))),{hidden:s,actions:l,selected:c,topLevel:p}=h(((t,n)=>{const r=n.getEvent("selected").first()===e;return{hidden:t.nodes[e]&&t.nodes[e].data.hidden,selected:r,topLevel:n.node(e).isTopLevelCanvas()}}));return i.createElement(U,{selected:c,ref:a,depth:t},i.createElement(F,{selected:c,isHidden:s,onClick:()=>l.setHidden(e,!s)},i.createElement(V,null)),i.createElement("div",{className:"inner"},i.createElement("div",{ref:o},p?i.createElement(G,null,i.createElement(W,null)):null,i.createElement("div",{className:"layer-name s"},i.createElement(M,null)),i.createElement("div",null,r&&r.length?i.createElement(X,{expanded:n,onMouseDown:()=>d()},i.createElement(q,null)):null))))},K=x.div` background: ${e=>e.hovered?"#f1f1f1":"transparent"}; display: block; padding-bottom: ${e=>e.hasCanvases&&e.expanded?5:0}px; `,Q=x.div` margin: 0 0 0 ${e=>e.hasCanvases?35:0}px; background: ${e=>e.hasCanvases?"rgba(255, 255, 255, 0.02)":"transparent"}; position: relative; ${e=>e.hasCanvases?'\n \n box-shadow: 0px 0px 44px -1px #00000014;\n border-radius: 10px;\n margin-right: 5px;\n margin-bottom:5px;\n margin-top:5px; \n > * { overflow:hidden; }\n &:before { \n position:absolute;\n left:-19px;\n width: 2px;\n height:100%;\n content: " ";\n background:#00000012;\n }\n ':""} `,ee=({children:e})=>{const{id:t,expanded:n,hovered:r,connectors:{layer:a}}=C((e=>({hovered:e.event.hovered,expanded:e.expanded}))),{hasChildCanvases:o}=h(((e,n)=>({hasChildCanvases:n.node(t).isParentOfTopLevelNodes()})));return i.createElement(K,{ref:a,expanded:n,hasCanvases:o,hovered:r},i.createElement(J,null),e?i.createElement(Q,{hasCanvases:o,className:"craft-layer-children"},e):null)},te=({children:e,options:t})=>{const n=r(D,{layers:{},events:{selected:null,dragged:null,hovered:null},options:{renderLayer:ee,...t}});return i.createElement(w.Provider,{value:{store:n}},i.createElement(B,null,e))},ne=({...e})=>i.createElement(te,{options:e},i.createElement(P,{id:a,depth:0}));export{ee as DefaultLayer,J as DefaultLayerHeader,M as EditableLayerName,ne as Layers,C as useLayer};