polotno 4.1.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/blueprint/side-panel/select-video.d.ts +10 -0
  2. package/blueprint/toolbar/html-toolbar.js +2 -2
  3. package/canvas/drawing-layer.d.ts +3 -2
  4. package/canvas/drawing-layer.js +1 -1
  5. package/canvas/element.js +1 -1
  6. package/canvas/hotkeys.js +1 -1
  7. package/canvas/page-controls.js +1 -1
  8. package/canvas/page.js +1 -1
  9. package/canvas/quill-font-formats.js +1 -1
  10. package/canvas/render-tag-element.js +1 -1
  11. package/canvas/rich-editor.d.ts +3 -1
  12. package/canvas/rich-editor.js +16 -3
  13. package/canvas/rules.js +1 -1
  14. package/canvas/text-element/font-specs-loader.d.ts +3 -0
  15. package/canvas/text-element/font-specs-loader.js +1 -0
  16. package/canvas/workspace-canvas.js +1 -1
  17. package/config.d.ts +1 -1
  18. package/config.js +1 -1
  19. package/icons/registry.d.ts +2 -0
  20. package/icons/registry.js +1 -1
  21. package/model/figure-model.d.ts +5 -0
  22. package/model/gif-model.d.ts +5 -0
  23. package/model/group-model.d.ts +40 -0
  24. package/model/group-model.js +1 -1
  25. package/model/image-model.d.ts +5 -0
  26. package/model/line-model.d.ts +5 -0
  27. package/model/page-model.d.ts +56 -0
  28. package/model/page-model.js +1 -1
  29. package/model/shape-model.d.ts +5 -0
  30. package/model/shape-model.js +1 -1
  31. package/model/store.d.ts +521 -0
  32. package/model/store.js +1 -1
  33. package/model/svg-model.d.ts +5 -0
  34. package/model/table-model.d.ts +5 -0
  35. package/model/text-model.d.ts +5 -0
  36. package/model/video-model.d.ts +5 -0
  37. package/package.json +4 -3
  38. package/pages-timeline/current-time.js +1 -1
  39. package/pages-timeline/element-track.js +1 -1
  40. package/pages-timeline/elements.js +1 -1
  41. package/pages-timeline/page-preview.js +1 -1
  42. package/pages-timeline/play-button.js +1 -1
  43. package/polotno.bundle.js +206 -130
  44. package/side-panel/select-video.d.ts +10 -0
  45. package/side-panel/size-panel.js +1 -1
  46. package/themes/carbon.css +157 -0
  47. package/toolbar/download-button.js +1 -1
  48. package/toolbar/html-toolbar.js +4 -4
  49. package/toolbar/image-toolbar.js +1 -1
  50. package/toolbar/text-toolbar.js +1 -1
  51. package/toolbar/video-toolbar.js +1 -1
  52. package/ui.css +1 -1
  53. package/utils/fonts.js +1 -1
  54. package/utils/l10n.d.ts +8 -0
  55. package/utils/l10n.js +1 -1
  56. package/utils/rich-text-html.d.ts +12 -0
  57. package/utils/rich-text-html.js +1 -1
  58. package/utils/split-element.d.ts +2 -0
  59. package/utils/split-element.js +1 -0
  60. package/utils/text-format-state.js +1 -1
  61. package/utils/text-format.d.ts +2 -2
  62. package/utils/text-format.js +1 -1
  63. package/utils/text.js +1 -1
  64. package/utils/timeline.d.ts +3 -0
  65. package/utils/timeline.js +1 -1
  66. package/utils/to-html.js +1 -1
  67. package/utils/to-pptx.js +1 -1
  68. package/utils/to-svg.js +1 -1
  69. package/utils/validate-key.js +1 -1
@@ -160,6 +160,11 @@ export declare const selectVideo: ({ src, droppedPos, targetElement, store, attr
160
160
  readonly locked: boolean;
161
161
  readonly a: import("../model/shape-model.js").AnimatedAttrs;
162
162
  animated(attr: any): any;
163
+ readonly timeRange: {
164
+ start: number;
165
+ end: number;
166
+ };
167
+ readonly active: boolean;
163
168
  readonly isSelected: boolean;
164
169
  readonly isSelectedDirectly: boolean;
165
170
  } & {
@@ -321,6 +326,11 @@ export declare const selectVideo: ({ src, droppedPos, targetElement, store, attr
321
326
  readonly locked: boolean;
322
327
  readonly a: import("../model/shape-model.js").AnimatedAttrs;
323
328
  animated(attr: any): any;
329
+ readonly timeRange: {
330
+ start: number;
331
+ end: number;
332
+ };
333
+ readonly active: boolean;
324
334
  readonly isSelected: boolean;
325
335
  readonly isSelectedDirectly: boolean;
326
336
  } & {
@@ -1 +1 @@
1
- var e=this&&this.__rest||function(e,n){var i={};for(var t in e){Object.prototype.hasOwnProperty.call(e,t)&&n.indexOf(t)<0&&(i[t]=e[t])}if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var a=0;for(t=Object.getOwnPropertySymbols(e);a<t.length;a++){n.indexOf(t[a])<0&&Object.prototype.propertyIsEnumerable.call(e,t[a])&&(i[t[a]]=e[t[a]])}}return i};import{jsx as n,jsxs as i}from"react/jsx-runtime";import*as t from"react";import{observer as a}from"mobx-react-lite";import{PolotnoIcon as s}from"../icons/registry.js";import{t as r}from"../utils/l10n.js";import{cn as p}from"../lib/utils.js";import{pxToUnit as o,pxToUnitRounded as l,unitToPx as c}from"../utils/unit.js";import{Button as m}from"../primitives/button.js";import{Input as d}from"../primitives/input.js";import{Switch as u}from"../primitives/switch.js";import{Select as h,SelectContent as x,SelectItem as v,SelectTrigger as b,SelectValue as f}from"../primitives/select.js";import{Tooltip as g,TooltipContent as z,TooltipTrigger as N}from"../primitives/tooltip.js";export const SIZE_CATEGORIES=[{name:"Instagram",icon:n(s,{name:"size.instagram"}),sizes:[["Post",1080,1080,"px",n(s,{name:"size.instagram"})],["Story",1080,1920,"px",n(s,{name:"size.instagram"})],["Ad",1080,1080,"px",n(s,{name:"size.instagram"})]]},{name:"Facebook",icon:n(s,{name:"size.facebook"}),sizes:[["Post (Landscape)",1200,630,"px",n(s,{name:"size.facebook"})],["Post (Square)",1080,1080,"px",n(s,{name:"size.facebook"})],["Cover",851,315,"px",n(s,{name:"size.facebook"})]]},{name:"Youtube",icon:n(s,{name:"size.youtube"}),sizes:[["Thumbnail",1280,720,"px",n(s,{name:"size.youtube"})],["Channel",2560,1440,"px",n(s,{name:"size.youtube"})],["Short",1080,1920,"px",n(s,{name:"size.youtube"})]]},{name:"LinkedIn",icon:n(s,{name:"size.linkedin"}),sizes:[["Post",1200,627,"px",n(s,{name:"size.linkedin"})],["Banner",1584,396,"px",n(s,{name:"size.linkedin"})],["Square",1080,1080,"px",n(s,{name:"size.linkedin"})]]},{name:"Twitter",icon:n(s,{name:"size.twitter"}),sizes:[["Post",1600,900,"px",n(s,{name:"size.twitter"})],["Header",1500,500,"px",n(s,{name:"size.twitter"})],["Square",1080,1080,"px",n(s,{name:"size.twitter"})]]},{name:"Video",icon:n(s,{name:"size.video"}),sizes:[["Full HD",1920,1080,"px",n(s,{name:"size.video"})],["4K UHD",3840,2160,"px",n(s,{name:"size.video"})],["Vertical HD",1080,1920,"px",n(s,{name:"size.video"})],["Square HD",1080,1080,"px",n(s,{name:"size.video"})]]},{name:"Print",icon:n(s,{name:"size.print"}),sizes:[["Invitation",14,14,"cm",n(s,{name:"size.print"})],["A4 Portrait",21,29.7,"cm",n(s,{name:"size.print"})],["A4 Landscape",29.7,21,"cm",n(s,{name:"size.print"})],["A3",29.7,42,"cm",n(s,{name:"size.print"})],["Letter Portrait",8.5,11,"in",n(s,{name:"size.print"})],["Letter Landscape",11,8.5,"in",n(s,{name:"size.print"})],["Business card",3.5,2,"in",n(s,{name:"size.businessCard"})],["Poster",18,24,"in",n(s,{name:"size.print"})]]}];const y=a=>{var{value:r,onChange:o}=a,l=e(a,["value","onChange"]);const[c,m]=t.useState(r.toString()),u=t.useRef(r);u.current=c;const h=()=>{o(Math.max(l.min||0,parseFloat(u.current)))};t.useEffect(()=>{m(String(r))},[r]);const x=Number(l.step)||1,v=e=>{const n=parseFloat(u.current);let i=(Number.isNaN(n)?Number(r)||0:n)+e*x;"number"==typeof l.min&&(i=Math.max(l.min,i)),"number"==typeof l.max&&(i=Math.min(l.max,i)),i=parseFloat(i.toFixed(4)),m(String(i)),o(i)},{className:b}=l,f=e(l,["className"]);return i("div",{className:"pn:relative",children:[n(d,Object.assign({},f,{type:"number",value:c.toString(),className:p("pn:pr-6 pn:[appearance:textfield] pn:[&::-webkit-inner-spin-button]:appearance-none pn:[&::-webkit-outer-spin-button]:appearance-none",b),onChange:e=>{const n=e.target.value;Number.isNaN(parseFloat(n))?""===n&&m(n):m(n)},onBlur:h,onFocus:e=>e.target.select(),onKeyDown:e=>{"Enter"===e.key&&h()}})),i("div",{className:"pn:absolute pn:inset-y-0 pn:right-0 pn:flex pn:w-5 pn:flex-col pn:border-l pn:border-input",children:[n("button",{type:"button",tabIndex:-1,"aria-label":"Increment",className:"pn:flex pn:flex-1 pn:appearance-none pn:cursor-pointer pn:items-center pn:justify-center pn:border-0 pn:bg-transparent pn:text-muted-foreground pn:hover:bg-muted pn:hover:text-foreground",onClick:()=>v(1),children:n(s,{name:"ui.chevronUp",className:"pn:size-3"})}),n("button",{type:"button",tabIndex:-1,"aria-label":"Decrement",className:"pn:flex pn:flex-1 pn:appearance-none pn:cursor-pointer pn:items-center pn:justify-center pn:border-0 pn:border-t pn:border-input pn:bg-transparent pn:text-muted-foreground pn:hover:bg-muted pn:hover:text-foreground",onClick:()=>v(-1),children:n(s,{name:"ui.chevronDown",className:"pn:size-3"})})]})]})},w=({width:e,height:i})=>{const t=e/i,a=t>=1?18:Math.max(4,18*t),s=t>=1?Math.max(4,18/t):18;return n("span",{className:"pn:flex pn:size-5 pn:shrink-0 pn:items-center pn:justify-center pn:text-muted-foreground",children:n("span",{className:"pn:rounded-[2px] pn:border pn:border-current",style:{width:a,height:s}})})};export const SizePanel=a(({store:e})=>{var a,p;const[d,k]=t.useState(!0),[P,j]=t.useState(e.width),[S,C]=t.useState(e.height),O=o({px:10,unit:e.unit,dpi:e.dpi}),E=(null===(a=e.activePage)||void 0===a?void 0:a.computedWidth)||e.width;t.useEffect(()=>{j(l({px:E,unit:e.unit,dpi:e.dpi}))},[E,e.unit,e.dpi]);const I=(null===(p=e.activePage)||void 0===p?void 0:p.computedHeight)||e.height;t.useEffect(()=>{C(l({px:I,unit:e.unit,dpi:e.dpi}))},[I,e.unit,e.dpi]);const B=(n,i,t)=>{var a,s,r,p;e.setSize(n,i,t),"auto"!==(null===(a=e.activePage)||void 0===a?void 0:a.width)&&(null===(s=e.activePage)||void 0===s||s.set({width:n})),"auto"!==(null===(r=e.activePage)||void 0===r?void 0:r.height)&&(null===(p=e.activePage)||void 0===p||p.set({height:i}))};return i("div",{style:{height:"100%",overflow:"auto",paddingRight:"3px"},children:[i("div",{style:{paddingBottom:"15px"},children:[i("label",{className:"pn:flex pn:items-center pn:justify-between",style:{marginTop:"8px",marginBottom:"25px"},children:[i("span",{className:"pn:flex pn:items-center pn:gap-1.5",children:[r("sidePanel.useMagicResize")," ",i(g,{children:[n(N,{render:n("span",{className:"pn:inline-flex",children:n(s,{name:"action.help",className:"pn:size-4"})})}),n(z,{side:"bottom",children:r("sidePanel.magicResizeDescription")})]})]}),n(u,{checked:d,onCheckedChange:e=>{k(Boolean(e))}})]}),i("div",{className:"pn:inline-block pn:w-1/2",children:[r("sidePanel.width")," (",e.unit,")"]}),n("div",{className:"pn:inline-block pn:w-1/2",children:n(y,{value:P,onChange:e=>{e||(e=O),j(e)},min:O,max:1e4,step:"px"===e.unit?1:.1})})]}),i("div",{style:{paddingBottom:"15px"},children:[i("div",{className:"pn:inline-block pn:w-1/2",children:[r("sidePanel.height")," (",e.unit,")"]}),n("div",{className:"pn:inline-block pn:w-1/2",children:n(y,{value:S,onChange:e=>{e||(e=O),C(e)},min:O,max:1e4,step:"px"===e.unit?1:.1})})]}),i("div",{style:{paddingBottom:"15px"},children:[n("div",{className:"pn:inline-block pn:w-1/2",children:r("sidePanel.units")}),n("div",{className:"pn:inline-block pn:w-1/2",children:i(h,{value:e.unit,onValueChange:n=>{const i=n;e.setUnit({unit:i,dpi:e.dpi})},children:[n(b,{className:"pn:w-full",children:n(f,{})}),i(x,{children:[n(v,{value:"px",children:"px"}),n(v,{value:"cm",children:"cm"}),n(v,{value:"in",children:"in"})]})]})})]}),n("div",{style:{paddingBottom:"15px"},children:n(m,{className:"pn:w-full",variant:"default",onClick:()=>{const n=c({unitVal:P,dpi:e.dpi,unit:e.unit}),i=c({unitVal:S,dpi:e.dpi,unit:e.unit});B(n,i,d)},children:r("sidePanel.resize")})}),SIZE_CATEGORIES.map(({name:a,icon:s,sizes:r})=>i(t.Fragment,{children:[i("div",{className:"pn:flex pn:items-center pn:gap-1.5 pn:pt-3 pn:pb-1 pn:text-[13px] pn:font-semibold",children:[s,a]}),n("div",{className:"pn:mb-1.5 pn:flex pn:flex-col",children:r.map(([t,a,s,r])=>i(m,{variant:"ghost",className:"pn:h-9 pn:w-full pn:justify-start pn:gap-2.5 pn:px-2 pn:text-[13px] pn:font-normal",onClick:()=>{const n=c({unitVal:a,dpi:e.dpi,unit:r}),i=c({unitVal:s,dpi:e.dpi,unit:r});e.setUnit({unit:r,dpi:e.dpi}),B(n,i,d)},children:[n(w,{width:a,height:s}),n("span",{className:"pn:truncate",children:t}),i("span",{className:"pn:ml-auto pn:shrink-0 pn:text-xs pn:text-muted-foreground",children:[a,"×",s," ",r]})]},t))})]},a))]})});
1
+ var e=this&&this.__rest||function(e,n){var i={};for(var t in e){Object.prototype.hasOwnProperty.call(e,t)&&n.indexOf(t)<0&&(i[t]=e[t])}if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var a=0;for(t=Object.getOwnPropertySymbols(e);a<t.length;a++){n.indexOf(t[a])<0&&Object.prototype.propertyIsEnumerable.call(e,t[a])&&(i[t[a]]=e[t[a]])}}return i};import{jsx as n,jsxs as i,Fragment as t}from"react/jsx-runtime";import*as a from"react";import{observer as s}from"mobx-react-lite";import{PolotnoIcon as p}from"../icons/registry.js";import{t as r}from"../utils/l10n.js";import{cn as o}from"../lib/utils.js";import{pxToUnit as l,pxToUnitRounded as d,unitToPx as c}from"../utils/unit.js";import{Button as m}from"../primitives/button.js";import{Input as u}from"../primitives/input.js";import{Switch as h}from"../primitives/switch.js";import{Select as x,SelectContent as v,SelectItem as b,SelectTrigger as g,SelectValue as f}from"../primitives/select.js";import{Tooltip as z,TooltipContent as N,TooltipTrigger as w}from"../primitives/tooltip.js";export const SIZE_CATEGORIES=[{name:"Instagram",icon:n(p,{name:"size.instagram"}),sizes:[["Post",1080,1080,"px",n(p,{name:"size.instagram"})],["Story",1080,1920,"px",n(p,{name:"size.instagram"})],["Ad",1080,1080,"px",n(p,{name:"size.instagram"})]]},{name:"Facebook",icon:n(p,{name:"size.facebook"}),sizes:[["Post (Landscape)",1200,630,"px",n(p,{name:"size.facebook"})],["Post (Square)",1080,1080,"px",n(p,{name:"size.facebook"})],["Cover",851,315,"px",n(p,{name:"size.facebook"})]]},{name:"Youtube",icon:n(p,{name:"size.youtube"}),sizes:[["Thumbnail",1280,720,"px",n(p,{name:"size.youtube"})],["Channel",2560,1440,"px",n(p,{name:"size.youtube"})],["Short",1080,1920,"px",n(p,{name:"size.youtube"})]]},{name:"LinkedIn",icon:n(p,{name:"size.linkedin"}),sizes:[["Post",1200,627,"px",n(p,{name:"size.linkedin"})],["Banner",1584,396,"px",n(p,{name:"size.linkedin"})],["Square",1080,1080,"px",n(p,{name:"size.linkedin"})]]},{name:"Twitter",icon:n(p,{name:"size.twitter"}),sizes:[["Post",1600,900,"px",n(p,{name:"size.twitter"})],["Header",1500,500,"px",n(p,{name:"size.twitter"})],["Square",1080,1080,"px",n(p,{name:"size.twitter"})]]},{name:"Video",icon:n(p,{name:"size.video"}),sizes:[["Full HD",1920,1080,"px",n(p,{name:"size.video"})],["4K UHD",3840,2160,"px",n(p,{name:"size.video"})],["Vertical HD",1080,1920,"px",n(p,{name:"size.video"})],["Square HD",1080,1080,"px",n(p,{name:"size.video"})]]},{name:"Print",icon:n(p,{name:"size.print"}),sizes:[["Invitation",14,14,"cm",n(p,{name:"size.print"})],["A4 Portrait",21,29.7,"cm",n(p,{name:"size.print"})],["A4 Landscape",29.7,21,"cm",n(p,{name:"size.print"})],["A3",29.7,42,"cm",n(p,{name:"size.print"})],["Letter Portrait",8.5,11,"in",n(p,{name:"size.print"})],["Letter Landscape",11,8.5,"in",n(p,{name:"size.print"})],["Business card",3.5,2,"in",n(p,{name:"size.businessCard"})],["Poster",18,24,"in",n(p,{name:"size.print"})]]}];const y=t=>{var{value:s,onChange:r}=t,l=e(t,["value","onChange"]);const[d,c]=a.useState(s.toString()),m=a.useRef(s);m.current=d;const h=()=>{r(Math.max(l.min||0,parseFloat(m.current)))};a.useEffect(()=>{c(String(s))},[s]);const x=Number(l.step)||1,v=e=>{const n=parseFloat(m.current);let i=(Number.isNaN(n)?Number(s)||0:n)+e*x;"number"==typeof l.min&&(i=Math.max(l.min,i)),"number"==typeof l.max&&(i=Math.min(l.max,i)),i=parseFloat(i.toFixed(4)),c(String(i)),r(i)},{className:b}=l,g=e(l,["className"]);return i("div",{className:"pn:relative",children:[n(u,Object.assign({},g,{type:"number",value:d.toString(),className:o("pn:pr-6 pn:[appearance:textfield] pn:[&::-webkit-inner-spin-button]:appearance-none pn:[&::-webkit-outer-spin-button]:appearance-none",b),onChange:e=>{const n=e.target.value;Number.isNaN(parseFloat(n))?""===n&&c(n):c(n)},onBlur:h,onFocus:e=>e.target.select(),onKeyDown:e=>{"Enter"===e.key&&h()}})),i("div",{className:"pn:absolute pn:inset-y-0 pn:right-0 pn:flex pn:w-5 pn:flex-col pn:border-l pn:border-input",children:[n("button",{type:"button",tabIndex:-1,"aria-label":"Increment",className:"pn:flex pn:flex-1 pn:appearance-none pn:cursor-pointer pn:items-center pn:justify-center pn:border-0 pn:bg-transparent pn:text-muted-foreground pn:hover:bg-muted pn:hover:text-foreground",onClick:()=>v(1),children:n(p,{name:"ui.chevronUp",className:"pn:size-3"})}),n("button",{type:"button",tabIndex:-1,"aria-label":"Decrement",className:"pn:flex pn:flex-1 pn:appearance-none pn:cursor-pointer pn:items-center pn:justify-center pn:border-0 pn:border-t pn:border-input pn:bg-transparent pn:text-muted-foreground pn:hover:bg-muted pn:hover:text-foreground",onClick:()=>v(-1),children:n(p,{name:"ui.chevronDown",className:"pn:size-3"})})]})]})},k=({width:e,height:i})=>{const t=e/i,a=t>=1?18:Math.max(4,18*t),s=t>=1?Math.max(4,18/t):18;return n("span",{className:"pn:flex pn:size-5 pn:shrink-0 pn:items-center pn:justify-center pn:text-muted-foreground",children:n("span",{className:"pn:rounded-[2px] pn:border pn:border-current",style:{width:a,height:s}})})};export const SizePanel=s(({store:e})=>{var s,o,u,P;const[j,S]=a.useState(!0),[C,B]=a.useState(!1),[E,O]=a.useState(e.width),[F,I]=a.useState(e.height),D=l({px:10,unit:e.unit,dpi:e.dpi}),V=(null===(s=e.activePage)||void 0===s?void 0:s.computedWidth)||e.width;a.useEffect(()=>{O(d({px:V,unit:e.unit,dpi:e.dpi}))},[V,e.unit,e.dpi]);const R=(null===(o=e.activePage)||void 0===o?void 0:o.computedHeight)||e.height;a.useEffect(()=>{I(d({px:R,unit:e.unit,dpi:e.dpi}))},[R,e.unit,e.dpi]);const L=(n,i,t)=>{var a,s,p,r;e.setSize(n,i,t),"auto"!==(null===(a=e.activePage)||void 0===a?void 0:a.width)&&(null===(s=e.activePage)||void 0===s||s.set({width:n})),"auto"!==(null===(p=e.activePage)||void 0===p?void 0:p.height)&&(null===(r=e.activePage)||void 0===r||r.set({height:i}))},A=d({px:null!==(P=null===(u=e.activePage)||void 0===u?void 0:u.computedBleed.top)&&void 0!==P?P:0,unit:e.unit,dpi:e.dpi});return i("div",{style:{height:"100%",overflow:"auto",paddingRight:"3px"},children:[i("div",{style:{paddingBottom:"15px"},children:[i("label",{className:"pn:flex pn:items-center pn:justify-between",style:{marginTop:"8px",marginBottom:"25px"},children:[i("span",{className:"pn:flex pn:items-center pn:gap-1.5",children:[r("sidePanel.useMagicResize")," ",i(z,{children:[n(w,{render:n("span",{className:"pn:inline-flex",children:n(p,{name:"action.help",className:"pn:size-4"})})}),n(N,{side:"bottom",children:r("sidePanel.magicResizeDescription")})]})]}),n(h,{checked:j,onCheckedChange:e=>{S(Boolean(e))}})]}),i("div",{className:"pn:inline-block pn:w-1/2",children:[r("sidePanel.width")," (",e.unit,")"]}),n("div",{className:"pn:inline-block pn:w-1/2",children:n(y,{value:E,onChange:e=>{e||(e=D),O(e)},min:D,max:1e4,step:"px"===e.unit?1:.1})})]}),i("div",{style:{paddingBottom:"15px"},children:[i("div",{className:"pn:inline-block pn:w-1/2",children:[r("sidePanel.height")," (",e.unit,")"]}),n("div",{className:"pn:inline-block pn:w-1/2",children:n(y,{value:F,onChange:e=>{e||(e=D),I(e)},min:D,max:1e4,step:"px"===e.unit?1:.1})})]}),i("div",{style:{paddingBottom:"15px"},children:[n("div",{className:"pn:inline-block pn:w-1/2",children:r("sidePanel.units")}),n("div",{className:"pn:inline-block pn:w-1/2",children:i(x,{value:e.unit,onValueChange:n=>{const i=n;e.setUnit({unit:i,dpi:e.dpi})},children:[n(g,{className:"pn:w-full",children:n(f,{})}),i(v,{children:[n(b,{value:"px",children:"px"}),n(b,{value:"cm",children:"cm"}),n(b,{value:"in",children:"in"})]})]})})]}),n("div",{style:{paddingBottom:"15px"},children:n(m,{className:"pn:w-full",variant:"default",onClick:()=>{const n=c({unitVal:E,dpi:e.dpi,unit:e.unit}),i=c({unitVal:F,dpi:e.dpi,unit:e.unit});L(n,i,j)},children:r("sidePanel.resize")})}),i(m,{variant:"ghost",className:"pn:mb-1.5 pn:w-full pn:justify-start pn:gap-1 pn:px-2 pn:text-[13px] pn:font-normal pn:text-muted-foreground",onClick:()=>B(!C),children:[n(p,{name:C?"ui.chevronDown":"ui.chevronRight",className:"pn:size-3"}),r("sidePanel.advanced")]}),C&&i(t,{children:[i("div",{style:{paddingBottom:"15px"},children:[i("div",{className:"pn:inline-block pn:w-1/2",children:[r("sidePanel.bleed")," (",e.unit,")"]}),n("div",{className:"pn:inline-block pn:w-1/2",children:n(y,{"aria-label":"bleed",value:A,onChange:n=>{if(!Number.isFinite(n)){return}const i=c({unitVal:n,dpi:e.dpi,unit:e.unit});e.pages.forEach(e=>{e.set({bleed:i,bleedTop:void 0,bleedRight:void 0,bleedBottom:void 0,bleedLeft:void 0})}),i>0&&e.toggleBleed(!0)},min:0,max:1e3,step:"px"===e.unit?1:.1})})]}),i("label",{className:"pn:flex pn:items-center pn:justify-between",style:{paddingBottom:"15px"},children:[n("span",{children:r("sidePanel.showBleed")}),n(h,{"aria-label":"show bleed",checked:e.bleedVisible,onCheckedChange:n=>{e.toggleBleed(Boolean(n))}})]})]}),SIZE_CATEGORIES.map(({name:t,icon:s,sizes:p})=>i(a.Fragment,{children:[i("div",{className:"pn:flex pn:items-center pn:gap-1.5 pn:pt-3 pn:pb-1 pn:text-[13px] pn:font-semibold",children:[s,t]}),n("div",{className:"pn:mb-1.5 pn:flex pn:flex-col",children:p.map(([t,a,s,p])=>i(m,{variant:"ghost",className:"pn:h-9 pn:w-full pn:justify-start pn:gap-2.5 pn:px-2 pn:text-[13px] pn:font-normal",onClick:()=>{const n=c({unitVal:a,dpi:e.dpi,unit:p}),i=c({unitVal:s,dpi:e.dpi,unit:p});e.setUnit({unit:p,dpi:e.dpi}),L(n,i,j)},children:[n(k,{width:a,height:s}),n("span",{className:"pn:truncate",children:t}),i("span",{className:"pn:ml-auto pn:shrink-0 pn:text-xs pn:text-muted-foreground",children:[a,"×",s," ",p]})]},t))})]},t))]})});
@@ -0,0 +1,157 @@
1
+ /*
2
+ * carbon.css — IBM Carbon theme for Polotno (and any shadcn consumer).
3
+ *
4
+ * Single source of truth for the Carbon look: IBM Plex fonts + the standard
5
+ * shadcn color tokens (--background / --foreground / --primary / …) on
6
+ * :root (light) and .dark. The Polotno editor reads these via its tier-2
7
+ * `var(--X, …)` chain, so importing this file re-themes the editor; a shadcn
8
+ * app consumes the same tokens natively. Import:
9
+ *
10
+ * import 'polotno/themes/carbon.css'; // editor + app
11
+ *
12
+ * Token format: raw color values (hex), matching Polotno's ui.css and
13
+ * Tailwind v4 / current shadcn. Tailwind v3 shadcn apps expect HSL channel
14
+ * triplets and will NOT consume these as-is.
15
+ *
16
+ * Accent is monochrome by design (--primary == --foreground); authentic
17
+ * Carbon Blue 60 (#0f62fe) is intentionally retired to match the Polotno
18
+ * brand. Red (#da1e28, Carbon Red 60) is kept for --destructive only.
19
+ */
20
+
21
+ /* IBM Plex Sans — 400 / 500 / 600 / 700 (latin) */
22
+ @font-face {
23
+ font-family: 'IBM Plex Sans';
24
+ font-style: normal;
25
+ font-weight: 400;
26
+ font-display: swap;
27
+ src: url('https://cdn.jsdelivr.net/fontsource/fonts/ibm-plex-sans@latest/latin-400-normal.woff2')
28
+ format('woff2');
29
+ }
30
+ @font-face {
31
+ font-family: 'IBM Plex Sans';
32
+ font-style: normal;
33
+ font-weight: 500;
34
+ font-display: swap;
35
+ src: url('https://cdn.jsdelivr.net/fontsource/fonts/ibm-plex-sans@latest/latin-500-normal.woff2')
36
+ format('woff2');
37
+ }
38
+ @font-face {
39
+ font-family: 'IBM Plex Sans';
40
+ font-style: normal;
41
+ font-weight: 600;
42
+ font-display: swap;
43
+ src: url('https://cdn.jsdelivr.net/fontsource/fonts/ibm-plex-sans@latest/latin-600-normal.woff2')
44
+ format('woff2');
45
+ }
46
+ @font-face {
47
+ font-family: 'IBM Plex Sans';
48
+ font-style: normal;
49
+ font-weight: 700;
50
+ font-display: swap;
51
+ src: url('https://cdn.jsdelivr.net/fontsource/fonts/ibm-plex-sans@latest/latin-700-normal.woff2')
52
+ format('woff2');
53
+ }
54
+
55
+ /* IBM Plex Mono — 400 / 500 (latin) */
56
+ @font-face {
57
+ font-family: 'IBM Plex Mono';
58
+ font-style: normal;
59
+ font-weight: 400;
60
+ font-display: swap;
61
+ src: url('https://cdn.jsdelivr.net/fontsource/fonts/ibm-plex-mono@latest/latin-400-normal.woff2')
62
+ format('woff2');
63
+ }
64
+ @font-face {
65
+ font-family: 'IBM Plex Mono';
66
+ font-style: normal;
67
+ font-weight: 500;
68
+ font-display: swap;
69
+ src: url('https://cdn.jsdelivr.net/fontsource/fonts/ibm-plex-mono@latest/latin-500-normal.woff2')
70
+ format('woff2');
71
+ }
72
+
73
+ /* Wire the IBM Plex families into Polotno's public override hooks. Setting them
74
+ on :root keeps this an opt-in, app-level choice; the editor reads
75
+ var(--pn-font-sans, <system stack>) on its scoped roots. */
76
+ :root {
77
+ --pn-font-sans: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
78
+ --pn-font-mono: 'IBM Plex Mono', ui-monospace, monospace;
79
+ }
80
+
81
+
82
+ /* Monochrome, matching the polotno-website sibling repo: black/white/gray only,
83
+ NO blue anywhere in the UI (the website reserves blue for blog prose, which this
84
+ app doesn't have). --primary == --foreground so every primary accent (buttons,
85
+ links, icons, badges, focus) is monochrome and inverts per theme. Red is kept for
86
+ `destructive` only — the one semantic color the website also keeps. Dark-first. */
87
+ :root {
88
+ --background: #ffffff;
89
+ --foreground: #161616; /* text + monochrome primary (inverts in .dark) */
90
+ --card: #ffffff; /* website card (white tile) */
91
+ --card-foreground: #161616;
92
+ --popover: #ffffff;
93
+ --popover-foreground: #161616;
94
+ --primary: #161616; /* monochrome (= foreground); blue retired */
95
+ --primary-foreground: #ffffff;
96
+ --secondary: #f4f4f4; /* subtle light surface (gray 10) */
97
+ --secondary-foreground: #161616;
98
+ --muted: #f4f4f4; /* gray 10 */
99
+ --muted-foreground: #525252; /* website light-muted (gray 70) */
100
+ --accent: #e8e8e8; /* hover (gray 10 hover) */
101
+ --accent-foreground: #161616;
102
+ --destructive: #da1e28; /* danger (red) — the only retained color */
103
+ --border: #c6c6c6; /* website card-border (gray 30) */
104
+ --input: #c6c6c6;
105
+ --ring: #161616; /* monochrome focus */
106
+ /* Monochrome data-vis ramp (dark -> light grays). */
107
+ --chart-1: #161616;
108
+ --chart-2: #525252;
109
+ --chart-3: #8d8d8d;
110
+ --chart-4: #a8a8a8;
111
+ --chart-5: #c6c6c6;
112
+ --radius: 0;
113
+ --sidebar: #ffffff;
114
+ --sidebar-foreground: #161616;
115
+ --sidebar-primary: #161616;
116
+ --sidebar-primary-foreground: #ffffff;
117
+ --sidebar-accent: #e8e8e8;
118
+ --sidebar-accent-foreground: #161616;
119
+ --sidebar-border: #c6c6c6;
120
+ --sidebar-ring: #161616;
121
+ }
122
+
123
+ /* dark = website brand surface (#161616). Default theme (see providers.tsx). */
124
+ .dark {
125
+ --background: #161616; /* website --color-bg */
126
+ --foreground: #ffffff; /* website --color-fg */
127
+ --card: #262626; /* Carbon g100 layer-01 (gray 90) */
128
+ --card-foreground: #ffffff;
129
+ --popover: #262626;
130
+ --popover-foreground: #ffffff;
131
+ --primary: #ffffff; /* monochrome (= foreground); blue retired */
132
+ --primary-foreground: #161616; /* contrast on the white primary surface */
133
+ --secondary: #393939; /* visible secondary surface */
134
+ --secondary-foreground: #ffffff;
135
+ --muted: #262626; /* Carbon g100 layer-01 (gray 90) */
136
+ --muted-foreground: #c6c6c6; /* Carbon g100 text-secondary (gray 30) */
137
+ --accent: #333333; /* Carbon g100 layer-hover-01 */
138
+ --accent-foreground: #ffffff;
139
+ --destructive: #da1e28; /* website dashboard danger (red) */
140
+ --border: #393939; /* website header divider (gray 80) */
141
+ --input: #393939;
142
+ --ring: #ffffff; /* monochrome focus */
143
+ /* Monochrome data-vis ramp (light -> dark grays). */
144
+ --chart-1: #ffffff;
145
+ --chart-2: #c6c6c6;
146
+ --chart-3: #a8a8a8;
147
+ --chart-4: #8d8d8d;
148
+ --chart-5: #6f6f6f;
149
+ --sidebar: #161616;
150
+ --sidebar-foreground: #ffffff;
151
+ --sidebar-primary: #ffffff;
152
+ --sidebar-primary-foreground: #161616;
153
+ --sidebar-accent: #333333;
154
+ --sidebar-accent-foreground: #ffffff;
155
+ --sidebar-border: #393939;
156
+ --sidebar-ring: #ffffff;
157
+ }
@@ -1 +1 @@
1
- import{jsx as o,jsxs as e}from"react/jsx-runtime";import*as s from"react";import{observer as t}from"mobx-react-lite";import{PolotnoIcon as a}from"../icons/registry.js";import{Button as r}from"../primitives/button.js";import{Spinner as i}from"../primitives/spinner.js";import{DropdownMenu as n,DropdownMenuContent as l,DropdownMenuItem as m,DropdownMenuTrigger as d}from"../primitives/dropdown-menu.js";import{t as p}from"../utils/l10n.js";import{downloadFile as c}from"../utils/download.js";import{getAPI as f}from"../utils/api.js";import{getKey as u}from"../utils/validate-key.js";import{flags as w}from"../utils/flags.js";const g=o=>{const e=[];return o.pages.forEach(o=>{o.children.forEach(o=>{"text"===o.type&&e.push(o.text)})}),e.join(" ").split(" ").slice(0,6).join(" ").replace(/\s/g,"-").toLowerCase()||"polotno"};export const DownloadButton=t(({store:t})=>{const[h,j]=s.useState(!1);return e(n,{children:[o(d,{render:e(r,{variant:"ghost",size:"sm",className:"polotno-download-button",disabled:h,children:[h?o(i,{className:"pn:mr-1.5"}):o(a,{name:"download.export",className:"pn:mr-1.5 pn:size-4"}),p("toolbar.download")]})}),e(l,{align:"end",children:[e(m,{onClick:async()=>{t.pages.forEach((o,e)=>{const s=t.pages.length>1?"-"+(e+1):"";t.saveAsImage({pageId:o.id,fileName:g(t)+s+".png"})})},children:[o(a,{name:"download.image",className:"pn:size-4"}),p("toolbar.saveAsImage")]}),e(m,{onClick:async()=>{j(!0),await t.saveAsPDF({fileName:g(t)+".pdf"}),j(!1)},children:[o(a,{name:"download.pdf",className:"pn:size-4"}),p("toolbar.saveAsPDF")]}),w.animationsEnabled&&e(m,{onClick:async()=>{j(!0);try{await(async({store:o,onProgress:e})=>{const s=o.toJSON(),t=await fetch(`${f()}/renders?KEY=${u()}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({design:s,pixelRatio:1,format:"mp4"})}),a=await t.json();for(;;){const s=await fetch(`${f()}/renders/${a.id}?KEY=${u()}`),t=await s.json();if("done"===t.status){c(t.output,g(o)+".mp4");break}if("error"===t.status){throw new Error("Failed to render video")}null==e||e(t.progress||0,t.status||"processing"),await new Promise(o=>setTimeout(o,5e3))}})({store:t})}catch(o){console.error("Video export failed:",o),alert("Failed to export video. Please try again.")}j(!1)},children:[o(a,{name:"download.video",className:"pn:size-4"}),"Save as Video"]})]})]})});export default DownloadButton;
1
+ import{jsx as e,jsxs as o}from"react/jsx-runtime";import*as s from"react";import{observer as t}from"mobx-react-lite";import{PolotnoIcon as a}from"../icons/registry.js";import{Button as r}from"../primitives/button.js";import{Spinner as i}from"../primitives/spinner.js";import{DropdownMenu as n,DropdownMenuContent as l,DropdownMenuItem as d,DropdownMenuTrigger as m}from"../primitives/dropdown-menu.js";import{t as p}from"../utils/l10n.js";import{downloadFile as c}from"../utils/download.js";import{getAPI as f}from"../utils/api.js";import{getKey as u}from"../utils/validate-key.js";import{flags as w}from"../utils/flags.js";const g=e=>{const o=[];return e.pages.forEach(e=>{e.children.forEach(e=>{"text"===e.type&&o.push(e.text)})}),o.join(" ").split(" ").slice(0,6).join(" ").replace(/\s/g,"-").toLowerCase()||"polotno"};export const DownloadButton=t(({store:t})=>{const[h,j]=s.useState(!1);return o(n,{children:[e(m,{render:o(r,{variant:"ghost",size:"sm",className:"polotno-download-button",disabled:h,children:[h?e(i,{className:"pn:mr-1.5"}):e(a,{name:"download.export",className:"pn:mr-1.5 pn:size-4"}),p("toolbar.download")]})}),o(l,{align:"end",children:[o(d,{onClick:async()=>{t.pages.forEach((e,o)=>{const s=t.pages.length>1?"-"+(o+1):"";t.saveAsImage({pageId:e.id,fileName:g(t)+s+".png"})})},children:[e(a,{name:"download.image",className:"pn:size-4"}),p("toolbar.saveAsImage")]}),o(d,{onClick:async()=>{j(!0),await t.saveAsPDF({fileName:g(t)+".pdf",includeBleed:!0}),j(!1)},children:[e(a,{name:"download.pdf",className:"pn:size-4"}),p("toolbar.saveAsPDF")]}),w.animationsEnabled&&o(d,{onClick:async()=>{j(!0);try{await(async({store:e,onProgress:o})=>{const s=e.toJSON(),t=await fetch(`${f()}/renders?KEY=${u()}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({design:s,pixelRatio:1,format:"mp4"})}),a=await t.json();for(;;){const s=await fetch(`${f()}/renders/${a.id}?KEY=${u()}`),t=await s.json();if("done"===t.status){c(t.output,g(e)+".mp4");break}if("error"===t.status){throw new Error("Failed to render video")}null==o||o(t.progress||0,t.status||"processing"),await new Promise(e=>setTimeout(e,5e3))}})({store:t})}catch(e){console.error("Video export failed:",e),alert("Failed to export video. Please try again.")}j(!1)},children:[e(a,{name:"download.video",className:"pn:size-4"}),"Save as Video"]})]})]})});export default DownloadButton;
@@ -1,4 +1,4 @@
1
- import{jsx as t,jsxs as e}from"react/jsx-runtime";import o from"react";import{observer as n}from"mobx-react-lite";import{PolotnoIcon as i}from"../icons/registry.js";import{Button as l}from"../primitives/button.js";import{Tooltip as r,TooltipContent as s,TooltipTrigger as a}from"../primitives/tooltip.js";import{TooltipIconButton as c}from"../primitives/tooltip-icon-button.js";import{ColorPicker as m}from"./color-picker.js";import p from"./filters-picker.js";import{ElementContainer as u,extendToolbar as d}from"./element-container.js";import f from"../utils/styled.js";import{AnimationsPicker as x}from"./animations-picker.js";import{flags as g}from"../utils/flags.js";import{TextAiWrite as v}from"./text-ai-write.js";import{t as h}from"../utils/l10n.js";import{quillRef as b,createQuill as T,setQuillContent as y}from"../canvas/html-element.js";import{FontMenu as F,fetcher as S,TextSpacing as z,TextFontSize as j,TextTransform as C,ALIGN_OPTIONS as w,VERTICAL_ALIGN_OPTIONS as A,VERTICAL_ALIGN_ICONS as D}from"./text-toolbar.js";import{cycleNext as N}from"./toolbar-shared.js";import E from"swr";import{getFontsList as k,globalFonts as I,isGoogleFontChanged as L}from"../utils/fonts.js";import{getGoogleFontsListAPI as M}from"../utils/api.js";import{normalizeRichTextHtml as W,listEffectiveFontFamilies as B}from"../utils/rich-text-html.js";import{patchTextFormat as R}from"../utils/text-format.js";import{useTextFormat as _,getActiveTextEditor as O,resolveSelectionScope as P,applyToLiveEditor as V}from"../utils/text-format-state.js";const G=f("div")`
1
+ import{jsx as t,jsxs as e}from"react/jsx-runtime";import o from"react";import{observer as n}from"mobx-react-lite";import{PolotnoIcon as i}from"../icons/registry.js";import{Button as l}from"../primitives/button.js";import{Tooltip as r,TooltipContent as s,TooltipTrigger as a}from"../primitives/tooltip.js";import{TooltipIconButton as c}from"../primitives/tooltip-icon-button.js";import{ColorPicker as m}from"./color-picker.js";import p from"./filters-picker.js";import{ElementContainer as u,extendToolbar as d}from"./element-container.js";import f from"../utils/styled.js";import{AnimationsPicker as x}from"./animations-picker.js";import{flags as g}from"../utils/flags.js";import{TextAiWrite as v}from"./text-ai-write.js";import{t as h}from"../utils/l10n.js";import{quillRef as b,createQuill as T,setQuillContent as y}from"../canvas/html-element.js";import{FontMenu as F,fetcher as S,TextSpacing as z,TextFontSize as j,TextTransform as C,ALIGN_OPTIONS as w,VERTICAL_ALIGN_OPTIONS as A,VERTICAL_ALIGN_ICONS as D}from"./text-toolbar.js";import{cycleNext as N}from"./toolbar-shared.js";import E from"swr";import{getFontsList as k,globalFonts as I,isGoogleFontChanged as L}from"../utils/fonts.js";import{getGoogleFontsListAPI as M}from"../utils/api.js";import{normalizeRichTextHtml as B,listEffectiveFontFamilies as R,isBoldWeight as W}from"../utils/rich-text-html.js";import{patchTextFormat as _}from"../utils/text-format.js";import{useTextFormat as O,getActiveTextEditor as P,resolveSelectionScope as V,applyToLiveEditor as G}from"../utils/text-format-state.js";const H=f("div")`
2
2
  position: relative;
3
3
  display: inline-block;
4
4
 
@@ -8,7 +8,7 @@ import{jsx as t,jsxs as e}from"react/jsx-runtime";import o from"react";import{ob
8
8
  &.polotno-mixed:focus-within input {
9
9
  color: inherit !important;
10
10
  }
11
- `,H=f("span")`
11
+ `,Q=f("span")`
12
12
  position: absolute;
13
13
  left: 11px;
14
14
  top: 0;
@@ -19,7 +19,7 @@ import{jsx as t,jsxs as e}from"react/jsx-runtime";import o from"react";import{ob
19
19
  font-size: inherit;
20
20
  color: inherit;
21
21
 
22
- ${G}:focus-within & {
22
+ ${H}:focus-within & {
23
23
  display: none;
24
24
  }
25
- `,Q=t=>{const e=O();return!!e&&e.store===t&&!!e.instance};let J=null;const U=()=>{b.pendingToolbarInteraction=!0,J&&clearTimeout(J),J=setTimeout(()=>{b.pendingToolbarInteraction=!1,J=null},100)},X=t=>{var e;(!(e=t.target)||"INPUT"!==e.tagName&&"TEXTAREA"!==e.tagName&&"SELECT"!==e.tagName&&!e.isContentEditable)&&t.preventDefault(),U()},$=n(({store:e,isActive:o,toggle:n,icon:i,ariaLabel:l,tooltipContent:r})=>{const{format:s,applyTextFormat:a}=_(e);return t(c,{label:r||l||"",side:"bottom",active:o(s),onMouseDown:t=>{t.preventDefault()},onClick:()=>n(s,a),children:i})});function q(t,e){const o=t.textDecoration.value||"",n="underline"===e?"line-through":"underline";return[!o.split(/\s+/).includes(e)&&e,o.split(/\s+/).includes(n)&&n].filter(Boolean).join(" ")}export const TextBold=n(({store:e})=>t($,{store:e,isActive:t=>"bold"===t.fontWeight.value||"700"===t.fontWeight.value,toggle:(t,e)=>e({fontWeight:"bold"===t.fontWeight.value||"700"===t.fontWeight.value?"normal":"bold"}),icon:t(i,{name:"text.bold",className:"pn:size-4"}),tooltipContent:h("toolbar.bold")}));export const FontStyleGroup=n(({element:o,store:n,elements:m,components:p})=>{const u=(null==p?void 0:p.TextBold)||TextBold;return e("div",{className:"pn:flex pn:items-center pn:gap-0.5",children:[t(u,{element:o,store:n}),t($,{store:n,isActive:t=>"italic"===t.fontStyle.value,toggle:(t,e)=>e({fontStyle:"italic"===t.fontStyle.value?"normal":"italic"}),icon:t(i,{name:"text.italic",className:"pn:size-4"}),tooltipContent:h("toolbar.italic")}),t($,{store:n,isActive:t=>{var e;return!!(null===(e=t.textDecoration.value)||void 0===e?void 0:e.split(/\s+/).includes("underline"))},toggle:(t,e)=>e({textDecoration:q(t,"underline")}),icon:t(i,{name:"text.underline",className:"pn:size-4"}),tooltipContent:h("toolbar.underline")}),t($,{store:n,isActive:t=>{var e;return!!(null===(e=t.textDecoration.value)||void 0===e?void 0:e.split(/\s+/).includes("line-through"))},toggle:(t,e)=>e({textDecoration:q(t,"line-through")}),icon:t(i,{name:"text.strikethrough",className:"pn:size-4"}),tooltipContent:h("toolbar.strikethrough")}),t(c,{label:h("toolbar.textAlign"),side:"bottom",onClick:()=>{const t=N(w,o.align);n.history.transaction(()=>{m.forEach(e=>{e.set({align:t})})})},children:"left"===o.align?t(i,{name:"text.alignLeft",className:"pn:size-4"}):"center"===o.align?t(i,{name:"text.alignCenter",className:"pn:size-4"}):"right"===o.align?t(i,{name:"text.alignRight",className:"pn:size-4"}):t(i,{name:"text.alignJustify",className:"pn:size-4"})}),g.textVerticalResizeEnabled&&e(r,{children:[t(a,{render:t(l,{variant:"ghost",size:"icon-sm",onClick:()=>{const t=N(A,o.verticalAlign);n.history.transaction(()=>{o.set({verticalAlign:t})})},"aria-label":h("toolbar.verticalAlign"),children:D[o.verticalAlign]})}),t(s,{side:"bottom",children:h("toolbar.verticalAlign")})]}),t(c,{label:h("toolbar.listFormat"),side:"bottom",onMouseDown:t=>{t.preventDefault()},onClick:()=>{let t=window.__polotnoQuill;const e=!t;t=t||(({html:t})=>{const e=document.createElement("div");document.body.appendChild(e),e.style.display="none",e.style.whiteSpace="pre-wrap";const o=T(e);return y(o,t),o})({html:o.text}),e&&t.setSelection(0,t.getLength(),"api");const n=t.getFormat();n.list?"bullet"===n.list?t.format("list","ordered"):t.format("list",!1):t.format("list","bullet"),e&&(o.set({text:W(t.root.innerHTML,{fontSize:o.fontSize,fontFamily:o.fontFamily})}),(t=>{t.root.parentElement.remove()})(t))},children:(()=>{const e=window.__polotnoQuill;return"bullet"===(e?e.getFormat(e.getSelection()):{}).list?t(i,{name:"text.numberedList",className:"pn:size-5"}):t(i,{name:"text.bulletList",className:"pn:size-5"})})()})]})});export const FontColorInput=n(({element:e,store:o})=>{var n;const{format:i,applyTextFormat:l}=_(o);return t("div",{"data-polotno-keep-focus":!0,onMouseDown:X,children:t(m,{value:null!==(n=i.fill.value)&&void 0!==n?n:e.fill,gradientEnabled:!0,onClose:()=>{const t=O();(null==t?void 0:t.instance)&&t.lastSelection&&t.instance.setSelection(t.lastSelection)},onChange:t=>l({fill:t}),store:o})})});export const DirectionInput=n(({element:e})=>{const o="rtl"===e.dir,n=h("toolbar.textDirection");return t(c,{label:n,side:"bottom",onClick:()=>{e.set({dir:o?"ltr":"rtl"})},children:t(i,o?{name:"text.paragraph",className:"pn:size-5 pn:-scale-x-100"}:{name:"text.richText",className:"pn:size-5"})})});const K=k(),Y={TextFontFamily:n(({elements:e,store:n})=>{var i;const{format:l,applyTextFormat:r}=_(n),s=Q(n),a=l.fontFamily.mixed,c=a?Array.from(new Set(e.flatMap(t=>B(t.text,t.fontFamily)))).sort((t,e)=>t.localeCompare(e,void 0,{sensitivity:"base"})):void 0,[m,p]=o.useState(!1),{data:u,mutate:d}=E(m?M():null,S,{isPaused:()=>L(),fallbackData:[]});o.useEffect(()=>{d()},[L()]);const f=n.fonts.concat(I).map(t=>t.fontFamily).concat((null==u?void 0:u.length)&&!L()?u:K),x=[];n.find(t=>("text"===t.type&&x.push(t.fontFamily),!1));const g=[...new Set(x.concat("_divider").concat(f))],v=null!==(i=l.fontFamily.value)&&void 0!==i?i:e[0].fontFamily;let h=v;h.length>15&&(h=h.slice(0,15)+"...");const b=t(F,{fonts:g,activeFont:v,activeFontLabel:h,store:n,mixed:a,mixedFonts:c,open:m,onOpenChange:p,onFontSelect:t=>r({fontFamily:t})});return s?t("div",{"data-polotno-keep-focus":!0,onMouseDown:X,children:b}):b}),TextFontSize:n(({elements:o,store:n})=>{const{format:i}=_(n),l=Q(n),r=i.fontSize.mixed,s=i.fontSize.value,a=o.map(t=>new Proxy(t,{get:(t,e)=>"fontSize"===e?null!=s?s:t.fontSize:"set"===e?e=>((t,e)=>{if(!e.fontSize){return void t.set(e)}const o=O();if(o&&o.store===n&&o.instance){const{scope:t,isEmpty:n}=P(o.instance,o.lastSelection);if("partial"===t||"collapsed"===t&&n){return void V(o.instance,{fontSize:e.fontSize},o.lastSelection)}}const{attrsToSet:i}=R(t,{fontSize:e.fontSize});t.set(Object.assign(Object.assign({},e),i))})(t,e):Reflect.get(t,e)})),c=e(G,{className:r?"polotno-mixed":"",children:[t(j,{elements:a,store:n}),r&&t(H,{"aria-hidden":!0,children:"—"})]});return l?t("div",{"data-polotno-keep-focus":!0,onMouseDown:U,children:c}):c}),TextFontVariant:FontStyleGroup,TextTransform:C,TextFilters:p,TextFill:FontColorInput,TextSpacing:z,TextDirection:DirectionInput,TextAnimations:x,TextAiWrite:v};export const HtmlToolbar=n(({store:e,components:o})=>{const n=e.selectedElements,i=e.selectedElements[0],l=["TextFill","TextFontFamily","TextFontSize","TextFontVariant","TextSpacing","TextTransform","TextFilters",g.animationsEnabled&&"TextAnimations",g.aiTextEnabled&&"TextAiWrite"],r=d({type:"text",usedItems:l,components:o});return t(u,{items:r,itemRender:l=>{if("TextBold"===l){return null}const r=(null==o?void 0:o[l])||Y[l];return t(r,{element:i,elements:n,store:e,components:o},l)}})});
25
+ `,J=t=>{const e=P();return!!e&&e.store===t&&!!e.instance};let U=null;const X=()=>{b.pendingToolbarInteraction=!0,U&&clearTimeout(U),U=setTimeout(()=>{b.pendingToolbarInteraction=!1,U=null},100)},$=t=>{var e;(!(e=t.target)||"INPUT"!==e.tagName&&"TEXTAREA"!==e.tagName&&"SELECT"!==e.tagName&&!e.isContentEditable)&&t.preventDefault(),X()},q=n(({store:e,isActive:o,toggle:n,icon:i,ariaLabel:l,tooltipContent:r})=>{const{format:s,applyTextFormat:a}=O(e);return t(c,{label:r||l||"",side:"bottom",active:o(s),onMouseDown:t=>{t.preventDefault()},onClick:()=>n(s,a),children:i})});function K(t,e){const o=t.textDecoration.value||"",n="underline"===e?"line-through":"underline";return[!o.split(/\s+/).includes(e)&&e,o.split(/\s+/).includes(n)&&n].filter(Boolean).join(" ")}export const TextBold=n(({store:e})=>t(q,{store:e,isActive:t=>W(t.fontWeight.value),toggle:(t,e)=>e({fontWeight:W(t.fontWeight.value)?400:700}),icon:t(i,{name:"text.bold",className:"pn:size-4"}),tooltipContent:h("toolbar.bold")}));export const FontStyleGroup=n(({element:o,store:n,elements:m,components:p})=>{const u=(null==p?void 0:p.TextBold)||TextBold;return e("div",{className:"pn:flex pn:items-center pn:gap-0.5",children:[t(u,{element:o,store:n}),t(q,{store:n,isActive:t=>"italic"===t.fontStyle.value,toggle:(t,e)=>e({fontStyle:"italic"===t.fontStyle.value?"normal":"italic"}),icon:t(i,{name:"text.italic",className:"pn:size-4"}),tooltipContent:h("toolbar.italic")}),t(q,{store:n,isActive:t=>{var e;return!!(null===(e=t.textDecoration.value)||void 0===e?void 0:e.split(/\s+/).includes("underline"))},toggle:(t,e)=>e({textDecoration:K(t,"underline")}),icon:t(i,{name:"text.underline",className:"pn:size-4"}),tooltipContent:h("toolbar.underline")}),t(q,{store:n,isActive:t=>{var e;return!!(null===(e=t.textDecoration.value)||void 0===e?void 0:e.split(/\s+/).includes("line-through"))},toggle:(t,e)=>e({textDecoration:K(t,"line-through")}),icon:t(i,{name:"text.strikethrough",className:"pn:size-4"}),tooltipContent:h("toolbar.strikethrough")}),t(c,{label:h("toolbar.textAlign"),side:"bottom",onClick:()=>{const t=N(w,o.align);n.history.transaction(()=>{m.forEach(e=>{e.set({align:t})})})},children:"left"===o.align?t(i,{name:"text.alignLeft",className:"pn:size-4"}):"center"===o.align?t(i,{name:"text.alignCenter",className:"pn:size-4"}):"right"===o.align?t(i,{name:"text.alignRight",className:"pn:size-4"}):t(i,{name:"text.alignJustify",className:"pn:size-4"})}),g.textVerticalResizeEnabled&&e(r,{children:[t(a,{render:t(l,{variant:"ghost",size:"icon-sm",onClick:()=>{const t=N(A,o.verticalAlign);n.history.transaction(()=>{o.set({verticalAlign:t})})},"aria-label":h("toolbar.verticalAlign"),children:D[o.verticalAlign]})}),t(s,{side:"bottom",children:h("toolbar.verticalAlign")})]}),t(c,{label:h("toolbar.listFormat"),side:"bottom",onMouseDown:t=>{t.preventDefault()},onClick:()=>{let t=window.__polotnoQuill;const e=!t;t=t||(({html:t})=>{const e=document.createElement("div");document.body.appendChild(e),e.style.display="none",e.style.whiteSpace="pre-wrap";const o=T(e);return y(o,t),o})({html:o.text}),e&&t.setSelection(0,t.getLength(),"api");const n=t.getFormat();n.list?"bullet"===n.list?t.format("list","ordered"):t.format("list",!1):t.format("list","bullet"),e&&(o.set({text:B(t.root.innerHTML,{fontSize:o.fontSize,fontFamily:o.fontFamily})}),(t=>{t.root.parentElement.remove()})(t))},children:(()=>{const e=window.__polotnoQuill;return"bullet"===(e?e.getFormat(e.getSelection()):{}).list?t(i,{name:"text.numberedList",className:"pn:size-5"}):t(i,{name:"text.bulletList",className:"pn:size-5"})})()})]})});export const FontColorInput=n(({element:e,store:o})=>{var n;const{format:i,applyTextFormat:l}=O(o);return t("div",{"data-polotno-keep-focus":!0,onMouseDown:$,children:t(m,{value:null!==(n=i.fill.value)&&void 0!==n?n:e.fill,gradientEnabled:!0,onClose:()=>{const t=P();(null==t?void 0:t.instance)&&t.lastSelection&&t.instance.setSelection(t.lastSelection)},onChange:t=>l({fill:t}),store:o})})});export const DirectionInput=n(({element:e})=>{const o="rtl"===e.dir,n=h("toolbar.textDirection");return t(c,{label:n,side:"bottom",onClick:()=>{e.set({dir:o?"ltr":"rtl"})},children:t(i,o?{name:"text.paragraph",className:"pn:size-5 pn:-scale-x-100"}:{name:"text.richText",className:"pn:size-5"})})});const Y=k(),Z={TextFontFamily:n(({elements:e,store:n})=>{var i;const{format:l,applyTextFormat:r}=O(n),s=J(n),a=l.fontFamily.mixed,c=a?Array.from(new Set(e.flatMap(t=>R(t.text,t.fontFamily)))).sort((t,e)=>t.localeCompare(e,void 0,{sensitivity:"base"})):void 0,[m,p]=o.useState(!1),{data:u,mutate:d}=E(m?M():null,S,{isPaused:()=>L(),fallbackData:[]});o.useEffect(()=>{d()},[L()]);const f=n.fonts.concat(I).map(t=>t.fontFamily).concat((null==u?void 0:u.length)&&!L()?u:Y),x=[];n.find(t=>("text"===t.type&&x.push(t.fontFamily),!1));const g=[...new Set(x.concat("_divider").concat(f))],v=null!==(i=l.fontFamily.value)&&void 0!==i?i:e[0].fontFamily;let h=v;h.length>15&&(h=h.slice(0,15)+"...");const b=t(F,{fonts:g,activeFont:v,activeFontLabel:h,store:n,mixed:a,mixedFonts:c,open:m,onOpenChange:p,onFontSelect:t=>r({fontFamily:t})});return s?t("div",{"data-polotno-keep-focus":!0,onMouseDown:$,children:b}):b}),TextFontSize:n(({elements:o,store:n})=>{const{format:i}=O(n),l=J(n),r=i.fontSize.mixed,s=i.fontSize.value,a=o.map(t=>new Proxy(t,{get:(t,e)=>"fontSize"===e?null!=s?s:t.fontSize:"set"===e?e=>((t,e)=>{if(!e.fontSize){return void t.set(e)}const o=P();if(o&&o.store===n&&o.instance){const{scope:t,isEmpty:n}=V(o.instance,o.lastSelection);if("partial"===t||"collapsed"===t&&n){return void G(o.instance,{fontSize:e.fontSize},o.lastSelection)}}const{attrsToSet:i}=_(t,{fontSize:e.fontSize});t.set(Object.assign(Object.assign({},e),i))})(t,e):Reflect.get(t,e)})),c=e(H,{className:r?"polotno-mixed":"",children:[t(j,{elements:a,store:n}),r&&t(Q,{"aria-hidden":!0,children:"—"})]});return l?t("div",{"data-polotno-keep-focus":!0,onMouseDown:X,children:c}):c}),TextFontVariant:FontStyleGroup,TextTransform:C,TextFilters:p,TextFill:FontColorInput,TextSpacing:z,TextDirection:DirectionInput,TextAnimations:x,TextAiWrite:v};export const HtmlToolbar=n(({store:e,components:o})=>{const n=e.selectedElements,i=e.selectedElements[0],l=["TextFill","TextFontFamily","TextFontSize","TextFontVariant","TextSpacing","TextTransform","TextFilters",g.animationsEnabled&&"TextAnimations",g.aiTextEnabled&&"TextAiWrite"],r=d({type:"text",usedItems:l,components:o});return t(u,{items:r,itemRender:l=>{if("TextBold"===l){return null}const r=(null==o?void 0:o[l])||Z[l];return t(r,{element:i,elements:n,store:e,components:o},l)}})});
@@ -1 +1 @@
1
- import{jsx as e,jsxs as o,Fragment as t}from"react/jsx-runtime";import r from"react";import{observer as i}from"mobx-react-lite";import{Button as a}from"../primitives/button.js";import{Tooltip as n,TooltipContent as m,TooltipTrigger as s}from"../primitives/tooltip.js";import{ElementContainer as c,extendToolbar as l}from"./element-container.js";import{PolotnoIcon as p}from"../icons/registry.js";import g from"./filters-picker.js";import{AnimationsPicker as d}from"./animations-picker.js";import h from"./flip-button.js";import{flags as u}from"../utils/flags.js";import{ImageRemoveBackground as b}from"./image-remove-background-button.js";export{ImageRemoveBackground}from"./image-remove-background-button.js";import{getCrop as C,getImageSize as f}from"../utils/image.js";import{t as I}from"../utils/l10n.js";export const ImageFitToBackground=({element:o})=>e(a,{variant:"ghost",size:"sm",onClick:async()=>{const{page:e}=o,t=e.computedWidth+2*e.bleed,r=e.computedHeight+2*e.bleed,i=await f(o.src),a=o.stretchEnabled?{cropX:0,cropY:0,cropWidth:1,cropHeight:1}:C({width:t,height:r},i);o.set(Object.assign({x:-e.bleed,y:-e.bleed,width:t,height:r,rotation:0},a))},children:I("toolbar.fitToBackground")});export const ImageClip=i(({element:o,store:t,elements:r})=>o.contentEditable?o.clipSrc?e(a,{variant:"ghost",size:"sm",onClickCapture:()=>{r.forEach(e=>{e.set({clipSrc:""})})},children:I("toolbar.removeClip")}):e(a,{variant:"ghost",size:"sm",onClickCapture:e=>{e.stopPropagation(),t.openSidePanel("image-clip")},children:I("toolbar.clip")}):null);export const ImageCrop=i(({element:t})=>t.contentEditable?t.stretchEnabled?null:o(n,{children:[e(s,{render:e(a,{variant:"ghost",size:"icon-sm",onClickCapture:e=>{e.stopPropagation(),t.toggleCropMode(!0)},"aria-label":I("toolbar.crop"),children:e(p,{name:"toolbar.crop",className:"pn:size-4"})})}),e(m,{children:I("toolbar.crop")})]}):null);export const ImageRemoveClip=i(({element:o})=>o.clipSrc?e(a,{variant:"ghost",size:"sm",onClickCapture:()=>{o.set({clipSrc:""})},children:I("toolbar.removeClip")}):null);const k={ImageFlip:h,ImageFilters:g,ImageFitToBackground,ImageCrop,ImageClip,ImageRemoveBackground:b,ImageAnimations:d};export const ImageToolbar=i(({store:i,components:n})=>{const m=i.selectedElements[0],s=m._cropModeEnabled,g=r.useRef({});r.useEffect(()=>{s&&(g.current={x:m.x,y:m.y,width:m.width,height:m.height,cropX:m.cropX,cropY:m.cropY,cropWidth:m.cropWidth,cropHeight:m.cropHeight})},[s]);const d=["ImageFlip","ImageFilters","ImageFitToBackground","ImageClip","ImageCrop",u.animationsEnabled&&"ImageAnimations",u.removeBackgroundEnabled&&"ImageRemoveBackground"],h=l({type:"image",usedItems:d,components:n});return o(t,{children:[!s&&e(c,{items:h,itemRender:o=>{const t=n[o]||k[o];return e(t,{element:m,store:i,elements:i.selectedElements},o)}}),s&&o("div",{className:"pn:flex pn:items-center",children:[o(a,{variant:"ghost",size:"sm",onClickCapture:()=>{m.toggleCropMode(!1)},children:[e(p,{name:"action.confirm",className:"pn:size-4"}),I("toolbar.cropDone")]}),o(a,{variant:"ghost",size:"sm",onClickCapture:()=>{m.set(Object.assign({},g.current)),m.toggleCropMode(!1)},children:[e(p,{name:"action.close",className:"pn:size-4"}),I("toolbar.cropCancel")]})]})]})});export default ImageToolbar;
1
+ import{jsx as e,jsxs as o,Fragment as t}from"react/jsx-runtime";import r from"react";import{observer as i}from"mobx-react-lite";import{Button as a}from"../primitives/button.js";import{Tooltip as n,TooltipContent as m,TooltipTrigger as s}from"../primitives/tooltip.js";import{ElementContainer as c,extendToolbar as l}from"./element-container.js";import{PolotnoIcon as p}from"../icons/registry.js";import g from"./filters-picker.js";import{AnimationsPicker as d}from"./animations-picker.js";import h from"./flip-button.js";import{flags as u}from"../utils/flags.js";import{ImageRemoveBackground as b}from"./image-remove-background-button.js";export{ImageRemoveBackground}from"./image-remove-background-button.js";import{getCrop as f,getImageSize as C}from"../utils/image.js";import{t as I}from"../utils/l10n.js";export const ImageFitToBackground=({element:o})=>e(a,{variant:"ghost",size:"sm",onClick:async()=>{const{page:e}=o,t=e.computedBleed,r=e.computedWidth+t.left+t.right,i=e.computedHeight+t.top+t.bottom,a=await C(o.src),n=o.stretchEnabled?{cropX:0,cropY:0,cropWidth:1,cropHeight:1}:f({width:r,height:i},a);o.set(Object.assign({x:-t.left,y:-t.top,width:r,height:i,rotation:0},n))},children:I("toolbar.fitToBackground")});export const ImageClip=i(({element:o,store:t,elements:r})=>o.contentEditable?o.clipSrc?e(a,{variant:"ghost",size:"sm",onClickCapture:()=>{r.forEach(e=>{e.set({clipSrc:""})})},children:I("toolbar.removeClip")}):e(a,{variant:"ghost",size:"sm",onClickCapture:e=>{e.stopPropagation(),t.openSidePanel("image-clip")},children:I("toolbar.clip")}):null);export const ImageCrop=i(({element:t})=>t.contentEditable?t.stretchEnabled?null:o(n,{children:[e(s,{render:e(a,{variant:"ghost",size:"icon-sm",onClickCapture:e=>{e.stopPropagation(),t.toggleCropMode(!0)},"aria-label":I("toolbar.crop"),children:e(p,{name:"toolbar.crop",className:"pn:size-4"})})}),e(m,{children:I("toolbar.crop")})]}):null);export const ImageRemoveClip=i(({element:o})=>o.clipSrc?e(a,{variant:"ghost",size:"sm",onClickCapture:()=>{o.set({clipSrc:""})},children:I("toolbar.removeClip")}):null);const k={ImageFlip:h,ImageFilters:g,ImageFitToBackground,ImageCrop,ImageClip,ImageRemoveBackground:b,ImageAnimations:d};export const ImageToolbar=i(({store:i,components:n})=>{const m=i.selectedElements[0],s=m._cropModeEnabled,g=r.useRef({});r.useEffect(()=>{s&&(g.current={x:m.x,y:m.y,width:m.width,height:m.height,cropX:m.cropX,cropY:m.cropY,cropWidth:m.cropWidth,cropHeight:m.cropHeight})},[s]);const d=["ImageFlip","ImageFilters","ImageFitToBackground","ImageClip","ImageCrop",u.animationsEnabled&&"ImageAnimations",u.removeBackgroundEnabled&&"ImageRemoveBackground"],h=l({type:"image",usedItems:d,components:n});return o(t,{children:[!s&&e(c,{items:h,itemRender:o=>{const t=n[o]||k[o];return e(t,{element:m,store:i,elements:i.selectedElements},o)}}),s&&o("div",{className:"pn:flex pn:items-center",children:[o(a,{variant:"ghost",size:"sm",onClickCapture:()=>{m.toggleCropMode(!1)},children:[e(p,{name:"action.confirm",className:"pn:size-4"}),I("toolbar.cropDone")]}),o(a,{variant:"ghost",size:"sm",onClickCapture:()=>{m.set(Object.assign({},g.current)),m.toggleCropMode(!1)},children:[e(p,{name:"action.close",className:"pn:size-4"}),I("toolbar.cropCancel")]})]})]})});export default ImageToolbar;
@@ -1 +1 @@
1
- import{jsx as t,jsxs as e}from"react/jsx-runtime";import n from"react";import{observer as o}from"mobx-react-lite";import{FixedSizeList as i}from"react-window";import r from"swr";import{PolotnoIcon as a}from"../icons/registry.js";import{getFontsList as l,globalFonts as s,isGoogleFontChanged as c}from"../utils/fonts.js";import{getGoogleFontImage as p,getGoogleFontsListAPI as m}from"../utils/api.js";import{t as d}from"../utils/l10n.js";import{flags as f}from"../utils/flags.js";import{Button as h}from"../primitives/button.js";import{NumberInput as u}from"../primitives/numeric-input.js";export{NumberInput}from"../primitives/numeric-input.js";import{InputGroup as x}from"../primitives/input-group.js";import{SliderField as g}from"../primitives/slider-field.js";import{Popover as b,PopoverContent as v,PopoverTrigger as T}from"../primitives/popover.js";import{Tooltip as y,TooltipContent as F,TooltipTrigger as N}from"../primitives/tooltip.js";import{TooltipIconButton as S}from"../primitives/tooltip-icon-button.js";import{Separator as C}from"../primitives/separator.js";import{cn as j}from"../lib/utils.js";import{cycleNext as z}from"./toolbar-shared.js";import{ColorPicker as w}from"./color-picker.js";import E from"./filters-picker.js";import{AnimationsPicker as A}from"./animations-picker.js";import{ElementContainer as D,extendToolbar as k}from"./element-container.js";import{TextAiWrite as I}from"./text-ai-write.js";const O=l(),M=({fontFamily:e,handleClick:o,modifiers:i,store:r,isCustom:a})=>{const[l,s]=n.useState(!a);if(n.useEffect(()=>{l||r.loadFont(e)},[e,l]),"_divider"===e){return t("div",{style:{paddingTop:"10px"},children:t(C,{})})}const c=l?t("img",{src:p(e),alt:e,onError:()=>{s(!1)},className:"pn:h-5 pn:dark:invert"}):e;return t("button",{type:"button",onClick:o,disabled:i.disabled,"data-active":i.active||void 0,className:j("pn:flex pn:w-full pn:items-center pn:rounded-sm pn:px-2 pn:py-1.5 pn:text-left pn:text-sm pn:hover:bg-muted",i.active&&"pn:bg-muted"),style:{fontFamily:'"'+e+'"'},children:c})},L=({onChange:o,defaultValue:i})=>{const r=n.useRef(null);return n.useEffect(()=>{r.current&&r.current.focus()},[]),e(x,{children:[t("span",{className:"pn:flex pn:items-center pn:pl-2 pn:pr-1 pn:text-muted-foreground",children:t(a,{name:"action.search",className:"pn:size-3.5 pn:shrink-0 pn:opacity-50"})}),t("input",{ref:r,"data-slot":"input-group-control",defaultValue:i,onChange:t=>o(t.target.value),className:"pn:h-full pn:w-full pn:flex-1 pn:border-0 pn:bg-transparent pn:px-2 pn:text-xs pn:outline-none pn:placeholder:text-muted-foreground"})]})};export const FontMenu=({store:o,fonts:r,activeFont:l,activeFontLabel:c,onFontSelect:p,mixed:m,mixedFonts:f,open:u,onOpenChange:x})=>{const[g,S]=n.useState(""),C=r.filter(t=>(null==t?void 0:t.toLowerCase().indexOf(g.toLowerCase()))>=0);return e(b,{open:u,onOpenChange:x,children:[e(y,{children:[t(N,{render:t(T,{render:e(h,{variant:"ghost",size:"sm",className:"pn:gap-1 pn:overflow-hidden pn:whitespace-nowrap",style:{fontFamily:m?void 0:'"'+l+'"',fontStyle:m?"italic":void 0,color:m?"#5c7080":void 0},"aria-label":d("toolbar.fontFamily"),children:[t("span",{className:"pn:truncate",children:m?d("toolbar.fontFamilyMixed"):c}),t(a,{name:"ui.chevronDown",className:"pn:size-3 pn:shrink-0 pn:opacity-50"})]})})}),t(F,{side:"bottom",children:m&&f&&f.length>0?`${d("toolbar.fontsInSelection")}: ${f.join(", ")}`:d("toolbar.fontFamily")})]}),t(v,{className:"pn:w-[230px] pn:p-2",align:"start",children:e("div",{children:[t(L,{onChange:t=>S(t),defaultValue:g}),t("div",{style:{paddingTop:"5px"},children:t(i,{height:Math.min(400,30*C.length)+10,width:210,itemCount:C.length,itemSize:30,children:({index:e,style:n})=>{const i=C[e];return t("div",{style:n,children:t(M,{fontFamily:i,modifiers:{active:l===i},handleClick:()=>p(i),store:o,isCustom:o.fonts.find(t=>t.fontFamily===i)||s.find(t=>t.fontFamily===i)},i)})}})})]})})]})};const V={};export const fetcher=t=>V[t]?Promise.resolve(V[t]):fetch(t).then(t=>t.json()).then(e=>(V[t]=e,e));export const TextFontFamily=o(({elements:e,store:o})=>{const[i,a]=n.useState(!1),{data:l,mutate:p}=r(i?m():null,fetcher,{isPaused:()=>c(),fallbackData:[]});n.useEffect(()=>{p()},[c()]);const d=o.fonts.concat(s).map(t=>t.fontFamily).concat((null==l?void 0:l.length)&&!c()?l:O);let f=e[0].fontFamily;f.length>15&&(f=f.slice(0,15)+"...");const h=[];o.find(t=>("text"===t.type&&h.push(t.fontFamily),!1));const u=[...new Set(h.concat("_divider").concat(d))];return t(FontMenu,{fonts:u,activeFont:e[0].fontFamily,activeFontLabel:f,store:o,open:i,onOpenChange:a,onFontSelect:t=>{o.history.transaction(()=>{e.forEach(e=>{e.set({fontFamily:t})})})}})});export const TextFontSize=o(({elements:o,store:i})=>{const[r,a]=n.useState(!1),[l,s]=n.useState(!1);return e(y,{open:!l&&r,onOpenChange:t=>{l||a(t)},children:[t(N,{render:t(u,{"aria-label":d("toolbar.fontSize"),onFocus:()=>s(!0),onBlur:()=>s(!1),onValueChange:t=>{i.history.transaction(()=>{o.forEach(e=>{e.set({fontSize:t,width:Math.max(t,e.width)})})})},value:Math.round(o[0].fontSize),style:{width:"50px"},min:5,max:4*i.height})}),t(F,{side:"bottom",children:d("toolbar.fontSize")})]})});export const ALIGN_OPTIONS=["left","center","right","justify"];export const VERTICAL_ALIGN_OPTIONS=["top","middle","bottom"];export const VERTICAL_ALIGN_ICONS={top:t(a,{name:"text.valignTop",className:"pn:size-4"}),middle:t(a,{name:"text.valignMiddle",className:"pn:size-4"}),bottom:t(a,{name:"text.valignBottom",className:"pn:size-4"})};export const TextFontVariant=o(({elements:n,store:o})=>{const i=n[0],r="bold"===i.fontWeight||"700"===i.fontWeight,l="italic"===i.fontStyle,s=i.textDecoration.indexOf("underline")>=0,c=i.textDecoration.indexOf("line-through")>=0;return e("div",{className:"pn:flex pn:items-center pn:gap-0.5",children:[e(y,{children:[t(N,{render:t(h,{variant:"ghost",size:"icon-sm",onMouseDown:t=>{t.preventDefault()},onClick:()=>{const t=z(ALIGN_OPTIONS,i.align);o.history.transaction(()=>{n.forEach(e=>{e.set({align:t})})})},"aria-label":d("toolbar.textAlign"),children:"left"===i.align?t(a,{name:"text.alignLeft",className:"pn:size-4"}):"center"===i.align?t(a,{name:"text.alignCenter",className:"pn:size-4"}):"right"===i.align?t(a,{name:"text.alignRight",className:"pn:size-4"}):t(a,{name:"text.alignJustify",className:"pn:size-4"})})}),t(F,{side:"bottom",children:d("toolbar.textAlign")})]}),f.textVerticalResizeEnabled&&e(y,{children:[t(N,{render:t(h,{variant:"ghost",size:"icon-sm",onMouseDown:t=>{t.preventDefault()},onClick:()=>{const t=z(VERTICAL_ALIGN_OPTIONS,i.verticalAlign);o.history.transaction(()=>{n.forEach(e=>{e.set({verticalAlign:t})})})},"aria-label":d("toolbar.verticalAlign"),children:VERTICAL_ALIGN_ICONS[i.verticalAlign]})}),t(F,{side:"bottom",children:d("toolbar.verticalAlign")})]}),t(S,{label:d("toolbar.bold"),side:"bottom",active:r,onMouseDown:t=>{t.preventDefault()},onClick:()=>{const t="bold"===i.fontWeight||"700"===i.fontWeight;o.history.transaction(()=>{n.forEach(e=>{t?e.set({fontWeight:"normal"}):e.set({fontWeight:"bold"})})})},children:t(a,{name:"text.bold",className:"pn:size-4"})}),t(S,{label:d("toolbar.italic"),side:"bottom",active:l,onMouseDown:t=>{t.preventDefault()},onClick:()=>{const t="italic"===i.fontStyle;o.history.transaction(()=>{n.forEach(e=>{t?e.set({fontStyle:"normal"}):e.set({fontStyle:"italic"})})})},children:t(a,{name:"text.italic",className:"pn:size-4"})}),t(S,{label:d("toolbar.underline"),side:"bottom",active:s,onMouseDown:t=>{t.preventDefault()},onClick:()=>{let t=i.textDecoration.split(" ");t.indexOf("underline")>=0?t=t.filter(t=>"underline"!==t):t.push("underline"),o.history.transaction(()=>{n.forEach(e=>{e.set({textDecoration:t.join(" ")})})})},children:t(a,{name:"text.underline",className:"pn:size-4"})}),t(S,{label:d("toolbar.strikethrough"),side:"bottom",active:c,onMouseDown:t=>{t.preventDefault()},onClick:()=>{let t=i.textDecoration.split(" ");t.indexOf("line-through")>=0?t=t.filter(t=>"line-through"!==t):t.push("line-through"),o.history.transaction(()=>{n.forEach(e=>{e.set({textDecoration:t.join(" ")})})})},children:t(a,{name:"text.strikethrough",className:"pn:size-4"})})]})});export const TextTransform=o(({elements:e,store:n})=>{const o="uppercase"==e[0].textTransform;return t("div",{className:"pn:flex pn:items-center pn:gap-0.5",children:t(S,{label:d("toolbar.uppercase"),active:o,onMouseDown:t=>{t.preventDefault()},onClick:()=>{n.history.transaction(()=>{e.forEach(t=>{t.set({textTransform:"uppercase"===t.textTransform?"none":"uppercase"})})})},children:t(a,{name:"text.uppercase",className:"pn:size-4"})})})});export const TextFill=o(({elements:e,store:n})=>t(w,{value:e[0].fill,gradientEnabled:!0,onChange:t=>n.history.transaction(()=>{e.forEach(e=>{e.set({fill:t})})}),store:n}));export const TextSpacing=o(({elements:n,store:o})=>{const i=n[0],r=t=>{o.history.transaction(()=>{n.forEach(e=>{e.set(t)})})},l="number"==typeof i.lineHeight?100*i.lineHeight:120;return e(b,{children:[e(y,{children:[t(N,{render:t(T,{render:t(h,{variant:"ghost",size:"icon-sm","aria-label":d("toolbar.spacing"),children:t(a,{name:"text.spacing",className:"pn:size-5"})})})}),t(F,{side:"bottom",children:d("toolbar.spacing")})]}),e(v,{align:"start",className:"pn:w-[230px] pn:p-[15px]",children:[t(g,{label:d("toolbar.lineHeight"),value:Math.round(l),onChange:t=>r({lineHeight:t/100}),min:50,max:250}),t(g,{label:d("toolbar.letterSpacing"),value:Math.round(100*i.letterSpacing),onChange:t=>r({letterSpacing:t/100}),min:-50,max:250})]})]})});export const TextFilters=E;export const TextAnimations=A;const _={TextFontFamily,TextFontSize,TextFontVariant,TextTransform,TextFill,TextSpacing,TextAiWrite:I,TextFilters:E,TextAnimations:A};export const TextToolbar=o(({store:e,components:n})=>{const o=e.selectedElements,i=["TextFill","TextFontFamily","TextFontSize","TextFontVariant","TextSpacing","TextTransform","TextFilters",f.animationsEnabled&&"TextAnimations",f.aiTextEnabled&&"TextAiWrite"],r=k({type:"text",usedItems:i,components:n});return t(D,{items:r,itemRender:i=>{const r=(null==n?void 0:n[i])||_[i];return r?t(r,{elements:o,element:o[0],store:e},i):null}})});export default TextToolbar;
1
+ import{jsx as t,jsxs as e}from"react/jsx-runtime";import n from"react";import{observer as o}from"mobx-react-lite";import{FixedSizeList as i}from"react-window";import r from"swr";import{PolotnoIcon as a}from"../icons/registry.js";import{getFontsList as s,globalFonts as l,isGoogleFontChanged as c}from"../utils/fonts.js";import{getGoogleFontImage as p,getGoogleFontsListAPI as m}from"../utils/api.js";import{t as d}from"../utils/l10n.js";import{flags as f}from"../utils/flags.js";import{Button as h}from"../primitives/button.js";import{NumberInput as u}from"../primitives/numeric-input.js";export{NumberInput}from"../primitives/numeric-input.js";import{InputGroup as x}from"../primitives/input-group.js";import{SliderField as g}from"../primitives/slider-field.js";import{Popover as b,PopoverContent as v,PopoverTrigger as T}from"../primitives/popover.js";import{Tooltip as y,TooltipContent as F,TooltipTrigger as N}from"../primitives/tooltip.js";import{TooltipIconButton as S}from"../primitives/tooltip-icon-button.js";import{Separator as C}from"../primitives/separator.js";import{cn as j}from"../lib/utils.js";import{cycleNext as z}from"./toolbar-shared.js";import{isBoldWeight as w}from"../utils/rich-text-html.js";import{ColorPicker as E}from"./color-picker.js";import A from"./filters-picker.js";import{AnimationsPicker as D}from"./animations-picker.js";import{ElementContainer as k,extendToolbar as I}from"./element-container.js";import{TextAiWrite as O}from"./text-ai-write.js";const M=s(),L=({fontFamily:e,handleClick:o,modifiers:i,store:r,isCustom:a})=>{const[s,l]=n.useState(!a);if(n.useEffect(()=>{s||r.loadFont(e)},[e,s]),"_divider"===e){return t("div",{style:{paddingTop:"10px"},children:t(C,{})})}const c=s?t("img",{src:p(e),alt:e,onError:()=>{l(!1)},className:"pn:h-5 pn:dark:invert"}):e;return t("button",{type:"button",onClick:o,disabled:i.disabled,"data-active":i.active||void 0,className:j("pn:flex pn:w-full pn:items-center pn:rounded-sm pn:px-2 pn:py-1.5 pn:text-left pn:text-sm pn:hover:bg-muted",i.active&&"pn:bg-muted"),style:{fontFamily:'"'+e+'"'},children:c})},V=({onChange:o,defaultValue:i})=>{const r=n.useRef(null);return n.useEffect(()=>{r.current&&r.current.focus()},[]),e(x,{children:[t("span",{className:"pn:flex pn:items-center pn:pl-2 pn:pr-1 pn:text-muted-foreground",children:t(a,{name:"action.search",className:"pn:size-3.5 pn:shrink-0 pn:opacity-50"})}),t("input",{ref:r,"data-slot":"input-group-control",defaultValue:i,onChange:t=>o(t.target.value),className:"pn:h-full pn:w-full pn:flex-1 pn:border-0 pn:bg-transparent pn:px-2 pn:text-xs pn:outline-none pn:placeholder:text-muted-foreground"})]})};export const FontMenu=({store:o,fonts:r,activeFont:s,activeFontLabel:c,onFontSelect:p,mixed:m,mixedFonts:f,open:u,onOpenChange:x})=>{const[g,S]=n.useState(""),C=r.filter(t=>(null==t?void 0:t.toLowerCase().indexOf(g.toLowerCase()))>=0);return e(b,{open:u,onOpenChange:x,children:[e(y,{children:[t(N,{render:t(T,{render:e(h,{variant:"ghost",size:"sm",className:"pn:gap-1 pn:overflow-hidden pn:whitespace-nowrap",style:{fontFamily:m?void 0:'"'+s+'"',fontStyle:m?"italic":void 0,color:m?"#5c7080":void 0},"aria-label":d("toolbar.fontFamily"),children:[t("span",{className:"pn:truncate",children:m?d("toolbar.fontFamilyMixed"):c}),t(a,{name:"ui.chevronDown",className:"pn:size-3 pn:shrink-0 pn:opacity-50"})]})})}),t(F,{side:"bottom",children:m&&f&&f.length>0?`${d("toolbar.fontsInSelection")}: ${f.join(", ")}`:d("toolbar.fontFamily")})]}),t(v,{className:"pn:w-[230px] pn:p-2",align:"start",children:e("div",{children:[t(V,{onChange:t=>S(t),defaultValue:g}),t("div",{style:{paddingTop:"5px"},children:t(i,{height:Math.min(400,30*C.length)+10,width:210,itemCount:C.length,itemSize:30,children:({index:e,style:n})=>{const i=C[e];return t("div",{style:n,children:t(L,{fontFamily:i,modifiers:{active:s===i},handleClick:()=>p(i),store:o,isCustom:o.fonts.find(t=>t.fontFamily===i)||l.find(t=>t.fontFamily===i)},i)})}})})]})})]})};const _={};export const fetcher=t=>_[t]?Promise.resolve(_[t]):fetch(t).then(t=>t.json()).then(e=>(_[t]=e,e));export const TextFontFamily=o(({elements:e,store:o})=>{const[i,a]=n.useState(!1),{data:s,mutate:p}=r(i?m():null,fetcher,{isPaused:()=>c(),fallbackData:[]});n.useEffect(()=>{p()},[c()]);const d=o.fonts.concat(l).map(t=>t.fontFamily).concat((null==s?void 0:s.length)&&!c()?s:M);let f=e[0].fontFamily;f.length>15&&(f=f.slice(0,15)+"...");const h=[];o.find(t=>("text"===t.type&&h.push(t.fontFamily),!1));const u=[...new Set(h.concat("_divider").concat(d))];return t(FontMenu,{fonts:u,activeFont:e[0].fontFamily,activeFontLabel:f,store:o,open:i,onOpenChange:a,onFontSelect:t=>{o.history.transaction(()=>{e.forEach(e=>{e.set({fontFamily:t})})})}})});export const TextFontSize=o(({elements:o,store:i})=>{const[r,a]=n.useState(!1),[s,l]=n.useState(!1);return e(y,{open:!s&&r,onOpenChange:t=>{s||a(t)},children:[t(N,{render:t(u,{"aria-label":d("toolbar.fontSize"),onFocus:()=>l(!0),onBlur:()=>l(!1),onValueChange:t=>{i.history.transaction(()=>{o.forEach(e=>{e.set({fontSize:t,width:Math.max(t,e.width)})})})},value:Math.round(o[0].fontSize),style:{width:"50px"},min:5,max:4*i.height})}),t(F,{side:"bottom",children:d("toolbar.fontSize")})]})});export const ALIGN_OPTIONS=["left","center","right","justify"];export const VERTICAL_ALIGN_OPTIONS=["top","middle","bottom"];export const VERTICAL_ALIGN_ICONS={top:t(a,{name:"text.valignTop",className:"pn:size-4"}),middle:t(a,{name:"text.valignMiddle",className:"pn:size-4"}),bottom:t(a,{name:"text.valignBottom",className:"pn:size-4"})};export const TextFontVariant=o(({elements:n,store:o})=>{const i=n[0],r=w(i.fontWeight),s="italic"===i.fontStyle,l=i.textDecoration.indexOf("underline")>=0,c=i.textDecoration.indexOf("line-through")>=0;return e("div",{className:"pn:flex pn:items-center pn:gap-0.5",children:[e(y,{children:[t(N,{render:t(h,{variant:"ghost",size:"icon-sm",onMouseDown:t=>{t.preventDefault()},onClick:()=>{const t=z(ALIGN_OPTIONS,i.align);o.history.transaction(()=>{n.forEach(e=>{e.set({align:t})})})},"aria-label":d("toolbar.textAlign"),children:"left"===i.align?t(a,{name:"text.alignLeft",className:"pn:size-4"}):"center"===i.align?t(a,{name:"text.alignCenter",className:"pn:size-4"}):"right"===i.align?t(a,{name:"text.alignRight",className:"pn:size-4"}):t(a,{name:"text.alignJustify",className:"pn:size-4"})})}),t(F,{side:"bottom",children:d("toolbar.textAlign")})]}),f.textVerticalResizeEnabled&&e(y,{children:[t(N,{render:t(h,{variant:"ghost",size:"icon-sm",onMouseDown:t=>{t.preventDefault()},onClick:()=>{const t=z(VERTICAL_ALIGN_OPTIONS,i.verticalAlign);o.history.transaction(()=>{n.forEach(e=>{e.set({verticalAlign:t})})})},"aria-label":d("toolbar.verticalAlign"),children:VERTICAL_ALIGN_ICONS[i.verticalAlign]})}),t(F,{side:"bottom",children:d("toolbar.verticalAlign")})]}),t(S,{label:d("toolbar.bold"),side:"bottom",active:r,onMouseDown:t=>{t.preventDefault()},onClick:()=>{const t=w(i.fontWeight);o.history.transaction(()=>{n.forEach(e=>{e.set({fontWeight:t?"400":"700"})})})},children:t(a,{name:"text.bold",className:"pn:size-4"})}),t(S,{label:d("toolbar.italic"),side:"bottom",active:s,onMouseDown:t=>{t.preventDefault()},onClick:()=>{const t="italic"===i.fontStyle;o.history.transaction(()=>{n.forEach(e=>{t?e.set({fontStyle:"normal"}):e.set({fontStyle:"italic"})})})},children:t(a,{name:"text.italic",className:"pn:size-4"})}),t(S,{label:d("toolbar.underline"),side:"bottom",active:l,onMouseDown:t=>{t.preventDefault()},onClick:()=>{let t=i.textDecoration.split(" ");t.indexOf("underline")>=0?t=t.filter(t=>"underline"!==t):t.push("underline"),o.history.transaction(()=>{n.forEach(e=>{e.set({textDecoration:t.join(" ")})})})},children:t(a,{name:"text.underline",className:"pn:size-4"})}),t(S,{label:d("toolbar.strikethrough"),side:"bottom",active:c,onMouseDown:t=>{t.preventDefault()},onClick:()=>{let t=i.textDecoration.split(" ");t.indexOf("line-through")>=0?t=t.filter(t=>"line-through"!==t):t.push("line-through"),o.history.transaction(()=>{n.forEach(e=>{e.set({textDecoration:t.join(" ")})})})},children:t(a,{name:"text.strikethrough",className:"pn:size-4"})})]})});export const TextTransform=o(({elements:e,store:n})=>{const o="uppercase"==e[0].textTransform;return t("div",{className:"pn:flex pn:items-center pn:gap-0.5",children:t(S,{label:d("toolbar.uppercase"),active:o,onMouseDown:t=>{t.preventDefault()},onClick:()=>{n.history.transaction(()=>{e.forEach(t=>{t.set({textTransform:"uppercase"===t.textTransform?"none":"uppercase"})})})},children:t(a,{name:"text.uppercase",className:"pn:size-4"})})})});export const TextFill=o(({elements:e,store:n})=>t(E,{value:e[0].fill,gradientEnabled:!0,onChange:t=>n.history.transaction(()=>{e.forEach(e=>{e.set({fill:t})})}),store:n}));export const TextSpacing=o(({elements:n,store:o})=>{const i=n[0],r=t=>{o.history.transaction(()=>{n.forEach(e=>{e.set(t)})})},s="number"==typeof i.lineHeight?100*i.lineHeight:120;return e(b,{children:[e(y,{children:[t(N,{render:t(T,{render:t(h,{variant:"ghost",size:"icon-sm","aria-label":d("toolbar.spacing"),children:t(a,{name:"text.spacing",className:"pn:size-5"})})})}),t(F,{side:"bottom",children:d("toolbar.spacing")})]}),e(v,{align:"start",className:"pn:w-[230px] pn:p-[15px]",children:[t(g,{label:d("toolbar.lineHeight"),value:Math.round(s),onChange:t=>r({lineHeight:t/100}),min:50,max:250}),t(g,{label:d("toolbar.letterSpacing"),value:Math.round(100*i.letterSpacing),onChange:t=>r({letterSpacing:t/100}),min:-50,max:250})]})]})});export const TextFilters=A;export const TextAnimations=D;const R={TextFontFamily,TextFontSize,TextFontVariant,TextTransform,TextFill,TextSpacing,TextAiWrite:O,TextFilters:A,TextAnimations:D};export const TextToolbar=o(({store:e,components:n})=>{const o=e.selectedElements,i=["TextFill","TextFontFamily","TextFontSize","TextFontVariant","TextSpacing","TextTransform","TextFilters",f.animationsEnabled&&"TextAnimations",f.aiTextEnabled&&"TextAiWrite"],r=I({type:"text",usedItems:i,components:n});return t(k,{items:r,itemRender:i=>{const r=(null==n?void 0:n[i])||R[i];return r?t(r,{elements:o,element:o[0],store:e},i):null}})});export default TextToolbar;
@@ -1 +1 @@
1
- import{jsx as e,jsxs as t}from"react/jsx-runtime";import i from"react";import{observer as o}from"mobx-react-lite";import{ElementContainer as r,extendToolbar as n}from"./element-container.js";import{Button as s}from"../primitives/button.js";import{clamp as a,firstSliderValue as d}from"../lib/utils.js";import{Input as l}from"../primitives/input.js";import{NumericInput as m}from"../primitives/numeric-input.js";import{SpeedControl as p}from"../primitives/speed-control.js";import{Slider as c}from"../primitives/slider.js";import{Popover as h,PopoverContent as u,PopoverTrigger as v}from"../primitives/popover.js";import{Tooltip as g,TooltipContent as f,TooltipTrigger as x}from"../primitives/tooltip.js";import{AnimationsPicker as b}from"./animations-picker.js";import{flags as w}from"../utils/flags.js";import{getVideoDuration as y,getVideoObjectPreview as C,getVideoSize as V}from"../utils/video.js";import{t as j}from"../utils/l10n.js";import{PolotnoIcon as T}from"../icons/registry.js";export const VideoTrim=o(({element:o})=>{const r=i.useRef(null),[n,a]=i.useState([]);i.useEffect(()=>{a([])},[o.src]);const d=async()=>{if(!o.src){return}if(n.length){return}const{width:e,height:t}=await V(o.src),i=e/t,{src:s}=o,d=r.current.offsetHeight,l=r.current.offsetWidth,m=d*i,p=Math.ceil(l/m),c=await y(s),h=document.createElement("video");h.crossOrigin="anonymous",h.src=s;const u=document.createElement("canvas");u.width=480;try{await new Promise((e,t)=>{h.addEventListener("loadeddata",()=>{const t=h.videoWidth/h.videoHeight;u.height=480/t,e()}),h.addEventListener("error",t)}),a([]);for(let e=0;e<p;e++){const t=e*c/p,i=await C(h,u,t);a(e=>e.concat(i))}}catch(v){console.error("Error generating previews:",v)}},m=(e,t)=>{e.preventDefault();const i=e=>{e.preventDefault();const{clientX:i}=e,{left:n,width:s}=r.current.getBoundingClientRect(),a=(i-n)/s;"start"===t?o.set({startTime:Math.min(o.endTime,Math.max(0,a))}):"end"===t&&o.set({endTime:Math.min(1,Math.max(o.startTime,a))})};window.addEventListener("mousemove",i),window.addEventListener("mouseup",()=>{window.removeEventListener("mousemove",i)})};return t(h,{onOpenChange:e=>{e&&setTimeout(d,0)},children:[e(v,{render:t(s,{variant:"ghost",size:"sm",children:[e(T,{name:"toolbar.trim",className:"pn:size-4"}),"Trim"]})}),e(u,{align:"start",className:"pn:p-2",style:{boxShadow:"none",backgroundColor:"transparent",width:"calc(100vw - 300px)"},children:t("div",{className:"pn:flex pn:items-center",children:[e(l,{type:"number",style:{width:"80px"},value:parseFloat((o.duration*(o.endTime-o.startTime)/1e3).toFixed(2)),step:.1,readOnly:!0}),t("div",{style:{width:"calc(100vw - 420px)",height:"30px",display:"flex",position:"relative",overflow:"hidden",marginLeft:"10px"},ref:r,children:[n.map((t,i)=>e("img",{src:t,style:{width:"auto",height:"100%",objectFit:"cover"}},i)),e("div",{style:{position:"absolute",top:"0",left:0,width:100*o.startTime+"%",height:"30px",backgroundColor:"rgb(0, 0, 0, 0.5)"}}),e("div",{style:{position:"absolute",top:"0",right:"0%",width:100-100*o.endTime+"%",height:"30px",backgroundColor:"rgb(0, 0, 0, 0.5)"}}),e("div",{style:{position:"absolute",top:"0",left:100*o.startTime+"%",width:"10px",height:"30px",borderRadius:"0px",backgroundColor:"rgb(0, 161, 255, 0.9)",cursor:"ew-resize"},onMouseDown:e=>{m(e,"start")}}),e("div",{style:{position:"absolute",top:"0",right:100-100*o.endTime+"%",width:"10px",height:"30px",borderRadius:"0px",backgroundColor:"rgb(0, 161, 255, 0.9)",cursor:"ew-resize"},onMouseDown:e=>{m(e,"end")}})]})]})})]})});const E=o(({element:i})=>{const o=Math.round(100*i.volume),r=e=>{i.set({volume:e/100})};return t(h,{children:[t(g,{children:[e(x,{render:e(v,{render:e(s,{variant:"ghost",size:"icon-sm","aria-label":j("toolbar.volume"),children:e(T,{name:"action.unmuted",className:"pn:size-4"})})})}),e(f,{children:j("toolbar.volume")})]}),e(u,{style:{padding:"10px",width:"250px"},align:"start",children:t("div",{style:{display:"flex",width:"100%",justifyContent:"space-between"},children:[e("div",{style:{paddingTop:"7px",paddingLeft:"10px",width:"calc(100% - 80px)"},children:e(c,{value:[o],onValueChange:e=>{r(d(e))},min:0,max:100,step:1})}),e(m,{value:o,onValueChange:e=>{r(a(e,0,100))},style:{width:"50px",padding:"0 5px",marginLeft:"10px"},min:0,max:100})]})})]})}),z=o(({element:i})=>t(h,{children:[t(g,{children:[e(x,{render:e(v,{render:t(s,{variant:"ghost",size:"sm","aria-label":j("toolbar.speed"),children:[e(T,{name:"toolbar.duration",className:"pn:size-4"}),i.speed,"×"]})})}),e(f,{children:j("toolbar.speed")})]}),t(u,{style:{padding:"10px",width:"250px"},align:"start",children:[e("div",{style:{fontSize:"12px",marginBottom:"8px"},children:j("toolbar.speed")}),e(p,{value:i.speed,onChange:e=>i.set({speed:e})})]})]}));export const VideoClip=o(({element:t,store:i})=>t.contentEditable?t.clipSrc?e(s,{variant:"ghost",size:"sm",onClickCapture:()=>{t.set({clipSrc:""})},children:j("toolbar.removeClip")}):e(s,{variant:"ghost",size:"sm",onClickCapture:e=>{e.stopPropagation(),i.openSidePanel("image-clip")},children:j("toolbar.clip")}):null);const k={VideoTrim,VideoAnimations:b,VideoVolume:E,VideoSpeed:z,VideoClip};export const VideoToolbar=o(({store:t,components:i})=>{const o=t.selectedElements,s=["VideoTrim","VideoVolume","VideoSpeed","VideoClip",w.animationsEnabled&&"VideoAnimations"],a=n({type:"video",usedItems:s,components:i});return e(r,{items:a,itemRender:r=>{const n=i[r]||k[r];return e(n,{elements:o,element:o[0],store:t},r)}})});export default VideoToolbar;
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import i from"react";import{observer as o}from"mobx-react-lite";import{ElementContainer as r,extendToolbar as n}from"./element-container.js";import{Button as s}from"../primitives/button.js";import{clamp as a,firstSliderValue as d}from"../lib/utils.js";import{NumericInput as l}from"../primitives/numeric-input.js";import{SpeedControl as m}from"../primitives/speed-control.js";import{Slider as p}from"../primitives/slider.js";import{Popover as c,PopoverContent as u,PopoverTrigger as h}from"../primitives/popover.js";import{Tooltip as g,TooltipContent as v,TooltipTrigger as x}from"../primitives/tooltip.js";import{AnimationsPicker as f}from"./animations-picker.js";import{flags as b}from"../utils/flags.js";import{getVideoDuration as w,getVideoObjectPreview as y,getVideoSize as V}from"../utils/video.js";import{t as C}from"../utils/l10n.js";import{PolotnoIcon as T}from"../icons/registry.js";export const VideoTrim=o(({element:o})=>{const r=i.useRef(null),[n,a]=i.useState([]);i.useEffect(()=>{a([])},[o.src]);const d=async()=>{if(!o.src){return}if(n.length){return}const{width:e,height:t}=await V(o.src),i=e/t,{src:s}=o,d=r.current.offsetHeight,l=r.current.offsetWidth,m=d*i,p=Math.ceil(l/m),c=await w(s),u=document.createElement("video");u.crossOrigin="anonymous",u.src=s;const h=document.createElement("canvas");h.width=480;try{await new Promise((e,t)=>{u.addEventListener("loadeddata",()=>{const t=u.videoWidth/u.videoHeight;h.height=480/t,e()}),u.addEventListener("error",t)}),a([]);for(let e=0;e<p;e++){const t=e*c/p,i=await y(u,h,t);a(e=>e.concat(i))}}catch(g){console.error("Error generating previews:",g)}},l=(e,t)=>{e.preventDefault();const i=e=>{e.preventDefault();const{clientX:i}=e,{left:n,width:s}=r.current.getBoundingClientRect(),a=(i-n)/s;"start"===t?o.set({startTime:Math.min(o.endTime,Math.max(0,a))}):"end"===t&&o.set({endTime:Math.min(1,Math.max(o.startTime,a))})},n=()=>{window.removeEventListener("mousemove",i),window.removeEventListener("mouseup",n)};window.addEventListener("mousemove",i),window.addEventListener("mouseup",n)};return t(c,{onOpenChange:e=>{e&&setTimeout(d,0)},children:[e(h,{render:t(s,{variant:"ghost",size:"sm",children:[e(T,{name:"toolbar.trim",className:"pn:size-4"}),"Trim"]})}),e(u,{align:"start",className:"pn:p-3",style:{width:"600px"},children:t("div",{className:"pn:flex pn:items-center",children:[e("div",{className:"pn:flex pn:h-[30px] pn:items-center pn:rounded-md pn:border pn:border-input pn:px-3 pn:text-sm pn:tabular-nums",children:(o.duration*(o.endTime-o.startTime)/1e3).toFixed(2)}),e("span",{className:"pn:ml-1 pn:text-xs pn:text-muted-foreground",children:C("toolbar.seconds")}),t("div",{style:{flex:1,height:"30px",display:"flex",position:"relative",overflow:"hidden",marginLeft:"10px",borderRadius:"4px"},ref:r,children:[n.map((t,i)=>e("img",{src:t,style:{width:"auto",height:"100%",objectFit:"cover"}},i)),e("div",{style:{position:"absolute",top:"0",left:0,width:100*o.startTime+"%",height:"30px",backgroundColor:"rgb(0, 0, 0, 0.5)"}}),e("div",{style:{position:"absolute",top:"0",right:"0%",width:100-100*o.endTime+"%",height:"30px",backgroundColor:"rgb(0, 0, 0, 0.5)"}}),e("div",{style:{position:"absolute",top:"0",left:100*o.startTime+"%",width:"10px",height:"30px",borderRadius:"0px",backgroundColor:"rgb(0, 161, 255, 0.9)",cursor:"ew-resize"},onMouseDown:e=>{l(e,"start")}}),e("div",{style:{position:"absolute",top:"0",right:100-100*o.endTime+"%",width:"10px",height:"30px",borderRadius:"0px",backgroundColor:"rgb(0, 161, 255, 0.9)",cursor:"ew-resize"},onMouseDown:e=>{l(e,"end")}})]})]})})]})});const j=o(({element:i})=>{const o=Math.round(100*i.volume),r=e=>{i.set({volume:e/100})};return t(c,{children:[t(g,{children:[e(x,{render:e(h,{render:e(s,{variant:"ghost",size:"icon-sm","aria-label":C("toolbar.volume"),children:e(T,{name:"action.unmuted",className:"pn:size-4"})})})}),e(v,{children:C("toolbar.volume")})]}),e(u,{style:{padding:"10px",width:"250px"},align:"start",children:t("div",{style:{display:"flex",width:"100%",justifyContent:"space-between"},children:[e("div",{style:{paddingTop:"7px",paddingLeft:"10px",width:"calc(100% - 80px)"},children:e(p,{value:[o],onValueChange:e=>{r(d(e))},min:0,max:100,step:1})}),e(l,{value:o,onValueChange:e=>{r(a(e,0,100))},style:{width:"50px",padding:"0 5px",marginLeft:"10px"},min:0,max:100})]})})]})}),E=o(({element:i})=>t(c,{children:[t(g,{children:[e(x,{render:e(h,{render:t(s,{variant:"ghost",size:"sm","aria-label":C("toolbar.speed"),children:[e(T,{name:"toolbar.duration",className:"pn:size-4"}),i.speed,"×"]})})}),e(v,{children:C("toolbar.speed")})]}),t(u,{style:{padding:"10px",width:"250px"},align:"start",children:[e("div",{style:{fontSize:"12px",marginBottom:"8px"},children:C("toolbar.speed")}),e(m,{value:i.speed,onChange:e=>i.set({speed:e})})]})]}));export const VideoClip=o(({element:t,store:i})=>t.contentEditable?t.clipSrc?e(s,{variant:"ghost",size:"sm",onClickCapture:()=>{t.set({clipSrc:""})},children:C("toolbar.removeClip")}):e(s,{variant:"ghost",size:"sm",onClickCapture:e=>{e.stopPropagation(),i.openSidePanel("image-clip")},children:C("toolbar.clip")}):null);const z={VideoTrim,VideoAnimations:f,VideoVolume:j,VideoSpeed:E,VideoClip};export const VideoToolbar=o(({store:t,components:i})=>{const o=t.selectedElements,s=["VideoTrim","VideoVolume","VideoSpeed","VideoClip",b.animationsEnabled&&"VideoAnimations"],a=n({type:"video",usedItems:s,components:i});return e(r,{items:a,itemRender:r=>{const n=i[r]||z[r];return e(n,{elements:o,element:o[0],store:t},r)}})});export default VideoToolbar;