@canva/design 2.2.1 → 2.3.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/index.d.ts CHANGED
@@ -10,7 +10,7 @@ export declare const addAudioTrack: (audioTrack: AudioTrack) => Promise<void>;
10
10
  * Add element to responsive documents, which slot things into a text stream
11
11
  */
12
12
  export declare const addElementAtCursor: (
13
- element: ElementAtCursor
13
+ element: ElementAtCursor,
14
14
  ) => Promise<void>;
15
15
 
16
16
  /**
@@ -18,7 +18,7 @@ export declare const addElementAtCursor: (
18
18
  * Add element to fixed designs, which use a coordinate-based positioning system.
19
19
  */
20
20
  export declare const addElementAtPoint: (
21
- element: DesignElement | ElementAtPoint
21
+ element: DesignElement | ElementAtPoint,
22
22
  ) => Promise<void>;
23
23
 
24
24
  /**
@@ -28,7 +28,7 @@ export declare const addElementAtPoint: (
28
28
  * @param element - The element to add to the user's design.
29
29
  */
30
30
  export declare const addNativeElement: (
31
- element: NativeElement | NativeElementWithBox
31
+ element: NativeElement | NativeElementWithBox,
32
32
  ) => Promise<void>;
33
33
 
34
34
  /**
@@ -88,7 +88,7 @@ export declare type AppElementChangeHandler<A extends AppElementData> = (
88
88
  */
89
89
  version: number;
90
90
  }
91
- | undefined
91
+ | undefined,
92
92
  ) => void;
93
93
 
94
94
  /**
@@ -103,6 +103,7 @@ export declare interface AppElementClient<A extends AppElementData> {
103
103
  * @param placement - The position, dimensions, and rotation of the app element.
104
104
  */
105
105
  addOrUpdateElement(appElementData: A, placement?: Placement): Promise<void>;
106
+
106
107
  /**
107
108
  * A callback that runs when:
108
109
  *
@@ -138,7 +139,7 @@ export declare type AppElementData = Record<string, Value>;
138
139
  * @param appElementData - The data the callback must use to render the app element.
139
140
  */
140
141
  export declare type AppElementRenderer<A extends AppElementData> = (
141
- appElementData: A
142
+ appElementData: A,
142
143
  ) => AppElementRendererOutput;
143
144
 
144
145
  /**
@@ -328,6 +329,14 @@ export declare interface ContentDraft<T> {
328
329
  */
329
330
  export declare type ContentType = "richtext";
330
331
 
332
+ /**
333
+ * @public
334
+ * Options for configuring where content in a design should be queried from.
335
+ */
336
+ declare type ContextOptions = {
337
+ target: "current_page";
338
+ };
339
+
331
340
  /**
332
341
  * @public
333
342
  * A set of X and Y coordinates.
@@ -440,37 +449,55 @@ export declare type Dimensions = {
440
449
 
441
450
  /**
442
451
  * @public
443
- * Callbacks for handling drag and drop events.
452
+ * An event that occurs when a user starts dragging an HTML element.
444
453
  */
445
- export declare type DragCallback = {
446
- /**
447
- * A callback that runs at the start of a drag event.
448
- * @param element - The element being dragged.
449
- */
450
- onDragStart: (element: HTMLElement) => void;
451
- /**
452
- * A callback that runs at the end of a drag event.
453
- * @param element - The element being dragged.
454
- */
455
- onDragEnd: (element: HTMLElement) => void;
454
+ export declare type DragStartEvent<E extends Element> = Pick<
455
+ DragEvent,
456
+ "dataTransfer" | "currentTarget" | "preventDefault" | "clientX" | "clientY"
457
+ > & {
458
+ currentTarget: E;
456
459
  };
457
460
 
458
461
  /**
459
462
  * @public
460
- * Options for adding drag and drop behavior to an `HTMLElement`.
463
+ * Reads and edits content of the specified type from the user's design.
464
+ * @param options - Options for configuring how a design is read.
465
+ * @param callback - A callback for operating on the read content.
461
466
  */
462
- export declare type DraggableElementData = ElementData | ImageElementData;
467
+ export declare const editContent: (
468
+ options: EditContentOptions,
469
+ callback: EditContentCallback,
470
+ ) => Promise<void>;
463
471
 
464
472
  /**
465
473
  * @public
466
- * An event that occurs when a user starts dragging an HTML element.
474
+ * A callback for reading and updating the requested design content.
475
+ * @param session - The result of reading the content in the design.
467
476
  */
468
- export declare type DragStartEvent<E extends Element> = Pick<
469
- DragEvent,
470
- "dataTransfer" | "currentTarget" | "preventDefault" | "clientX" | "clientY"
471
- > & {
472
- currentTarget: E;
473
- };
477
+ export declare type EditContentCallback = (session: {
478
+ /**
479
+ * The individual content items returned by a query.
480
+ */
481
+ readonly contents: readonly RichtextContentRange[];
482
+ /**
483
+ * Commits any changes made to the items in the `contents` array.
484
+ *
485
+ * @remarks
486
+ * An app must call this method for any changes to be reflected in the user's design.
487
+ */
488
+ sync(): Promise<void>;
489
+ }) => Promise<void> | void;
490
+
491
+ /**
492
+ * @public
493
+ * Options for configuring how the design content is read.
494
+ */
495
+ export declare type EditContentOptions = {
496
+ /**
497
+ * The type of content to edit from the user's design
498
+ */
499
+ contentType: ContentType;
500
+ } & ContextOptions;
474
501
 
475
502
  /**
476
503
  * @public
@@ -497,17 +524,6 @@ export declare type ElementAtPoint =
497
524
  | GroupElementAtPoint
498
525
  | RichtextElementAtPoint;
499
526
 
500
- /**
501
- * @public
502
- * Options for adding drag and drop behavior to an `HTMLElement`.
503
- */
504
- export declare type ElementData = DragCallback & {
505
- /**
506
- * The `HTMLElement` to be made draggable.
507
- */
508
- node: HTMLElement;
509
- };
510
-
511
527
  /**
512
528
  * @public
513
529
  * Embed element to be added to the design at the end of a drag event.
@@ -843,6 +859,9 @@ export declare type ImageElement = {
843
859
  type: "image";
844
860
  /**
845
861
  * A description of the image content.
862
+ *
863
+ * @remarks
864
+ * Use `undefined` for content with no description.
846
865
  */
847
866
  altText: AltText | undefined;
848
867
  } & (
@@ -876,17 +895,6 @@ export declare type ImageElementAtPoint = ImageElement &
876
895
  Point &
877
896
  (WidthAndHeight | Width | Height);
878
897
 
879
- /**
880
- * @public
881
- * Options for adding drag and drop behavior to an `HTMLImageElement`.
882
- */
883
- export declare type ImageElementData = DragCallback & {
884
- /**
885
- * The `HTMLImageElement` to be made draggable.
886
- */
887
- node: HTMLImageElement;
888
- };
889
-
890
898
  /**
891
899
  * @public
892
900
  * An image asset that fills a path's interior.
@@ -900,6 +908,13 @@ export declare type ImageFill = {
900
908
  * A unique identifier that points to an image asset in Canva's backend.
901
909
  */
902
910
  ref: ImageRef;
911
+ /**
912
+ * A description of the image content.
913
+ *
914
+ * @remarks
915
+ * Use `undefined` for content with no description.
916
+ */
917
+ altText?: AltText;
903
918
  };
904
919
 
905
920
  /**
@@ -915,7 +930,7 @@ export declare type ImageRef = string & {
915
930
  * @param appElementConfig - Configuration for an AppElementClient
916
931
  */
917
932
  export declare const initAppElement: <A extends AppElementData>(
918
- appElementConfig: AppElementClientConfiguration<A>
933
+ appElementConfig: AppElementClientConfiguration<A>,
919
934
  ) => AppElementClient<A>;
920
935
 
921
936
  /**
@@ -1271,9 +1286,20 @@ declare type Primitive = undefined | null | number | boolean | string;
1271
1286
  * @param request - The request object containing configurations of the design export.
1272
1287
  */
1273
1288
  export declare const requestExport: (
1274
- request: ExportRequest
1289
+ request: ExportRequest,
1275
1290
  ) => Promise<ExportResponse>;
1276
1291
 
1292
+ /**
1293
+ * @public
1294
+ * Provides methods for interacting with a range of formatted text.
1295
+ */
1296
+ export declare interface RichtextContentRange extends RichtextRange {
1297
+ /**
1298
+ * Indicates whether the object containing this richtext range has been deleted.
1299
+ */
1300
+ readonly deleted: boolean;
1301
+ }
1302
+
1277
1303
  /**
1278
1304
  * @public
1279
1305
  * An element that renders richtext content.
@@ -1381,7 +1407,7 @@ export declare type RichtextRange = {
1381
1407
  */
1382
1408
  appendText(
1383
1409
  characters: string,
1384
- formatting?: InlineFormatting
1410
+ formatting?: InlineFormatting,
1385
1411
  ): {
1386
1412
  bounds: Bounds;
1387
1413
  };
@@ -1395,7 +1421,7 @@ export declare type RichtextRange = {
1395
1421
  replaceText(
1396
1422
  bounds: Bounds,
1397
1423
  characters: string,
1398
- formatting?: InlineFormatting
1424
+ formatting?: InlineFormatting,
1399
1425
  ): {
1400
1426
  /**
1401
1427
  * The bounds of the replacement characters within the updated range.
@@ -1533,7 +1559,7 @@ export declare type SelectionValue<Scope extends SelectionScope> = {
1533
1559
  * an image or a video.
1534
1560
  */
1535
1561
  export declare const setCurrentPageBackground: (
1536
- opts: PageBackgroundFill
1562
+ opts: PageBackgroundFill,
1537
1563
  ) => Promise<void>;
1538
1564
 
1539
1565
  /**
@@ -1770,7 +1796,7 @@ export declare type TextElement = {
1770
1796
  * @public
1771
1797
  * An element that renders text content and has positional properties.
1772
1798
  */
1773
- export declare type TextElementAtPoint = TextElement & TextAttributes & TextBox;
1799
+ export declare type TextElementAtPoint = TextElement & TextBox;
1774
1800
 
1775
1801
  /**
1776
1802
  * @public
@@ -1807,7 +1833,7 @@ export declare interface UI {
1807
1833
  | AudioDragConfig
1808
1834
  | EmbedDragConfig
1809
1835
  | VideoDragConfigForElement<E>
1810
- | ImageDragConfigForElement<E>
1836
+ | ImageDragConfigForElement<E>,
1811
1837
  ): Promise<void>;
1812
1838
  /**
1813
1839
  * @public
@@ -1823,7 +1849,7 @@ export declare interface UI {
1823
1849
  | AudioDragConfig
1824
1850
  | EmbedDragConfig
1825
1851
  | VideoDragConfigForElement<E>
1826
- | ImageDragConfigForElement<E>
1852
+ | ImageDragConfigForElement<E>,
1827
1853
  ): Promise<void>;
1828
1854
  /**
1829
1855
  * @public
@@ -1837,7 +1863,7 @@ export declare interface UI {
1837
1863
  dragData:
1838
1864
  | EmbedDragConfig
1839
1865
  | VideoDragConfigForElement<E>
1840
- | ImageDragConfigForElement<E>
1866
+ | ImageDragConfigForElement<E>,
1841
1867
  ): Promise<void>;
1842
1868
  }
1843
1869
 
@@ -1917,6 +1943,9 @@ export declare type VideoElement = {
1917
1943
  ref: VideoRef;
1918
1944
  /**
1919
1945
  * A description of the video content.
1946
+ *
1947
+ * @remarks
1948
+ * Use `undefined` for content with no description.
1920
1949
  */
1921
1950
  altText: AltText | undefined;
1922
1951
  };
@@ -1942,6 +1971,13 @@ export declare type VideoFill = {
1942
1971
  * A unique identifier that points to a video asset in Canva's backend.
1943
1972
  */
1944
1973
  ref: VideoRef;
1974
+ /**
1975
+ * A description of the image content.
1976
+ *
1977
+ * @remarks
1978
+ * Use `undefined` for content with no description.
1979
+ */
1980
+ altText?: AltText;
1945
1981
  };
1946
1982
 
1947
1983
  /**
@@ -0,0 +1,27 @@
1
+ "use strict"
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "createFakeDesignClients", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return createFakeDesignClients;
9
+ }
10
+ });
11
+ const _synthetic_delay = require('../../utils/synthetic_delay');
12
+ const _fake_design_interaction_client = require("./fake_design_interaction_client");
13
+ const _fake_drag_and_drop_client = require("./fake_drag_and_drop_client");
14
+ const _fake_export_client = require("./fake_export_client");
15
+ function createFakeDesignClients() {
16
+ const syntheticDelay = (0, _synthetic_delay.createSyntheticDelay)(10);
17
+ const v2 = {
18
+ designInteraction: new _fake_design_interaction_client.FakeDesignInteractionClient(syntheticDelay),
19
+ dragAndDrop: new _fake_drag_and_drop_client.FakeDragAndDropClient(syntheticDelay),
20
+ export: new _fake_export_client.FakeExportClient(syntheticDelay)
21
+ };
22
+ return {
23
+ design: {
24
+ v2
25
+ }
26
+ };
27
+ }
@@ -0,0 +1,217 @@
1
+ "use strict"
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "FakeDesignInteractionClient", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return FakeDesignInteractionClient;
9
+ }
10
+ });
11
+ class FakeDesignInteractionClient {
12
+ async getDesignToken() {
13
+ await this.delay();
14
+ return {
15
+ token: 'token'
16
+ };
17
+ }
18
+ async addNativeElement(element) {
19
+ await this.delay();
20
+ }
21
+ async addElementAtPoint(element) {
22
+ await this.delay();
23
+ }
24
+ async addElementAtCursor(element) {
25
+ await this.delay();
26
+ }
27
+ async addAudioTrack(audioTrack) {
28
+ await this.delay();
29
+ }
30
+ async addPage(opts) {
31
+ await this.delay();
32
+ }
33
+ async setCurrentPageBackground(opts) {
34
+ await this.delay();
35
+ }
36
+ async setAppElementData(appElementData, placement) {
37
+ await this.delay();
38
+ }
39
+ onAppElementChange(handler) {}
40
+ async addAppElement(opts) {
41
+ await this.delay();
42
+ }
43
+ async updateAppElement(opts) {
44
+ await this.delay();
45
+ }
46
+ onAppElementDrop(handler) {}
47
+ onAppElementCreateFromPreset(handler) {}
48
+ registerRenderAppElement(renderAppElement) {}
49
+ async getCurrentPageContext() {
50
+ await this.delay();
51
+ return {
52
+ dimensions: fakePageDimensions
53
+ };
54
+ }
55
+ async getDefaultPageDimensions() {
56
+ await this.delay();
57
+ return fakePageDimensions;
58
+ }
59
+ initAppElement(appElementConfig) {
60
+ return {
61
+ addOrUpdateElement: async ()=>{
62
+ await this.delay();
63
+ },
64
+ registerOnElementChange: (handler)=>{},
65
+ addElement: async (opts)=>{
66
+ await this.delay();
67
+ }
68
+ };
69
+ }
70
+ createRichtextRange() {
71
+ return fakeRichtextRange;
72
+ }
73
+ async editContent(options, callback) {
74
+ await this.delay();
75
+ await callback({
76
+ contents: [],
77
+ sync: async ()=>{
78
+ await this.delay();
79
+ }
80
+ });
81
+ }
82
+ async openDesign(options, callback) {
83
+ await this.delay();
84
+ await callback({
85
+ page: fakePage,
86
+ save: async ()=>{
87
+ await this.delay();
88
+ }
89
+ }, {
90
+ elementBuilder: fakeElementBuilder
91
+ });
92
+ }
93
+ constructor(delay){
94
+ this.delay = delay;
95
+ this.selection = {
96
+ registerOnChange: (e)=>{
97
+ return ()=>{};
98
+ }
99
+ };
100
+ this.overlay = {
101
+ registerOnCanOpen: (e)=>{
102
+ return ()=>{};
103
+ }
104
+ };
105
+ }
106
+ }
107
+ const fakeBounds = {
108
+ index: 0,
109
+ length: 12
110
+ };
111
+ const fakeTextRegion = {
112
+ text: 'Hello World!',
113
+ formatting: {
114
+ fontWeight: 'bold'
115
+ }
116
+ };
117
+ const fakeRichtextRange = {
118
+ formatParagraph: ()=>{},
119
+ formatText: ()=>{},
120
+ appendText: ()=>{
121
+ return {
122
+ bounds: fakeBounds
123
+ };
124
+ },
125
+ replaceText: ()=>{
126
+ return {
127
+ bounds: fakeBounds
128
+ };
129
+ },
130
+ readPlaintext: ()=>'',
131
+ readTextRegions: ()=>[
132
+ fakeTextRegion
133
+ ]
134
+ };
135
+ const fakePageDimensions = {
136
+ width: 800,
137
+ height: 600
138
+ };
139
+ const fakeFill = {
140
+ media: undefined,
141
+ color: {
142
+ type: 'solid',
143
+ color: '#FFFFFF'
144
+ }
145
+ };
146
+ const fakePage = {
147
+ type: 'fixed',
148
+ locked: false,
149
+ dimensions: fakePageDimensions,
150
+ background: fakeFill,
151
+ elements: {
152
+ count: ()=>0,
153
+ toArray: ()=>[],
154
+ insertBefore: (ref)=>ref,
155
+ insertAfter: (ref)=>ref,
156
+ forEach: (callback)=>{},
157
+ filter: (filter)=>[],
158
+ moveBefore: (item)=>{},
159
+ moveAfter: (item)=>{},
160
+ delete: (item)=>{}
161
+ }
162
+ };
163
+ const fakeElement = {
164
+ top: 0,
165
+ left: 0,
166
+ rotation: 0,
167
+ transparency: 0,
168
+ locked: true,
169
+ width: 100,
170
+ height: 100
171
+ };
172
+ const fakeRectElement = {
173
+ ...fakeElement,
174
+ type: 'rect',
175
+ fill: fakeFill,
176
+ stroke: {
177
+ weight: 10,
178
+ color: fakeFill.color
179
+ }
180
+ };
181
+ const fakeShapeElement = {
182
+ ...fakeElement,
183
+ type: 'shape',
184
+ viewBox: {
185
+ top: 0,
186
+ left: 0,
187
+ width: 100,
188
+ height: 100
189
+ },
190
+ paths: {
191
+ count: ()=>0,
192
+ toArray: ()=>[],
193
+ forEach: (callback)=>{},
194
+ filter: (filter)=>[]
195
+ }
196
+ };
197
+ const fakeEmbedElement = {
198
+ ...fakeElement,
199
+ type: 'embed',
200
+ url: 'https://canva.dev/docs/apps/testing/'
201
+ };
202
+ const fakeTextElement = {
203
+ ...fakeElement,
204
+ type: 'text',
205
+ text: fakeRichtextRange
206
+ };
207
+ function cloneElement(element) {
208
+ return fakeRectElement;
209
+ }
210
+ const fakeElementBuilder = {
211
+ createRectElement: (opts)=>fakeRectElement,
212
+ createShapeElement: (opts)=>fakeShapeElement,
213
+ createEmbedElement: (opts)=>fakeEmbedElement,
214
+ createTextElement: (opts)=>fakeTextElement,
215
+ createRichtextRange: ()=>fakeRichtextRange,
216
+ cloneElement
217
+ };
@@ -0,0 +1,24 @@
1
+ "use strict"
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "FakeDragAndDropClient", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return FakeDragAndDropClient;
9
+ }
10
+ });
11
+ class FakeDragAndDropClient {
12
+ async startDrag(event, dragData) {
13
+ await this.delay();
14
+ }
15
+ async startDragToPoint(event, dragData) {
16
+ await this.delay();
17
+ }
18
+ async startDragToCursor(event, dragData) {
19
+ await this.delay();
20
+ }
21
+ constructor(delay){
22
+ this.delay = delay;
23
+ }
24
+ }
@@ -0,0 +1,34 @@
1
+ "use strict"
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "FakeExportClient", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return FakeExportClient;
9
+ }
10
+ });
11
+ class FakeExportClient {
12
+ async queueDocument(request) {
13
+ await this.delay();
14
+ return {
15
+ status: 'completed',
16
+ exportBlobs: fakeExportBlobs
17
+ };
18
+ }
19
+ async requestExport(request) {
20
+ await this.delay();
21
+ return {
22
+ status: 'completed',
23
+ exportBlobs: fakeExportBlobs
24
+ };
25
+ }
26
+ constructor(delay){
27
+ this.delay = delay;
28
+ }
29
+ }
30
+ const fakeExportBlobs = [
31
+ {
32
+ url: 'https://canva.dev/docs/apps/testing/'
33
+ }
34
+ ];
@@ -17,4 +17,4 @@ function _export_star(from, to) {
17
17
  return from;
18
18
  }
19
19
  var _window___canva___sdkRegistration, _window___canva__;
20
- (_window___canva__ = window.__canva__) === null || _window___canva__ === void 0 ? void 0 : (_window___canva___sdkRegistration = _window___canva__.sdkRegistration) === null || _window___canva___sdkRegistration === void 0 ? void 0 : _window___canva___sdkRegistration.registerPackageVersion('design', '2.2.1', 'ga');
20
+ (_window___canva__ = window.__canva__) === null || _window___canva__ === void 0 ? void 0 : (_window___canva___sdkRegistration = _window___canva__.sdkRegistration) === null || _window___canva___sdkRegistration === void 0 ? void 0 : _window___canva___sdkRegistration.registerPackageVersion('design', '2.3.0', 'ga');
@@ -53,6 +53,9 @@ _export(exports, {
53
53
  },
54
54
  createRichtextRange: function() {
55
55
  return createRichtextRange;
56
+ },
57
+ editContent: function() {
58
+ return editContent;
56
59
  }
57
60
  });
58
61
  const { canva_sdk } = window;
@@ -71,3 +74,4 @@ const getCurrentPageContext = canva_sdk.design.v2.designInteraction.getCurrentPa
71
74
  const initAppElement = canva_sdk.design.v2.designInteraction.initAppElement;
72
75
  const getDesignToken = canva_sdk.design.v2.designInteraction.getDesignToken;
73
76
  const createRichtextRange = canva_sdk.design.v2.designInteraction.createRichtextRange;
77
+ const editContent = canva_sdk.design.v2.designInteraction.editContent;
@@ -0,0 +1,16 @@
1
+ "use strict"
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "initTestEnvironment", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return initTestEnvironment;
9
+ }
10
+ });
11
+ const _create = require('../fake/create');
12
+ const _canva_sdk = require('../../utils/canva_sdk');
13
+ function initTestEnvironment() {
14
+ (0, _canva_sdk.assertIsTestCanvaSdk)();
15
+ (0, _canva_sdk.injectFakeAPIClients)((0, _create.createFakeDesignClients)());
16
+ }
@@ -0,0 +1,41 @@
1
+ "use strict"
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ getCanvaSdk: function() {
13
+ return getCanvaSdk;
14
+ },
15
+ assertIsTestCanvaSdk: function() {
16
+ return assertIsTestCanvaSdk;
17
+ },
18
+ injectFakeAPIClients: function() {
19
+ return injectFakeAPIClients;
20
+ }
21
+ });
22
+ function getCanvaSdk() {
23
+ return window.canva_sdk;
24
+ }
25
+ function assertIsTestCanvaSdk() {
26
+ var _window___canva__;
27
+ if ((_window___canva__ = window.__canva__) === null || _window___canva__ === void 0 ? void 0 : _window___canva__.uiKit) {
28
+ var _getCanvaSdk_error, _getCanvaSdk;
29
+ const CanvaError = (_getCanvaSdk = getCanvaSdk()) === null || _getCanvaSdk === void 0 ? void 0 : (_getCanvaSdk_error = _getCanvaSdk.error) === null || _getCanvaSdk_error === void 0 ? void 0 : _getCanvaSdk_error.v2.CanvaError;
30
+ throw new CanvaError({
31
+ code: 'failed_precondition',
32
+ message: "Canva App SDK: You're attempting to call `initTestEnvironment` in a non-test environment, such as in production. This method should be called in test environments, once and only once. For more info refer to https://canva.dev/docs/apps/testing/"
33
+ });
34
+ }
35
+ }
36
+ function injectFakeAPIClients(clients) {
37
+ window.canva_sdk = {
38
+ ...getCanvaSdk(),
39
+ ...clients
40
+ };
41
+ }
@@ -0,0 +1,13 @@
1
+ "use strict"
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "createSyntheticDelay", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return createSyntheticDelay;
9
+ }
10
+ });
11
+ function createSyntheticDelay(timeout) {
12
+ return ()=>new Promise((res)=>setTimeout(res, timeout));
13
+ }
@@ -0,0 +1,17 @@
1
+ import { createSyntheticDelay } from '../../utils/synthetic_delay';
2
+ import { FakeDesignInteractionClient } from './fake_design_interaction_client';
3
+ import { FakeDragAndDropClient } from './fake_drag_and_drop_client';
4
+ import { FakeExportClient } from './fake_export_client';
5
+ export function createFakeDesignClients() {
6
+ const syntheticDelay = createSyntheticDelay(10);
7
+ const v2 = {
8
+ designInteraction: new FakeDesignInteractionClient(syntheticDelay),
9
+ dragAndDrop: new FakeDragAndDropClient(syntheticDelay),
10
+ export: new FakeExportClient(syntheticDelay)
11
+ };
12
+ return {
13
+ design: {
14
+ v2
15
+ }
16
+ };
17
+ }
@@ -0,0 +1,207 @@
1
+ export class FakeDesignInteractionClient {
2
+ async getDesignToken() {
3
+ await this.delay();
4
+ return {
5
+ token: 'token'
6
+ };
7
+ }
8
+ async addNativeElement(element) {
9
+ await this.delay();
10
+ }
11
+ async addElementAtPoint(element) {
12
+ await this.delay();
13
+ }
14
+ async addElementAtCursor(element) {
15
+ await this.delay();
16
+ }
17
+ async addAudioTrack(audioTrack) {
18
+ await this.delay();
19
+ }
20
+ async addPage(opts) {
21
+ await this.delay();
22
+ }
23
+ async setCurrentPageBackground(opts) {
24
+ await this.delay();
25
+ }
26
+ async setAppElementData(appElementData, placement) {
27
+ await this.delay();
28
+ }
29
+ onAppElementChange(handler) {}
30
+ async addAppElement(opts) {
31
+ await this.delay();
32
+ }
33
+ async updateAppElement(opts) {
34
+ await this.delay();
35
+ }
36
+ onAppElementDrop(handler) {}
37
+ onAppElementCreateFromPreset(handler) {}
38
+ registerRenderAppElement(renderAppElement) {}
39
+ async getCurrentPageContext() {
40
+ await this.delay();
41
+ return {
42
+ dimensions: fakePageDimensions
43
+ };
44
+ }
45
+ async getDefaultPageDimensions() {
46
+ await this.delay();
47
+ return fakePageDimensions;
48
+ }
49
+ initAppElement(appElementConfig) {
50
+ return {
51
+ addOrUpdateElement: async ()=>{
52
+ await this.delay();
53
+ },
54
+ registerOnElementChange: (handler)=>{},
55
+ addElement: async (opts)=>{
56
+ await this.delay();
57
+ }
58
+ };
59
+ }
60
+ createRichtextRange() {
61
+ return fakeRichtextRange;
62
+ }
63
+ async editContent(options, callback) {
64
+ await this.delay();
65
+ await callback({
66
+ contents: [],
67
+ sync: async ()=>{
68
+ await this.delay();
69
+ }
70
+ });
71
+ }
72
+ async openDesign(options, callback) {
73
+ await this.delay();
74
+ await callback({
75
+ page: fakePage,
76
+ save: async ()=>{
77
+ await this.delay();
78
+ }
79
+ }, {
80
+ elementBuilder: fakeElementBuilder
81
+ });
82
+ }
83
+ constructor(delay){
84
+ this.delay = delay;
85
+ this.selection = {
86
+ registerOnChange: (e)=>{
87
+ return ()=>{};
88
+ }
89
+ };
90
+ this.overlay = {
91
+ registerOnCanOpen: (e)=>{
92
+ return ()=>{};
93
+ }
94
+ };
95
+ }
96
+ }
97
+ const fakeBounds = {
98
+ index: 0,
99
+ length: 12
100
+ };
101
+ const fakeTextRegion = {
102
+ text: 'Hello World!',
103
+ formatting: {
104
+ fontWeight: 'bold'
105
+ }
106
+ };
107
+ const fakeRichtextRange = {
108
+ formatParagraph: ()=>{},
109
+ formatText: ()=>{},
110
+ appendText: ()=>{
111
+ return {
112
+ bounds: fakeBounds
113
+ };
114
+ },
115
+ replaceText: ()=>{
116
+ return {
117
+ bounds: fakeBounds
118
+ };
119
+ },
120
+ readPlaintext: ()=>'',
121
+ readTextRegions: ()=>[
122
+ fakeTextRegion
123
+ ]
124
+ };
125
+ const fakePageDimensions = {
126
+ width: 800,
127
+ height: 600
128
+ };
129
+ const fakeFill = {
130
+ media: undefined,
131
+ color: {
132
+ type: 'solid',
133
+ color: '#FFFFFF'
134
+ }
135
+ };
136
+ const fakePage = {
137
+ type: 'fixed',
138
+ locked: false,
139
+ dimensions: fakePageDimensions,
140
+ background: fakeFill,
141
+ elements: {
142
+ count: ()=>0,
143
+ toArray: ()=>[],
144
+ insertBefore: (ref)=>ref,
145
+ insertAfter: (ref)=>ref,
146
+ forEach: (callback)=>{},
147
+ filter: (filter)=>[],
148
+ moveBefore: (item)=>{},
149
+ moveAfter: (item)=>{},
150
+ delete: (item)=>{}
151
+ }
152
+ };
153
+ const fakeElement = {
154
+ top: 0,
155
+ left: 0,
156
+ rotation: 0,
157
+ transparency: 0,
158
+ locked: true,
159
+ width: 100,
160
+ height: 100
161
+ };
162
+ const fakeRectElement = {
163
+ ...fakeElement,
164
+ type: 'rect',
165
+ fill: fakeFill,
166
+ stroke: {
167
+ weight: 10,
168
+ color: fakeFill.color
169
+ }
170
+ };
171
+ const fakeShapeElement = {
172
+ ...fakeElement,
173
+ type: 'shape',
174
+ viewBox: {
175
+ top: 0,
176
+ left: 0,
177
+ width: 100,
178
+ height: 100
179
+ },
180
+ paths: {
181
+ count: ()=>0,
182
+ toArray: ()=>[],
183
+ forEach: (callback)=>{},
184
+ filter: (filter)=>[]
185
+ }
186
+ };
187
+ const fakeEmbedElement = {
188
+ ...fakeElement,
189
+ type: 'embed',
190
+ url: 'https://canva.dev/docs/apps/testing/'
191
+ };
192
+ const fakeTextElement = {
193
+ ...fakeElement,
194
+ type: 'text',
195
+ text: fakeRichtextRange
196
+ };
197
+ function cloneElement(element) {
198
+ return fakeRectElement;
199
+ }
200
+ const fakeElementBuilder = {
201
+ createRectElement: (opts)=>fakeRectElement,
202
+ createShapeElement: (opts)=>fakeShapeElement,
203
+ createEmbedElement: (opts)=>fakeEmbedElement,
204
+ createTextElement: (opts)=>fakeTextElement,
205
+ createRichtextRange: ()=>fakeRichtextRange,
206
+ cloneElement
207
+ };
@@ -0,0 +1,14 @@
1
+ export class FakeDragAndDropClient {
2
+ async startDrag(event, dragData) {
3
+ await this.delay();
4
+ }
5
+ async startDragToPoint(event, dragData) {
6
+ await this.delay();
7
+ }
8
+ async startDragToCursor(event, dragData) {
9
+ await this.delay();
10
+ }
11
+ constructor(delay){
12
+ this.delay = delay;
13
+ }
14
+ }
@@ -0,0 +1,24 @@
1
+ export class FakeExportClient {
2
+ async queueDocument(request) {
3
+ await this.delay();
4
+ return {
5
+ status: 'completed',
6
+ exportBlobs: fakeExportBlobs
7
+ };
8
+ }
9
+ async requestExport(request) {
10
+ await this.delay();
11
+ return {
12
+ status: 'completed',
13
+ exportBlobs: fakeExportBlobs
14
+ };
15
+ }
16
+ constructor(delay){
17
+ this.delay = delay;
18
+ }
19
+ }
20
+ const fakeExportBlobs = [
21
+ {
22
+ url: 'https://canva.dev/docs/apps/testing/'
23
+ }
24
+ ];
@@ -1,3 +1,3 @@
1
1
  var _window___canva___sdkRegistration, _window___canva__;
2
2
  export * from './public';
3
- (_window___canva__ = window.__canva__) === null || _window___canva__ === void 0 ? void 0 : (_window___canva___sdkRegistration = _window___canva__.sdkRegistration) === null || _window___canva___sdkRegistration === void 0 ? void 0 : _window___canva___sdkRegistration.registerPackageVersion('design', '2.2.1', 'ga');
3
+ (_window___canva__ = window.__canva__) === null || _window___canva__ === void 0 ? void 0 : (_window___canva___sdkRegistration = _window___canva__.sdkRegistration) === null || _window___canva___sdkRegistration === void 0 ? void 0 : _window___canva___sdkRegistration.registerPackageVersion('design', '2.3.0', 'ga');
@@ -14,3 +14,4 @@ export const getCurrentPageContext = canva_sdk.design.v2.designInteraction.getCu
14
14
  export const initAppElement = canva_sdk.design.v2.designInteraction.initAppElement;
15
15
  export const getDesignToken = canva_sdk.design.v2.designInteraction.getDesignToken;
16
16
  export const createRichtextRange = canva_sdk.design.v2.designInteraction.createRichtextRange;
17
+ export const editContent = canva_sdk.design.v2.designInteraction.editContent;
@@ -0,0 +1,6 @@
1
+ import { createFakeDesignClients } from '../fake/create';
2
+ import { assertIsTestCanvaSdk, injectFakeAPIClients } from '../../utils/canva_sdk';
3
+ export function initTestEnvironment() {
4
+ assertIsTestCanvaSdk();
5
+ injectFakeAPIClients(createFakeDesignClients());
6
+ }
@@ -0,0 +1,20 @@
1
+ export function getCanvaSdk() {
2
+ return window.canva_sdk;
3
+ }
4
+ export function assertIsTestCanvaSdk() {
5
+ var _window___canva__;
6
+ if ((_window___canva__ = window.__canva__) === null || _window___canva__ === void 0 ? void 0 : _window___canva__.uiKit) {
7
+ var _getCanvaSdk_error, _getCanvaSdk;
8
+ const CanvaError = (_getCanvaSdk = getCanvaSdk()) === null || _getCanvaSdk === void 0 ? void 0 : (_getCanvaSdk_error = _getCanvaSdk.error) === null || _getCanvaSdk_error === void 0 ? void 0 : _getCanvaSdk_error.v2.CanvaError;
9
+ throw new CanvaError({
10
+ code: 'failed_precondition',
11
+ message: "Canva App SDK: You're attempting to call `initTestEnvironment` in a non-test environment, such as in production. This method should be called in test environments, once and only once. For more info refer to https://canva.dev/docs/apps/testing/"
12
+ });
13
+ }
14
+ }
15
+ export function injectFakeAPIClients(clients) {
16
+ window.canva_sdk = {
17
+ ...getCanvaSdk(),
18
+ ...clients
19
+ };
20
+ }
@@ -0,0 +1,3 @@
1
+ export function createSyntheticDelay(timeout) {
2
+ return ()=>new Promise((res)=>setTimeout(res, timeout));
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canva/design",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "description": "The Canva Apps SDK design library",
5
5
  "author": "Canva Pty Ltd.",
6
6
  "license": "SEE LICENSE IN LICENSE.md FILE",
@@ -11,14 +11,14 @@
11
11
  "module": "./lib/esm/sdk/design/index.js",
12
12
  "exports": {
13
13
  ".": {
14
- "require": {
15
- "types": "./index.d.ts",
16
- "default": "./lib/cjs/sdk/design/index.js"
17
- },
18
- "import": {
19
- "types": "./index.d.ts",
20
- "default": "./lib/esm/sdk/design/index.js"
21
- }
14
+ "types": "./index.d.ts",
15
+ "require": "./lib/cjs/sdk/design/index.js",
16
+ "import": "./lib/esm/sdk/design/index.js"
17
+ },
18
+ "./test": {
19
+ "types": "./test/index.d.ts",
20
+ "require": "./lib/cjs/sdk/design/test/index.js",
21
+ "import": "./lib/esm/sdk/design/test/index.js"
22
22
  }
23
23
  },
24
24
  "typings": "./index.d.ts"
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @public
3
+ * Initializes a test environment for the `@canva/design` package, enabling unit tests to mock Canva's APIs.
4
+ * @remarks
5
+ * This method should only be called once in a test environment, such as in a Jest setup file.
6
+ * @see
7
+ * https://www.canva.dev/docs/apps/testing/
8
+ */
9
+ export declare function initTestEnvironment(): void;
10
+
11
+ export {};