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 +21 -0
- package/README.md +314 -0
- package/dist/cli.js +457 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.js +295 -0
- package/dist/index.js.map +1 -0
- package/dist/preview.d.ts +25 -0
- package/dist/preview.js +50 -0
- package/dist/preview.js.map +1 -0
- package/dist/server.d.ts +52 -0
- package/dist/server.js +75 -0
- package/dist/server.js.map +1 -0
- package/dist/stubs/image.d.ts +10 -0
- package/dist/stubs/image.js +9 -0
- package/dist/stubs/image.js.map +1 -0
- package/dist/stubs/link.d.ts +14 -0
- package/dist/stubs/link.js +9 -0
- package/dist/stubs/link.js.map +1 -0
- package/dist/types-DE6lplQu.d.ts +191 -0
- package/package.json +84 -0
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
|
+
[](https://www.fullfatthings.com)
|
|
309
|
+
|
|
310
|
+
Get in touch for commercial support.
|
|
311
|
+
|
|
312
|
+
## License
|
|
313
|
+
|
|
314
|
+
MIT
|