diff --git a/drawnix.d.ts b/drawnix.d.ts index 9213e459cd38986bddf2ea16466d3c0ffe02e4fd..b87f6325282f8cb07250dc06cc12f60b4285960a 100644 --- a/drawnix.d.ts +++ b/drawnix.d.ts @@ -1,5 +1,5 @@ import { BoardChangeData } from '../../react-board/src/index.ts'; -import { PlaitBoard, PlaitElement, PlaitTheme, Selection, ThemeColorMode, Viewport } from '@plait/core'; +import { PlaitBoard, PlaitPlugin, PlaitElement, PlaitTheme, Selection, ThemeColorMode, Viewport } from '@plait/core'; import { default as React } from 'react'; export type DrawnixProps = { value: PlaitElement[]; @@ -12,5 +12,6 @@ export type DrawnixProps = { onThemeChange?: (value: ThemeColorMode) => void; afterInit?: (board: PlaitBoard) => void; tutorial?: boolean; + plugins?: PlaitPlugin[]; } & React.HTMLAttributes; export declare const Drawnix: React.FC; diff --git a/index.js b/index.js index 9ddff1710edab6c8949c0c213a4be2409ce5dfcb..1172df1e8619c7ce030cd86a3a3770ec18f69e2b 100644 --- a/index.js +++ b/index.js @@ -173,4 +173,4 @@ B --> C{Let me think} C -->|One| D[Laptop] C -->|Two| E[iPhone] - C -->|Three| F[Car]`,Gr=()=>{const{appState:e,setAppState:t}=G(),{t:o,language:r}=R(),[i,a]=x.useState({loaded:!1,api:Promise.resolve({parseMermaidToDrawnix:async()=>({elements:[]})})});x.useEffect(()=>{(async()=>{try{const y=await import("@plait-board/mermaid-to-drawnix");a({loaded:!0,api:Promise.resolve(y)})}catch(y){console.error("Failed to load mermaid library:",y),u(new Error(o("dialog.error.loadMermaid")))}})()},[]);const[s,l]=x.useState(()=>Kr),[d,h]=x.useState(()=>[]),m=x.useDeferredValue(s.trim()),[p,u]=x.useState(null),g=B.useBoard();x.useEffect(()=>{(async()=>{try{const y=await i.api;let L;try{L=await y.parseMermaidToDrawnix(m)}catch{L=await y.parseMermaidToDrawnix(m.replace(/"/g,"'"))}const{elements:j}=L;h(j),u(null)}catch(y){u(y)}})()},[m,i]);const w=()=>{if(!d.length)return;const f=c.PlaitBoard.getBoardContainer(g).getBoundingClientRect(),y=[f.width/2,f.height/2],L=g.viewport.zoom,j=c.getViewportOrigination(g),S=j[0]+y[0]/L,v=j[1]+y[1]/L,k=d,I=c.RectangleClient.getBoundingRectangle(k.filter(A=>!c.PlaitGroupElement.isGroup(A)).map(A=>c.RectangleClient.getRectangleByPoints(A.points))),E=[S-I.width/2,v-I.height/2];g.insertFragment({elements:JSON.parse(JSON.stringify(k))},E,c.WritableClipboardOperationType.paste),t({...e,openDialogType:null})};return n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"ttd-dialog-desc",children:r==="zh"?n.jsxs(n.Fragment,{children:[o("dialog.mermaid.description")," ",n.jsx("a",{href:"https://mermaid.js.org/syntax/flowchart.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.flowchart")}),"、",n.jsx("a",{href:"https://mermaid.js.org/syntax/sequenceDiagram.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.sequence")})," ","和"," ",n.jsx("a",{href:"https://mermaid.js.org/syntax/classDiagram.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.class")}),o("dialog.mermaid.otherTypes")]}):n.jsxs(n.Fragment,{children:[o("dialog.mermaid.description")," ",n.jsx("a",{href:"https://mermaid.js.org/syntax/flowchart.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.flowchart")}),","," ",n.jsx("a",{href:"https://mermaid.js.org/syntax/sequenceDiagram.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.sequence")}),","," ",n.jsx("a",{href:"https://mermaid.js.org/syntax/classDiagram.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.class")}),o("dialog.mermaid.otherTypes")]})}),n.jsxs(Jt,{children:[n.jsx(ge,{label:o("dialog.mermaid.syntax"),children:n.jsx(Qt,{input:s,placeholder:o("dialog.mermaid.placeholder"),onChange:f=>l(f.target.value),onKeyboardSubmit:()=>{w()}})}),n.jsx(ge,{label:o("dialog.mermaid.preview"),panelAction:{action:()=>{w()},label:o("dialog.mermaid.insert")},renderSubmitShortcut:()=>n.jsx(tn,{}),children:n.jsx(en,{value:d,loaded:i.loaded,error:p})})]})]})},Wr=()=>{const{appState:e,setAppState:t}=G(),{t:o,language:r}=R(),[i,a]=x.useState({loaded:!1,api:Promise.resolve({parseMarkdownToDrawnix:(f,y)=>null})});x.useEffect(()=>{(async()=>{try{const y=await import("@plait-board/markdown-to-drawnix");a({loaded:!0,api:Promise.resolve(y)})}catch(y){console.error("Failed to load mermaid library:",y),u(new Error(o("dialog.error.loadMermaid")))}})()},[]);const[s,l]=x.useState(()=>o("markdown.example")),[d,h]=x.useState(()=>[]),m=x.useDeferredValue(s.trim()),[p,u]=x.useState(null),g=B.useBoard();x.useEffect(()=>{l(o("markdown.example"))},[r]),x.useEffect(()=>{(async()=>{try{const y=await i.api;let L;try{L=await y.parseMarkdownToDrawnix(m)}catch{L=await y.parseMarkdownToDrawnix(m.replace(/"/g,"'"))}const j=L;j.points=[[0,0]],j&&(h([j]),u(null))}catch(y){u(y)}})()},[m,i]);const w=()=>{if(!d.length)return;const f=c.PlaitBoard.getBoardContainer(g).getBoundingClientRect(),y=[f.width/4,f.height/2-20],L=g.viewport.zoom,j=c.getViewportOrigination(g),S=j[0]+y[0]/L,v=j[1]+y[1]/L,k=d;g.insertFragment({elements:JSON.parse(JSON.stringify(k))},[S,v],c.WritableClipboardOperationType.paste),t({...e,openDialogType:null})};return n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"ttd-dialog-desc",children:o("dialog.markdown.description")}),n.jsxs(Jt,{children:[n.jsx(ge,{label:o("dialog.markdown.syntax"),children:n.jsx(Qt,{input:s,placeholder:o("dialog.markdown.placeholder"),onChange:f=>l(f.target.value),onKeyboardSubmit:()=>{w()}})}),n.jsx(ge,{label:o("dialog.markdown.preview"),panelAction:{action:()=>{w()},label:o("dialog.markdown.insert")},renderSubmitShortcut:()=>n.jsx(tn,{}),children:n.jsx(en,{value:d,loaded:i.loaded,error:p})})]})]})},Vr=({container:e})=>{const{appState:t,setAppState:o}=G();return n.jsxs(n.Fragment,{children:[n.jsx(ke,{open:t.openDialogType===J.mermaidToDrawnix,onOpenChange:r=>{o({...t,openDialogType:r?J.mermaidToDrawnix:null})},children:n.jsx(be,{className:"Dialog ttd-dialog",container:e,children:n.jsx(Gr,{})})}),n.jsx(ke,{open:t.openDialogType===J.markdownToDrawnix,onOpenChange:r=>{o({...t,openDialogType:r?J.markdownToDrawnix:null})},children:n.jsx(be,{className:"Dialog ttd-dialog",container:e,children:n.jsx(Wr,{})})})]})},Zr=({container:e})=>{const{appState:t,setAppState:o}=G(),{t:r}=R(),i=B.useBoard();return n.jsx(ke,{open:t.openCleanConfirm,onOpenChange:a=>{o({...t,openCleanConfirm:a})},children:n.jsxs(be,{className:"clean-confirm",container:e,children:[n.jsx("h2",{className:"clean-confirm__title",children:r("cleanConfirm.title")}),n.jsx("p",{className:"clean-confirm__description",children:r("cleanConfirm.description")}),n.jsxs("div",{className:"clean-confirm__actions",children:[n.jsx("button",{className:"clean-confirm__button clean-confirm__button--cancel",onClick:()=>{o({...t,openCleanConfirm:!1})},children:r("cleanConfirm.cancel")}),n.jsx("button",{className:"clean-confirm__button clean-confirm__button--ok",autoFocus:!0,onClick:()=>{i.deleteFragment(i.children),o({...t,openCleanConfirm:!1})},children:r("cleanConfirm.ok")})]})]})})},nt=e=>{const{appState:t}=e;return t&&t.linkState&&t.linkState.isHovering},ot=e=>{const{appState:t}=e;return t&&t.linkState&&t.linkState.isEditing},$r=e=>o=>{const{pointerMove:r}=o;let i=null,a=null;return o.pointerMove=s=>{(c.PlaitBoard.isPointer(o,c.PlaitPointerType.selection)||c.PlaitBoard.isPointer(o,c.PlaitPointerType.hand))&&!c.isMovingElements(o)&&!b.isResizing(o)&&!nt(o)&&!ot(o)&&c.throttleRAF(o,"with-text-link",()=>{const l=s.target.closest(".plait-board-link");if(l&&l!==i){const d=l.closest(".plait-text-container"),h=ne.ReactEditor.toSlateNode(void 0,d),m=ne.ReactEditor.toSlateNode(void 0,l);i=l,e({linkState:{targetDom:l,targetElement:m,editor:h,isEditing:!1,isHovering:!1,isHoveringOrigin:!0}}),clearTimeout(a)}else!l&&i&&(a=setTimeout(()=>{!nt(o)&&!ot(o)&&e({linkState:null})},300),i=null)}),r(s)},o},Xr=()=>{var y,L,j,S;const{t:e}=R(),[t,o]=x.useState(""),{appState:r,setAppState:i}=G(),a=B.useBoard(),{refs:s,floatingStyles:l}=M.useFloating({placement:"top",middleware:[M.offset(20),M.flip()]}),d=r.linkState,h=((y=r.linkState)==null?void 0:y.targetDom)||null,m=((L=r.linkState)==null?void 0:L.isEditing)||!1,p=((j=r.linkState)==null?void 0:j.isHoveringOrigin)||!1,u=((S=r.linkState)==null?void 0:S.isHovering)||!1,g=m||p||u,w=x.useRef(r.linkState);x.useEffect(()=>{w.current=r.linkState,r.linkState?o(r.linkState.targetElement.url):o("")},[r.linkState]),x.useEffect(()=>{if(h){const v=h.getBoundingClientRect();s.setPositionReference({getBoundingClientRect(){return{x:v.x,y:v.y,width:v.width,height:v.height,top:v.y,left:v.x,right:v.x+v.width,bottom:v.y+v.height}}})}},[a.viewport,h]),x.useEffect(()=>{const v=k=>{if(s.floating.current&&!s.floating.current.contains(k.target)){if(w.current){const I=K.LinkEditor.getLinkElement(w.current.editor);I&&!I[0].url.trim()&&K.LinkEditor.unwrapLink(w.current.editor)}i({...r,linkState:null})}};return document.addEventListener("mousedown",v),()=>{document.removeEventListener("mousedown",v)}},[]);const f=()=>{if(t!==d.targetElement.url){const k=d.editor,I=d.targetElement,E=ne.ReactEditor.findPath(k,I);xe.Transforms.setNodes(k,{url:t},{at:E})}const v=K.LinkEditor.getLinkElement(d.editor);i({...r,linkState:{...r.linkState,targetElement:v[0],isEditing:!1,isHoveringOrigin:!0}})};return g&&n.jsx(_,{ref:s.setFloating,style:l,padding:1,className:P("link-popup"),onPointerEnter:()=>{u||i({...r,linkState:{...r.linkState,isHovering:!0}})},onPointerLeave:()=>{m||i({...r,linkState:{...r.linkState,isHovering:!1}})},children:n.jsx(H.Row,{gap:1,align:"center",children:m?n.jsxs(n.Fragment,{children:[n.jsx("input",{type:"text",value:t,onChange:v=>{o(v.target.value)},onKeyDown:v=>{v.key==="Enter"&&f()},className:"link-popup__input",autoFocus:!0}),n.jsx(D,{type:"icon",visible:!0,icon:me,title:e("popupLink.delLink"),"aria-label":e("popupLink.delLink"),onPointerDown:()=>{const v=d.editor,k=d.targetElement,I=ne.ReactEditor.findPath(v,k);xe.Transforms.unwrapNodes(v,{at:I}),i({...r,linkState:null})}})]}):n.jsxs(n.Fragment,{children:[n.jsx("a",{href:t,target:"_blank",rel:"noopener noreferrer",className:"link-popup__link",children:t}),n.jsx(D,{className:"link-popup__edit",type:"icon",visible:!0,icon:Se,title:"Edit link","aria-label":"Edit link",onPointerDown:({event:v})=>{v.preventDefault(),i({...r,linkState:{...r.linkState,isEditing:!0}})}}),n.jsx(D,{type:"icon",visible:!0,icon:me,title:e("popupLink.delLink"),"aria-label":e("popupLink.delLink"),onPointerDown:()=>{const v=d.editor,k=d.targetElement,I=ne.ReactEditor.findPath(v,k);xe.Transforms.unwrapNodes(v,{at:I}),i({...r,linkState:null})}})]})})})},qr=()=>{const{t:e}=R();return n.jsx("div",{className:"drawnix-tutorial",children:n.jsx("div",{className:"tutorial-overlay",children:n.jsxs("div",{className:"tutorial-content",children:[n.jsx("h1",{className:"brand-title",children:e("tutorial.title")}),n.jsx("p",{className:"brand-description",children:e("tutorial.description")}),n.jsx("p",{className:"brand-tooltip",children:e("tutorial.dataDescription")}),n.jsxs("div",{className:"feature-pointer top-left",children:[n.jsxs("svg",{className:"pointer-arrow-svg",width:"130",height:"100",viewBox:"0 0 130 100",children:[n.jsx("defs",{children:n.jsx("marker",{id:"arrow-left",markerWidth:"10",markerHeight:"10",refX:"0",refY:"3",orient:"auto",markerUnits:"strokeWidth",children:n.jsx("path",{d:"M0,0 L0,6 L6,3 z",fill:"#888"})})}),n.jsx("path",{d:"M 80,70 Q 35,60 15,15",fill:"none",stroke:"#aaa",strokeWidth:"1.5",markerEnd:"url(#arrow-left)"})]}),n.jsx("div",{className:"pointer-content",children:n.jsx("p",{children:e("tutorial.appToolbar")})})]}),n.jsxs("div",{className:"feature-pointer top-center",children:[n.jsxs("svg",{className:"pointer-arrow-svg",width:"100",height:"130",viewBox:"0 0 100 130",children:[n.jsx("defs",{children:n.jsx("marker",{id:"arrow-top",markerWidth:"10",markerHeight:"10",refX:"0",refY:"3",orient:"auto",markerUnits:"strokeWidth",children:n.jsx("path",{d:"M0,0 L0,6 L6,3 z",fill:"#888"})})}),n.jsx("path",{d:"M 45,90 Q 20,50 45,10",fill:"none",stroke:"#aaa",strokeWidth:"1.5",markerEnd:"url(#arrow-top)"})]}),n.jsx("div",{className:"pointer-content",children:n.jsx("p",{children:e("tutorial.creationToolbar")})})]}),n.jsxs("div",{className:"feature-pointer bottom-right",children:[n.jsxs("svg",{className:"pointer-arrow-svg",width:"180",height:"100",viewBox:"0 0 180 100",children:[n.jsx("defs",{children:n.jsx("marker",{id:"arrow-right",markerWidth:"10",markerHeight:"10",refX:"0",refY:"3",orient:"auto",markerUnits:"strokeWidth",children:n.jsx("path",{d:"M0,0 L0,6 L6,3 z",fill:"#888"})})}),n.jsx("path",{d:"M 20,25 Q 75,20 105,70",fill:"none",stroke:"#aaa",strokeWidth:"1.5",markerEnd:"url(#arrow-right)"})]}),n.jsx("div",{className:"pointer-content",children:n.jsx("p",{children:e("tutorial.themeDescription")})})]})]})})})},Yr=({value:e,viewport:t,theme:o,onChange:r,onSelectionChange:i,onViewportChange:a,onThemeChange:s,onValueChange:l,afterInit:d,tutorial:h=!1})=>{const m={readonly:!1,hideScrollbar:!1,disabledScrollOnNonFocus:!1,themeColors:F.MindThemeColors},[p,u]=x.useState(()=>{const j=new dn(window.navigator.userAgent);return{pointer:c.PlaitPointerType.hand,isMobile:j.mobile()!==null,isPencilMode:!1,openDialogType:null,openCleanConfirm:!1}}),[g,w]=x.useState(null);g&&(g.appState=p);const f=j=>{u({...p,...j})},y=[C.withDraw,b.withGroup,F.withMind,mn,ht,kr(f),Or,Hr(f),$r(f)],L=x.useRef(null);return n.jsx(dt,{children:n.jsx(Tt.Provider,{value:{appState:p,setAppState:u},children:n.jsxs("div",{className:P("drawnix",{"drawnix--mobile":p.isMobile}),ref:L,children:[n.jsxs(B.Wrapper,{value:e,viewport:t,theme:o,options:m,plugins:y,onChange:j=>{r&&r(j)},onSelectionChange:i,onViewportChange:a,onThemeChange:s,onValueChange:l,children:[n.jsx(B.Board,{afterInit:j=>{w(j),d&&d(j)},children:h&&g&&c.PlaitBoard.isPointer(g,c.PlaitPointerType.selection)&&n.jsx(qr,{})}),n.jsx(Cr,{}),n.jsx(Xo,{}),n.jsx(qo,{}),n.jsx(Ar,{}),n.jsx(mr,{}),n.jsx(Xr,{}),n.jsx(zr,{}),n.jsx(Vr,{container:L.current}),n.jsx(Zr,{container:L.current})]}),n.jsx("canvas",{className:`${$t} mouse-course-hidden`})]})})})};exports.Drawnix=Yr;exports.I18nProvider=dt;exports.addImage=Ee;exports.applyOpacityToHex=ee;exports.base64ToBlob=pt;exports.boardToImage=ft;exports.composeEventHandlers=gt;exports.download=Me;exports.getCurrentFill=Oe;exports.getCurrentFontColor=tr;exports.getCurrentStrokeColor=Ae;exports.getShortcutKey=re;exports.hexAlphaToOpacity=te;exports.i18nInsidePlaitHook=ut;exports.isClosedElement=Ne;exports.isDefaultStroke=Nt;exports.isFullyOpaque=ae;exports.isFullyTransparent=Fe;exports.isNoColor=Q;exports.isPromiseLike=mt;exports.isTransparent=Qo;exports.isValidColor=Rt;exports.isWhite=Ie;exports.removeHexAlpha=Y;exports.saveAsImage=se;exports.saveAsSvg=Bt;exports.splitRows=pe;exports.useI18n=R; + C -->|Three| F[Car]`,Gr=()=>{const{appState:e,setAppState:t}=G(),{t:o,language:r}=R(),[i,a]=x.useState({loaded:!1,api:Promise.resolve({parseMermaidToDrawnix:async()=>({elements:[]})})});x.useEffect(()=>{(async()=>{try{const y=await import("@plait-board/mermaid-to-drawnix");a({loaded:!0,api:Promise.resolve(y)})}catch(y){console.error("Failed to load mermaid library:",y),u(new Error(o("dialog.error.loadMermaid")))}})()},[]);const[s,l]=x.useState(()=>Kr),[d,h]=x.useState(()=>[]),m=x.useDeferredValue(s.trim()),[p,u]=x.useState(null),g=B.useBoard();x.useEffect(()=>{(async()=>{try{const y=await i.api;let L;try{L=await y.parseMermaidToDrawnix(m)}catch{L=await y.parseMermaidToDrawnix(m.replace(/"/g,"'"))}const{elements:j}=L;h(j),u(null)}catch(y){u(y)}})()},[m,i]);const w=()=>{if(!d.length)return;const f=c.PlaitBoard.getBoardContainer(g).getBoundingClientRect(),y=[f.width/2,f.height/2],L=g.viewport.zoom,j=c.getViewportOrigination(g),S=j[0]+y[0]/L,v=j[1]+y[1]/L,k=d,I=c.RectangleClient.getBoundingRectangle(k.filter(A=>!c.PlaitGroupElement.isGroup(A)).map(A=>c.RectangleClient.getRectangleByPoints(A.points))),E=[S-I.width/2,v-I.height/2];g.insertFragment({elements:JSON.parse(JSON.stringify(k))},E,c.WritableClipboardOperationType.paste),t({...e,openDialogType:null})};return n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"ttd-dialog-desc",children:r==="zh"?n.jsxs(n.Fragment,{children:[o("dialog.mermaid.description")," ",n.jsx("a",{href:"https://mermaid.js.org/syntax/flowchart.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.flowchart")}),"、",n.jsx("a",{href:"https://mermaid.js.org/syntax/sequenceDiagram.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.sequence")})," ","和"," ",n.jsx("a",{href:"https://mermaid.js.org/syntax/classDiagram.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.class")}),o("dialog.mermaid.otherTypes")]}):n.jsxs(n.Fragment,{children:[o("dialog.mermaid.description")," ",n.jsx("a",{href:"https://mermaid.js.org/syntax/flowchart.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.flowchart")}),","," ",n.jsx("a",{href:"https://mermaid.js.org/syntax/sequenceDiagram.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.sequence")}),","," ",n.jsx("a",{href:"https://mermaid.js.org/syntax/classDiagram.html",target:"_blank",rel:"noreferrer",children:o("dialog.mermaid.class")}),o("dialog.mermaid.otherTypes")]})}),n.jsxs(Jt,{children:[n.jsx(ge,{label:o("dialog.mermaid.syntax"),children:n.jsx(Qt,{input:s,placeholder:o("dialog.mermaid.placeholder"),onChange:f=>l(f.target.value),onKeyboardSubmit:()=>{w()}})}),n.jsx(ge,{label:o("dialog.mermaid.preview"),panelAction:{action:()=>{w()},label:o("dialog.mermaid.insert")},renderSubmitShortcut:()=>n.jsx(tn,{}),children:n.jsx(en,{value:d,loaded:i.loaded,error:p})})]})]})},Wr=()=>{const{appState:e,setAppState:t}=G(),{t:o,language:r}=R(),[i,a]=x.useState({loaded:!1,api:Promise.resolve({parseMarkdownToDrawnix:(f,y)=>null})});x.useEffect(()=>{(async()=>{try{const y=await import("@plait-board/markdown-to-drawnix");a({loaded:!0,api:Promise.resolve(y)})}catch(y){console.error("Failed to load mermaid library:",y),u(new Error(o("dialog.error.loadMermaid")))}})()},[]);const[s,l]=x.useState(()=>o("markdown.example")),[d,h]=x.useState(()=>[]),m=x.useDeferredValue(s.trim()),[p,u]=x.useState(null),g=B.useBoard();x.useEffect(()=>{l(o("markdown.example"))},[r]),x.useEffect(()=>{(async()=>{try{const y=await i.api;let L;try{L=await y.parseMarkdownToDrawnix(m)}catch{L=await y.parseMarkdownToDrawnix(m.replace(/"/g,"'"))}const j=L;j.points=[[0,0]],j&&(h([j]),u(null))}catch(y){u(y)}})()},[m,i]);const w=()=>{if(!d.length)return;const f=c.PlaitBoard.getBoardContainer(g).getBoundingClientRect(),y=[f.width/4,f.height/2-20],L=g.viewport.zoom,j=c.getViewportOrigination(g),S=j[0]+y[0]/L,v=j[1]+y[1]/L,k=d;g.insertFragment({elements:JSON.parse(JSON.stringify(k))},[S,v],c.WritableClipboardOperationType.paste),t({...e,openDialogType:null})};return n.jsxs(n.Fragment,{children:[n.jsx("div",{className:"ttd-dialog-desc",children:o("dialog.markdown.description")}),n.jsxs(Jt,{children:[n.jsx(ge,{label:o("dialog.markdown.syntax"),children:n.jsx(Qt,{input:s,placeholder:o("dialog.markdown.placeholder"),onChange:f=>l(f.target.value),onKeyboardSubmit:()=>{w()}})}),n.jsx(ge,{label:o("dialog.markdown.preview"),panelAction:{action:()=>{w()},label:o("dialog.markdown.insert")},renderSubmitShortcut:()=>n.jsx(tn,{}),children:n.jsx(en,{value:d,loaded:i.loaded,error:p})})]})]})},Vr=({container:e})=>{const{appState:t,setAppState:o}=G();return n.jsxs(n.Fragment,{children:[n.jsx(ke,{open:t.openDialogType===J.mermaidToDrawnix,onOpenChange:r=>{o({...t,openDialogType:r?J.mermaidToDrawnix:null})},children:n.jsx(be,{className:"Dialog ttd-dialog",container:e,children:n.jsx(Gr,{})})}),n.jsx(ke,{open:t.openDialogType===J.markdownToDrawnix,onOpenChange:r=>{o({...t,openDialogType:r?J.markdownToDrawnix:null})},children:n.jsx(be,{className:"Dialog ttd-dialog",container:e,children:n.jsx(Wr,{})})})]})},Zr=({container:e})=>{const{appState:t,setAppState:o}=G(),{t:r}=R(),i=B.useBoard();return n.jsx(ke,{open:t.openCleanConfirm,onOpenChange:a=>{o({...t,openCleanConfirm:a})},children:n.jsxs(be,{className:"clean-confirm",container:e,children:[n.jsx("h2",{className:"clean-confirm__title",children:r("cleanConfirm.title")}),n.jsx("p",{className:"clean-confirm__description",children:r("cleanConfirm.description")}),n.jsxs("div",{className:"clean-confirm__actions",children:[n.jsx("button",{className:"clean-confirm__button clean-confirm__button--cancel",onClick:()=>{o({...t,openCleanConfirm:!1})},children:r("cleanConfirm.cancel")}),n.jsx("button",{className:"clean-confirm__button clean-confirm__button--ok",autoFocus:!0,onClick:()=>{i.deleteFragment(i.children),o({...t,openCleanConfirm:!1})},children:r("cleanConfirm.ok")})]})]})})},nt=e=>{const{appState:t}=e;return t&&t.linkState&&t.linkState.isHovering},ot=e=>{const{appState:t}=e;return t&&t.linkState&&t.linkState.isEditing},$r=e=>o=>{const{pointerMove:r}=o;let i=null,a=null;return o.pointerMove=s=>{(c.PlaitBoard.isPointer(o,c.PlaitPointerType.selection)||c.PlaitBoard.isPointer(o,c.PlaitPointerType.hand))&&!c.isMovingElements(o)&&!b.isResizing(o)&&!nt(o)&&!ot(o)&&c.throttleRAF(o,"with-text-link",()=>{const l=s.target.closest(".plait-board-link");if(l&&l!==i){const d=l.closest(".plait-text-container"),h=ne.ReactEditor.toSlateNode(void 0,d),m=ne.ReactEditor.toSlateNode(void 0,l);i=l,e({linkState:{targetDom:l,targetElement:m,editor:h,isEditing:!1,isHovering:!1,isHoveringOrigin:!0}}),clearTimeout(a)}else!l&&i&&(a=setTimeout(()=>{!nt(o)&&!ot(o)&&e({linkState:null})},300),i=null)}),r(s)},o},Xr=()=>{var y,L,j,S;const{t:e}=R(),[t,o]=x.useState(""),{appState:r,setAppState:i}=G(),a=B.useBoard(),{refs:s,floatingStyles:l}=M.useFloating({placement:"top",middleware:[M.offset(20),M.flip()]}),d=r.linkState,h=((y=r.linkState)==null?void 0:y.targetDom)||null,m=((L=r.linkState)==null?void 0:L.isEditing)||!1,p=((j=r.linkState)==null?void 0:j.isHoveringOrigin)||!1,u=((S=r.linkState)==null?void 0:S.isHovering)||!1,g=m||p||u,w=x.useRef(r.linkState);x.useEffect(()=>{w.current=r.linkState,r.linkState?o(r.linkState.targetElement.url):o("")},[r.linkState]),x.useEffect(()=>{if(h){const v=h.getBoundingClientRect();s.setPositionReference({getBoundingClientRect(){return{x:v.x,y:v.y,width:v.width,height:v.height,top:v.y,left:v.x,right:v.x+v.width,bottom:v.y+v.height}}})}},[a.viewport,h]),x.useEffect(()=>{const v=k=>{if(s.floating.current&&!s.floating.current.contains(k.target)){if(w.current){const I=K.LinkEditor.getLinkElement(w.current.editor);I&&!I[0].url.trim()&&K.LinkEditor.unwrapLink(w.current.editor)}i({...r,linkState:null})}};return document.addEventListener("mousedown",v),()=>{document.removeEventListener("mousedown",v)}},[]);const f=()=>{if(t!==d.targetElement.url){const k=d.editor,I=d.targetElement,E=ne.ReactEditor.findPath(k,I);xe.Transforms.setNodes(k,{url:t},{at:E})}const v=K.LinkEditor.getLinkElement(d.editor);i({...r,linkState:{...r.linkState,targetElement:v[0],isEditing:!1,isHoveringOrigin:!0}})};return g&&n.jsx(_,{ref:s.setFloating,style:l,padding:1,className:P("link-popup"),onPointerEnter:()=>{u||i({...r,linkState:{...r.linkState,isHovering:!0}})},onPointerLeave:()=>{m||i({...r,linkState:{...r.linkState,isHovering:!1}})},children:n.jsx(H.Row,{gap:1,align:"center",children:m?n.jsxs(n.Fragment,{children:[n.jsx("input",{type:"text",value:t,onChange:v=>{o(v.target.value)},onKeyDown:v=>{v.key==="Enter"&&f()},className:"link-popup__input",autoFocus:!0}),n.jsx(D,{type:"icon",visible:!0,icon:me,title:e("popupLink.delLink"),"aria-label":e("popupLink.delLink"),onPointerDown:()=>{const v=d.editor,k=d.targetElement,I=ne.ReactEditor.findPath(v,k);xe.Transforms.unwrapNodes(v,{at:I}),i({...r,linkState:null})}})]}):n.jsxs(n.Fragment,{children:[n.jsx("a",{href:t,target:"_blank",rel:"noopener noreferrer",className:"link-popup__link",children:t}),n.jsx(D,{className:"link-popup__edit",type:"icon",visible:!0,icon:Se,title:"Edit link","aria-label":"Edit link",onPointerDown:({event:v})=>{v.preventDefault(),i({...r,linkState:{...r.linkState,isEditing:!0}})}}),n.jsx(D,{type:"icon",visible:!0,icon:me,title:e("popupLink.delLink"),"aria-label":e("popupLink.delLink"),onPointerDown:()=>{const v=d.editor,k=d.targetElement,I=ne.ReactEditor.findPath(v,k);xe.Transforms.unwrapNodes(v,{at:I}),i({...r,linkState:null})}})]})})})},qr=()=>{const{t:e}=R();return n.jsx("div",{className:"drawnix-tutorial",children:n.jsx("div",{className:"tutorial-overlay",children:n.jsxs("div",{className:"tutorial-content",children:[n.jsx("h1",{className:"brand-title",children:e("tutorial.title")}),n.jsx("p",{className:"brand-description",children:e("tutorial.description")}),n.jsx("p",{className:"brand-tooltip",children:e("tutorial.dataDescription")}),n.jsxs("div",{className:"feature-pointer top-left",children:[n.jsxs("svg",{className:"pointer-arrow-svg",width:"130",height:"100",viewBox:"0 0 130 100",children:[n.jsx("defs",{children:n.jsx("marker",{id:"arrow-left",markerWidth:"10",markerHeight:"10",refX:"0",refY:"3",orient:"auto",markerUnits:"strokeWidth",children:n.jsx("path",{d:"M0,0 L0,6 L6,3 z",fill:"#888"})})}),n.jsx("path",{d:"M 80,70 Q 35,60 15,15",fill:"none",stroke:"#aaa",strokeWidth:"1.5",markerEnd:"url(#arrow-left)"})]}),n.jsx("div",{className:"pointer-content",children:n.jsx("p",{children:e("tutorial.appToolbar")})})]}),n.jsxs("div",{className:"feature-pointer top-center",children:[n.jsxs("svg",{className:"pointer-arrow-svg",width:"100",height:"130",viewBox:"0 0 100 130",children:[n.jsx("defs",{children:n.jsx("marker",{id:"arrow-top",markerWidth:"10",markerHeight:"10",refX:"0",refY:"3",orient:"auto",markerUnits:"strokeWidth",children:n.jsx("path",{d:"M0,0 L0,6 L6,3 z",fill:"#888"})})}),n.jsx("path",{d:"M 45,90 Q 20,50 45,10",fill:"none",stroke:"#aaa",strokeWidth:"1.5",markerEnd:"url(#arrow-top)"})]}),n.jsx("div",{className:"pointer-content",children:n.jsx("p",{children:e("tutorial.creationToolbar")})})]}),n.jsxs("div",{className:"feature-pointer bottom-right",children:[n.jsxs("svg",{className:"pointer-arrow-svg",width:"180",height:"100",viewBox:"0 0 180 100",children:[n.jsx("defs",{children:n.jsx("marker",{id:"arrow-right",markerWidth:"10",markerHeight:"10",refX:"0",refY:"3",orient:"auto",markerUnits:"strokeWidth",children:n.jsx("path",{d:"M0,0 L0,6 L6,3 z",fill:"#888"})})}),n.jsx("path",{d:"M 20,25 Q 75,20 105,70",fill:"none",stroke:"#aaa",strokeWidth:"1.5",markerEnd:"url(#arrow-right)"})]}),n.jsx("div",{className:"pointer-content",children:n.jsx("p",{children:e("tutorial.themeDescription")})})]})]})})})},Yr=({value:e,viewport:t,theme:o,onChange:r,onSelectionChange:i,onViewportChange:a,onThemeChange:s,onValueChange:l,afterInit:d,tutorial:h=!1,plugins:additionalPlugins=[]})=>{const m={readonly:!1,hideScrollbar:!1,disabledScrollOnNonFocus:!1,themeColors:F.MindThemeColors},[p,u]=x.useState(()=>{const j=new dn(window.navigator.userAgent);return{pointer:c.PlaitPointerType.hand,isMobile:j.mobile()!==null,isPencilMode:!1,openDialogType:null,openCleanConfirm:!1}}),[g,w]=x.useState(null);g&&(g.appState=p);const f=j=>{u({...p,...j})},y=[C.withDraw,b.withGroup,F.withMind,mn,ht,kr(f),Or,Hr(f),$r(f),...additionalPlugins],L=x.useRef(null);return n.jsx(dt,{children:n.jsx(Tt.Provider,{value:{appState:p,setAppState:u},children:n.jsxs("div",{className:P("drawnix",{"drawnix--mobile":p.isMobile}),ref:L,children:[n.jsxs(B.Wrapper,{value:e,viewport:t,theme:o,options:m,plugins:y,onChange:j=>{r&&r(j)},onSelectionChange:i,onViewportChange:a,onThemeChange:s,onValueChange:l,children:[n.jsx(B.Board,{afterInit:j=>{w(j),d&&d(j)},children:h&&g&&c.PlaitBoard.isPointer(g,c.PlaitPointerType.selection)&&n.jsx(qr,{})}),n.jsx(Cr,{}),n.jsx(Xo,{}),n.jsx(qo,{}),n.jsx(Ar,{}),n.jsx(mr,{}),n.jsx(Xr,{}),n.jsx(zr,{}),n.jsx(Vr,{container:L.current}),n.jsx(Zr,{container:L.current})]}),n.jsx("canvas",{className:`${$t} mouse-course-hidden`})]})})})};exports.Drawnix=Yr;exports.I18nProvider=dt;exports.addImage=Ee;exports.applyOpacityToHex=ee;exports.base64ToBlob=pt;exports.boardToImage=ft;exports.composeEventHandlers=gt;exports.download=Me;exports.getCurrentFill=Oe;exports.getCurrentFontColor=tr;exports.getCurrentStrokeColor=Ae;exports.getShortcutKey=re;exports.hexAlphaToOpacity=te;exports.i18nInsidePlaitHook=ut;exports.isClosedElement=Ne;exports.isDefaultStroke=Nt;exports.isFullyOpaque=ae;exports.isFullyTransparent=Fe;exports.isNoColor=Q;exports.isPromiseLike=mt;exports.isTransparent=Qo;exports.isValidColor=Rt;exports.isWhite=Ie;exports.removeHexAlpha=Y;exports.saveAsImage=se;exports.saveAsSvg=Bt;exports.splitRows=pe;exports.useI18n=R; diff --git a/index.mjs b/index.mjs index 4de52a3e0dc8699dca864e83ed795bca3de13dfc..b564547e9a59d646416bc580ae95f4267a0cdc67 100644 --- a/index.mjs +++ b/index.mjs @@ -5426,7 +5426,8 @@ const ao = ({ children: e }) => /* @__PURE__ */ o("div", { className: "ttd-dialo onThemeChange: l, onValueChange: s, afterInit: c, - tutorial: u = !1 + tutorial: u = !1, + plugins: additionalPlugins = [] }) => { const h = { readonly: !1, @@ -5458,7 +5459,8 @@ const ao = ({ children: e }) => /* @__PURE__ */ o("div", { className: "ttd-dialo Ma(p), Ua, Ga(p), - Ja(p) + Ja(p), + ...additionalPlugins ], x = te(null); return /* @__PURE__ */ o(Yr, { children: /* @__PURE__ */ o(In.Provider, { value: { appState: g, setAppState: d }, children: /* @__PURE__ */ w( "div",