@canva/cli 1.10.0 → 1.11.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 (64) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/cli.js +472 -463
  3. package/lib/cjs/index.cjs +2 -2
  4. package/lib/esm/index.mjs +2 -2
  5. package/lib/index.d.ts +2 -0
  6. package/package.json +1 -1
  7. package/templates/base/package.json +3 -2
  8. package/templates/base/styles/components.css +18 -0
  9. package/templates/common/.env.template +1 -1
  10. package/templates/dam/canva-app.json +5 -0
  11. package/templates/dam/package.json +4 -2
  12. package/templates/dam/src/index.tsx +3 -21
  13. package/templates/dam/src/intents/design_editor/index.tsx +25 -0
  14. package/templates/data_connector/package.json +3 -2
  15. package/templates/data_connector/src/api/data_sources/designs.tsx +1 -1
  16. package/templates/data_connector/src/api/data_sources/templates.tsx +1 -1
  17. package/templates/data_connector/src/components/header.tsx +1 -1
  18. package/templates/data_connector/src/index.tsx +2 -66
  19. package/templates/data_connector/src/{app.tsx → intents/data_connector/app.tsx} +3 -3
  20. package/templates/data_connector/src/{entrypoint.tsx → intents/data_connector/entrypoint.tsx} +5 -5
  21. package/templates/data_connector/src/{home.tsx → intents/data_connector/home.tsx} +1 -1
  22. package/templates/data_connector/src/intents/data_connector/index.tsx +56 -0
  23. package/templates/data_connector/src/pages/error.tsx +1 -1
  24. package/templates/data_connector/src/pages/login.tsx +1 -1
  25. package/templates/data_connector/src/routes/protected_route.tsx +1 -1
  26. package/templates/data_connector/src/routes/routes.tsx +3 -3
  27. package/templates/data_connector/styles/components.css +18 -0
  28. package/templates/gen_ai/canva-app.json +5 -0
  29. package/templates/gen_ai/package.json +4 -2
  30. package/templates/gen_ai/src/components/footer.tsx +1 -1
  31. package/templates/gen_ai/src/components/loading_results.tsx +1 -1
  32. package/templates/gen_ai/src/components/prompt_input.tsx +1 -1
  33. package/templates/gen_ai/src/index.tsx +3 -14
  34. package/templates/gen_ai/src/{app.tsx → intents/design_editor/app.tsx} +3 -3
  35. package/templates/gen_ai/src/{home.tsx → intents/design_editor/home.tsx} +1 -1
  36. package/templates/gen_ai/src/intents/design_editor/index.tsx +17 -0
  37. package/templates/gen_ai/src/pages/error.tsx +1 -1
  38. package/templates/gen_ai/src/routes/routes.tsx +2 -2
  39. package/templates/gen_ai/styles/components.css +18 -0
  40. package/templates/hello_world/canva-app.json +5 -0
  41. package/templates/hello_world/package.json +4 -2
  42. package/templates/hello_world/src/index.tsx +3 -21
  43. package/templates/hello_world/src/{app.tsx → intents/design_editor/app.tsx} +26 -3
  44. package/templates/hello_world/src/intents/design_editor/index.tsx +25 -0
  45. package/templates/hello_world/src/{tests → intents/design_editor/tests}/app.tests.tsx +19 -13
  46. package/templates/hello_world/styles/components.css +18 -0
  47. package/templates/optional/AGENTS.md +80 -2
  48. package/templates/optional/CLAUDE.md +80 -2
  49. package/templates/base/utils/use_add_element.ts +0 -58
  50. package/templates/base/utils/use_feature_support.ts +0 -28
  51. package/templates/common/utils/table_wrapper.ts +0 -520
  52. package/templates/common/utils/use_add_element.ts +0 -58
  53. package/templates/common/utils/use_feature_support.ts +0 -28
  54. package/templates/common/utils/use_overlay_hook.ts +0 -76
  55. package/templates/common/utils/use_selection_hook.ts +0 -37
  56. package/templates/hello_world/utils/use_add_element.ts +0 -58
  57. package/templates/hello_world/utils/use_feature_support.ts +0 -28
  58. /package/templates/dam/src/{adapter.ts → intents/design_editor/adapter.ts} +0 -0
  59. /package/templates/dam/src/{app.tsx → intents/design_editor/app.tsx} +0 -0
  60. /package/templates/dam/src/{config.ts → intents/design_editor/config.ts} +0 -0
  61. /package/templates/dam/src/{index.css → intents/design_editor/index.css} +0 -0
  62. /package/templates/data_connector/src/{paths.ts → routes/paths.ts} +0 -0
  63. /package/templates/gen_ai/src/{paths.ts → routes/paths.ts} +0 -0
  64. /package/templates/hello_world/src/{tests → intents/design_editor/tests}/__snapshots__/app.tests.tsx.snap +0 -0
@@ -36,3 +36,21 @@
36
36
  .scrollContainer:focus-within::-webkit-scrollbar-thumb {
37
37
  visibility: visible;
38
38
  }
39
+
40
+ /* Main container for the content publisher preview UI */
41
+ .previewContainer {
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ flex-direction: column;
46
+ width: 100%;
47
+ height: 100%;
48
+ }
49
+
50
+ /* Wrapper for the content publisher post preview */
51
+ .previewWrapper {
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: center;
55
+ width: calc(400px + 32px + 2px); /* Image width + padding + border */
56
+ }
@@ -29,8 +29,9 @@ The app, once submitted to Canva, will be rendered in a sandboxed iframe within
29
29
  ## Architecture
30
30
 
31
31
  - **Main App**:
32
- - `src/index.tsx` - Main application react application entry point.
33
- - `src/app.tsx` - Main application component, which can/should be split into smaller components as needed, following react best practices.
32
+ - `src/index.tsx` - Main application React application entry point.
33
+ - `src/intents/[intent]/index.tsx` - Every intent that the app implements should be contained in the intents path.
34
+ - `src/intents/[intent]/app.tsx` - Main application component for each intent, which should be split into smaller components as needed, following React best practices.
34
35
  - `src/styles/component.css` - Main application styles.
35
36
  - `utils/` - Utility functions and helpers, which can be used across the app.
36
37
  - `scripts/` - Scripts for building, and running the app, should not contain any business logic.
@@ -74,3 +75,80 @@ The app, once submitted to Canva, will be rendered in a sandboxed iframe within
74
75
  - **Required**: AI agents should verify and encourage the user to enable Canva Dev MCP server.
75
76
  - **Documentation**: <https://www.canva.dev/docs/apps/mcp-server.md>
76
77
  - **If not setup**: Read the docs and prompt user to configure the MCP server for enhanced Canva APIs assistance.
78
+
79
+ ## Intent-based architecture
80
+
81
+ All apps should follow the intent-based architecture pattern. Each root index file should call the prepare function for each enabled intent. Each intent index file should implement the full intent contract.
82
+
83
+ ### File structure
84
+
85
+ Organize code with a dedicated folder for each intent under `src/intents/`:
86
+
87
+ ```
88
+ src/
89
+ ├── intents/
90
+ │ ├── design_editor/
91
+ │ │ ├── index.tsx
92
+ │ │ └── editor_app.tsx
93
+ │ └── content_publisher/
94
+ │ ├── index.tsx
95
+ │ ├── preview_ui.tsx
96
+ │ └── setting_ui.tsx
97
+ └── index.tsx
98
+ ```
99
+
100
+ ### Root index file
101
+
102
+ The root `src/index.tsx` should be minimal, containing only:
103
+
104
+ - Importing each prepare function
105
+ - Importing each intent
106
+ - The prepare call for each intent implementation.
107
+
108
+ ```tsx
109
+ import { prepareContentPublisher } from "@canva/intents/content";
110
+ import { prepareDesignEditor } from "@canva/intents/design";
111
+
112
+ import contentPublisher from "./intents/content_publisher";
113
+ import designEditor from "./intents/design_editor";
114
+
115
+ prepareContentPublisher(contentPublisher);
116
+ prepareDesignEditor(designEditor);
117
+ ```
118
+
119
+ ### Intent index files
120
+
121
+ Each intent's `index.tsx` file should:
122
+
123
+ - Import dependencies, including the app ui kit css.
124
+ - Implement the full contract for the intent and use this as the default export from the file.
125
+
126
+ ```tsx
127
+ // src/intents/design_editor/index.tsx
128
+ import "@canva/app-ui-kit/styles.css";
129
+ import type { DesignEditorIntent } from "@canva/intents/design";
130
+ import { prepareDesignEditor } from "@canva/intents/design";
131
+ import { AppI18nProvider } from "@canva/app-i18n-kit";
132
+ import { AppUiProvider } from "@canva/app-ui-kit";
133
+ import { createRoot } from "react-dom/client";
134
+ import { App } from "./app";
135
+
136
+ async function render() {
137
+ const root = createRoot(document.getElementById("root") as Element);
138
+
139
+ root.render(
140
+ <AppI18nProvider>
141
+ <AppUiProvider>
142
+ <App />
143
+ </AppUiProvider>
144
+ </AppI18nProvider>,
145
+ );
146
+ }
147
+
148
+ const designEditor: DesignEditorIntent = { render };
149
+ export default designEditor;
150
+
151
+ if (module.hot) {
152
+ module.hot.accept("./app", render);
153
+ }
154
+ ```
@@ -29,8 +29,9 @@ The app, once submitted to Canva, will be rendered in a sandboxed iframe within
29
29
  ## Architecture
30
30
 
31
31
  - **Main App**:
32
- - `src/index.tsx` - Main application react application entry point.
33
- - `src/app.tsx` - Main application component, which can/should be split into smaller components as needed, following react best practices.
32
+ - `src/index.tsx` - Main application React application entry point.
33
+ - `src/intents/[intent]/index.tsx` - Every intent that the app implements should be contained in the intents path.
34
+ - `src/intents/[intent]/app.tsx` - Main application component for each intent, which should be split into smaller components as needed, following React best practices.
34
35
  - `src/styles/component.css` - Main application styles.
35
36
  - `utils/` - Utility functions and helpers, which can be used across the app.
36
37
  - `scripts/` - Scripts for building, and running the app, should not contain any business logic.
@@ -74,3 +75,80 @@ The app, once submitted to Canva, will be rendered in a sandboxed iframe within
74
75
  - **Required**: AI agents should verify and encourage the user to enable Canva Dev MCP server.
75
76
  - **Documentation**: <https://www.canva.dev/docs/apps/mcp-server.md>
76
77
  - **If not setup**: Read the docs and prompt user to configure the MCP server for enhanced Canva APIs assistance.
78
+
79
+ ## Intent-based architecture
80
+
81
+ All apps should follow the intent-based architecture pattern. Each root index file should call the prepare function for each enabled intent. Each intent index file should implement the full intent contract.
82
+
83
+ ### File structure
84
+
85
+ Organize code with a dedicated folder for each intent under `src/intents/`:
86
+
87
+ ```
88
+ src/
89
+ ├── intents/
90
+ │ ├── design_editor/
91
+ │ │ ├── index.tsx
92
+ │ │ └── editor_app.tsx
93
+ │ └── content_publisher/
94
+ │ ├── index.tsx
95
+ │ ├── preview_ui.tsx
96
+ │ └── setting_ui.tsx
97
+ └── index.tsx
98
+ ```
99
+
100
+ ### Root index file
101
+
102
+ The root `src/index.tsx` should be minimal, containing only:
103
+
104
+ - Importing each prepare function
105
+ - Importing each intent
106
+ - The prepare call for each intent implementation.
107
+
108
+ ```tsx
109
+ import { prepareContentPublisher } from "@canva/intents/content";
110
+ import { prepareDesignEditor } from "@canva/intents/design";
111
+
112
+ import contentPublisher from "./intents/content_publisher";
113
+ import designEditor from "./intents/design_editor";
114
+
115
+ prepareContentPublisher(contentPublisher);
116
+ prepareDesignEditor(designEditor);
117
+ ```
118
+
119
+ ### Intent index files
120
+
121
+ Each intent's `index.tsx` file should:
122
+
123
+ - Import dependencies, including the app ui kit css.
124
+ - Implement the full contract for the intent and use this as the default export from the file.
125
+
126
+ ```tsx
127
+ // src/intents/design_editor/index.tsx
128
+ import "@canva/app-ui-kit/styles.css";
129
+ import type { DesignEditorIntent } from "@canva/intents/design";
130
+ import { prepareDesignEditor } from "@canva/intents/design";
131
+ import { AppI18nProvider } from "@canva/app-i18n-kit";
132
+ import { AppUiProvider } from "@canva/app-ui-kit";
133
+ import { createRoot } from "react-dom/client";
134
+ import { App } from "./app";
135
+
136
+ async function render() {
137
+ const root = createRoot(document.getElementById("root") as Element);
138
+
139
+ root.render(
140
+ <AppI18nProvider>
141
+ <AppUiProvider>
142
+ <App />
143
+ </AppUiProvider>
144
+ </AppI18nProvider>,
145
+ );
146
+ }
147
+
148
+ const designEditor: DesignEditorIntent = { render };
149
+ export default designEditor;
150
+
151
+ if (module.hot) {
152
+ module.hot.accept("./app", render);
153
+ }
154
+ ```
@@ -1,58 +0,0 @@
1
- import type {
2
- EmbedElement,
3
- ImageElement,
4
- RichtextElement,
5
- TableElement,
6
- TextElement,
7
- VideoElement,
8
- } from "@canva/design";
9
- import { addElementAtCursor, addElementAtPoint } from "@canva/design";
10
- import { features } from "@canva/platform";
11
- import { useEffect, useState } from "react";
12
- import { useFeatureSupport } from "./use_feature_support";
13
-
14
- type AddElementParams =
15
- | ImageElement
16
- | VideoElement
17
- | EmbedElement
18
- | TextElement
19
- | RichtextElement
20
- | TableElement;
21
-
22
- export const useAddElement = () => {
23
- const isSupported = useFeatureSupport();
24
-
25
- // Store a wrapped addElement function that checks feature support
26
- const [addElement, setAddElement] = useState(() => {
27
- return (element: AddElementParams) => {
28
- if (features.isSupported(addElementAtPoint)) {
29
- return addElementAtPoint(element);
30
- } else if (features.isSupported(addElementAtCursor)) {
31
- return addElementAtCursor(element);
32
- }
33
- // eslint-disable-next-line no-console
34
- console.warn(
35
- "Neither addElementAtPoint nor addElementAtCursor are supported",
36
- );
37
- return Promise.resolve();
38
- };
39
- });
40
-
41
- useEffect(() => {
42
- const addElement = (element: AddElementParams) => {
43
- if (isSupported(addElementAtPoint)) {
44
- return addElementAtPoint(element);
45
- } else if (isSupported(addElementAtCursor)) {
46
- return addElementAtCursor(element);
47
- }
48
- // eslint-disable-next-line no-console
49
- console.warn(
50
- "Neither addElementAtPoint nor addElementAtCursor are supported",
51
- );
52
- return Promise.resolve();
53
- };
54
- setAddElement(() => addElement);
55
- }, [isSupported]);
56
-
57
- return addElement;
58
- };
@@ -1,28 +0,0 @@
1
- import { features } from "@canva/platform";
2
- import type { Feature } from "@canva/platform";
3
- import { useEffect, useState } from "react";
4
-
5
- /**
6
- * This hook allows re-rendering of a React component whenever
7
- * the state of feature support changes in Canva.
8
- *
9
- * @returns isSupported - callback to inspect a Canva SDK method.
10
- **/
11
- export function useFeatureSupport() {
12
- // Store a wrapped function that checks feature support
13
- const [isSupported, setIsSupported] = useState(() => {
14
- return (...args: Feature[]) => features.isSupported(...args);
15
- });
16
-
17
- useEffect(() => {
18
- // create new function ref when feature support changes to trigger
19
- // re-render
20
- return features.registerOnSupportChange(() => {
21
- setIsSupported(() => {
22
- return (...args: Feature[]) => features.isSupported(...args);
23
- });
24
- });
25
- }, []);
26
-
27
- return isSupported;
28
- }