drupal-canvas-react 0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Full Fat Things
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,314 @@
1
+ # drupal-canvas-react
2
+
3
+ Use Drupal Canvas to build pages from React components, then render them anywhere.
4
+
5
+ ## Package Exports
6
+
7
+ | Export | Purpose |
8
+ |--------|---------|
9
+ | `drupal-canvas-react` | Config utilities, types, CLI |
10
+ | `drupal-canvas-react/preview` | Browser-side rendering for Canvas UI preview |
11
+ | `drupal-canvas-react/server` | Server-side rendering for Next.js / RSC |
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install drupal-canvas-react
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ### 1. Create your components
22
+
23
+ ```tsx
24
+ // components/Hero.tsx
25
+ interface HeroProps {
26
+ /** Main heading text */
27
+ title: string
28
+ /** Optional subtitle */
29
+ subtitle?: string
30
+ }
31
+
32
+ export default function Hero({ title, subtitle }: HeroProps) {
33
+ return (
34
+ <section className="hero">
35
+ <h1>{title}</h1>
36
+ {subtitle && <p>{subtitle}</p>}
37
+ </section>
38
+ )
39
+ }
40
+ ```
41
+
42
+ ### 2. Create config file
43
+
44
+ Create `canvas.config.ts` in your project root:
45
+
46
+ ```typescript
47
+ import { defineConfig } from 'drupal-canvas-react'
48
+
49
+ export default defineConfig({
50
+ outDir: '../drupal/web/components',
51
+ components: {
52
+ Hero: {
53
+ path: 'components/Hero.tsx',
54
+ loader: () => import('./components/Hero'),
55
+ },
56
+ },
57
+ })
58
+ ```
59
+
60
+ ### 3. Build
61
+
62
+ ```bash
63
+ npx drupal-canvas-react build
64
+ ```
65
+
66
+ This generates:
67
+ - `component-index.json` - Component metadata for Canvas
68
+ - `drupal-canvas.js` - Bundled runtime with all components
69
+
70
+ ### 4. Register with Drupal
71
+
72
+ Requires [Drupal Canvas](https://www.drupal.org/project/canvas) and [Canvas External JS](https://www.drupal.org/project/canvas_extjs):
73
+
74
+ ```bash
75
+ composer require drupal/canvas drupal/canvas_extjs
76
+ drush en canvas canvas_extjs
77
+ drush canvas:extjs-register web/components/component-index.json \
78
+ --javascript=https://example.com/components/drupal-canvas.js
79
+ ```
80
+
81
+ ## Config Reference
82
+
83
+ ```typescript
84
+ defineConfig({
85
+ // Required: Output directory for generated files
86
+ outDir: string
87
+
88
+ // Required: Component definitions
89
+ components: {
90
+ [id: string]: {
91
+ // Required: Path to component file (for prop extraction)
92
+ path: string
93
+
94
+ // Required: Dynamic import for bundling
95
+ loader: () => Promise<{ default: ComponentType }>
96
+
97
+ // Optional: Display name in Canvas UI
98
+ name?: string
99
+
100
+ // Optional: Component description
101
+ description?: string
102
+
103
+ // Optional: Override default category
104
+ category?: string
105
+
106
+ // Optional: Manual prop definitions (merged with auto-detected)
107
+ // Set to false to exclude an auto-detected prop
108
+ props?: Record<string, {
109
+ type: 'string' | 'number' | 'boolean' | 'image'
110
+ title: string
111
+ description?: string
112
+ default?: unknown
113
+ } | false>
114
+
115
+ // Optional: Manual slot definitions (merged with auto-detected)
116
+ slots?: Record<string, {
117
+ title: string
118
+ description?: string
119
+ }>
120
+
121
+ // Optional: Transform props before passing to component
122
+ transformProps?: (props: Record<string, unknown>) => Record<string, unknown>
123
+ }
124
+ }
125
+
126
+ // Optional: Default category for components
127
+ defaultCategory?: string // Default: 'Components'
128
+
129
+ // Optional: Prefix for component IDs (useful for multi-project setups)
130
+ idPrefix?: string // e.g., 'MyProject' → IDs become 'MyProjectHero'
131
+
132
+ // Optional: Output filename
133
+ outputFilename?: string // Default: 'drupal-canvas.js'
134
+
135
+ // Optional: Path to tsconfig.json
136
+ tsconfig?: string
137
+
138
+ // Optional: Module stub overrides
139
+ stubs?: Record<string, string>
140
+
141
+ // Optional: Minify the output bundle
142
+ minify?: boolean // Default: true
143
+ })
144
+ ```
145
+
146
+ ## Auto-Detection
147
+
148
+ The package automatically extracts from your TypeScript components:
149
+
150
+ - **Props**: Types, titles (from JSDoc or prop name), descriptions, defaults
151
+ - **Slots**: Props typed as `ReactNode` become slots
152
+
153
+ ```tsx
154
+ interface MyComponentProps {
155
+ /** Page title */ // → description
156
+ title: string // → type: 'string', title: 'Title'
157
+
158
+ /** Item count */
159
+ count?: number // → type: 'number', title: 'Count'
160
+
161
+ /** Show border */
162
+ bordered?: boolean // → type: 'boolean', title: 'Bordered'
163
+
164
+ /** Main content */
165
+ children: ReactNode // → slot: { title: 'Children', ... }
166
+ }
167
+ ```
168
+
169
+ ## Prop Transforms
170
+
171
+ Use `transformProps` to adapt Canvas data to your component's expected format, and set props to `false` to exclude them from the Canvas UI:
172
+
173
+ ```typescript
174
+ defineConfig({
175
+ components: {
176
+ Avatar: {
177
+ path: 'components/Avatar.tsx',
178
+ loader: () => import('./components/Avatar'),
179
+ props: {
180
+ size: false, // Exclude from Canvas UI
181
+ alt: false, // Derived from image below
182
+ imagePath: { type: 'image', title: 'Image' },
183
+ },
184
+ // Canvas sends { src, alt, width, height }, component expects strings
185
+ transformProps: (props) => ({
186
+ ...props,
187
+ imagePath: props.imagePath?.src,
188
+ alt: props.imagePath?.alt,
189
+ }),
190
+ },
191
+ },
192
+ })
193
+ ```
194
+
195
+ **Note:** Transform functions must be self-contained arrow functions (they are stringified into the bundle).
196
+
197
+ ## Server-Side Rendering (Next.js / RSC)
198
+
199
+ Use the `drupal-canvas-react/server` export to render Canvas pages in Next.js or any React Server Components environment.
200
+
201
+ ```typescript
202
+ import {
203
+ renderCanvasComponents,
204
+ type DrupalCanvasComponent,
205
+ } from 'drupal-canvas-react/server'
206
+ import canvasConfig from './canvas.config'
207
+ ```
208
+
209
+ ### Usage
210
+
211
+ ```tsx
212
+ // app/[...slug]/page.tsx
213
+ import { renderCanvasComponents, type DrupalCanvasComponent } from 'drupal-canvas-react/server'
214
+ import config from '@/canvas.config'
215
+
216
+ interface CanvasPage {
217
+ title: string
218
+ components: DrupalCanvasComponent[]
219
+ }
220
+
221
+ export default async function Page({ params }) {
222
+ // Fetch page data from Drupal JSON:API
223
+ const page: CanvasPage = await fetchCanvasPage(params.slug)
224
+
225
+ return (
226
+ <>
227
+ <h1>{page.title}</h1>
228
+ {await renderCanvasComponents(page.components, config)}
229
+ </>
230
+ )
231
+ }
232
+ ```
233
+
234
+ ### Error Handling
235
+
236
+ By default, missing or broken components are silently skipped. Use `onError` to render a placeholder:
237
+
238
+ ```tsx
239
+ await renderCanvasComponents(page.components, config, {
240
+ onError: (error, component) => <div>Error: {error.message}</div>,
241
+ })
242
+ ```
243
+
244
+ ## Next.js Components
245
+
246
+ For Next.js components using `next/image` or `next/link`, the package provides built-in stubs that render standard HTML elements:
247
+
248
+ - `next/image` → `<img>`
249
+ - `next/link` → `<a>`
250
+
251
+ To use custom stubs:
252
+
253
+ ```typescript
254
+ defineConfig({
255
+ stubs: {
256
+ 'next/image': './my-stubs/image.tsx',
257
+ 'next/link': './my-stubs/link.tsx',
258
+ },
259
+ // ...
260
+ })
261
+ ```
262
+
263
+ ## CLI Commands
264
+
265
+ ```bash
266
+ # Full build (index + bundle)
267
+ npx drupal-canvas-react build
268
+
269
+ # Generate only component-index.json
270
+ npx drupal-canvas-react generate-index
271
+
272
+ # Build only the JS bundle
273
+ npx drupal-canvas-react bundle
274
+
275
+ # Create config template
276
+ npx drupal-canvas-react init
277
+ ```
278
+
279
+ ## Example Project Structure
280
+
281
+ ```
282
+ my-project/
283
+ ├── components/
284
+ │ └── Hero.tsx
285
+ ├── canvas.config.ts
286
+ ├── package.json
287
+ └── tsconfig.json
288
+
289
+ drupal/web/components/
290
+ ├── component-index.json ← generated
291
+ └── drupal-canvas.js ← generated
292
+ ```
293
+
294
+ ## CSS / Tailwind
295
+
296
+ The package only builds JavaScript. For CSS, run your own build process:
297
+
298
+ ```json
299
+ {
300
+ "scripts": {
301
+ "build:components": "drupal-canvas-react build && tailwindcss -i src/styles.css -o ../drupal/web/components/styles.css"
302
+ }
303
+ }
304
+ ```
305
+
306
+ ## Maintainer
307
+
308
+ [![Full Fat Things](https://www.fullfatthings.com/sites/default/files/logo.svg)](https://www.fullfatthings.com)
309
+
310
+ Get in touch for commercial support.
311
+
312
+ ## License
313
+
314
+ MIT