@bagelink/blox 1.5.3
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 +844 -0
- package/components/base/Button.vue +140 -0
- package/components/base/Container.vue +64 -0
- package/components/base/Image.vue +75 -0
- package/components/base/Spacer.vue +33 -0
- package/components/base/Text.vue +37 -0
- package/components/base/Title.vue +55 -0
- package/components/index.ts +20 -0
- package/config/baseComponents.ts +342 -0
- package/core/communication.ts +140 -0
- package/core/registry.ts +108 -0
- package/core/renderer.ts +217 -0
- package/core/types.ts +148 -0
- package/dist/blox.css +296 -0
- package/dist/components/base/Button.vue.d.ts +26 -0
- package/dist/components/base/Button.vue.d.ts.map +1 -0
- package/dist/components/base/Container.vue.d.ts +37 -0
- package/dist/components/base/Container.vue.d.ts.map +1 -0
- package/dist/components/base/Image.vue.d.ts +26 -0
- package/dist/components/base/Image.vue.d.ts.map +1 -0
- package/dist/components/base/Spacer.vue.d.ts +16 -0
- package/dist/components/base/Spacer.vue.d.ts.map +1 -0
- package/dist/components/base/Text.vue.d.ts +13 -0
- package/dist/components/base/Text.vue.d.ts.map +1 -0
- package/dist/components/base/Title.vue.d.ts +14 -0
- package/dist/components/base/Title.vue.d.ts.map +1 -0
- package/dist/components/index.d.ts +18 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/config/baseComponents.d.ts +39 -0
- package/dist/config/baseComponents.d.ts.map +1 -0
- package/dist/core/communication.d.ts +44 -0
- package/dist/core/communication.d.ts.map +1 -0
- package/dist/core/registry.d.ts +56 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/renderer.d.ts +27 -0
- package/dist/core/renderer.d.ts.map +1 -0
- package/dist/core/types.d.ts +105 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/index.cjs +1305 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +1260 -0
- package/dist/setup.d.ts +24 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/utils/normalizer.d.ts +18 -0
- package/dist/utils/normalizer.d.ts.map +1 -0
- package/dist/utils/styles.d.ts +13 -0
- package/dist/utils/styles.d.ts.map +1 -0
- package/dist/views/ExternalPreview.vue.d.ts +12 -0
- package/dist/views/ExternalPreview.vue.d.ts.map +1 -0
- package/dist/views/RenderPage.vue.d.ts +10 -0
- package/dist/views/RenderPage.vue.d.ts.map +1 -0
- package/dist/vite.config.d.ts +3 -0
- package/dist/vite.config.d.ts.map +1 -0
- package/index.ts +27 -0
- package/package.json +94 -0
- package/setup.ts +56 -0
- package/utils/normalizer.ts +74 -0
- package/utils/styles.ts +228 -0
- package/views/ExternalPreview.vue +420 -0
- package/views/RenderPage.vue +127 -0
package/README.md
ADDED
|
@@ -0,0 +1,844 @@
|
|
|
1
|
+
# @bagelink/blox
|
|
2
|
+
|
|
3
|
+
Blox is a Vue 3 library for building drag-and-drop page builders and managing static data for web applications. It provides a complete solution for creating external preview systems and rendering dynamic page content.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎨 **Page Builder Integration** - Full support for drag-and-drop page building
|
|
8
|
+
- 📄 **Static Page Management** - Manage JSON-based static page data
|
|
9
|
+
- 🔌 **Component Registry** - Flexible component registration system
|
|
10
|
+
- 📡 **Communication System** - Built-in messaging for builder-preview communication
|
|
11
|
+
- 🎯 **Type-Safe** - Full TypeScript support
|
|
12
|
+
- 🖼️ **Base Components** - Pre-built components (Button, Text, Image, etc.)
|
|
13
|
+
- 📱 **Responsive** - Mobile and desktop support
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @bagelink/blox
|
|
19
|
+
# or
|
|
20
|
+
pnpm add @bagelink/blox
|
|
21
|
+
# or
|
|
22
|
+
yarn add @bagelink/blox
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### 1. Register Base Components
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { createApp } from 'vue'
|
|
31
|
+
import { registerBaseComponents } from '@bagelink/blox'
|
|
32
|
+
|
|
33
|
+
const app = createApp(App)
|
|
34
|
+
|
|
35
|
+
// Register all base components
|
|
36
|
+
registerBaseComponents(app)
|
|
37
|
+
|
|
38
|
+
app.mount('#app')
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. Use the RenderPage Component
|
|
42
|
+
|
|
43
|
+
```vue
|
|
44
|
+
<template>
|
|
45
|
+
<RenderPage :page-data="pageData" />
|
|
46
|
+
</template>
|
|
47
|
+
|
|
48
|
+
<script setup lang="ts">
|
|
49
|
+
import { RenderPage } from '@bagelink/blox'
|
|
50
|
+
|
|
51
|
+
const pageData = {
|
|
52
|
+
components: [...],
|
|
53
|
+
pageSettings: {...}
|
|
54
|
+
}
|
|
55
|
+
</script>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. Use ExternalPreview for Page Builder
|
|
59
|
+
|
|
60
|
+
```vue
|
|
61
|
+
<template>
|
|
62
|
+
<ExternalPreview :origin="editorOrigin" />
|
|
63
|
+
</template>
|
|
64
|
+
|
|
65
|
+
<script setup lang="ts">
|
|
66
|
+
import { ExternalPreview } from '@bagelink/blox'
|
|
67
|
+
|
|
68
|
+
const editorOrigin = 'https://your-editor.com'
|
|
69
|
+
</script>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Core Concepts
|
|
73
|
+
|
|
74
|
+
### Component Registry
|
|
75
|
+
|
|
76
|
+
Register your custom components to make them available in the page builder:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { registerComponent, registerComponents } from '@bagelink/blox'
|
|
80
|
+
import MyButton from './MyButton.vue'
|
|
81
|
+
|
|
82
|
+
// Register a single component
|
|
83
|
+
registerComponent('Button', MyButton)
|
|
84
|
+
|
|
85
|
+
// Or register multiple components at once
|
|
86
|
+
registerComponents({
|
|
87
|
+
Button: MyButton,
|
|
88
|
+
Hero: MyHero,
|
|
89
|
+
Text: MyText,
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Communication System
|
|
94
|
+
|
|
95
|
+
Blox includes a built-in communication system for coordinating between the builder and preview:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { createCommunicationBridge } from '@bagelink/blox'
|
|
99
|
+
|
|
100
|
+
// Create a communication bridge
|
|
101
|
+
const bridge = createCommunicationBridge({
|
|
102
|
+
origin: 'https://editor.com',
|
|
103
|
+
targetWindow: window.parent,
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
// Listen for messages
|
|
107
|
+
bridge.on('update', ({ data }) => {
|
|
108
|
+
console.log('Received update:', data)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
// Send messages
|
|
112
|
+
bridge.send('ready', { components: ['Button', 'Hero'] })
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Styling Utilities
|
|
116
|
+
|
|
117
|
+
Use the built-in styling utilities to apply consistent styles:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { generateBlockStyles, getResponsiveClasses } from '@bagelink/blox'
|
|
121
|
+
|
|
122
|
+
const styles = generateBlockStyles(blockData, false)
|
|
123
|
+
const classes = getResponsiveClasses(blockData)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Base Components
|
|
127
|
+
|
|
128
|
+
The library includes these pre-built components:
|
|
129
|
+
|
|
130
|
+
- **Button** - Customizable button with variants
|
|
131
|
+
- **Container** - Layout container with spacing
|
|
132
|
+
- **Image** - Responsive image component
|
|
133
|
+
- **Spacer** - Vertical/horizontal spacing
|
|
134
|
+
- **Text** - Rich text content
|
|
135
|
+
- **Title** - Heading component
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## API Reference
|
|
140
|
+
|
|
141
|
+
### Registry API
|
|
142
|
+
|
|
143
|
+
#### `registerComponent(type: string, component: ComponentConstructor)`
|
|
144
|
+
|
|
145
|
+
Register a single component.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { registerComponent } from '@bagelink/blox'
|
|
149
|
+
import MyButton from './MyButton.vue'
|
|
150
|
+
|
|
151
|
+
registerComponent('Button', MyButton)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Parameters:**
|
|
155
|
+
- `type` - The block type identifier (e.g., 'Button', 'Hero')
|
|
156
|
+
- `component` - Vue component constructor or async import
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
#### `registerComponents(components: ComponentRegistry)`
|
|
161
|
+
|
|
162
|
+
Register multiple components at once.
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { registerComponents } from '@bagelink/blox'
|
|
166
|
+
|
|
167
|
+
registerComponents({
|
|
168
|
+
Button: MyButton,
|
|
169
|
+
Hero: MyHero,
|
|
170
|
+
Text: MyText,
|
|
171
|
+
})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Parameters:**
|
|
175
|
+
- `components` - Object mapping type names to components
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
#### `getComponent(type: string): ComponentConstructor | undefined`
|
|
180
|
+
|
|
181
|
+
Get a registered component by type.
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
const ButtonComponent = getComponent('Button')
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
#### `hasComponent(type: string): boolean`
|
|
190
|
+
|
|
191
|
+
Check if a component type is registered.
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
if (hasComponent('Button')) {
|
|
195
|
+
// Button is registered
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
#### `getAllComponents(): ComponentRegistry`
|
|
202
|
+
|
|
203
|
+
Get all registered components.
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
const allComponents = getAllComponents()
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
#### `unregisterComponent(type: string)`
|
|
212
|
+
|
|
213
|
+
Remove a component from the registry.
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
unregisterComponent('Button')
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
#### `clearRegistry()`
|
|
222
|
+
|
|
223
|
+
Remove all registered components.
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
clearRegistry()
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
#### `getRegisteredTypes(): string[]`
|
|
232
|
+
|
|
233
|
+
Get array of all registered type names.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
const types = getRegisteredTypes()
|
|
237
|
+
// ['Button', 'Hero', 'Text']
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
#### `createNamespacedRegistry(namespace: string)`
|
|
243
|
+
|
|
244
|
+
Create a namespaced registry for multi-tenant scenarios.
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
const siteA = createNamespacedRegistry('site-a')
|
|
248
|
+
siteA.register('Button', ButtonA)
|
|
249
|
+
|
|
250
|
+
const siteB = createNamespacedRegistry('site-b')
|
|
251
|
+
siteB.register('Button', ButtonB)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Returns:** Object with methods:
|
|
255
|
+
- `register(type, component)` - Register to namespace
|
|
256
|
+
- `get(type)` - Get from namespace
|
|
257
|
+
- `getAll()` - Get all from namespace
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
### Communication API
|
|
262
|
+
|
|
263
|
+
#### `createCommunicationBridge(config: CommunicationConfig): CommunicationBridge`
|
|
264
|
+
|
|
265
|
+
Create a communication bridge for postMessage communication.
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { createCommunicationBridge } from '@bagelink/blox'
|
|
269
|
+
|
|
270
|
+
const bridge = createCommunicationBridge({
|
|
271
|
+
origin: 'https://editor.com',
|
|
272
|
+
targetWindow: window.parent,
|
|
273
|
+
})
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Parameters:**
|
|
277
|
+
- `config.origin` - Allowed origin (string or '*')
|
|
278
|
+
- `config.targetWindow` - Target window (default: window.parent)
|
|
279
|
+
- `config.onMessage` - Optional global message handler
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
#### `CommunicationBridge.on(type: MessageType, handler: MessageHandler): () => void`
|
|
284
|
+
|
|
285
|
+
Register a message handler.
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
const unsubscribe = bridge.on('update', ({ data }) => {
|
|
289
|
+
console.log('Received update:', data)
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
// Later: unsubscribe()
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Parameters:**
|
|
296
|
+
- `type` - Message type or '*' for all messages
|
|
297
|
+
- `handler` - Handler function
|
|
298
|
+
|
|
299
|
+
**Returns:** Unsubscribe function
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
#### `CommunicationBridge.off(type: MessageType, handler: MessageHandler)`
|
|
304
|
+
|
|
305
|
+
Unregister a message handler.
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
bridge.off('update', myHandler)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
#### `CommunicationBridge.send(type: MessageType, message?: any, data?: any)`
|
|
314
|
+
|
|
315
|
+
Send a message to the target window.
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
bridge.send('focus', 'block-123')
|
|
319
|
+
bridge.send('update', null, { components: [...] })
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Parameters:**
|
|
323
|
+
- `type` - Message type
|
|
324
|
+
- `message` - Optional message payload
|
|
325
|
+
- `data` - Optional data payload
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
#### `CommunicationBridge.destroy()`
|
|
330
|
+
|
|
331
|
+
Clean up and remove all listeners.
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
bridge.destroy()
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
#### `sendMessage(type, message?, targetWindow?, origin?)`
|
|
340
|
+
|
|
341
|
+
Send a one-off message without creating a bridge.
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
import { sendMessage } from '@bagelink/blox'
|
|
345
|
+
|
|
346
|
+
sendMessage('ready', { components: ['Button', 'Hero'] })
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
### Renderer API
|
|
352
|
+
|
|
353
|
+
#### `initializePage(pageData: PageData): Promise<void>`
|
|
354
|
+
|
|
355
|
+
Initialize a page with all settings and assets.
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
import { initializePage } from '@bagelink/blox'
|
|
359
|
+
|
|
360
|
+
await initializePage(pageData)
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**What it does:**
|
|
364
|
+
- Injects responsive CSS
|
|
365
|
+
- Applies page settings
|
|
366
|
+
- Loads Google Fonts
|
|
367
|
+
- Injects custom code
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
#### `injectResponsiveCSS()`
|
|
372
|
+
|
|
373
|
+
Inject the responsive CSS system.
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
import { injectResponsiveCSS } from '@bagelink/blox'
|
|
377
|
+
|
|
378
|
+
injectResponsiveCSS()
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
#### `injectCode(code: string | undefined, target: 'head' | 'body')`
|
|
384
|
+
|
|
385
|
+
Inject custom code into head or body.
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
injectCode('<script>console.log("Hello")</script>', 'head')
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
#### `loadGoogleFont(fontName: string): Promise<void>`
|
|
394
|
+
|
|
395
|
+
Load a Google Font.
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
await loadGoogleFont('Roboto')
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
#### `loadComponentFonts(components: ComponentData[]): Promise<void>`
|
|
404
|
+
|
|
405
|
+
Load all fonts used in components.
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
await loadComponentFonts(pageData.components)
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
#### `applyGlobalFont(fontName: string)`
|
|
414
|
+
|
|
415
|
+
Apply a font globally to the page.
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
applyGlobalFont('Inter')
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
#### `applyPageSettings(pageData: PageData)`
|
|
424
|
+
|
|
425
|
+
Apply all page settings to the document.
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
applyPageSettings(pageData)
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
### Styles API
|
|
434
|
+
|
|
435
|
+
#### `generateBlockStyles(data: Record<string, any>, isMobile?: boolean): Record<string, string>`
|
|
436
|
+
|
|
437
|
+
Generate CSS styles from block data.
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
import { generateBlockStyles } from '@bagelink/blox'
|
|
441
|
+
|
|
442
|
+
const styles = generateBlockStyles(blockData, false)
|
|
443
|
+
// { 'margin-top': '2rem', 'padding': '1rem', ... }
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**Parameters:**
|
|
447
|
+
- `data` - Block data object
|
|
448
|
+
- `isMobile` - Whether to use mobile overrides (default: false)
|
|
449
|
+
|
|
450
|
+
**Returns:** CSS styles object
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
#### `getResponsiveClasses(data: Record<string, any>): string[]`
|
|
455
|
+
|
|
456
|
+
Get responsive CSS classes for a block.
|
|
457
|
+
|
|
458
|
+
```typescript
|
|
459
|
+
const classes = getResponsiveClasses(blockData)
|
|
460
|
+
// ['blox-block', 'responsive-colors', 'full-width-mobile']
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
#### `getResponsiveCSS(): string`
|
|
466
|
+
|
|
467
|
+
Get the responsive CSS to inject.
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
const css = getResponsiveCSS()
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
### Normalizer API
|
|
476
|
+
|
|
477
|
+
#### `normalizeComponentData(data: Record<string, any>): Record<string, any>`
|
|
478
|
+
|
|
479
|
+
Normalize component data (convert string booleans, numbers, etc.).
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
import { normalizeComponentData } from '@bagelink/blox'
|
|
483
|
+
|
|
484
|
+
const normalized = normalizeComponentData({
|
|
485
|
+
width: '800',
|
|
486
|
+
fullWidth: 'true',
|
|
487
|
+
title: 'Hello',
|
|
488
|
+
})
|
|
489
|
+
// { width: 800, fullWidth: true, title: 'Hello' }
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
#### `deepClone<T>(obj: T): T`
|
|
495
|
+
|
|
496
|
+
Deep clone an object.
|
|
497
|
+
|
|
498
|
+
```typescript
|
|
499
|
+
const cloned = deepClone(originalData)
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
#### `deepMerge(target: any, source: any): any`
|
|
505
|
+
|
|
506
|
+
Deep merge two objects.
|
|
507
|
+
|
|
508
|
+
```typescript
|
|
509
|
+
const merged = deepMerge(defaults, customSettings)
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## Components
|
|
515
|
+
|
|
516
|
+
### ExternalPreview
|
|
517
|
+
|
|
518
|
+
Preview component for external sites.
|
|
519
|
+
|
|
520
|
+
```vue
|
|
521
|
+
<ExternalPreview
|
|
522
|
+
:origin="editorOrigin"
|
|
523
|
+
:initial-page-data="pageData"
|
|
524
|
+
/>
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Props:**
|
|
528
|
+
- `origin?: string` - Allowed editor origin (default: '*')
|
|
529
|
+
- `initialPageData?: PageData` - Optional initial page data
|
|
530
|
+
|
|
531
|
+
**Events:**
|
|
532
|
+
Communicates via postMessage with these message types:
|
|
533
|
+
- `ready` - Sent when preview is ready
|
|
534
|
+
- `focus` - Sent when block is focused
|
|
535
|
+
- `highlight` - Sent when block is highlighted
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
### RenderPage
|
|
540
|
+
|
|
541
|
+
Production render component.
|
|
542
|
+
|
|
543
|
+
```vue
|
|
544
|
+
<RenderPage
|
|
545
|
+
:page-data="pageData"
|
|
546
|
+
:mobile-breakpoint="910"
|
|
547
|
+
/>
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
**Props:**
|
|
551
|
+
- `pageData: PageData` - **Required** page data to render
|
|
552
|
+
- `mobileBreakpoint?: number` - Window width for mobile (default: 910)
|
|
553
|
+
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
## TypeScript Types
|
|
557
|
+
|
|
558
|
+
### ComponentData
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
interface ComponentData {
|
|
562
|
+
id: string
|
|
563
|
+
type: string
|
|
564
|
+
data: Record<string, any>
|
|
565
|
+
}
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
### PageData
|
|
571
|
+
|
|
572
|
+
```typescript
|
|
573
|
+
interface PageData {
|
|
574
|
+
id?: string
|
|
575
|
+
components: ComponentData[]
|
|
576
|
+
pageSettings?: PageSettings
|
|
577
|
+
header_code?: string
|
|
578
|
+
body_code?: string
|
|
579
|
+
language?: Record<string, any>
|
|
580
|
+
}
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
### PageSettings
|
|
586
|
+
|
|
587
|
+
```typescript
|
|
588
|
+
interface PageSettings {
|
|
589
|
+
selectedGoogleFont?: string
|
|
590
|
+
pageLanguage?: string
|
|
591
|
+
pageDirection?: 'ltr' | 'rtl'
|
|
592
|
+
additionalHeadCode?: string
|
|
593
|
+
additionalBodyCode?: string
|
|
594
|
+
customFavicon?: string
|
|
595
|
+
customOgImage?: string
|
|
596
|
+
customKeywords?: string
|
|
597
|
+
customRobotsMeta?: string
|
|
598
|
+
customAnalyticsCode?: string
|
|
599
|
+
disableGlobalHeadCode?: boolean
|
|
600
|
+
disableGlobalBodyCode?: boolean
|
|
601
|
+
disableGoogleAnalytics?: boolean
|
|
602
|
+
disableFacebookPixel?: boolean
|
|
603
|
+
}
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
### GlobalSettings
|
|
609
|
+
|
|
610
|
+
```typescript
|
|
611
|
+
interface GlobalSettings {
|
|
612
|
+
selectedGoogleFont?: string
|
|
613
|
+
pageLanguage?: string
|
|
614
|
+
pageDirection?: 'ltr' | 'rtl'
|
|
615
|
+
globalHeadCode?: string
|
|
616
|
+
globalBodyCode?: string
|
|
617
|
+
favicon?: string
|
|
618
|
+
ogImage?: string
|
|
619
|
+
siteKeywords?: string
|
|
620
|
+
googleAnalyticsId?: string
|
|
621
|
+
facebookPixelId?: string
|
|
622
|
+
}
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
---
|
|
626
|
+
|
|
627
|
+
### MessageType
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
type MessageType =
|
|
631
|
+
| 'ready'
|
|
632
|
+
| 'update'
|
|
633
|
+
| 'focus'
|
|
634
|
+
| 'highlight'
|
|
635
|
+
| 'preview'
|
|
636
|
+
| 'meta'
|
|
637
|
+
| 'delete'
|
|
638
|
+
| 'disableLinks'
|
|
639
|
+
| 'newBlock'
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
---
|
|
643
|
+
|
|
644
|
+
### EditorMessage
|
|
645
|
+
|
|
646
|
+
```typescript
|
|
647
|
+
interface EditorMessage {
|
|
648
|
+
type: MessageType
|
|
649
|
+
message?: any
|
|
650
|
+
data?: any
|
|
651
|
+
isMobile?: boolean
|
|
652
|
+
}
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
### BlockProps
|
|
658
|
+
|
|
659
|
+
```typescript
|
|
660
|
+
interface BlockProps {
|
|
661
|
+
isMobile?: boolean
|
|
662
|
+
[key: string]: any
|
|
663
|
+
}
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
---
|
|
667
|
+
|
|
668
|
+
### StyleConfig
|
|
669
|
+
|
|
670
|
+
```typescript
|
|
671
|
+
interface StyleConfig {
|
|
672
|
+
// Spacing
|
|
673
|
+
marginTop?: number
|
|
674
|
+
marginBottom?: number
|
|
675
|
+
marginTopMobile?: number
|
|
676
|
+
marginBottomMobile?: number
|
|
677
|
+
padding?: number
|
|
678
|
+
paddingMobile?: number
|
|
679
|
+
|
|
680
|
+
// Width
|
|
681
|
+
width?: number
|
|
682
|
+
widthMobile?: number
|
|
683
|
+
widthPercent?: number
|
|
684
|
+
widthPercentMobile?: number
|
|
685
|
+
fullWidth?: boolean
|
|
686
|
+
fullWidthMobile?: boolean
|
|
687
|
+
|
|
688
|
+
// Colors
|
|
689
|
+
backgroundColor?: string
|
|
690
|
+
backgroundColorMobile?: string
|
|
691
|
+
textColor?: string
|
|
692
|
+
textColorMobile?: string
|
|
693
|
+
|
|
694
|
+
// Border
|
|
695
|
+
borderWidth?: number
|
|
696
|
+
borderWidthMobile?: number
|
|
697
|
+
borderStyle?: string
|
|
698
|
+
borderStyleMobile?: string
|
|
699
|
+
borderColor?: string
|
|
700
|
+
borderColorMobile?: string
|
|
701
|
+
borderRadius?: number
|
|
702
|
+
borderRadiusMobile?: number
|
|
703
|
+
|
|
704
|
+
// Typography
|
|
705
|
+
fontFamily?: string
|
|
706
|
+
fontFamilyMobile?: string
|
|
707
|
+
center?: boolean
|
|
708
|
+
centerMobile?: boolean
|
|
709
|
+
|
|
710
|
+
// Effects
|
|
711
|
+
shadowType?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'custom'
|
|
712
|
+
shadowTypeMobile?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'custom'
|
|
713
|
+
zIndex?: number
|
|
714
|
+
zIndexMobile?: number
|
|
715
|
+
|
|
716
|
+
// Visibility
|
|
717
|
+
showDesktop?: boolean
|
|
718
|
+
showMobile?: boolean
|
|
719
|
+
|
|
720
|
+
// Custom
|
|
721
|
+
customId?: string
|
|
722
|
+
customCSS?: string
|
|
723
|
+
}
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
---
|
|
727
|
+
|
|
728
|
+
## Message Protocol
|
|
729
|
+
|
|
730
|
+
### Editor → Preview
|
|
731
|
+
|
|
732
|
+
#### `update`
|
|
733
|
+
Update components data.
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
{
|
|
737
|
+
type: 'update',
|
|
738
|
+
data: ComponentData[],
|
|
739
|
+
isMobile: boolean
|
|
740
|
+
}
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
#### `focus`
|
|
744
|
+
Focus a specific block.
|
|
745
|
+
|
|
746
|
+
```typescript
|
|
747
|
+
{
|
|
748
|
+
type: 'focus',
|
|
749
|
+
message: 'block-id-123'
|
|
750
|
+
}
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
#### `highlight`
|
|
754
|
+
Highlight a specific block.
|
|
755
|
+
|
|
756
|
+
```typescript
|
|
757
|
+
{
|
|
758
|
+
type: 'highlight',
|
|
759
|
+
message: 'block-id-123'
|
|
760
|
+
}
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
#### `preview`
|
|
764
|
+
Toggle preview mode.
|
|
765
|
+
|
|
766
|
+
```typescript
|
|
767
|
+
{
|
|
768
|
+
type: 'preview',
|
|
769
|
+
message: true | false
|
|
770
|
+
}
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
#### `disableLinks`
|
|
774
|
+
Disable link navigation.
|
|
775
|
+
|
|
776
|
+
```typescript
|
|
777
|
+
{
|
|
778
|
+
type: 'disableLinks',
|
|
779
|
+
message: true | false
|
|
780
|
+
}
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
---
|
|
784
|
+
|
|
785
|
+
### Preview → Editor
|
|
786
|
+
|
|
787
|
+
#### `ready`
|
|
788
|
+
Preview is ready.
|
|
789
|
+
|
|
790
|
+
```typescript
|
|
791
|
+
{
|
|
792
|
+
type: 'ready',
|
|
793
|
+
message: {
|
|
794
|
+
registeredTypes: string[]
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
#### `focus`
|
|
800
|
+
User focused a block.
|
|
801
|
+
|
|
802
|
+
```typescript
|
|
803
|
+
{
|
|
804
|
+
type: 'focus',
|
|
805
|
+
message: 'block-id-123'
|
|
806
|
+
}
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
#### `highlight`
|
|
810
|
+
User highlighted a block.
|
|
811
|
+
|
|
812
|
+
```typescript
|
|
813
|
+
{
|
|
814
|
+
type: 'highlight',
|
|
815
|
+
message: 'block-id-123'
|
|
816
|
+
}
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
#### `delete`
|
|
820
|
+
User wants to delete a block.
|
|
821
|
+
|
|
822
|
+
```typescript
|
|
823
|
+
{
|
|
824
|
+
type: 'delete',
|
|
825
|
+
message: 'block-id-123'
|
|
826
|
+
}
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
---
|
|
830
|
+
|
|
831
|
+
## Contributing
|
|
832
|
+
|
|
833
|
+
Contributions are welcome! Please read our [Contributing Guide](../../CONTRIBUTING.md) for details.
|
|
834
|
+
|
|
835
|
+
## License
|
|
836
|
+
|
|
837
|
+
MIT © [Bagel Studio](https://bagelstudio.co.il)
|
|
838
|
+
|
|
839
|
+
## Links
|
|
840
|
+
|
|
841
|
+
- [GitHub Repository](https://github.com/bageldb/bagelink)
|
|
842
|
+
- [Documentation](https://github.com/bageldb/bagelink/tree/master/packages/blox)
|
|
843
|
+
- [Issues](https://github.com/bageldb/bagelink/issues)
|
|
844
|
+
|