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.
- package/blueprint/side-panel/select-video.d.ts +10 -0
- package/blueprint/toolbar/html-toolbar.js +2 -2
- package/canvas/drawing-layer.d.ts +3 -2
- package/canvas/drawing-layer.js +1 -1
- package/canvas/element.js +1 -1
- package/canvas/hotkeys.js +1 -1
- package/canvas/page-controls.js +1 -1
- package/canvas/page.js +1 -1
- package/canvas/quill-font-formats.js +1 -1
- package/canvas/render-tag-element.js +1 -1
- package/canvas/rich-editor.d.ts +3 -1
- package/canvas/rich-editor.js +16 -3
- package/canvas/rules.js +1 -1
- package/canvas/text-element/font-specs-loader.d.ts +3 -0
- package/canvas/text-element/font-specs-loader.js +1 -0
- package/canvas/workspace-canvas.js +1 -1
- package/config.d.ts +1 -1
- package/config.js +1 -1
- package/icons/registry.d.ts +2 -0
- package/icons/registry.js +1 -1
- package/model/figure-model.d.ts +5 -0
- package/model/gif-model.d.ts +5 -0
- package/model/group-model.d.ts +40 -0
- package/model/group-model.js +1 -1
- package/model/image-model.d.ts +5 -0
- package/model/line-model.d.ts +5 -0
- package/model/page-model.d.ts +56 -0
- package/model/page-model.js +1 -1
- package/model/shape-model.d.ts +5 -0
- package/model/shape-model.js +1 -1
- package/model/store.d.ts +521 -0
- package/model/store.js +1 -1
- package/model/svg-model.d.ts +5 -0
- package/model/table-model.d.ts +5 -0
- package/model/text-model.d.ts +5 -0
- package/model/video-model.d.ts +5 -0
- package/package.json +4 -3
- package/pages-timeline/current-time.js +1 -1
- package/pages-timeline/element-track.js +1 -1
- package/pages-timeline/elements.js +1 -1
- package/pages-timeline/page-preview.js +1 -1
- package/pages-timeline/play-button.js +1 -1
- package/polotno.bundle.js +206 -130
- package/side-panel/select-video.d.ts +10 -0
- package/side-panel/size-panel.js +1 -1
- package/themes/carbon.css +157 -0
- package/toolbar/download-button.js +1 -1
- package/toolbar/html-toolbar.js +4 -4
- package/toolbar/image-toolbar.js +1 -1
- package/toolbar/text-toolbar.js +1 -1
- package/toolbar/video-toolbar.js +1 -1
- package/ui.css +1 -1
- package/utils/fonts.js +1 -1
- package/utils/l10n.d.ts +8 -0
- package/utils/l10n.js +1 -1
- package/utils/rich-text-html.d.ts +12 -0
- package/utils/rich-text-html.js +1 -1
- package/utils/split-element.d.ts +2 -0
- package/utils/split-element.js +1 -0
- package/utils/text-format-state.js +1 -1
- package/utils/text-format.d.ts +2 -2
- package/utils/text-format.js +1 -1
- package/utils/text.js +1 -1
- package/utils/timeline.d.ts +3 -0
- package/utils/timeline.js +1 -1
- package/utils/to-html.js +1 -1
- package/utils/to-pptx.js +1 -1
- package/utils/to-svg.js +1 -1
- 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
|
} & {
|
package/side-panel/size-panel.js
CHANGED
|
@@ -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
|
|
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
|
|
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;
|
package/toolbar/html-toolbar.js
CHANGED
|
@@ -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
|
|
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
|
-
`,
|
|
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
|
-
${
|
|
22
|
+
${H}:focus-within & {
|
|
23
23
|
display: none;
|
|
24
24
|
}
|
|
25
|
-
`,
|
|
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)}})});
|
package/toolbar/image-toolbar.js
CHANGED
|
@@ -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
|
|
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;
|
package/toolbar/text-toolbar.js
CHANGED
|
@@ -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;
|
package/toolbar/video-toolbar.js
CHANGED
|
@@ -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{
|
|
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;
|