@janbox/storefront-builder 1.0.3 → 1.0.5

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 (70) hide show
  1. package/README.md +477 -0
  2. package/dist/editor/lib/index.d.ts +3 -3
  3. package/dist/editor/lib/sidebar/index.d.ts +1 -1
  4. package/dist/editor/lib/sidebar/insert-action.d.ts +2 -2
  5. package/dist/editor/ui/dialog/dialog/helpers.d.ts +1 -1
  6. package/dist/editor/ui/dialog/dialog-close/dialog-close.d.ts +1 -1
  7. package/dist/editor.js +326 -313
  8. package/dist/lib/accordion/README.md +39 -0
  9. package/dist/lib/accordion-content/README.md +36 -0
  10. package/dist/lib/accordion-group/README.md +106 -0
  11. package/dist/lib/accordion-summary/README.md +37 -0
  12. package/dist/lib/box/README.md +107 -0
  13. package/dist/lib/button/README.md +94 -0
  14. package/dist/lib/cell/README.md +119 -0
  15. package/dist/lib/countdown-timer/README.md +157 -0
  16. package/dist/lib/flex-item/README.md +111 -0
  17. package/dist/lib/flexbox/README.md +120 -0
  18. package/dist/lib/grid/README.md +133 -0
  19. package/dist/lib/heading/README.md +53 -0
  20. package/dist/lib/icon/README.md +98 -0
  21. package/dist/lib/image/README.md +107 -0
  22. package/dist/lib/link/README.md +111 -0
  23. package/dist/lib/list-item/README.md +31 -0
  24. package/dist/lib/marquee/README.md +111 -0
  25. package/dist/lib/marquee-item/README.md +31 -0
  26. package/dist/lib/paragraph/README.md +82 -0
  27. package/dist/lib/root/README.md +33 -0
  28. package/dist/lib/swiper/README.md +108 -0
  29. package/dist/lib/swiper-slide/README.md +32 -0
  30. package/dist/lib/tab/README.md +35 -0
  31. package/dist/lib/tab-content/README.md +35 -0
  32. package/dist/lib/tab-list/README.md +35 -0
  33. package/dist/lib/tab-panel/README.md +35 -0
  34. package/dist/lib/tabs/README.md +90 -0
  35. package/dist/lib/text/README.md +90 -0
  36. package/dist/lib/unknown/README.md +48 -0
  37. package/dist/lib/unordered-list/README.md +82 -0
  38. package/dist/lib/video/README.md +91 -0
  39. package/lib/accordion/README.md +39 -0
  40. package/lib/accordion-content/README.md +36 -0
  41. package/lib/accordion-group/README.md +106 -0
  42. package/lib/accordion-summary/README.md +37 -0
  43. package/lib/box/README.md +107 -0
  44. package/lib/button/README.md +94 -0
  45. package/lib/cell/README.md +119 -0
  46. package/lib/countdown-timer/README.md +157 -0
  47. package/lib/flex-item/README.md +111 -0
  48. package/lib/flexbox/README.md +120 -0
  49. package/lib/grid/README.md +133 -0
  50. package/lib/heading/README.md +53 -0
  51. package/lib/icon/README.md +98 -0
  52. package/lib/image/README.md +107 -0
  53. package/lib/link/README.md +111 -0
  54. package/lib/list-item/README.md +31 -0
  55. package/lib/marquee/README.md +111 -0
  56. package/lib/marquee-item/README.md +31 -0
  57. package/lib/paragraph/README.md +82 -0
  58. package/lib/root/README.md +33 -0
  59. package/lib/swiper/README.md +108 -0
  60. package/lib/swiper-slide/README.md +32 -0
  61. package/lib/tab/README.md +35 -0
  62. package/lib/tab-content/README.md +35 -0
  63. package/lib/tab-list/README.md +35 -0
  64. package/lib/tab-panel/README.md +35 -0
  65. package/lib/tabs/README.md +90 -0
  66. package/lib/text/README.md +90 -0
  67. package/lib/unknown/README.md +48 -0
  68. package/lib/unordered-list/README.md +82 -0
  69. package/lib/video/README.md +91 -0
  70. package/package.json +5 -9
package/README.md ADDED
@@ -0,0 +1,477 @@
1
+ # @janbox/storefront-builder
2
+
3
+ A standalone visual page builder library built on [CraftJS](https://craft.js.org/). Provides drag-and-drop storefront creation with a full editor UI, 33 pre-built node components, and responsive design support.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @janbox/storefront-builder
9
+ # or
10
+ pnpm add @janbox/storefront-builder
11
+ ```
12
+
13
+ ### Peer dependencies
14
+
15
+ ```bash
16
+ npm install react@^19 react-dom@^19 @janbox/storefront-ui@>=2
17
+ ```
18
+
19
+ ## Package Exports
20
+
21
+ | Import path | Contents |
22
+ | --- | --- |
23
+ | `@janbox/storefront-builder` | Node components (all 33 nodes) |
24
+ | `@janbox/storefront-builder/editor` | Full editor UI (`Editor` component + toolbars) |
25
+ | `@janbox/storefront-builder/templates` | Pre-built element groups and section templates |
26
+ | `@janbox/storefront-builder/style.css` | Required CSS bundle |
27
+
28
+ ---
29
+
30
+ ## Quick Start — Full Editor
31
+
32
+ The `Editor` component from `/editor` renders the complete visual builder UI (header toolbar, sidebar with component library, drag-and-drop canvas).
33
+
34
+ ```tsx
35
+ import '@janbox/storefront-builder/style.css';
36
+ import { Editor } from '@janbox/storefront-builder/editor';
37
+ import {
38
+ LAYOUT_ELEMENT_GROUP,
39
+ TEXT_ELEMENT_GROUP,
40
+ MEDIA_ELEMENT_GROUP,
41
+ INTERACTIVE_ELEMENT_GROUP,
42
+ HERO_SECTION_GROUP,
43
+ } from '@janbox/storefront-builder/templates';
44
+ import type { Theme } from '@janbox/storefront-ui/theme';
45
+
46
+ const myTheme: Theme = {
47
+ palette: {
48
+ primary: {
49
+ 500: '#fa8c16',
50
+ 600: '#d46b08',
51
+ },
52
+ // ... full theme
53
+ },
54
+ typography: {
55
+ base: { fontSize: '1rem', lineHeight: '1.5rem' },
56
+ // ...
57
+ },
58
+ };
59
+
60
+ export default function BuilderPage() {
61
+ return (
62
+ <Editor
63
+ theme={myTheme}
64
+ insert={{
65
+ elements: [LAYOUT_ELEMENT_GROUP, TEXT_ELEMENT_GROUP, MEDIA_ELEMENT_GROUP, INTERACTIVE_ELEMENT_GROUP],
66
+ sections: [HERO_SECTION_GROUP],
67
+ }}
68
+ />
69
+ );
70
+ }
71
+ ```
72
+
73
+ `Editor` occupies the full viewport (`100vw × 100vh`). It should be the root of a dedicated page/route.
74
+
75
+ ---
76
+
77
+ ## Quick Start — Render Only (No Editor UI)
78
+
79
+ Use `Composer` + `Canvas` to render a saved page without the editor chrome. This is for the storefront-facing page.
80
+
81
+ ```tsx
82
+ import '@janbox/storefront-builder/style.css';
83
+ import { Composer, Canvas } from '@janbox/storefront-builder';
84
+ import { RootNode } from '@janbox/storefront-builder';
85
+ import type { SerializedNodes } from '@janbox/storefront-builder';
86
+
87
+ const savedData: SerializedNodes = { /* JSON from editor */ };
88
+
89
+ export default function StorefrontPage() {
90
+ return (
91
+ <Composer>
92
+ <Canvas data={savedData}>
93
+ <RootNode />
94
+ </Canvas>
95
+ </Composer>
96
+ );
97
+ }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Core Concepts
103
+
104
+ ### Nodes
105
+
106
+ Every element on the canvas is a **node** — a React component registered with CraftJS. The library ships 33 built-in nodes:
107
+
108
+ | Category | Nodes |
109
+ | --- | --- |
110
+ | Layout | `RootNode`, `Box`, `Flexbox`, `FlexItem`, `Grid`, `Cell` |
111
+ | Typography | `Text`, `Paragraph`, `Heading` |
112
+ | Media | `Image`, `Video`, `Icon` |
113
+ | Navigation | `Link`, `Button` |
114
+ | Lists | `UnorderedList`, `ListItem` |
115
+ | Tabs | `Tabs`, `TabList`, `Tab`, `TabContent`, `TabPanel` |
116
+ | Accordion | `Accordion`, `AccordionGroup`, `AccordionSummary`, `AccordionContent` |
117
+ | Carousel | `Swiper`, `SwiperSlide` |
118
+ | Marquee | `Marquee`, `MarqueeItem` |
119
+ | Utilities | `CountdownTimer` |
120
+ | Internal | `UnknownNode` (fallback for unresolved nodes) |
121
+
122
+ All nodes are exported from `@janbox/storefront-builder`.
123
+
124
+ ### Responsive Props
125
+
126
+ All style props accept either a plain value or a responsive object keyed by breakpoint:
127
+
128
+ ```ts
129
+ // Breakpoints: xs (390px), sm (768px), md (1280px), lg (1680px)
130
+
131
+ // Plain value (applies at all breakpoints)
132
+ { fontSize: '16px' }
133
+
134
+ // Responsive object (xs is the base; other keys override upward)
135
+ { fontSize: { xs: '14px', md: '18px' } }
136
+ ```
137
+
138
+ The current breakpoint is controlled via the `?screen=xs|sm|md|lg` query param.
139
+
140
+ ### Serialized State
141
+
142
+ The canvas state is plain JSON (`SerializedNodes` from `@craftjs/core`). Use `useComposer()` to read and serialize it:
143
+
144
+ ```tsx
145
+ import { useComposer } from '@janbox/storefront-builder';
146
+
147
+ function SaveButton() {
148
+ const { query } = useComposer();
149
+
150
+ const handleSave = () => {
151
+ const json = query.serialize(); // SerializedNodes as JSON string
152
+ // save to your backend
153
+ };
154
+
155
+ return <button onClick={handleSave}>Save</button>;
156
+ }
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Templates
162
+
163
+ Templates are pre-configured drag-and-drop groups shown in the editor sidebar.
164
+
165
+ ### Element Groups (sidebar "Elements" tab)
166
+
167
+ ```ts
168
+ import {
169
+ LAYOUT_ELEMENT_GROUP, // Box, Flexbox, Grid
170
+ TEXT_ELEMENT_GROUP, // Text, Heading, Paragraph
171
+ MEDIA_ELEMENT_GROUP, // Image, Video, Icon
172
+ INTERACTIVE_ELEMENT_GROUP, // Button, Link, Accordion, Tabs
173
+ CONTENT_LIST_ELEMENT_GROUP, // UnorderedList, Marquee, Swiper
174
+ UTILITIES_ELEMENT_GROUP, // CountdownTimer
175
+ } from '@janbox/storefront-builder/templates';
176
+ ```
177
+
178
+ ### Section Groups (sidebar "Sections" tab)
179
+
180
+ ```ts
181
+ import {
182
+ HERO_SECTION_GROUP,
183
+ FAQS_SECTION_GROUP,
184
+ GUARANTEE_SECTION_GROUP,
185
+ } from '@janbox/storefront-builder/templates';
186
+ ```
187
+
188
+ Pass them to `Editor` via the `insert` prop:
189
+
190
+ ```tsx
191
+ <Editor
192
+ theme={myTheme}
193
+ insert={{
194
+ elements: [LAYOUT_ELEMENT_GROUP, TEXT_ELEMENT_GROUP],
195
+ sections: [HERO_SECTION_GROUP],
196
+ }}
197
+ />
198
+ ```
199
+
200
+ ---
201
+
202
+ ## Custom Nodes
203
+
204
+ ### 1. Create a node component
205
+
206
+ ```tsx
207
+ // my-badge.node.tsx
208
+ import { defineNode } from '@janbox/storefront-builder';
209
+ import { useNode } from '@janbox/storefront-builder';
210
+
211
+ type MyBadgeProps = { label: string; color?: string };
212
+
213
+ export const MyBadge = ({ label, color = '#fa8c16' }: MyBadgeProps) => {
214
+ const { connectors } = useNode();
215
+
216
+ return (
217
+ <span
218
+ ref={(el) => el && connectors.connect(el)}
219
+ style={{ background: color, padding: '2px 8px', borderRadius: 4 }}
220
+ >
221
+ {label}
222
+ </span>
223
+ );
224
+ };
225
+
226
+ defineNode(MyBadge, {
227
+ resolved: 'MyBadge',
228
+ isCanvas: false,
229
+ info: { displayName: 'Badge' },
230
+ defaultProps: { label: 'Badge', color: '#fa8c16' },
231
+ });
232
+ ```
233
+
234
+ ### 2. Pass a resolver to the editor
235
+
236
+ ```tsx
237
+ import { MyBadge } from './my-badge.node';
238
+
239
+ <Editor
240
+ theme={myTheme}
241
+ resolver={{ MyBadge }}
242
+ insert={{ elements: [/* ... */], sections: [] }}
243
+ />
244
+ ```
245
+
246
+ ### 3. Add a toolbar (optional)
247
+
248
+ ```tsx
249
+ // my-badge.toolbar.tsx
250
+ import { useNodeProps } from '@janbox/storefront-builder';
251
+
252
+ export function MyBadgeToolbar() {
253
+ const { nodeProps, setNodeProps } = useNodeProps<MyBadgeProps>();
254
+
255
+ return (
256
+ <div>
257
+ <label>Label</label>
258
+ <input
259
+ value={nodeProps.label}
260
+ onChange={(e) => setNodeProps({ label: e.target.value })}
261
+ />
262
+ </div>
263
+ );
264
+ }
265
+ ```
266
+
267
+ Register the toolbar in `defineNode`:
268
+
269
+ ```ts
270
+ defineNode(MyBadge, {
271
+ resolved: 'MyBadge',
272
+ info: { displayName: 'Badge' },
273
+ related: { inspector: MyBadgeToolbar },
274
+ });
275
+ ```
276
+
277
+ ---
278
+
279
+ ## Hooks
280
+
281
+ All hooks must be called inside a `<Composer>` tree.
282
+
283
+ ### `useComposer(collector?)`
284
+
285
+ Enhanced wrapper around CraftJS `useEditor`. Adds `actions.duplicate()` and `actions.move()`.
286
+
287
+ ```ts
288
+ const { query, actions } = useComposer();
289
+
290
+ // Serialize current canvas state
291
+ const json = query.serialize();
292
+
293
+ // Duplicate a node
294
+ actions.duplicate(nodeId);
295
+
296
+ // Move a node
297
+ actions.move({ nodeId, sourceIndex: 0, destinationIndex: 2 });
298
+ ```
299
+
300
+ ### `useNodeProps<P>(options?)`
301
+
302
+ Read and write props for the current node (or a specific node via `options.nodeId`). Supports responsive updates.
303
+
304
+ ```ts
305
+ const { nodeProps, setNodeProps, setNodeResponsiveProps } = useNodeProps<MyProps>();
306
+
307
+ // Set a flat prop
308
+ setNodeProps({ color: '#ff0000' });
309
+
310
+ // Set a responsive prop for a specific breakpoint
311
+ setNodeResponsiveProps({ fontSize: '18px' }, 'md');
312
+ ```
313
+
314
+ ### `useNode()`
315
+
316
+ Direct access to the CraftJS node context (re-exported from `@craftjs/core`).
317
+
318
+ ```ts
319
+ const { id, connectors, actions } = useNode();
320
+ ```
321
+
322
+ ---
323
+
324
+ ## TailwindCSS Integration
325
+
326
+ The library uses TailwindCSS v4 internally with a `tw:` prefix. To extend it in your app:
327
+
328
+ ```ts
329
+ // tailwind.config.ts
330
+ import builderConfig from '@janbox/storefront-builder/tailwind.config';
331
+
332
+ export default {
333
+ presets: [builderConfig],
334
+ // your overrides
335
+ };
336
+ ```
337
+
338
+ Import the stylesheet once at your app entry:
339
+
340
+ ```ts
341
+ import '@janbox/storefront-builder/style.css';
342
+ ```
343
+
344
+ ---
345
+
346
+ ## Theme Shape
347
+
348
+ The `theme` prop on `Editor` follows the `@janbox/storefront-ui` `Theme` type:
349
+
350
+ ```ts
351
+ type Theme = {
352
+ palette: {
353
+ primary: Record<100 | 200 | 300 | 400 | 500 | 600 | 700 | 800, string>;
354
+ secondary: Record<...>;
355
+ red, orange, yellow, green, blue, violet, neutral: Record<...>;
356
+ black: string;
357
+ white: string;
358
+ background: { subtle, default, emphasis: string };
359
+ surface: { default: string };
360
+ border: { default: string };
361
+ inherit: string;
362
+ current: string;
363
+ transparent: string;
364
+ };
365
+ typography: Record<'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl', {
366
+ fontSize: string;
367
+ lineHeight: string;
368
+ }>;
369
+ };
370
+ ```
371
+
372
+ ---
373
+
374
+ ## TypeScript
375
+
376
+ The package ships full `.d.ts` declarations. Key types:
377
+
378
+ ```ts
379
+ import type {
380
+ SerializedNodes, // canvas JSON state
381
+ NodeId, // string node identifier
382
+ NodeTree, // tree of nodes
383
+ Resolver, // map of resolvedName → component
384
+ NodeConfig, // config passed to defineNode()
385
+ DisplayOnValue, // responsive visibility: Partial<Record<Screen, boolean>>
386
+ } from '@janbox/storefront-builder';
387
+ ```
388
+
389
+ ---
390
+
391
+ ## Node Reference
392
+
393
+ Chi tiết props, usage và rules cho từng node:
394
+
395
+ ### Layout
396
+
397
+ - [RootNode](lib/root/README.md) — top-level canvas container
398
+ - [BoxNode](lib/box/README.md) — block container
399
+ - [FlexboxNode](lib/flexbox/README.md) — flex container
400
+ - [FlexItemNode](lib/flex-item/README.md) — flex item
401
+ - [GridNode](lib/grid/README.md) — CSS grid container
402
+ - [CellNode](lib/cell/README.md) — grid cell
403
+
404
+ ### Typography
405
+
406
+ - [TextNode](lib/text/README.md) — inline/block text
407
+ - [HeadingNode](lib/heading/README.md) — h1–h6 heading
408
+ - [ParagraphNode](lib/paragraph/README.md) — paragraph
409
+
410
+ ### Media
411
+
412
+ - [ImageNode](lib/image/README.md) — image
413
+ - [VideoNode](lib/video/README.md) — video player
414
+ - [IconNode](lib/icon/README.md) — inline SVG icon
415
+
416
+ ### Navigation
417
+
418
+ - [LinkNode](lib/link/README.md) — anchor link
419
+ - [ButtonNode](lib/button/README.md) — CTA button
420
+
421
+ ### Lists
422
+
423
+ - [UnorderedListNode](lib/unordered-list/README.md) — list container
424
+ - [ListItemNode](lib/list-item/README.md) — list item
425
+
426
+ ### Accordion
427
+
428
+ - [AccordionGroupNode](lib/accordion-group/README.md) — accordion container
429
+ - [AccordionNode](lib/accordion/README.md) — accordion item
430
+ - [AccordionSummaryNode](lib/accordion-summary/README.md) — accordion header
431
+ - [AccordionContentNode](lib/accordion-content/README.md) — accordion content
432
+
433
+ ### Tabs
434
+
435
+ - [TabsNode](lib/tabs/README.md) — tabs container
436
+ - [TabListNode](lib/tab-list/README.md) — tab headers container
437
+ - [TabNode](lib/tab/README.md) — tab header button
438
+ - [TabContentNode](lib/tab-content/README.md) — tab panels container
439
+ - [TabPanelNode](lib/tab-panel/README.md) — tab panel content
440
+
441
+ ### Carousel
442
+
443
+ - [SwiperNode](lib/swiper/README.md) — carousel container
444
+ - [SwiperSlideNode](lib/swiper-slide/README.md) — carousel slide
445
+
446
+ ### Marquee
447
+
448
+ - [MarqueeNode](lib/marquee/README.md) — auto-scrolling ticker
449
+ - [MarqueeItemNode](lib/marquee-item/README.md) — ticker item
450
+
451
+ ### Utilities
452
+
453
+ - [CountdownTimerNode](lib/countdown-timer/README.md) — countdown timer
454
+
455
+ ### Internal
456
+
457
+ - [UnknownNode](lib/unknown/README.md) — fallback for unresolved nodes
458
+
459
+ ---
460
+
461
+ ## Monorepo Development
462
+
463
+ ```bash
464
+ # Install dependencies
465
+ pnpm install
466
+
467
+ # Start demo app (React Router 7)
468
+ pnpm dev
469
+
470
+ # Build the library
471
+ pnpm build
472
+
473
+ # Type check
474
+ pnpm typecheck
475
+ ```
476
+
477
+ Requires Node.js >= 20 and pnpm.
@@ -3,8 +3,8 @@ import { SidebarProps } from './sidebar';
3
3
  import { Resolver } from '../../types';
4
4
  export type EditorProps = {
5
5
  theme: Theme;
6
- insert: SidebarProps['insert'];
7
- resolver: Resolver;
6
+ insert?: SidebarProps['insert'];
7
+ resolver?: Resolver;
8
8
  };
9
9
  export type { InsertElementGroup, InsertSectionGroup } from './sidebar/insert-action';
10
- export declare const Editor: ({ theme, insert }: EditorProps) => import("@emotion/react/jsx-runtime").JSX.Element;
10
+ export declare const Editor: ({ theme, insert, resolver }: EditorProps) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import { InsertActionProps } from './insert-action';
2
2
  export type SidebarProps = {
3
- insert: InsertActionProps;
3
+ insert?: InsertActionProps;
4
4
  };
5
5
  export declare const Sidebar: ({ insert }: SidebarProps) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -20,8 +20,8 @@ export type InsertSectionGroup = {
20
20
  }[];
21
21
  };
22
22
  export interface InsertActionProps {
23
- elements: InsertElementGroup[];
24
- sections: InsertSectionGroup[];
23
+ elements?: InsertElementGroup[];
24
+ sections?: InsertSectionGroup[];
25
25
  }
26
26
  export declare const InsertAction: ({ elements, sections }: InsertActionProps) => import("@emotion/react/jsx-runtime").JSX.Element;
27
27
  export declare const SectionInsertionGroup: ({ group }: {
@@ -1 +1 @@
1
- export declare const useDialogContext: () => import('../../floating').WbFloatingContextValue;
1
+ export declare const useDialogContext: () => import('../..').WbFloatingContextValue;
@@ -1 +1 @@
1
- export declare const WbDialogClose: import('react').ForwardRefExoticComponent<Omit<import('../../floating').WbFloatingCloseProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
1
+ export declare const WbDialogClose: import('react').ForwardRefExoticComponent<Omit<import('../..').WbFloatingCloseProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;