polotno 4.0.2 → 4.1.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 (51) hide show
  1. package/blueprint/side-panel/select-video.d.ts +2 -0
  2. package/canvas/audio.js +1 -1
  3. package/canvas/context-menu/context-menu.js +1 -1
  4. package/canvas/page.js +1 -1
  5. package/canvas/use-mediabunny-video.js +1 -1
  6. package/canvas/use-transformer-snap.js +1 -1
  7. package/canvas/video-element.js +1 -1
  8. package/model/audio-model.d.ts +2 -0
  9. package/model/audio-model.js +1 -1
  10. package/model/group-model.d.ts +1 -0
  11. package/model/page-model.d.ts +1 -0
  12. package/model/schema.d.ts +20 -253
  13. package/model/store.d.ts +12 -0
  14. package/model/store.js +1 -1
  15. package/model/video-model.d.ts +1 -0
  16. package/model/video-model.js +1 -1
  17. package/package.json +11 -10
  18. package/pages-timeline/audio-track.js +1 -1
  19. package/pages-timeline/pages-timeline.js +1 -1
  20. package/polotno.bundle.js +118 -118
  21. package/primitives/dropdown-menu.d.ts +1 -0
  22. package/primitives/dropdown-menu.js +1 -1
  23. package/primitives/floating-control.d.ts +1 -0
  24. package/primitives/floating-control.js +2 -0
  25. package/primitives/overflow-list.d.ts +2 -1
  26. package/primitives/overflow-list.js +1 -1
  27. package/primitives/separator.js +1 -1
  28. package/primitives/speed-control.d.ts +7 -0
  29. package/primitives/speed-control.js +1 -0
  30. package/side-panel/select-video.d.ts +2 -0
  31. package/side-panel/side-panel.js +1 -1
  32. package/side-panel/size-panel.js +1 -1
  33. package/side-panel/tab-button.js +1 -1
  34. package/toolbar/element-container.js +1 -1
  35. package/toolbar/figure-toolbar.js +1 -1
  36. package/toolbar/html-toolbar.js +2 -2
  37. package/toolbar/line-toolbar.js +1 -1
  38. package/toolbar/sketch.js +1 -1
  39. package/toolbar/svg-toolbar.js +1 -1
  40. package/toolbar/table-toolbar.js +1 -1
  41. package/toolbar/text-toolbar.js +1 -1
  42. package/toolbar/video-toolbar.js +1 -1
  43. package/toolbar/zoom-buttons.js +1 -1
  44. package/ui.css +1 -1
  45. package/utils/l10n.d.ts +2 -0
  46. package/utils/l10n.js +1 -1
  47. package/utils/text-format-state.d.ts +1 -0
  48. package/utils/text-format-state.js +1 -1
  49. package/utils/timeline.d.ts +11 -0
  50. package/utils/timeline.js +1 -0
  51. package/utils/validate-key.js +1 -1
package/model/schema.d.ts CHANGED
@@ -1,253 +1,20 @@
1
- export interface Store {
2
- schemaVersion: number;
3
- width: number;
4
- height: number;
5
- unit: 'px' | 'pt' | 'mm' | 'cm' | 'in';
6
- dpi: number;
7
- custom?: unknown;
8
- fonts: Font[];
9
- pages: Page[];
10
- audios: Audio[];
11
- }
12
- export interface FontStyleVariant {
13
- src: string;
14
- fontStyle?: string;
15
- fontWeight?: string;
16
- }
17
- export interface Font {
18
- fontFamily: string;
19
- url?: string;
20
- styles?: FontStyleVariant[];
21
- }
22
- export interface Audio {
23
- id: string;
24
- src: string;
25
- duration: number;
26
- startTime: number;
27
- endTime: number;
28
- volume: number;
29
- delay: number;
30
- }
31
- export interface Page {
32
- id: string;
33
- width: number | 'auto';
34
- height: number | 'auto';
35
- background: string;
36
- bleed: number;
37
- custom?: unknown;
38
- duration: number;
39
- children: Element[];
40
- }
41
- export type Element = TextElement | ImageElement | SVGElement | LineElement | VideoElement | FigureElement | GifElement | GroupElement | TableElement;
42
- export interface Animation {
43
- delay: number;
44
- duration: number;
45
- enabled: boolean;
46
- type: 'enter' | 'exit' | 'loop';
47
- name: string;
48
- data: unknown;
49
- }
50
- interface ShapeAttributes {
51
- id: string;
52
- type: string;
53
- name?: string;
54
- custom?: unknown;
55
- x: number;
56
- y: number;
57
- width: number;
58
- height: number;
59
- rotation: number;
60
- opacity: number;
61
- animations: Animation[];
62
- blurEnabled: boolean;
63
- blurRadius: number;
64
- brightnessEnabled: boolean;
65
- brightness: number;
66
- sepiaEnabled: boolean;
67
- grayscaleEnabled: boolean;
68
- filters: Record<string, {
69
- intensity: number;
70
- }>;
71
- shadowEnabled: boolean;
72
- shadowBlur: number;
73
- shadowOffsetX: number;
74
- shadowOffsetY: number;
75
- shadowColor: string;
76
- shadowOpacity: number;
77
- visible: boolean;
78
- draggable: boolean;
79
- resizable: boolean;
80
- selectable: boolean;
81
- contentEditable: boolean;
82
- styleEditable: boolean;
83
- alwaysOnTop: boolean;
84
- showInExport: boolean;
85
- }
86
- export interface GroupElement {
87
- id: string;
88
- type: 'group';
89
- name?: string;
90
- custom?: unknown;
91
- opacity?: number;
92
- visible?: boolean;
93
- selectable?: boolean;
94
- removable?: boolean;
95
- alwaysOnTop?: boolean;
96
- showInExport?: boolean;
97
- animations?: Animation[];
98
- children: Element[];
99
- }
100
- export interface TextElement extends ShapeAttributes {
101
- type: 'text';
102
- text: string;
103
- placeholder: string;
104
- fontSize: number;
105
- fontFamily: string;
106
- fontStyle: string;
107
- fontWeight: string;
108
- textDecoration: string;
109
- textTransform: string;
110
- fill: string;
111
- align: 'left' | 'center' | 'right' | 'justify';
112
- height: number;
113
- verticalAlign: string;
114
- strokeWidth: number;
115
- stroke: string;
116
- lineHeight: number | string;
117
- letterSpacing: number;
118
- backgroundEnabled: boolean;
119
- backgroundColor: string;
120
- backgroundOpacity: number;
121
- backgroundCornerRadius: number;
122
- backgroundPadding: number;
123
- curveEnabled: boolean;
124
- curvePower: number;
125
- }
126
- interface BaseImageProps {
127
- src: string;
128
- cropX: number;
129
- cropY: number;
130
- cropWidth: number;
131
- cropHeight: number;
132
- cornerRadius: number;
133
- flipX: boolean;
134
- flipY: boolean;
135
- clipSrc: string;
136
- borderColor: string;
137
- borderSize: number;
138
- keepRatio: boolean;
139
- stretchEnabled: boolean;
140
- }
141
- export interface ImageElement extends ShapeAttributes, BaseImageProps {
142
- type: 'image';
143
- }
144
- export interface SVGElement extends ShapeAttributes {
145
- type: 'svg';
146
- src: string;
147
- maskSrc: string;
148
- cropX: number;
149
- cropY: number;
150
- cropWidth: number;
151
- cropHeight: number;
152
- keepRatio: boolean;
153
- stretchEnabled: boolean;
154
- flipX: boolean;
155
- flipY: boolean;
156
- borderColor: string;
157
- borderSize: number;
158
- cornerRadius: number;
159
- colorsReplace: Record<string, string>;
160
- }
161
- export interface LineElement extends ShapeAttributes {
162
- type: 'line';
163
- color: string;
164
- dash: number[];
165
- startHead: string;
166
- endHead: string;
167
- }
168
- export interface FigureElement extends ShapeAttributes {
169
- type: 'figure';
170
- subType: string;
171
- fill: string;
172
- dash: number[];
173
- strokeWidth: number;
174
- stroke: string;
175
- cornerRadius: number;
176
- }
177
- export interface GifElement extends ShapeAttributes, BaseImageProps {
178
- type: 'gif';
179
- duration: number;
180
- keepRatio: boolean;
181
- }
182
- export interface VideoElement extends ShapeAttributes, BaseImageProps {
183
- type: 'video';
184
- duration: number;
185
- startTime: number;
186
- endTime: number;
187
- volume: number;
188
- }
189
- export interface BorderSide {
190
- color?: string;
191
- width?: number;
192
- style?: 'solid' | 'dashed' | 'dotted' | 'none';
193
- }
194
- export interface CellBorders {
195
- top?: BorderSide;
196
- right?: BorderSide;
197
- bottom?: BorderSide;
198
- left?: BorderSide;
199
- }
200
- export interface TableCell {
201
- id: string;
202
- type: 'tablecell';
203
- text?: string;
204
- opacity?: number;
205
- rowSpan?: number;
206
- colSpan?: number;
207
- mergedInto?: string;
208
- name?: string;
209
- custom?: unknown;
210
- borders?: CellBorders;
211
- fontSize?: number;
212
- fontFamily?: string;
213
- fontWeight?: string;
214
- fontStyle?: string;
215
- textDecoration?: string;
216
- textTransform?: string;
217
- fill?: string;
218
- align?: string;
219
- verticalAlign?: string;
220
- lineHeight?: number | string;
221
- letterSpacing?: number;
222
- strokeWidth?: number;
223
- stroke?: string;
224
- cellBackground?: string;
225
- cellPadding?: number;
226
- }
227
- export interface TableElement extends Omit<ShapeAttributes, 'blurEnabled' | 'blurRadius' | 'brightnessEnabled' | 'brightness' | 'sepiaEnabled' | 'grayscaleEnabled' | 'filters' | 'shadowEnabled' | 'shadowBlur' | 'shadowOffsetX' | 'shadowOffsetY' | 'shadowColor' | 'shadowOpacity'> {
228
- type: 'table';
229
- rows: number;
230
- cols: number;
231
- colWidths: number[];
232
- rowHeights: number[];
233
- cells: TableCell[];
234
- borderColor: string;
235
- borderWidth: number;
236
- borderStyle: 'solid' | 'dashed' | 'dotted' | 'none';
237
- fontSize: number;
238
- fontFamily: string;
239
- fontWeight: string;
240
- fontStyle: string;
241
- textDecoration: string;
242
- textTransform: string;
243
- fill: string;
244
- align: string;
245
- verticalAlign: string;
246
- lineHeight: number | string;
247
- letterSpacing: number;
248
- strokeWidth: number;
249
- stroke: string;
250
- cellBackground: string;
251
- cellPadding: number;
252
- }
253
- export {};
1
+ import type * as Schema from '@polotno/schema';
2
+ export type Store = Schema.Design;
3
+ export type FontStyleVariant = Schema.FontStyleVariant;
4
+ export type Font = Schema.Font;
5
+ export type Audio = Schema.Audio;
6
+ export type Page = Schema.Page;
7
+ export type Element = Schema.Element;
8
+ export type Animation = Schema.Animation;
9
+ export type GroupElement = Schema.GroupElement;
10
+ export type TextElement = Schema.TextElement;
11
+ export type ImageElement = Schema.ImageElement;
12
+ export type SVGElement = Schema.SVGElement;
13
+ export type LineElement = Schema.LineElement;
14
+ export type FigureElement = Schema.FigureElement;
15
+ export type GifElement = Schema.GifElement;
16
+ export type VideoElement = Schema.VideoElement;
17
+ export type BorderSide = Schema.BorderSide;
18
+ export type CellBorders = Schema.CellBorders;
19
+ export type TableCell = Schema.TableCell;
20
+ export type TableElement = Schema.TableElement;
package/model/store.d.ts CHANGED
@@ -801,6 +801,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
801
801
  startTime: import("mobx-state-tree").IType<number | undefined, number, number>;
802
802
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
803
803
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
804
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
804
805
  }, {
805
806
  readonly page: any;
806
807
  readonly store: any;
@@ -1969,6 +1970,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
1969
1970
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
1970
1971
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
1971
1972
  delay: import("mobx-state-tree").IType<number | undefined, number, number>;
1973
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
1972
1974
  custom: import("mobx-state-tree").IType<any, any, any>;
1973
1975
  }, {
1974
1976
  readonly visibleDuration: number;
@@ -1981,6 +1983,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
1981
1983
  endTime: number;
1982
1984
  volume: number;
1983
1985
  delay: number;
1986
+ speed: number;
1984
1987
  custom: any;
1985
1988
  };
1986
1989
  } & {
@@ -2792,6 +2795,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
2792
2795
  startTime: import("mobx-state-tree").IType<number | undefined, number, number>;
2793
2796
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
2794
2797
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
2798
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
2795
2799
  }, {
2796
2800
  readonly page: any;
2797
2801
  readonly store: any;
@@ -4697,6 +4701,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
4697
4701
  startTime: import("mobx-state-tree").IType<number | undefined, number, number>;
4698
4702
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
4699
4703
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
4704
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
4700
4705
  }, {
4701
4706
  readonly page: any;
4702
4707
  readonly store: any;
@@ -6890,6 +6895,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
6890
6895
  startTime: import("mobx-state-tree").IType<number | undefined, number, number>;
6891
6896
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
6892
6897
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
6898
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
6893
6899
  }, {
6894
6900
  readonly page: any;
6895
6901
  readonly store: any;
@@ -8795,6 +8801,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
8795
8801
  startTime: import("mobx-state-tree").IType<number | undefined, number, number>;
8796
8802
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
8797
8803
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
8804
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
8798
8805
  }, {
8799
8806
  readonly page: any;
8800
8807
  readonly store: any;
@@ -10701,6 +10708,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
10701
10708
  startTime: import("mobx-state-tree").IType<number | undefined, number, number>;
10702
10709
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
10703
10710
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
10711
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
10704
10712
  }, {
10705
10713
  readonly page: any;
10706
10714
  readonly store: any;
@@ -12606,6 +12614,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
12606
12614
  startTime: import("mobx-state-tree").IType<number | undefined, number, number>;
12607
12615
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
12608
12616
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
12617
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
12609
12618
  }, {
12610
12619
  readonly page: any;
12611
12620
  readonly store: any;
@@ -14544,6 +14553,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
14544
14553
  startTime: import("mobx-state-tree").IType<number | undefined, number, number>;
14545
14554
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
14546
14555
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
14556
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
14547
14557
  }, {
14548
14558
  readonly page: any;
14549
14559
  readonly store: any;
@@ -16449,6 +16459,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
16449
16459
  startTime: import("mobx-state-tree").IType<number | undefined, number, number>;
16450
16460
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
16451
16461
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
16462
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
16452
16463
  }, {
16453
16464
  readonly page: any;
16454
16465
  readonly store: any;
@@ -17675,6 +17686,7 @@ export declare const Store: import("mobx-state-tree").IModelType<{
17675
17686
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
17676
17687
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
17677
17688
  delay: import("mobx-state-tree").IType<number | undefined, number, number>;
17689
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
17678
17690
  custom: import("mobx-state-tree").IType<any, any, any>;
17679
17691
  }>[];
17680
17692
  unit: UnitType;
package/model/store.js CHANGED
@@ -1 +1 @@
1
- var e=this&&this.__rest||function(e,t){var i={};for(var o in e){Object.prototype.hasOwnProperty.call(e,o)&&t.indexOf(o)<0&&(i[o]=e[o])}if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var n=0;for(o=Object.getOwnPropertySymbols(e);n<o.length;n++){t.indexOf(o[n])<0&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(i[o[n]]=e[o[n]])}}return i};import{applySnapshot as t,cast as i,destroy as o,detach as n,getSnapshot as a,onSnapshot as s,setLivelinessChecking as r,types as l}from"mobx-state-tree";import{UndoManager as d}from"./history.js";import{nanoid as c}from"nanoid";import p from"konva";import{computed as g}from"mobx";import{downloadFile as m}from"../utils/download.js";import{getJsPDF as u}from"../utils/pdf.js";import{createGIF as f}from"../utils/gif-lib.js";import{validateKey as h,setKey as b}from"../utils/validate-key.js";import*as y from"../utils/fonts.js";import{flags as v}from"../utils/flags.js";import{addDpiMetadataToImage as P}from"../utils/image-dpi.js";import{nodeToCanvas as w}from"../utils/canvas.js";import{whenLoaded as E}from"../utils/loader.js";import{pxToUnit as x}from"../utils/unit.js";import{deepEqual as I}from"../utils/deep-equal.js";import{waitTillAvailable as _}from"../utils/wait.js";import{jsonToHTML as k}from"../utils/to-html.js";import{jsonToSVG as S}from"../utils/to-svg.js";import{Page as T}from"./page-model.js";import{forEveryChild as O,forEveryNode as j}from"./group-model.js";import{Audio as R}from"./audio-model.js";r("ignore");export const Font=l.model("Font",{fontFamily:l.string,url:l.optional(l.string,""),styles:l.frozen()}).preProcessSnapshot(e=>Object.assign(Object.assign({},e),{fontFamily:e.fontFamily||e.name}));export const ROLES={ADMIN:"admin",VIEWER:"viewer"};export const Store=l.model("Store",{role:"",pages:l.array(T),fonts:l.array(Font),audios:l.array(R),width:1080,height:1080,currentTime:0,isPlaying:!1,scale:1,scaleToFit:1,unit:l.optional(l.enumeration("UnitType",["pt","mm","cm","in","px"]),"px"),dpi:72,schemaVersion:3,bleedVisible:!1,rulesVisible:!1,distanceGuidesVisible:!1,openedSidePanel:"",previousOpenedSidePanel:"",custom:l.frozen(),tool:l.optional(l.enumeration("Tool",["selection","draw","pan","text","eraser"]),"selection"),toolOptions:l.optional(l.model({brushType:l.optional(l.enumeration("BrushType",["brush","highlighter"]),"brush"),strokeWidth:l.optional(l.number,5),stroke:l.optional(l.string,"#000000"),opacity:l.optional(l.number,1)}),{}),selectedElementsIds:l.array(l.string),animatedElementsIds:l.array(l.string),history:l.optional(d,{targetPath:"../pages"}),_elementsPixelRatio:Math.min(2,"undefined"!=typeof window&&window.devicePixelRatio||1),_activePageId:"",_selectedPagesIds:l.array(l.string),_forceShowCredit:!1,_validated:!1}).views(e=>{const t=g(()=>{const t={};return j({children:e.pages},e=>(t[e.id]=e,!1)),t},{keepAlive:!0});return{get _idsMap(){return t.get()}}}).views(e=>({get _bleedVisible(){return console.warn("store._bleedVisible is deprecated. Please use store.bleedVisible instead."),e.bleedVisible},get selectedElements(){return e.selectedElementsIds.map(t=>e._idsMap[t]).filter(e=>!!e)},get children(){return e.pages},get selectedShapes(){const e=[];return O({children:this.selectedElements},t=>{"group"!==t.type&&e.push(t)}),e},get activePage(){return e.pages.slice().find(t=>t.id===e._activePageId)||(e.pages.length?e.pages[0]:null)},get selectedPages(){return e._selectedPagesIds.map(t=>e.pages.find(e=>e.id===t))},get duration(){let t=0;return e.pages.forEach(e=>{t+=e.duration}),t},get _hasCroppedImages(){return this.find(e=>"image"===e.type&&e._cropModeEnabled)},find(t){let i;return j({children:e.pages},e=>{if(!i&&t(e)){return i=e,!0}}),i},getElementById:t=>e._idsMap[t]})).actions(r=>{let l=0,d=null,g=!1;const b={afterCreate(){r.history.canUndo},setCurrentTime(e){r.currentTime=e},_togglePlaying(e=!r.isPlaying){r.isPlaying=e},play({animatedElementsIds:e=[],startTime:t=0,currentTime:o=0,endTime:n=r.duration,repeat:a=!1}={}){o&&(console.warn("currentTime property of store.play() is deprecated. Please use startTime instead."),t=o),r.animatedElementsIds=i(e),r.currentTime=t,r.isPlaying=!0,l=Date.now(),d=n,g=a,requestAnimationFrame(()=>b.seek())},checkActivePage(){let e=0;for(const t of r.pages){if(r.currentTime>=t.startTime&&r.currentTime<t.startTime+t.duration){b.selectPage(t.id);break}e+=t.duration}},seek(){if(!r.isPlaying){return}const e=Date.now(),t=e-l;l=e,r.currentTime+=t,b.checkActivePage();const i=d||r.duration;r.isPlaying&&r.currentTime<i?requestAnimationFrame(()=>b.seek()):r.isPlaying&&g?(r.currentTime=0,requestAnimationFrame(()=>b.seek())):b.stop()},stop(){r.isPlaying=!1,r.currentTime=0,r.animatedElementsIds=i([]),b.checkActivePage()},__(){r._validated||(h(r._forceShowCredit),r._validated=!0)},set(e){Object.assign(r,e)},setUnit({unit:e,dpi:t}){r.unit=e||r.unit,r.dpi=t||r.dpi},setRole(e){r.role=e},setTool(e){r.tool=e},setToolOptions(e){Object.assign(r.toolOptions,e)},addPage(e){const t=T.create(Object.assign({id:c(10)},e));return r.pages.push(t),r._activePageId=t.id,t},selectPage(e){r._activePageId=e,1===r._selectedPagesIds.length&&(r._selectedPagesIds=i([e]))},selectPages(e){r._selectedPagesIds=i(e),1===r._selectedPagesIds.length&&(r._activePageId=r._selectedPagesIds[0])},selectElements(e){const t=e.map(e=>r.getElementById(e)).filter(e=>!!e);t.sort((e,t)=>{var i,o,n,a;return(null!==(o=null===(i=e.parent)||void 0===i?void 0:i.children.indexOf(e))&&void 0!==o?o:0)-(null!==(a=null===(n=t.parent)||void 0===n?void 0:n.children.indexOf(t))&&void 0!==a?a:0)}),r.selectedElementsIds=i(t.map(e=>e.id))},toggleBleed(e){r.bleedVisible=null!=e?e:!r.bleedVisible},toggleRulers(e){r.rulesVisible=null!=e?e:!r.rulesVisible},toggleDistanceGuides(e){r.distanceGuidesVisible=null!=e?e:!r.distanceGuidesVisible},openSidePanel(e){r.openedSidePanel!==e&&(r.previousOpenedSidePanel=r.openedSidePanel,r.openedSidePanel=e)},restoreSidePanel(){const e=r.previousOpenedSidePanel;e&&e!==r.openedSidePanel?r.openedSidePanel=e:r.openedSidePanel="photos"},setScale(e){r.scale=e},_setScaleToFit(e){r.scaleToFit=e},setElementsPixelRatio(e){r._elementsPixelRatio=e},setSize(e,t,i){r.pages.forEach(o=>{o.setSize({width:e,height:t,useMagic:i,softChange:!0})}),r.width=e,r.height=t},setPageZIndex(e,t){const i=r.pages.find(t=>t.id===e);i&&(n(i),r.pages.remove(i),r.pages.splice(t,0,i))},deletePages(e){const t=r.pages.indexOf(r.activePage);e.forEach(e=>{const t=r.pages.find(t=>t.id===e);o(t)});const n=Math.min(r.pages.length-1,t),a=r.pages[n];a&&(r._activePageId=a.id),r.selectedElementsIds=i(r.selectedElementsIds.filter(e=>r.getElementById(e)))},groupElements(e,t={}){const o=e.map(e=>r.getElementById(e)).filter(e=>!!e);if(!o.length){return}const a=o[0].parent;if(!a){return}if(!o.every(e=>e.parent===a)){return void console.warn("store.groupElements: refusing to group elements that do not share a parent. Pass ids whose elements all live under the same page or the same group.")}o.forEach(e=>n(e));const s=a.children.reduce((e,t)=>{var i;if("group"===t.type){const o=null===(i=t.name)||void 0===i?void 0:i.match(/group-(\d+)/);if(o){const t=parseInt(o[1],10);return Math.max(e,t)}}return e},0),l=Object.assign({id:c(10),name:`group-${s+1}`,children:o,type:"group"},t);return a.children.push(l),r.selectedElementsIds=i([l.id]),a.children.find(e=>e.id===l.id)},ungroupElements(e){const t=e.map(e=>r.getElementById(e)),o=[];t.forEach(e=>{if(e&&"group"===e.type){const t=e.parent;if(!t){return}const i=t.children.indexOf(e);e.children.forEach(e=>{o.push(e.id)}),e.children.slice().forEach(e=>{n(e),t.children.push(e)}),t.children.splice(i,1)}}),r.selectedElementsIds=i(o)},deleteElements(e){const t=[];r.find(i=>(e.includes(i.id)&&t.push(i),!1)),t.forEach(e=>{o(e)}),r.selectedElementsIds=i(r.selectedElementsIds.filter(e=>r.getElementById(e)))},on(e,t){if("change"===e){let e=b.toJSON();return s(r,i=>{const o=b.toJSON();!I(e,o)&&(e=o,t(o))})}},async _toCanvas({pixelRatio:e,ignoreBackground:t,pageId:i,mimeType:o,includeBleed:n,_skipTimeout:a,quickMode:s=!1,_exportCanvases:l}={}){var d;const c=e||1;i=i||(null===(d=r.pages[0])||void 0===d?void 0:d.id);const g=r.pages.find(e=>e.id===i);if(!g){throw new Error(`No page for export with id ${i}`)}const m=r._elementsPixelRatio;c>r._elementsPixelRatio&&b.setElementsPixelRatio(c),s?null==g||g.set({_forceMount:!0}):null==g||g.set({_exporting:!0});const u=await _(()=>{const e=p.stages.filter(e=>e.getAttr("pageId")===i);return 0===e.length?null:e});if(!u){throw null==g||g.set({_forceMount:!1,_exporting:!1}),b.setElementsPixelRatio(m),new Error(`Export is failed. Can not find stage for page ${i}. Looks like <Workspace /> component is not mounted, but it is required in order to process the export.`)}u.length>1&&console.error(`Polotno error: Detected several canvas elements for page "${i}" in the document. This is not supported and will lead to incorrect export. Make sure to use unique ids for all pages and make sure you unmount <Workspace /> when it is not needed.`);const f=u[0];await b.waitLoading({_skipTimeout:a});const h=f.findOne(".page-container");if(!h){throw b.setElementsPixelRatio(m),null==g||g.set({_forceMount:!1,_exporting:!1}),new Error("Export is failed. Canvas was unmounted.")}const y=f.position();f.position({x:0,y:0}),f.find("Transformer").forEach(e=>{e.setAttr("oldVisible",e.visible()),e.visible(!1)}),h.find(".page-background").forEach(e=>e.shadowEnabled(!1)),h.find(".page-background").forEach(e=>e.strokeEnabled(!1)),h.find(".highlighter").forEach(e=>e.visible(!1));const v=h.findOne(".page-background-group"),P=v.clip();v.clip({x:null,y:null,width:null,height:null});const E=h.findOne(".elements-container"),x=E.clip();E.clip({x:null,y:null,width:null,height:null});const I=h.find(e=>!e.visible()&&e.getAttr("editModeEnabled")&&!e.getAttr("hideInExport"));I.forEach(e=>{e.setAttr("oldVisible",e.visible()),e.show()});const k=h.find(e=>e.getAttr("hideInExport"));k.forEach(e=>{e.setAttr("oldVisible",e.visible()),e.hide()}),t&&h.find(".page-background").forEach(e=>e.hide());const S=n?g.bleed:0;let T=S;!r.bleedVisible&&n||(r.bleedVisible||n?r.bleedVisible&&n?T=0:r.bleedVisible&&!n&&(T=-g.bleed):T=0);const O=g.computedWidth+2*S,j=g.computedHeight+2*S,R=h.scale();h.scale({x:1,y:1});const F=w(h,{x:h.x()-T,y:h.y()-T,width:O,height:j,pixelRatio:c,sceneCanvas:null==l?void 0:l.sceneCanvas,bufferCanvas:null==l?void 0:l.bufferCanvas});h.scale(R);const C=F._canvas;if("image/jpeg"===o){const e=C.getContext("2d");e.save(),e.globalCompositeOperation="destination-over",e.fillStyle="white",e.fillRect(0,0,C.width,C.height),e.restore()}return t&&h.find(".page-background").forEach(e=>e.show()),k.forEach(e=>{e.visible(e.getAttr("oldVisible"))}),I.forEach(e=>{e.visible(e.getAttr("oldVisible"))}),h.find(".page-background").forEach(e=>e.shadowEnabled(!0)),h.find(".page-background").forEach(e=>e.strokeEnabled(!0)),f.find("Transformer").forEach(e=>{e.visible(e.getAttr("oldVisible"))}),h.find(".highlighter").forEach(e=>e.visible(!0)),v.clip(P),E.clip(x),f.position(y),null==g||g.set({_exporting:!1,_forceMount:!1}),await Promise.resolve(),b.setElementsPixelRatio(m),C},async toDataURL(t={}){var{mimeType:i,quality:o,dpi:n,dpiMetadata:a="auto"}=t,s=e(t,["mimeType","quality","dpi","dpiMetadata"]);const l=await b._toCanvas(Object.assign({mimeType:i},s)),d=i||"image/png",c=l.toDataURL(d,o);p.Util.releaseCanvas(l);const g=null!=n?n:r.dpi;return"image/png"!==d&&"image/jpeg"!==d||"never"===a||"auto"===a&&72===g?c:P(c,d,g)},async toBlob(t={}){var{mimeType:i,quality:o}=t,n=e(t,["mimeType","quality"]);const a=await b._toCanvas(Object.assign({mimeType:i},n)),s=await new Promise(e=>{a.toBlob(e,i,o)});return p.Util.releaseCanvas(a),s},async saveAsImage(t={}){var{fileName:i}=t,o=e(t,["fileName"]);const n=(o.mimeType||"image/png").split("/")[1];m(await b.toDataURL(o),i||"polotno."+n)},async _toPDF(e){const t=e.dpi||r.dpi,i=e.parallel||1,o=e.unit||("px"===r.unit?"mm":r.unit),n=e.pixelRatio||1,a=e.pageIds||(e.pageId?[e.pageId]:r.pages.map(e=>e.id)),s=r.pages.filter(e=>a.includes(e.id)),l=await u(),d=e=>x({px:e,unit:o,dpi:t}),c=e.cropMarkSize||0,p=d(c),g=s[0]||{},m=e.includeBleed?g.bleed:0,f=d(g.computedWidth+2*m+2*p),h=d(g.computedHeight+2*m+2*p);var y=new l({unit:o,orientation:f>h?"landscape":"portrait",format:[f,h],compress:!0,putOnlyUsedFonts:!0});y.deletePage(1);const v=((e,t)=>{const i=[];for(let o=0;o<e.length;o+=t){i.push(e.slice(o,o+t))}return i})(s,i);let P=0;for(const r of v){const t=r.map(async t=>{const i=e.includeBleed?t.bleed:0,o=t.computedWidth+2*i+2*c,s=t.computedHeight+2*i+2*c,r=d(o),l=d(s);let p=0,g=n;for(;p<10;){p+=1;const i=await b.toDataURL(Object.assign(Object.assign({},e),{pageId:t.id,pixelRatio:g,dpiMetadata:"never"}));if(i.length>20){return g!==n&&console.error(`Polotno can not export PDF with current settings. Quality is automatically reduced. pixelRatio was reduced to ${parseFloat(g.toFixed(3))}.`),e.onProgress&&e.onProgress(++P/a.length*.9),{url:i,width:r,height:l,widthPx:o,heightPx:s}}g*=.8}});(await Promise.all(t)).filter(e=>void 0!==e).forEach(({url:e,width:t,height:i,widthPx:n,heightPx:a})=>{y.addPage([t,i],t>i?"landscape":"portrait");const s=y.getCurrentPageInfo();var r;switch(o){case"pt":r=1;break;case"mm":r=72/25.4;break;case"cm":r=72/2.54;break;case"in":r=72;break;case"px":r=.75;break;default:throw"Invalid unit: "+o}if(s.pageContext.cropBox={bottomLeftX:0,bottomLeftY:0,topRightX:t*r,topRightY:i*r},s.pageContext.artBox={bottomLeftX:d(c+m)*r,bottomLeftY:d(c+m)*r,topRightX:d(n-c-m)*r,topRightY:d(a-c-m)*r},s.pageContext.bleedBox={bottomLeftX:d(c+m)*r,bottomLeftY:d(c+m)*r,topRightX:d(n-c-m)*r,topRightY:d(a-c-m)*r},p){y.setLineWidth(d(1));const e=p+d(m);y.line(e,0,e,p),y.line(0,e,p,e),y.line(t-e,0,t-e,p),y.line(t,e,t-p,e),y.line(0,i-e,p,i-e),y.line(e,i,e,i-p),y.line(t,i-e,t-p,i-e),y.line(t-e,i,t-e,i-p)}y.addImage(e,p,p,t-2*p,i-2*p,void 0,"FAST")})}return y},toPDFDataURL:async e=>(await b._toPDF(Object.assign({mimeType:"image/jpeg"},e))).output("datauristring"),async toGIFDataURL(e={}){const t=e.pixelRatio||1,i=e.pageIds||(e.pageId?[e.pageId]:r.pages.map(e=>e.id)),o=r.pages.filter(e=>i.includes(e.id));if(!o.length){throw new Error("No pages found for GIF export")}const n=o[0],a=await f({width:n.computedWidth*t,height:n.computedHeight*t}),s=1e3/(e.fps||10);for(const l of o){const e=Math.max(1,Math.floor(l.duration/s));for(let i=0;i<e;i++){const e=l.startTime+i*s||1;b.setCurrentTime(e);for(const t of r.pages){t.set({_rendering:t.id===l.id})}const o=await b._toCanvas({pixelRatio:t,pageId:l.id,_skipTimeout:!0});a.addFrame(o.getContext("2d"),{delay:s,copy:!0})}}for(const l of r.pages){l.set({_rendering:!1})}return b.stop(),a.render(),new Promise(e=>{a.on("finished",function(t){!function(e,t){var i=new FileReader;i.onload=function(e){t(e.target.result)},i.readAsDataURL(e)}(t,e)})})},async saveAsGIF(t={}){var{fileName:i}=t,o=e(t,["fileName"]);const n=await b.toGIFDataURL(o);m(n,i||"polotno.gif")},async toHTML({elementHook:e}={}){const t=b.toJSON();return k({json:t,elementHook:e})},async saveAsHTML({fileName:e,elementHook:t}={}){const i=await b.toHTML({elementHook:t}),o="data:text/html;base64,"+window.btoa(unescape(encodeURIComponent(i)));m(o,e||"polotno.html")},async toSVG({elementHook:e,pageId:t,fontEmbedding:i="inline"}={fontEmbedding:"inline"}){var o;const n=b.toJSON();t=t||(null===(o=n.pages[0])||void 0===o?void 0:o.id);const a=n.pages.find(e=>e.id===t);return S({json:Object.assign(Object.assign({},n),{pages:a?[a]:[]}),elementHook:e,fontEmbedding:i})},async saveAsSVG({fileName:e,elementHook:t,pageId:i,fontEmbedding:o="inline"}={}){const n=await b.toSVG({elementHook:t,pageId:i,fontEmbedding:o}),a="data:text/svg;base64,"+window.btoa(unescape(encodeURIComponent(n)));m(a,e||"polotno.svg")},async saveAsPDF(t={}){var{fileName:i}=t,o=e(t,["fileName"]);(await b._toPDF(Object.assign({mimeType:"image/jpeg"},o))).save(i||"polotno.pdf")},async waitLoading({_skipTimeout:e=!1}={}){e||await new Promise(e=>setTimeout(e,50)),await E()},toJSON:()=>({width:r.width,height:r.height,fonts:a(r.fonts),pages:a(r.pages),audios:a(r.audios),unit:r.unit,dpi:r.dpi,custom:r.custom,schemaVersion:r.schemaVersion}),loadJSON(e,i=!1){var o,n,s;const l="boolean"==typeof i?i:null!==(o=null==i?void 0:i.keepHistory)&&void 0!==o&&o,d="boolean"!=typeof i&&null!==(n=null==i?void 0:i.modernizeTextBackground)&&void 0!==n&&n,c=JSON.parse(JSON.stringify(e)),p=c.schemaVersion||0;p<1&&(v.htmlRenderEnabled||v.renderTagTextEnabled)&&j({children:c.pages},e=>{if("text"===e.type){const t=16,i=e.letterSpacing*t;e.letterSpacing=i/e.fontSize}}),p<2&&j({children:c.pages},e=>{e.filters&&Object.keys(e.filters).forEach(t=>{if(["warm","cold","natural"].includes(t)){return}const i=e.filters[t];i&&"number"==typeof i.intensity&&(i.intensity=i.intensity/100)})}),p<3&&(v.htmlRenderEnabled||v.renderTagTextEnabled)&&!d&&j({children:c.pages},e=>{"text"===e.type&&e.backgroundEnabled&&(e.legacyBackground=!0)}),delete c.schemaVersion;const g=r.activePage?r.pages.indexOf(r.activePage):0;let m=null===(s=c.pages[g]||c.pages[0])||void 0===s?void 0:s.id;c._activePageId=m;const u=Object.assign({},a(r));Object.assign(u,c),u.history=l?a(r.history):{history:[],undoIdx:-1,targetPath:""},t(r,u)},clear({keepHistory:e=!1}={}){const t=r.pages.map(e=>e.id);b.deletePages(t),r.custom=null,e||r.history.clear()},addFont(e){b.removeFont(e.fontFamily),r.fonts.push(e)},removeFont(e){r.fonts.filter(t=>t.fontFamily===e).forEach(e=>o(e))},addAudio(e){const t=R.create(Object.assign({id:c(10)},e));r.audios.push(t)},removeAudio(e){const t=r.audios.find(t=>t.id===e);t&&r.audios.remove(t)},async loadFont(e,t,i,o){const n=r.fonts.find(t=>t.fontFamily===e)||y.globalFonts.find(t=>t.fontFamily===e);let a=[{fontStyle:"normal",fontWeight:"normal"},{fontStyle:"normal",fontWeight:"bold"}];return n?(n.styles&&(a=n.styles.map(e=>({fontStyle:e.fontStyle||"normal",fontWeight:e.fontWeight||"normal"}))),y.injectCustomFont(n)):y.injectGoogleFont(e),t&&i&&!a.some(e=>e.fontStyle===t&&e.fontWeight===i)&&a.push({fontStyle:t,fontWeight:i}),Promise.all(a.map(t=>y.loadFont(e,t.fontStyle,t.fontWeight,o)))},validate:e=>Store.validate(e,[{path:"",type:Store}]).map(e=>({path:"store"+e.context.map(e=>e.path).join("."),message:e.message}))};return b});export function createStore({key:e,showCredit:t}={key:"",showCredit:!1}){return b(e),Store.create({_forceShowCredit:t})}export default createStore;
1
+ var e=this&&this.__rest||function(e,t){var i={};for(var o in e){Object.prototype.hasOwnProperty.call(e,o)&&t.indexOf(o)<0&&(i[o]=e[o])}if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var n=0;for(o=Object.getOwnPropertySymbols(e);n<o.length;n++){t.indexOf(o[n])<0&&Object.prototype.propertyIsEnumerable.call(e,o[n])&&(i[o[n]]=e[o[n]])}}return i};import{applySnapshot as t,cast as i,destroy as o,detach as n,getSnapshot as a,onSnapshot as s,setLivelinessChecking as r,types as l}from"mobx-state-tree";import{UndoManager as d}from"./history.js";import{nanoid as c}from"nanoid";import p from"konva";import{computed as g}from"mobx";import{downloadFile as m}from"../utils/download.js";import{getJsPDF as u}from"../utils/pdf.js";import{createGIF as f}from"../utils/gif-lib.js";import{validateKey as h,setKey as b}from"../utils/validate-key.js";import*as y from"../utils/fonts.js";import{flags as v}from"../utils/flags.js";import{addDpiMetadataToImage as P}from"../utils/image-dpi.js";import{nodeToCanvas as w}from"../utils/canvas.js";import{whenLoaded as E}from"../utils/loader.js";import{pxToUnit as x}from"../utils/unit.js";import{deepEqual as I}from"../utils/deep-equal.js";import{waitTillAvailable as _}from"../utils/wait.js";import{jsonToHTML as k}from"../utils/to-html.js";import{jsonToSVG as S}from"../utils/to-svg.js";import{Page as T}from"./page-model.js";import{forEveryChild as O,forEveryNode as j}from"./group-model.js";import{Audio as R}from"./audio-model.js";r("ignore");export const Font=l.model("Font",{fontFamily:l.string,url:l.optional(l.string,""),styles:l.frozen()}).preProcessSnapshot(e=>Object.assign(Object.assign({},e),{fontFamily:e.fontFamily||e.name}));export const ROLES={ADMIN:"admin",VIEWER:"viewer"};export const Store=l.model("Store",{role:"",pages:l.array(T),fonts:l.array(Font),audios:l.array(R),width:1080,height:1080,currentTime:0,isPlaying:!1,scale:1,scaleToFit:1,unit:l.optional(l.enumeration("UnitType",["pt","mm","cm","in","px"]),"px"),dpi:72,schemaVersion:4,bleedVisible:!1,rulesVisible:!1,distanceGuidesVisible:!1,openedSidePanel:"",previousOpenedSidePanel:"",custom:l.frozen(),tool:l.optional(l.enumeration("Tool",["selection","draw","pan","text","eraser"]),"selection"),toolOptions:l.optional(l.model({brushType:l.optional(l.enumeration("BrushType",["brush","highlighter"]),"brush"),strokeWidth:l.optional(l.number,5),stroke:l.optional(l.string,"#000000"),opacity:l.optional(l.number,1)}),{}),selectedElementsIds:l.array(l.string),animatedElementsIds:l.array(l.string),history:l.optional(d,{targetPath:"../pages"}),_elementsPixelRatio:Math.min(2,"undefined"!=typeof window&&window.devicePixelRatio||1),_activePageId:"",_selectedPagesIds:l.array(l.string),_forceShowCredit:!1,_validated:!1}).views(e=>{const t=g(()=>{const t={};return j({children:e.pages},e=>(t[e.id]=e,!1)),t},{keepAlive:!0});return{get _idsMap(){return t.get()}}}).views(e=>({get _bleedVisible(){return console.warn("store._bleedVisible is deprecated. Please use store.bleedVisible instead."),e.bleedVisible},get selectedElements(){return e.selectedElementsIds.map(t=>e._idsMap[t]).filter(e=>!!e)},get children(){return e.pages},get selectedShapes(){const e=[];return O({children:this.selectedElements},t=>{"group"!==t.type&&e.push(t)}),e},get activePage(){return e.pages.slice().find(t=>t.id===e._activePageId)||(e.pages.length?e.pages[0]:null)},get selectedPages(){return e._selectedPagesIds.map(t=>e.pages.find(e=>e.id===t))},get duration(){let t=0;return e.pages.forEach(e=>{t+=e.duration}),t},get _hasCroppedImages(){return this.find(e=>"image"===e.type&&e._cropModeEnabled)},find(t){let i;return j({children:e.pages},e=>{if(!i&&t(e)){return i=e,!0}}),i},getElementById:t=>e._idsMap[t]})).actions(r=>{let l=0,d=null,g=!1;const b={afterCreate(){r.history.canUndo},setCurrentTime(e){r.currentTime=e},_togglePlaying(e=!r.isPlaying){r.isPlaying=e},play({animatedElementsIds:e=[],startTime:t=0,currentTime:o=0,endTime:n=r.duration,repeat:a=!1}={}){o&&(console.warn("currentTime property of store.play() is deprecated. Please use startTime instead."),t=o),r.animatedElementsIds=i(e),r.currentTime=t,r.isPlaying=!0,l=Date.now(),d=n,g=a,requestAnimationFrame(()=>b.seek())},checkActivePage(){let e=0;for(const t of r.pages){if(r.currentTime>=t.startTime&&r.currentTime<t.startTime+t.duration){b.selectPage(t.id);break}e+=t.duration}},seek(){if(!r.isPlaying){return}const e=Date.now(),t=e-l;l=e,r.currentTime+=t,b.checkActivePage();const i=d||r.duration;r.isPlaying&&r.currentTime<i?requestAnimationFrame(()=>b.seek()):r.isPlaying&&g?(r.currentTime=0,requestAnimationFrame(()=>b.seek())):b.stop()},stop(){r.isPlaying=!1,r.currentTime=0,r.animatedElementsIds=i([]),b.checkActivePage()},__(){r._validated||(h(r._forceShowCredit),r._validated=!0)},set(e){Object.assign(r,e)},setUnit({unit:e,dpi:t}){r.unit=e||r.unit,r.dpi=t||r.dpi},setRole(e){r.role=e},setTool(e){r.tool=e},setToolOptions(e){Object.assign(r.toolOptions,e)},addPage(e){const t=T.create(Object.assign({id:c(10)},e));return r.pages.push(t),r._activePageId=t.id,t},selectPage(e){r._activePageId=e,1===r._selectedPagesIds.length&&(r._selectedPagesIds=i([e]))},selectPages(e){r._selectedPagesIds=i(e),1===r._selectedPagesIds.length&&(r._activePageId=r._selectedPagesIds[0])},selectElements(e){const t=e.map(e=>r.getElementById(e)).filter(e=>!!e);t.sort((e,t)=>{var i,o,n,a;return(null!==(o=null===(i=e.parent)||void 0===i?void 0:i.children.indexOf(e))&&void 0!==o?o:0)-(null!==(a=null===(n=t.parent)||void 0===n?void 0:n.children.indexOf(t))&&void 0!==a?a:0)}),r.selectedElementsIds=i(t.map(e=>e.id))},toggleBleed(e){r.bleedVisible=null!=e?e:!r.bleedVisible},toggleRulers(e){r.rulesVisible=null!=e?e:!r.rulesVisible},toggleDistanceGuides(e){r.distanceGuidesVisible=null!=e?e:!r.distanceGuidesVisible},openSidePanel(e){r.openedSidePanel!==e&&(r.previousOpenedSidePanel=r.openedSidePanel,r.openedSidePanel=e)},restoreSidePanel(){const e=r.previousOpenedSidePanel;e&&e!==r.openedSidePanel?r.openedSidePanel=e:r.openedSidePanel="photos"},setScale(e){r.scale=e},_setScaleToFit(e){r.scaleToFit=e},setElementsPixelRatio(e){r._elementsPixelRatio=e},setSize(e,t,i){r.pages.forEach(o=>{o.setSize({width:e,height:t,useMagic:i,softChange:!0})}),r.width=e,r.height=t},setPageZIndex(e,t){const i=r.pages.find(t=>t.id===e);i&&(n(i),r.pages.remove(i),r.pages.splice(t,0,i))},deletePages(e){const t=r.pages.indexOf(r.activePage);e.forEach(e=>{const t=r.pages.find(t=>t.id===e);o(t)});const n=Math.min(r.pages.length-1,t),a=r.pages[n];a&&(r._activePageId=a.id),r.selectedElementsIds=i(r.selectedElementsIds.filter(e=>r.getElementById(e)))},groupElements(e,t={}){const o=e.map(e=>r.getElementById(e)).filter(e=>!!e);if(!o.length){return}const a=o[0].parent;if(!a){return}if(!o.every(e=>e.parent===a)){return void console.warn("store.groupElements: refusing to group elements that do not share a parent. Pass ids whose elements all live under the same page or the same group.")}o.forEach(e=>n(e));const s=a.children.reduce((e,t)=>{var i;if("group"===t.type){const o=null===(i=t.name)||void 0===i?void 0:i.match(/group-(\d+)/);if(o){const t=parseInt(o[1],10);return Math.max(e,t)}}return e},0),l=Object.assign({id:c(10),name:`group-${s+1}`,children:o,type:"group"},t);return a.children.push(l),r.selectedElementsIds=i([l.id]),a.children.find(e=>e.id===l.id)},ungroupElements(e){const t=e.map(e=>r.getElementById(e)),o=[];t.forEach(e=>{if(e&&"group"===e.type){const t=e.parent;if(!t){return}const i=t.children.indexOf(e);e.children.forEach(e=>{o.push(e.id)}),e.children.slice().forEach(e=>{n(e),t.children.push(e)}),t.children.splice(i,1)}}),r.selectedElementsIds=i(o)},deleteElements(e){const t=[];r.find(i=>(e.includes(i.id)&&t.push(i),!1)),t.forEach(e=>{o(e)}),r.selectedElementsIds=i(r.selectedElementsIds.filter(e=>r.getElementById(e)))},on(e,t){if("change"===e){let e=b.toJSON();return s(r,i=>{const o=b.toJSON();!I(e,o)&&(e=o,t(o))})}},async _toCanvas({pixelRatio:e,ignoreBackground:t,pageId:i,mimeType:o,includeBleed:n,_skipTimeout:a,quickMode:s=!1,_exportCanvases:l}={}){var d;const c=e||1;i=i||(null===(d=r.pages[0])||void 0===d?void 0:d.id);const g=r.pages.find(e=>e.id===i);if(!g){throw new Error(`No page for export with id ${i}`)}const m=r._elementsPixelRatio;c>r._elementsPixelRatio&&b.setElementsPixelRatio(c),s?null==g||g.set({_forceMount:!0}):null==g||g.set({_exporting:!0});const u=await _(()=>{const e=p.stages.filter(e=>e.getAttr("pageId")===i);return 0===e.length?null:e});if(!u){throw null==g||g.set({_forceMount:!1,_exporting:!1}),b.setElementsPixelRatio(m),new Error(`Export is failed. Can not find stage for page ${i}. Looks like <Workspace /> component is not mounted, but it is required in order to process the export.`)}u.length>1&&console.error(`Polotno error: Detected several canvas elements for page "${i}" in the document. This is not supported and will lead to incorrect export. Make sure to use unique ids for all pages and make sure you unmount <Workspace /> when it is not needed.`);const f=u[0];await b.waitLoading({_skipTimeout:a});const h=f.findOne(".page-container");if(!h){throw b.setElementsPixelRatio(m),null==g||g.set({_forceMount:!1,_exporting:!1}),new Error("Export is failed. Canvas was unmounted.")}const y=f.position();f.position({x:0,y:0}),f.find("Transformer").forEach(e=>{e.setAttr("oldVisible",e.visible()),e.visible(!1)}),h.find(".page-background").forEach(e=>e.shadowEnabled(!1)),h.find(".page-background").forEach(e=>e.strokeEnabled(!1)),h.find(".highlighter").forEach(e=>e.visible(!1));const v=h.findOne(".page-background-group"),P=v.clip();v.clip({x:null,y:null,width:null,height:null});const E=h.findOne(".elements-container"),x=E.clip();E.clip({x:null,y:null,width:null,height:null});const I=h.find(e=>!e.visible()&&e.getAttr("editModeEnabled")&&!e.getAttr("hideInExport"));I.forEach(e=>{e.setAttr("oldVisible",e.visible()),e.show()});const k=h.find(e=>e.getAttr("hideInExport"));k.forEach(e=>{e.setAttr("oldVisible",e.visible()),e.hide()}),t&&h.find(".page-background").forEach(e=>e.hide());const S=n?g.bleed:0;let T=S;!r.bleedVisible&&n||(r.bleedVisible||n?r.bleedVisible&&n?T=0:r.bleedVisible&&!n&&(T=-g.bleed):T=0);const O=g.computedWidth+2*S,j=g.computedHeight+2*S,R=h.scale();h.scale({x:1,y:1});const F=w(h,{x:h.x()-T,y:h.y()-T,width:O,height:j,pixelRatio:c,sceneCanvas:null==l?void 0:l.sceneCanvas,bufferCanvas:null==l?void 0:l.bufferCanvas});h.scale(R);const C=F._canvas;if("image/jpeg"===o){const e=C.getContext("2d");e.save(),e.globalCompositeOperation="destination-over",e.fillStyle="white",e.fillRect(0,0,C.width,C.height),e.restore()}return t&&h.find(".page-background").forEach(e=>e.show()),k.forEach(e=>{e.visible(e.getAttr("oldVisible"))}),I.forEach(e=>{e.visible(e.getAttr("oldVisible"))}),h.find(".page-background").forEach(e=>e.shadowEnabled(!0)),h.find(".page-background").forEach(e=>e.strokeEnabled(!0)),f.find("Transformer").forEach(e=>{e.visible(e.getAttr("oldVisible"))}),h.find(".highlighter").forEach(e=>e.visible(!0)),v.clip(P),E.clip(x),f.position(y),null==g||g.set({_exporting:!1,_forceMount:!1}),await Promise.resolve(),b.setElementsPixelRatio(m),C},async toDataURL(t={}){var{mimeType:i,quality:o,dpi:n,dpiMetadata:a="auto"}=t,s=e(t,["mimeType","quality","dpi","dpiMetadata"]);const l=await b._toCanvas(Object.assign({mimeType:i},s)),d=i||"image/png",c=l.toDataURL(d,o);p.Util.releaseCanvas(l);const g=null!=n?n:r.dpi;return"image/png"!==d&&"image/jpeg"!==d||"never"===a||"auto"===a&&72===g?c:P(c,d,g)},async toBlob(t={}){var{mimeType:i,quality:o}=t,n=e(t,["mimeType","quality"]);const a=await b._toCanvas(Object.assign({mimeType:i},n)),s=await new Promise(e=>{a.toBlob(e,i,o)});return p.Util.releaseCanvas(a),s},async saveAsImage(t={}){var{fileName:i}=t,o=e(t,["fileName"]);const n=(o.mimeType||"image/png").split("/")[1];m(await b.toDataURL(o),i||"polotno."+n)},async _toPDF(e){const t=e.dpi||r.dpi,i=e.parallel||1,o=e.unit||("px"===r.unit?"mm":r.unit),n=e.pixelRatio||1,a=e.pageIds||(e.pageId?[e.pageId]:r.pages.map(e=>e.id)),s=r.pages.filter(e=>a.includes(e.id)),l=await u(),d=e=>x({px:e,unit:o,dpi:t}),c=e.cropMarkSize||0,p=d(c),g=s[0]||{},m=e.includeBleed?g.bleed:0,f=d(g.computedWidth+2*m+2*p),h=d(g.computedHeight+2*m+2*p);var y=new l({unit:o,orientation:f>h?"landscape":"portrait",format:[f,h],compress:!0,putOnlyUsedFonts:!0});y.deletePage(1);const v=((e,t)=>{const i=[];for(let o=0;o<e.length;o+=t){i.push(e.slice(o,o+t))}return i})(s,i);let P=0;for(const r of v){const t=r.map(async t=>{const i=e.includeBleed?t.bleed:0,o=t.computedWidth+2*i+2*c,s=t.computedHeight+2*i+2*c,r=d(o),l=d(s);let p=0,g=n;for(;p<10;){p+=1;const i=await b.toDataURL(Object.assign(Object.assign({},e),{pageId:t.id,pixelRatio:g,dpiMetadata:"never"}));if(i.length>20){return g!==n&&console.error(`Polotno can not export PDF with current settings. Quality is automatically reduced. pixelRatio was reduced to ${parseFloat(g.toFixed(3))}.`),e.onProgress&&e.onProgress(++P/a.length*.9),{url:i,width:r,height:l,widthPx:o,heightPx:s}}g*=.8}});(await Promise.all(t)).filter(e=>void 0!==e).forEach(({url:e,width:t,height:i,widthPx:n,heightPx:a})=>{y.addPage([t,i],t>i?"landscape":"portrait");const s=y.getCurrentPageInfo();var r;switch(o){case"pt":r=1;break;case"mm":r=72/25.4;break;case"cm":r=72/2.54;break;case"in":r=72;break;case"px":r=.75;break;default:throw"Invalid unit: "+o}if(s.pageContext.cropBox={bottomLeftX:0,bottomLeftY:0,topRightX:t*r,topRightY:i*r},s.pageContext.artBox={bottomLeftX:d(c+m)*r,bottomLeftY:d(c+m)*r,topRightX:d(n-c-m)*r,topRightY:d(a-c-m)*r},s.pageContext.bleedBox={bottomLeftX:d(c+m)*r,bottomLeftY:d(c+m)*r,topRightX:d(n-c-m)*r,topRightY:d(a-c-m)*r},p){y.setLineWidth(d(1));const e=p+d(m);y.line(e,0,e,p),y.line(0,e,p,e),y.line(t-e,0,t-e,p),y.line(t,e,t-p,e),y.line(0,i-e,p,i-e),y.line(e,i,e,i-p),y.line(t,i-e,t-p,i-e),y.line(t-e,i,t-e,i-p)}y.addImage(e,p,p,t-2*p,i-2*p,void 0,"FAST")})}return y},toPDFDataURL:async e=>(await b._toPDF(Object.assign({mimeType:"image/jpeg"},e))).output("datauristring"),async toGIFDataURL(e={}){const t=e.pixelRatio||1,i=e.pageIds||(e.pageId?[e.pageId]:r.pages.map(e=>e.id)),o=r.pages.filter(e=>i.includes(e.id));if(!o.length){throw new Error("No pages found for GIF export")}const n=o[0],a=await f({width:n.computedWidth*t,height:n.computedHeight*t}),s=1e3/(e.fps||10);for(const l of o){const e=Math.max(1,Math.floor(l.duration/s));for(let i=0;i<e;i++){const e=l.startTime+i*s||1;b.setCurrentTime(e);for(const t of r.pages){t.set({_rendering:t.id===l.id})}const o=await b._toCanvas({pixelRatio:t,pageId:l.id,_skipTimeout:!0});a.addFrame(o.getContext("2d"),{delay:s,copy:!0})}}for(const l of r.pages){l.set({_rendering:!1})}return b.stop(),a.render(),new Promise(e=>{a.on("finished",function(t){!function(e,t){var i=new FileReader;i.onload=function(e){t(e.target.result)},i.readAsDataURL(e)}(t,e)})})},async saveAsGIF(t={}){var{fileName:i}=t,o=e(t,["fileName"]);const n=await b.toGIFDataURL(o);m(n,i||"polotno.gif")},async toHTML({elementHook:e}={}){const t=b.toJSON();return k({json:t,elementHook:e})},async saveAsHTML({fileName:e,elementHook:t}={}){const i=await b.toHTML({elementHook:t}),o="data:text/html;base64,"+window.btoa(unescape(encodeURIComponent(i)));m(o,e||"polotno.html")},async toSVG({elementHook:e,pageId:t,fontEmbedding:i="inline"}={fontEmbedding:"inline"}){var o;const n=b.toJSON();t=t||(null===(o=n.pages[0])||void 0===o?void 0:o.id);const a=n.pages.find(e=>e.id===t);return S({json:Object.assign(Object.assign({},n),{pages:a?[a]:[]}),elementHook:e,fontEmbedding:i})},async saveAsSVG({fileName:e,elementHook:t,pageId:i,fontEmbedding:o="inline"}={}){const n=await b.toSVG({elementHook:t,pageId:i,fontEmbedding:o}),a="data:text/svg;base64,"+window.btoa(unescape(encodeURIComponent(n)));m(a,e||"polotno.svg")},async saveAsPDF(t={}){var{fileName:i}=t,o=e(t,["fileName"]);(await b._toPDF(Object.assign({mimeType:"image/jpeg"},o))).save(i||"polotno.pdf")},async waitLoading({_skipTimeout:e=!1}={}){e||await new Promise(e=>setTimeout(e,50)),await E()},toJSON:()=>({width:r.width,height:r.height,fonts:a(r.fonts),pages:a(r.pages),audios:a(r.audios),unit:r.unit,dpi:r.dpi,custom:r.custom,schemaVersion:r.schemaVersion}),loadJSON(e,i=!1){var o,n,s;const l="boolean"==typeof i?i:null!==(o=null==i?void 0:i.keepHistory)&&void 0!==o&&o,d="boolean"!=typeof i&&null!==(n=null==i?void 0:i.modernizeTextBackground)&&void 0!==n&&n,c=JSON.parse(JSON.stringify(e)),p=c.schemaVersion||0;p<1&&(v.htmlRenderEnabled||v.renderTagTextEnabled)&&j({children:c.pages},e=>{if("text"===e.type){const t=16,i=e.letterSpacing*t;e.letterSpacing=i/e.fontSize}}),p<2&&j({children:c.pages},e=>{e.filters&&Object.keys(e.filters).forEach(t=>{if(["warm","cold","natural"].includes(t)){return}const i=e.filters[t];i&&"number"==typeof i.intensity&&(i.intensity=i.intensity/100)})}),p<3&&(v.htmlRenderEnabled||v.renderTagTextEnabled)&&!d&&j({children:c.pages},e=>{"text"===e.type&&e.backgroundEnabled&&(e.legacyBackground=!0)}),delete c.schemaVersion;const g=r.activePage?r.pages.indexOf(r.activePage):0;let m=null===(s=c.pages[g]||c.pages[0])||void 0===s?void 0:s.id;c._activePageId=m;const u=Object.assign({},a(r));Object.assign(u,c),u.history=l?a(r.history):{history:[],undoIdx:-1,targetPath:""},t(r,u)},clear({keepHistory:e=!1}={}){const t=r.pages.map(e=>e.id);b.deletePages(t),r.custom=null,e||r.history.clear()},addFont(e){b.removeFont(e.fontFamily),r.fonts.push(e)},removeFont(e){r.fonts.filter(t=>t.fontFamily===e).forEach(e=>o(e))},addAudio(e){const t=R.create(Object.assign({id:c(10)},e));r.audios.push(t)},removeAudio(e){const t=r.audios.find(t=>t.id===e);t&&r.audios.remove(t)},async loadFont(e,t,i,o){const n=r.fonts.find(t=>t.fontFamily===e)||y.globalFonts.find(t=>t.fontFamily===e);let a=[{fontStyle:"normal",fontWeight:"normal"},{fontStyle:"normal",fontWeight:"bold"}];return n?(n.styles&&(a=n.styles.map(e=>({fontStyle:e.fontStyle||"normal",fontWeight:e.fontWeight||"normal"}))),y.injectCustomFont(n)):y.injectGoogleFont(e),t&&i&&!a.some(e=>e.fontStyle===t&&e.fontWeight===i)&&a.push({fontStyle:t,fontWeight:i}),Promise.all(a.map(t=>y.loadFont(e,t.fontStyle,t.fontWeight,o)))},validate:e=>Store.validate(e,[{path:"",type:Store}]).map(e=>({path:"store"+e.context.map(e=>e.path).join("."),message:e.message}))};return b});export function createStore({key:e,showCredit:t}={key:"",showCredit:!1}){return b(e),Store.create({_forceShowCredit:t})}export default createStore;
@@ -71,6 +71,7 @@ export declare const VideoElement: import("mobx-state-tree").IModelType<{
71
71
  startTime: import("mobx-state-tree").IType<number | undefined, number, number>;
72
72
  endTime: import("mobx-state-tree").IType<number | undefined, number, number>;
73
73
  volume: import("mobx-state-tree").IType<number | undefined, number, number>;
74
+ speed: import("mobx-state-tree").IType<number | undefined, number, number>;
74
75
  }, {
75
76
  readonly page: any;
76
77
  readonly store: any;
@@ -1 +1 @@
1
- import{ImageElement as e}from"./image-model.js";export const VideoElement=e.named("Video").props({type:"video",duration:0,startTime:0,endTime:1,volume:1});
1
+ import{ImageElement as e}from"./image-model.js";export const VideoElement=e.named("Video").props({type:"video",duration:0,startTime:0,endTime:1,volume:1,speed:1});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polotno",
3
- "version": "4.0.2",
3
+ "version": "4.1.0",
4
4
  "description": "Design Editor Framework",
5
5
  "author": "Anton Lavrenov",
6
6
  "keywords": [
@@ -95,6 +95,7 @@
95
95
  },
96
96
  "dependencies": {
97
97
  "@base-ui/react": "^1.5.0",
98
+ "@polotno/schema": "0.1.0",
98
99
  "class-variance-authority": "^0.7.1",
99
100
  "clsx": "^2.1.1",
100
101
  "gifuct-js": "^2.1.2",
@@ -102,7 +103,7 @@
102
103
  "konva": "^10.3.0",
103
104
  "lodash-es": "^4.18.1",
104
105
  "lucide-react": "^1.18.0",
105
- "mediabunny": "^1.46.0",
106
+ "mediabunny": "^1.47.0",
106
107
  "mensch": "^0.3.4",
107
108
  "mobx": "6.16.1",
108
109
  "mobx-react-lite": "^4.1.1",
@@ -192,18 +193,19 @@
192
193
  "jsdom": "^29.1.1",
193
194
  "license-checker": "^25.0.1",
194
195
  "playwright": "^1.60.0",
196
+ "postcss": "^8.5.15",
195
197
  "postcss-selector-parser": "^7.1.4",
196
198
  "pptxgenjs": "^4.0.1",
197
199
  "process": "^0.11.10",
198
200
  "react": "^19.2.7",
199
201
  "react-dom": "^19.2.7",
200
202
  "size-limit": "^12.1.0",
201
- "skia-canvas": "^3.0.8",
202
203
  "tailwindcss": "^4.3.1",
203
204
  "terser": "^5.48.0",
204
205
  "tw-animate-css": "^1.4.0",
205
- "typescript": "^6.0.3",
206
- "vitest": "^4.1.8"
206
+ "typescript": "~6.0.3",
207
+ "vite": "^8.0.16",
208
+ "vitest": "^4.1.9"
207
209
  },
208
210
  "homepage": "https://polotno.com/",
209
211
  "scripts": {
@@ -216,15 +218,14 @@
216
218
  "check:css": "node build/check-css-hygiene.cjs ./lib/ui.css",
217
219
  "check:agreement": "node build/check-agreement.cjs ./lib/ui.css ./lib/toolbar ./lib/side-panel ./lib/pages-timeline ./lib/primitives ./lib/canvas",
218
220
  "check:parity": "node build/structural-parity.cjs",
219
- "test:parity": "npm run check:parity && npm run check:agreement && npm run check:css",
221
+ "test:parity": "pnpm run check:parity && pnpm run check:agreement && pnpm run check:css",
220
222
  "minify": "node minify.cjs",
221
- "build:schema": "node scripts/generate-schema.cjs",
222
- "build": "npm run typecheck && npm run clean && npm run prefix-build && npm run tsc && npm run add_version && node rename-imports.js && npm run minify && npm run build:css && npm run check:css && npm run check:agreement && npm run build:bundle && node blueprint-scope.js && cp ./src/fonts.css ./lib/fonts.css && mkdir -p ./lib/themes && cp ./src/themes/blueprint.css ./lib/themes/blueprint.css && cp ./package.json ./lib && cp ./README.md ./lib && cp ./LICENSE.md ./lib && npm run remove-test-from-lib && npm run build:schema",
223
+ "build": "pnpm run typecheck && pnpm run clean && pnpm run prefix-build && pnpm run tsc && pnpm run add_version && node rename-imports.js && pnpm run minify && pnpm run build:css && pnpm run check:css && pnpm run check:agreement && pnpm run build:bundle && node blueprint-scope.js && cp ./src/fonts.css ./lib/fonts.css && mkdir -p ./lib/themes && cp ./src/themes/blueprint.css ./lib/themes/blueprint.css && node build/copy-package-json.cjs && cp ./README.md ./lib && cp ./LICENSE.md ./lib && pnpm run remove-test-from-lib",
223
224
  "remove-test-from-lib": "find ./lib -type d -name \"__tests__\" -exec rm -rf {} + && find ./lib \\( -name \"*.test.js\" -o -name \"*.test.d.ts\" \\) -type f -delete",
224
225
  "add_version": "sed -i.bak 's/SDK_VERSION/'$npm_package_version'/' ./lib/utils/validate-key.js && rm -f ./lib/utils/validate-key.js.bak",
225
226
  "build:bundle": "vite build && find ./lib -name '*.js.map' -type f -delete",
226
- "size": "npm run build && size-limit",
227
- "test": "vitest"
227
+ "size": "pnpm run build && size-limit",
228
+ "test": "vitest run"
228
229
  },
229
230
  "license": "SEE LICENSE IN LICENSE.md"
230
231
  }
@@ -1 +1 @@
1
- var e=this&&this.__rest||function(e,t){var n={};for(var i in e){Object.prototype.hasOwnProperty.call(e,i)&&t.indexOf(i)<0&&(n[i]=e[i])}if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(i=Object.getOwnPropertySymbols(e);o<i.length;o++){t.indexOf(i[o])<0&&Object.prototype.propertyIsEnumerable.call(e,i[o])&&(n[i[o]]=e[i[o]])}}return n};import{jsx as t,jsxs as n}from"react/jsx-runtime";import i from"react";import{observer as o}from"mobx-react-lite";import{PolotnoIcon as s}from"../icons/registry.js";import{t as a}from"../utils/l10n.js";import{firstSliderValue as r}from"../lib/utils.js";import{DropdownMenu as l,DropdownMenuContent as m,DropdownMenuItem as d,DropdownMenuSeparator as p}from"../primitives/dropdown-menu.js";import{Slider as c}from"../primitives/slider.js";import{Spinner as u}from"./spinner.js";import{useWaveformData as h,useWaveformPath as v}from"./waveform.js";import{TrackWrapper as f,TrackContainer as x,TrackMenu as y,TrackMenuButton as M,TrackHandleLeft as w,TrackHandleRight as g,WaveformSvg as T}from"./track-styles.js";export const AUDIO_ROW_HEIGHT=28;export const AUDIO_TRACK_HEIGHT=24;const b=({position:e,store:t,scale:n})=>{const i=t.pages;for(const o of i){const t=o.startTime,i=o.startTime+o.duration;if(Math.abs(e-t)<10/n){return t}if(Math.abs(e-i)<10/n){return i}}return null};export const AudioTrack=o(({audio:o,scale:j,store:I,index:O})=>{const[D,E]=i.useState(1),A=0===o.volume,L=()=>{A?o.set({volume:D>0?D:1}):(E(o.volume),o.set({volume:0}))},N=(e=o.startTime,t=o.endTime)=>Math.max(0,(t-e)*(o.duration||0)),P=e=>Math.max(0,I.duration-e),S=(e,t=N())=>Math.min(Math.max(0,e),P(t)),_=N(),C=I.duration*j-o.delay*j,X=Math.min(_*j,C),k=o.delay*j,{data:z,isLoading:H}=h(o.src),$=o.visibleDuration*j,R=v(z,20).path,V=(e,t)=>{e.stopPropagation(),e.preventDefault();const n=e.clientX,i=k,s=X,a=o.endTime,r=o.startTime,l=o.delay,m=o.duration||1,d=e=>{e.preventDefault();const d=(e.clientX-n)/j;if("start"===t){if(d>=0){const e=d,t=Math.max(0,a-.1-r)*m,n=Math.min(e,t);if(n<=0){return}let i=r+n/m;const s=(o.endTime-i)*m,p=l+n,c=P(s);let u=Math.min(Math.max(0,p),c);const h=b({position:u,store:I,scale:j});u=Math.min(Math.max(0,null!=h?h:u),c);const v=u-p;i=Math.min(o.endTime-.1,Math.max(0,i+v/m)),o.set({delay:u,startTime:i})}else{const e=-d,t=r*m,n=Math.min(e,t);if(n<=0){return}const i=n/m;let s=Math.max(0,r-i);const a=(o.endTime-s)*m,p=l-n,c=P(a);let u=Math.min(Math.max(0,p),c);const h=b({position:u,store:I,scale:j});u=Math.min(Math.max(0,null!=h?h:u),c);const v=u-p;s=Math.max(0,Math.min(o.endTime-.1,s+v/m)),o.set({delay:u,startTime:s})}}else{const e=i/j+s/j;let t=e+d;const n=b({position:t,store:I,scale:j});t=null!=n?n:t;const r=(t-e)/o.duration,l=Math.min(1,Math.max(o.startTime+.1,a+r));o.set({endTime:l})}},p=()=>{if(window.removeEventListener("mousemove",d),window.removeEventListener("mouseup",p),"start"===t){const e=b({position:o.delay,store:I,scale:j});if(null!=e&&e!==o.delay){const t=N(o.startTime,o.endTime),n=S(e,t),i=n-o.delay,s=Math.max(0,Math.min(o.endTime-.1,o.startTime+i/m));o.set({delay:n,startTime:s})}}};window.addEventListener("mousemove",d),window.addEventListener("mouseup",p)};return t(f,{style:{left:`${k}px`,top:28*O+"px",width:`${X}px`,height:"24px"},className:"polotno-audio-container",children:n(x,{style:{width:"100%",height:"100%"},onMouseDown:e=>{const t=e.clientX,n=k;e.preventDefault();const i=e=>{e.preventDefault();const i=(e.clientX-t)/j;let s=n/j+i;const a=s+_,r=b({position:s,store:I,scale:j}),l=b({position:a,store:I,scale:j}),m=null!==r?Math.abs(s-r):Number.POSITIVE_INFINITY,d=null!==l?Math.abs(a-l):Number.POSITIVE_INFINITY;let p;p=S(null!==r&&m<d?r:null!==l?l-_:s),o.set({delay:S(p)})},s=()=>{window.removeEventListener("mousemove",i),window.removeEventListener("mouseup",s)};window.addEventListener("mousemove",i),window.addEventListener("mouseup",s)},children:[t("div",{style:{position:"absolute",left:"4px",top:"50%",transform:"translateY(-50%)",zIndex:10,pointerEvents:"auto"},onClick:e=>{e.stopPropagation(),L()},onMouseDown:e=>e.stopPropagation(),children:t(s,A?{name:"action.muted",className:"pn:size-3.5",style:{opacity:.7,cursor:"pointer"}}:{name:"action.unmuted",className:"pn:size-3.5",style:{opacity:.7,cursor:"pointer"}})}),t("div",{style:{position:"absolute",inset:"0 0 0 0",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:n("div",{style:{display:"flex",alignItems:"center",width:"100%",height:"100%",gap:"8px",paddingLeft:"22px"},children:[R&&t("div",{style:{flex:1,height:"14px",overflow:"hidden",opacity:A?.4:1},children:t(T,{width:$,height:"14",viewBox:`0 0 ${$} 20`,preserveAspectRatio:"none",style:{width:$+"px",height:"14px",transform:`translateX(-${o.startTime*$}px)`},children:t("path",{d:R})})}),H&&t("div",{style:{flex:1,display:"flex",justifyContent:"center",alignItems:"center"},children:t(u,{})})]})}),t(w,{onMouseDown:e=>V(e,"start")}),t(g,{onMouseDown:e=>V(e,"end")}),t(y,{onClick:e=>{e.stopPropagation()},onMouseDown:e=>e.stopPropagation(),children:n(l,{children:[t(M,{}),n(m,{side:"top",style:{width:"180px"},children:[n("div",{style:{padding:"8px 12px"},children:[n("div",{style:{fontSize:"12px",marginBottom:"6px",display:"flex",justifyContent:"space-between",alignItems:"center"},children:[t("span",{children:a("pagesTimeline.volume")}),n("span",{children:[Math.round(100*o.volume),"%"]})]}),t(c,{value:[o.volume],min:0,max:1,step:.01,onValueChange:e=>(e=>{const t=Math.max(0,Math.min(1,e));t>0&&E(t),o.set({volume:t})})(r(e))})]}),t(p,{}),n(d,{onSelect:e=>{e.preventDefault(),L()},children:[t(s,A?{name:"action.unmuted"}:{name:"action.muted"}),a(A?"pagesTimeline.unmuteAudio":"pagesTimeline.muteAudio")]}),n(d,{onSelect:t=>{t.preventDefault(),(()=>{const t=o.toJSON(),n=o.visibleDuration,i=o.delay+n,s=I.duration-i;let a=o.delay;s>=n?a=i:s>0&&(a=Math.max(0,I.duration-n));const{id:r}=t,l=e(t,["id"]);I.addAudio(Object.assign(Object.assign({},l),{delay:a}))})()},children:[t(s,{name:"action.duplicate"}),a("pagesTimeline.duplicateAudio")]}),t(p,{}),n(d,{onSelect:e=>{e.preventDefault(),I.removeAudio(o.id)},children:[t(s,{name:"action.remove"}),a("pagesTimeline.removeAudio")]})]})]})})]})})});
1
+ var e=this&&this.__rest||function(e,t){var n={};for(var i in e){Object.prototype.hasOwnProperty.call(e,i)&&t.indexOf(i)<0&&(n[i]=e[i])}if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(i=Object.getOwnPropertySymbols(e);o<i.length;o++){t.indexOf(i[o])<0&&Object.prototype.propertyIsEnumerable.call(e,i[o])&&(n[i[o]]=e[i[o]])}}return n};import{jsx as t,jsxs as n}from"react/jsx-runtime";import i from"react";import{observer as o}from"mobx-react-lite";import{PolotnoIcon as s}from"../icons/registry.js";import{t as a}from"../utils/l10n.js";import{firstSliderValue as r}from"../lib/utils.js";import{DropdownMenu as l,DropdownMenuContent as m,DropdownMenuItem as d,DropdownMenuSeparator as p}from"../primitives/dropdown-menu.js";import{Slider as c}from"../primitives/slider.js";import{SpeedControl as u}from"../primitives/speed-control.js";import{Spinner as h}from"./spinner.js";import{useWaveformData as v,useWaveformPath as f}from"./waveform.js";import{TrackWrapper as x,TrackContainer as y,TrackMenu as g,TrackMenuButton as M,TrackHandleLeft as T,TrackHandleRight as w,WaveformSvg as b}from"./track-styles.js";export const AUDIO_ROW_HEIGHT=28;export const AUDIO_TRACK_HEIGHT=24;const j=({position:e,store:t,scale:n})=>{const i=t.pages;for(const o of i){const t=o.startTime,i=o.startTime+o.duration;if(Math.abs(e-t)<10/n){return t}if(Math.abs(e-i)<10/n){return i}}return null};export const AudioTrack=o(({audio:o,scale:I,store:O,index:D})=>{const[E,A]=i.useState(1),S=i.useRef(null),L=0===o.volume,N=()=>{L?o.set({volume:E>0?E:1}):(A(o.volume),o.set({volume:0}))},P=(e=o.startTime,t=o.endTime,n=o.speed)=>Math.max(0,(t-e)*(o.duration||0)/n),C=e=>Math.max(0,O.duration-e),_=(e,t=P())=>Math.min(Math.max(0,e),C(t)),z=P(),X=O.duration*I-o.delay*I,k=Math.min(z*I,X),H=o.delay*I,{data:R,isLoading:$}=v(o.src),B=o.visibleDuration*I,V=f(R,20).path,Y=(e,t)=>{e.stopPropagation(),e.preventDefault();const n=e.clientX,i=H,s=k,a=o.endTime,r=o.startTime,l=o.delay,m=o.duration||1,d=o.speed,p=e=>{e.preventDefault();const p=(e.clientX-n)/I;if("start"===t){if(p>=0){const e=p*d,t=Math.max(0,a-.1-r)*m,n=Math.min(e,t);if(n<=0){return}let i=r+n/m;const s=(o.endTime-i)*m/d,c=l+n/d,u=C(s);let h=Math.min(Math.max(0,c),u);const v=j({position:h,store:O,scale:I});h=Math.min(Math.max(0,null!=v?v:h),u);const f=h-c;i=Math.min(o.endTime-.1,Math.max(0,i+f*d/m)),o.set({delay:h,startTime:i})}else{const e=-p*d,t=r*m,n=Math.min(e,t);if(n<=0){return}const i=n/m;let s=Math.max(0,r-i);const a=(o.endTime-s)*m/d,c=l-n/d,u=C(a);let h=Math.min(Math.max(0,c),u);const v=j({position:h,store:O,scale:I});h=Math.min(Math.max(0,null!=v?v:h),u);const f=h-c;s=Math.max(0,Math.min(o.endTime-.1,s+f*d/m)),o.set({delay:h,startTime:s})}}else{const e=i/I+s/I;let t=e+p;const n=j({position:t,store:O,scale:I});t=null!=n?n:t;const r=(t-e)*d/o.duration,l=Math.min(1,Math.max(o.startTime+.1,a+r));o.set({endTime:l})}},c=()=>{if(window.removeEventListener("mousemove",p),window.removeEventListener("mouseup",c),"start"===t){const e=j({position:o.delay,store:O,scale:I});if(null!=e&&e!==o.delay){const t=P(o.startTime,o.endTime),n=_(e,t),i=n-o.delay,s=Math.max(0,Math.min(o.endTime-.1,o.startTime+i*d/m));o.set({delay:n,startTime:s})}}};window.addEventListener("mousemove",p),window.addEventListener("mouseup",c)};return t(x,{ref:S,style:{left:`${H}px`,top:28*D+"px",width:`${k}px`,height:"24px"},className:"polotno-audio-container",children:n(y,{style:{width:"100%",height:"100%"},onMouseDown:e=>{const t=e.clientX,n=H;e.preventDefault();const i=e=>{e.preventDefault();const i=(e.clientX-t)/I;let s=n/I+i;const a=s+z,r=j({position:s,store:O,scale:I}),l=j({position:a,store:O,scale:I}),m=null!==r?Math.abs(s-r):Number.POSITIVE_INFINITY,d=null!==l?Math.abs(a-l):Number.POSITIVE_INFINITY;let p;p=_(null!==r&&m<d?r:null!==l?l-z:s),o.set({delay:_(p)})},s=()=>{window.removeEventListener("mousemove",i),window.removeEventListener("mouseup",s)};window.addEventListener("mousemove",i),window.addEventListener("mouseup",s)},children:[t("div",{style:{position:"absolute",left:"4px",top:"50%",transform:"translateY(-50%)",zIndex:10,pointerEvents:"auto"},onClick:e=>{e.stopPropagation(),N()},onMouseDown:e=>e.stopPropagation(),children:t(s,L?{name:"action.muted",className:"pn:size-3.5",style:{opacity:.7,cursor:"pointer"}}:{name:"action.unmuted",className:"pn:size-3.5",style:{opacity:.7,cursor:"pointer"}})}),t("div",{style:{position:"absolute",inset:"0 0 0 0",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:n("div",{style:{display:"flex",alignItems:"center",width:"100%",height:"100%",gap:"8px",paddingLeft:"22px"},children:[V&&t("div",{style:{flex:1,height:"14px",overflow:"hidden",opacity:L?.4:1},children:t(b,{width:B,height:"14",viewBox:`0 0 ${B} 20`,preserveAspectRatio:"none",style:{width:B+"px",height:"14px",transform:`translateX(-${o.startTime*B}px)`},children:t("path",{d:V})})}),$&&t("div",{style:{flex:1,display:"flex",justifyContent:"center",alignItems:"center"},children:t(h,{})})]})}),t(T,{onMouseDown:e=>Y(e,"start")}),t(w,{onMouseDown:e=>Y(e,"end")}),t(g,{onClick:e=>{e.stopPropagation()},onMouseDown:e=>e.stopPropagation(),children:n(l,{children:[t(M,{}),n(m,{side:"top",align:"start",anchor:S,style:{width:"220px"},children:[n("div",{style:{padding:"8px 12px"},children:[n("div",{style:{fontSize:"12px",marginBottom:"6px",display:"flex",justifyContent:"space-between",alignItems:"center"},children:[t("span",{children:a("pagesTimeline.volume")}),n("span",{children:[Math.round(100*o.volume),"%"]})]}),t(c,{value:[o.volume],min:0,max:1,step:.01,onValueChange:e=>(e=>{const t=Math.max(0,Math.min(1,e));t>0&&A(t),o.set({volume:t})})(r(e))})]}),n("div",{style:{padding:"8px 12px"},children:[t("div",{style:{fontSize:"12px",marginBottom:"6px"},children:a("pagesTimeline.speed")}),t(u,{value:o.speed,onChange:e=>{const t=P(o.startTime,o.endTime,e);o.set({speed:e,delay:_(o.delay,t)})}})]}),t(p,{}),n(d,{onSelect:e=>{e.preventDefault(),N()},children:[t(s,L?{name:"action.unmuted"}:{name:"action.muted"}),a(L?"pagesTimeline.unmuteAudio":"pagesTimeline.muteAudio")]}),n(d,{onSelect:t=>{t.preventDefault(),(()=>{const t=o.toJSON(),n=o.visibleDuration,i=o.delay+n,s=O.duration-i;let a=o.delay;s>=n?a=i:s>0&&(a=Math.max(0,O.duration-n));const{id:r}=t,l=e(t,["id"]);O.addAudio(Object.assign(Object.assign({},l),{delay:a}))})()},children:[t(s,{name:"action.duplicate"}),a("pagesTimeline.duplicateAudio")]}),t(p,{}),n(d,{onSelect:e=>{e.preventDefault(),O.removeAudio(o.id)},children:[t(s,{name:"action.remove"}),a("pagesTimeline.removeAudio")]})]})]})})]})})});
@@ -1 +1 @@
1
- import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import i from"react";import{observer as r}from"mobx-react-lite";import{PolotnoIcon as a}from"../icons/registry.js";import{flags as s}from"../utils/flags.js";import{t as o}from"../utils/l10n.js";import{Button as l}from"../primitives/button.js";import{Navbar as p}from"../primitives/navbar.js";import{Pages as m}from"./pages.js";import{CurrentTime as d}from"./current-time.js";import{Audios as c}from"./audios.js";import{ElementsTimeline as u}from"./elements.js";import{PlayButton as h}from"./play-button.js";import{TimeRuler as v}from"./time-ruler.js";export const PagesTimeline=r(({store:r,defaultOpened:g=!1})=>{const f=i.useRef(null),[b,x]=i.useState(g),[w,y]=i.useState(.02),[j,E]=i.useState(()=>(e=>{if(!s.animationsEnabled){return 65}const t=e.pages.reduce((e,t)=>e+t.children.length,0),n=25*e.audios.length+20*t+140;return Math.min(Math.max(n,140),420)})(r)),[z,k]=i.useState(!1),L=i.useRef(0),C=i.useRef(j),N=i.useRef(!1),M=r.duration*w,R=i.useCallback(e=>{if(!N.current){return}const t=e.clientY-L.current,n=C.current-t,i=Math.min(420,Math.max(140,n));E(i)},[]),S=i.useCallback(()=>{N.current&&(N.current=!1,k(!1),window.removeEventListener("mousemove",R),window.removeEventListener("mouseup",S))},[R]);return i.useEffect(()=>()=>{window.removeEventListener("mousemove",R),window.removeEventListener("mouseup",S)},[R,S]),t(n,{children:[e("div",{style:{position:"relative",height:"0px"},children:t(l,{variant:"ghost",size:"sm",onClick:()=>{x(!b)},className:"pn:absolute pn:bottom-[5px] pn:left-[5px] pn:z-[1] pn:h-[35px] pn:bg-background pn:shadow-md pn:dark:hover:bg-accent",children:[s.animationsEnabled&&!b?e(a,{name:"pagesTimeline.play",className:"pn:size-4"}):null,o("pagesTimeline.pages")]})}),t(p,{attached:"top",style:{padding:"5px",height:"auto",zIndex:1,position:"relative",overflow:"visible",display:b?"block":"none"},className:"polotno-pages-timeline pn:whitespace-normal pn:bg-background",children:[s.animationsEnabled&&e("div",{onMouseDown:e=>{e.preventDefault(),L.current=e.clientY,C.current=j,N.current=!0,k(!0),window.addEventListener("mousemove",R),window.addEventListener("mouseup",S)},className:"pn:group/pn-resize-handle pn:absolute pn:top-0 pn:left-0 pn:right-0 pn:flex pn:h-[14px] pn:-translate-y-1/2 pn:cursor-ns-resize pn:items-center pn:justify-center"+(z?" active":""),title:"Drag to adjust timeline height",children:e("div",{className:"pn:h-1 pn:w-full pn:rounded-[2px] pn:transition-colors pn:group-hover/pn-resize-handle:bg-primary"+(z?" pn:bg-primary":" pn:bg-transparent")})}),s.animationsEnabled&&e("div",{style:{display:"flex",justifyContent:"center"},children:e(h,{store:r,scale:w,onScaleChange:y})}),e("div",{dir:"ltr",style:{width:"100%",position:"relative",height:j},children:e("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,overflowX:"auto",padding:"0 24px"},ref:f,children:t("div",{style:{position:"relative",minWidth:s.animationsEnabled?M+"px":void 0},children:[s.animationsEnabled&&e(v,{store:r,scale:w,minWidth:M}),t("div",{style:{position:"relative",display:"flex"},children:[e("div",{style:{position:"relative",minWidth:s.animationsEnabled?M+"px":void 0,height:"60px"},children:e(m,{store:r,scale:w})}),e(l,{variant:"ghost",size:"icon",style:{width:"60px",height:"60px",marginLeft:"12px"},onClick:()=>{var e;r.addPage({bleed:(null===(e=r.activePage)||void 0===e?void 0:e.bleed)||0})},children:e(a,{name:"action.add",className:"pn:size-4"})})]}),s.animationsEnabled&&t(n,{children:[e(u,{store:r,scale:w,width:M}),e(c,{store:r,scale:w,width:M})]}),s.animationsEnabled&&e(d,{store:r,scale:w,dragAreaRef:f,variant:"timeline"})]})})})]})]})});
1
+ import{jsx as e,jsxs as t,Fragment as i}from"react/jsx-runtime";import n from"react";import{observer as r}from"mobx-react-lite";import{PolotnoIcon as s}from"../icons/registry.js";import{flags as o}from"../utils/flags.js";import{t as a}from"../utils/l10n.js";import{cn as l}from"../lib/utils.js";import{Button as p}from"../primitives/button.js";import{floatingControl as m}from"../primitives/floating-control.js";import{Navbar as d}from"../primitives/navbar.js";import{Pages as c}from"./pages.js";import{CurrentTime as u}from"./current-time.js";import{Audios as h}from"./audios.js";import{ElementsTimeline as v}from"./elements.js";import{PlayButton as f}from"./play-button.js";import{TimeRuler as g}from"./time-ruler.js";export const PagesTimeline=r(({store:r,defaultOpened:b=!1})=>{const x=n.useRef(null),[w,y]=n.useState(b),[j,E]=n.useState(.02),[z,k]=n.useState(()=>(e=>{if(!o.animationsEnabled){return 65}const t=e.pages.reduce((e,t)=>e+t.children.length,0),i=25*e.audios.length+20*t+140;return Math.min(Math.max(i,140),420)})(r)),[L,C]=n.useState(!1),N=n.useRef(0),M=n.useRef(z),R=n.useRef(!1),S=r.duration*j,D=n.useCallback(e=>{if(!R.current){return}const t=e.clientY-N.current,i=M.current-t,n=Math.min(420,Math.max(140,i));k(n)},[]),P=n.useCallback(()=>{R.current&&(R.current=!1,C(!1),window.removeEventListener("mousemove",D),window.removeEventListener("mouseup",P))},[D]);return n.useEffect(()=>()=>{window.removeEventListener("mousemove",D),window.removeEventListener("mouseup",P)},[D,P]),t(i,{children:[e("div",{style:{position:"relative",height:"0px"},children:t(p,{variant:"ghost",size:"sm",onClick:()=>{y(!w)},className:l(m(),"pn:absolute pn:bottom-[5px] pn:left-[5px] pn:z-[1] pn:dark:hover:bg-accent"),children:[o.animationsEnabled&&!w?e(s,{name:"pagesTimeline.play",className:"pn:size-4"}):null,a("pagesTimeline.pages")]})}),t(d,{attached:"top",style:{padding:"5px",height:"auto",zIndex:1,position:"relative",overflow:"visible",display:w?"block":"none"},className:"polotno-pages-timeline pn:whitespace-normal pn:bg-background",children:[o.animationsEnabled&&e("div",{onMouseDown:e=>{e.preventDefault(),N.current=e.clientY,M.current=z,R.current=!0,C(!0),window.addEventListener("mousemove",D),window.addEventListener("mouseup",P)},className:"pn:group/pn-resize-handle pn:absolute pn:top-0 pn:left-0 pn:right-0 pn:flex pn:h-[14px] pn:-translate-y-1/2 pn:cursor-ns-resize pn:items-center pn:justify-center"+(L?" active":""),title:"Drag to adjust timeline height",children:e("div",{className:"pn:h-1 pn:w-full pn:rounded-[2px] pn:transition-colors pn:group-hover/pn-resize-handle:bg-primary"+(L?" pn:bg-primary":" pn:bg-transparent")})}),o.animationsEnabled&&e("div",{style:{display:"flex",justifyContent:"center"},children:e(f,{store:r,scale:j,onScaleChange:E})}),e("div",{dir:"ltr",style:{width:"100%",position:"relative",height:z},children:e("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,overflowX:"auto",padding:"0 24px"},ref:x,children:t("div",{style:{position:"relative",minWidth:o.animationsEnabled?S+"px":void 0},children:[o.animationsEnabled&&e(g,{store:r,scale:j,minWidth:S}),t("div",{style:{position:"relative",display:"flex"},children:[e("div",{style:{position:"relative",minWidth:o.animationsEnabled?S+"px":void 0,height:"60px"},children:e(c,{store:r,scale:j})}),e(p,{variant:"ghost",size:"icon",style:{width:"60px",height:"60px",marginLeft:"12px"},onClick:()=>{var e;r.addPage({bleed:(null===(e=r.activePage)||void 0===e?void 0:e.bleed)||0})},children:e(s,{name:"action.add",className:"pn:size-4"})})]}),o.animationsEnabled&&t(i,{children:[e(v,{store:r,scale:j,width:S}),e(h,{store:r,scale:j,width:S})]}),o.animationsEnabled&&e(u,{store:r,scale:j,dragAreaRef:x,variant:"timeline"})]})})})]})]})});