@janbox/storefront-builder 1.0.9 → 2.0.1
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/README.md +83 -110
- package/dist/{countdown-timer.node-j79tvSTR.js → countdown-timer.node-OmDiT-pz.js} +139 -140
- package/dist/editor/lib/index.d.ts +1 -1
- package/dist/editor/lib/sidebar/insert-action.d.ts +15 -22
- package/dist/editor.js +981 -483
- package/dist/{index-C9Q0Iqvf.js → index-CwrFnubn.js} +342 -341
- package/dist/index.js +33 -33
- package/dist/style.css +1 -1
- package/dist/templates/elements/carousel/index.d.ts +2 -2
- package/dist/templates/elements/content-list/index.d.ts +2 -2
- package/dist/templates/elements/interactive/index.d.ts +2 -2
- package/dist/templates/elements/layout/index.d.ts +2 -2
- package/dist/templates/elements/media/index.d.ts +2 -2
- package/dist/templates/elements/text/index.d.ts +2 -2
- package/dist/templates/elements/utilities/index.d.ts +2 -2
- package/dist/templates/index.d.ts +0 -1
- package/dist/templates/sections/faqs/index.d.ts +2 -2
- package/dist/templates/sections/guarantee/index.d.ts +2 -2
- package/dist/templates/sections/hero/index.d.ts +2 -2
- package/dist/templates.js +79 -578
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,46 +1,38 @@
|
|
|
1
1
|
# @janbox/storefront-builder
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Thư viện visual page builder độc lập, xây dựng trên [CraftJS](https://craft.js.org/). Hỗ trợ kéo-thả tạo storefront với giao diện editor đầy đủ, 33 node component có sẵn và responsive design theo breakpoint.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Cài đặt
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @janbox/storefront-builder
|
|
9
|
-
# or
|
|
10
8
|
pnpm add @janbox/storefront-builder
|
|
11
9
|
```
|
|
12
10
|
|
|
13
11
|
### Peer dependencies
|
|
14
12
|
|
|
15
13
|
```bash
|
|
16
|
-
|
|
14
|
+
pnpm add react@^19 react-dom@^19 @janbox/storefront-ui@>=2
|
|
17
15
|
```
|
|
18
16
|
|
|
19
17
|
## Package Exports
|
|
20
18
|
|
|
21
|
-
| Import path |
|
|
19
|
+
| Import path | Nội dung |
|
|
22
20
|
| --- | --- |
|
|
23
|
-
| `@janbox/storefront-builder` | Node components (
|
|
24
|
-
| `@janbox/storefront-builder/editor` |
|
|
25
|
-
| `@janbox/storefront-builder/templates` |
|
|
26
|
-
| `@janbox/storefront-builder/style.css` |
|
|
21
|
+
| `@janbox/storefront-builder` | Node components (33 nodes) |
|
|
22
|
+
| `@janbox/storefront-builder/editor` | Giao diện editor đầy đủ (`Editor` component + toolbars) |
|
|
23
|
+
| `@janbox/storefront-builder/templates` | Element groups và section templates có sẵn |
|
|
24
|
+
| `@janbox/storefront-builder/style.css` | CSS bundle (bắt buộc import) |
|
|
27
25
|
|
|
28
26
|
---
|
|
29
27
|
|
|
30
28
|
## Quick Start — Full Editor
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
Component `Editor` render giao diện visual builder hoàn chỉnh: header toolbar, sidebar thư viện component, canvas kéo-thả.
|
|
33
31
|
|
|
34
32
|
```tsx
|
|
35
33
|
import '@janbox/storefront-builder/style.css';
|
|
36
34
|
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';
|
|
35
|
+
import { HERO_SECTION_GROUP, FAQS_SECTION_GROUP } from '@janbox/storefront-builder/templates';
|
|
44
36
|
import type { Theme } from '@janbox/storefront-ui/theme';
|
|
45
37
|
|
|
46
38
|
const myTheme: Theme = {
|
|
@@ -48,8 +40,9 @@ const myTheme: Theme = {
|
|
|
48
40
|
primary: {
|
|
49
41
|
500: '#fa8c16',
|
|
50
42
|
600: '#d46b08',
|
|
43
|
+
// ...
|
|
51
44
|
},
|
|
52
|
-
// ...
|
|
45
|
+
// ...
|
|
53
46
|
},
|
|
54
47
|
typography: {
|
|
55
48
|
base: { fontSize: '1rem', lineHeight: '1.5rem' },
|
|
@@ -62,34 +55,36 @@ export default function BuilderPage() {
|
|
|
62
55
|
<Editor
|
|
63
56
|
theme={myTheme}
|
|
64
57
|
handlers={{
|
|
65
|
-
upload: async () =>
|
|
66
|
-
submit: (
|
|
67
|
-
|
|
58
|
+
upload: async (file) => URL.createObjectURL(file),
|
|
59
|
+
submit: async (data) => {
|
|
60
|
+
await savePage(data);
|
|
61
|
+
},
|
|
62
|
+
close: () => navigateBack(),
|
|
68
63
|
}}
|
|
69
64
|
insert={{
|
|
70
|
-
|
|
71
|
-
sections: [HERO_SECTION_GROUP],
|
|
65
|
+
groups: [HERO_SECTION_GROUP, FAQS_SECTION_GROUP],
|
|
72
66
|
}}
|
|
73
67
|
/>
|
|
74
68
|
);
|
|
75
69
|
}
|
|
76
70
|
```
|
|
77
71
|
|
|
78
|
-
`Editor`
|
|
72
|
+
`Editor` chiếm toàn bộ viewport (`100vw × 100vh`), nên đặt ở một route/page riêng.
|
|
73
|
+
|
|
74
|
+
> Chi tiết đầy đủ về `Editor` xem tại [editor/lib/README.md](editor/lib/README.md).
|
|
79
75
|
|
|
80
76
|
---
|
|
81
77
|
|
|
82
|
-
## Quick Start — Render Only (
|
|
78
|
+
## Quick Start — Render Only (không có editor UI)
|
|
83
79
|
|
|
84
|
-
|
|
80
|
+
Dùng `Composer` + `Canvas` để render một trang đã lưu, không cần giao diện editor. Đây là cách dùng cho phía storefront hiển thị cho người mua.
|
|
85
81
|
|
|
86
82
|
```tsx
|
|
87
83
|
import '@janbox/storefront-builder/style.css';
|
|
88
|
-
import { Composer, Canvas } from '@janbox/storefront-builder';
|
|
89
|
-
import { RootNode } from '@janbox/storefront-builder';
|
|
84
|
+
import { Composer, Canvas, RootNode } from '@janbox/storefront-builder';
|
|
90
85
|
import type { SerializedNodes } from '@janbox/storefront-builder';
|
|
91
86
|
|
|
92
|
-
const savedData: SerializedNodes = { /* JSON
|
|
87
|
+
const savedData: SerializedNodes = { /* JSON từ editor */ };
|
|
93
88
|
|
|
94
89
|
export default function StorefrontPage() {
|
|
95
90
|
return (
|
|
@@ -104,13 +99,13 @@ export default function StorefrontPage() {
|
|
|
104
99
|
|
|
105
100
|
---
|
|
106
101
|
|
|
107
|
-
##
|
|
102
|
+
## Khái niệm cơ bản
|
|
108
103
|
|
|
109
104
|
### Nodes
|
|
110
105
|
|
|
111
|
-
|
|
106
|
+
Mỗi phần tử trên canvas là một **node** — React component được đăng ký với CraftJS. Thư viện có 33 node có sẵn:
|
|
112
107
|
|
|
113
|
-
|
|
|
108
|
+
| Nhóm | Nodes |
|
|
114
109
|
| --- | --- |
|
|
115
110
|
| Layout | `RootNode`, `Box`, `Flexbox`, `FlexItem`, `Grid`, `Cell` |
|
|
116
111
|
| Typography | `Text`, `Paragraph`, `Heading` |
|
|
@@ -122,29 +117,29 @@ Every element on the canvas is a **node** — a React component registered with
|
|
|
122
117
|
| Carousel | `Swiper`, `SwiperSlide` |
|
|
123
118
|
| Marquee | `Marquee`, `MarqueeItem` |
|
|
124
119
|
| Utilities | `CountdownTimer` |
|
|
125
|
-
| Internal | `UnknownNode` (fallback
|
|
120
|
+
| Internal | `UnknownNode` (fallback cho node không resolve được) |
|
|
126
121
|
|
|
127
|
-
|
|
122
|
+
Tất cả đều được export từ `@janbox/storefront-builder`.
|
|
128
123
|
|
|
129
124
|
### Responsive Props
|
|
130
125
|
|
|
131
|
-
|
|
126
|
+
Tất cả style prop đều nhận plain value hoặc responsive object theo breakpoint:
|
|
132
127
|
|
|
133
128
|
```ts
|
|
134
129
|
// Breakpoints: xs (390px), sm (768px), md (1280px), lg (1680px)
|
|
135
130
|
|
|
136
|
-
// Plain value (
|
|
131
|
+
// Plain value (áp dụng tại mọi breakpoint)
|
|
137
132
|
{ fontSize: '16px' }
|
|
138
133
|
|
|
139
|
-
// Responsive object (xs
|
|
134
|
+
// Responsive object (xs là base; các key khác override theo hướng tăng dần)
|
|
140
135
|
{ fontSize: { xs: '14px', md: '18px' } }
|
|
141
136
|
```
|
|
142
137
|
|
|
143
|
-
|
|
138
|
+
Breakpoint hiện tại được điều khiển qua query param `?screen=xs|sm|md|lg`.
|
|
144
139
|
|
|
145
140
|
### Serialized State
|
|
146
141
|
|
|
147
|
-
|
|
142
|
+
Trạng thái canvas là plain JSON (`SerializedNodes`). Dùng `useComposer()` để đọc và serialize:
|
|
148
143
|
|
|
149
144
|
```tsx
|
|
150
145
|
import { useComposer } from '@janbox/storefront-builder';
|
|
@@ -153,11 +148,11 @@ function SaveButton() {
|
|
|
153
148
|
const { query } = useComposer();
|
|
154
149
|
|
|
155
150
|
const handleSave = () => {
|
|
156
|
-
const json = query.serialize(); //
|
|
157
|
-
//
|
|
151
|
+
const json = query.serialize(); // JSON string dạng SerializedNodes
|
|
152
|
+
// lưu vào backend
|
|
158
153
|
};
|
|
159
154
|
|
|
160
|
-
return <button onClick={handleSave}>
|
|
155
|
+
return <button onClick={handleSave}>Lưu</button>;
|
|
161
156
|
}
|
|
162
157
|
```
|
|
163
158
|
|
|
@@ -165,22 +160,11 @@ function SaveButton() {
|
|
|
165
160
|
|
|
166
161
|
## Templates
|
|
167
162
|
|
|
168
|
-
Templates
|
|
163
|
+
Templates là các nhóm kéo-thả có sẵn trong sidebar editor.
|
|
169
164
|
|
|
170
|
-
|
|
165
|
+
Sidebar **Basics** được tích hợp sẵn trong editor và chứa toàn bộ element cơ bản. Consumer không cần import hay truyền các nhóm này.
|
|
171
166
|
|
|
172
|
-
|
|
173
|
-
import {
|
|
174
|
-
LAYOUT_ELEMENT_GROUP, // Box, Flexbox, Grid
|
|
175
|
-
TEXT_ELEMENT_GROUP, // Text, Heading, Paragraph
|
|
176
|
-
MEDIA_ELEMENT_GROUP, // Image, Video, Icon
|
|
177
|
-
INTERACTIVE_ELEMENT_GROUP, // Button, Link, Accordion, Tabs
|
|
178
|
-
CONTENT_LIST_ELEMENT_GROUP, // UnorderedList, Marquee, Swiper
|
|
179
|
-
UTILITIES_ELEMENT_GROUP, // CountdownTimer
|
|
180
|
-
} from '@janbox/storefront-builder/templates';
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Section Groups (sidebar "Sections" tab)
|
|
167
|
+
### Section Groups
|
|
184
168
|
|
|
185
169
|
```ts
|
|
186
170
|
import {
|
|
@@ -190,7 +174,7 @@ import {
|
|
|
190
174
|
} from '@janbox/storefront-builder/templates';
|
|
191
175
|
```
|
|
192
176
|
|
|
193
|
-
|
|
177
|
+
Truyền vào `Editor` qua prop `insert.groups`:
|
|
194
178
|
|
|
195
179
|
```tsx
|
|
196
180
|
<Editor
|
|
@@ -201,8 +185,7 @@ Pass them to `Editor` via the `insert` prop:
|
|
|
201
185
|
close: () => {},
|
|
202
186
|
}}
|
|
203
187
|
insert={{
|
|
204
|
-
|
|
205
|
-
sections: [HERO_SECTION_GROUP],
|
|
188
|
+
groups: [HERO_SECTION_GROUP, FAQS_SECTION_GROUP],
|
|
206
189
|
}}
|
|
207
190
|
/>
|
|
208
191
|
```
|
|
@@ -211,12 +194,11 @@ Pass them to `Editor` via the `insert` prop:
|
|
|
211
194
|
|
|
212
195
|
## Custom Nodes
|
|
213
196
|
|
|
214
|
-
### 1.
|
|
197
|
+
### 1. Tạo node component
|
|
215
198
|
|
|
216
199
|
```tsx
|
|
217
200
|
// my-badge.node.tsx
|
|
218
|
-
import { defineNode } from '@janbox/storefront-builder';
|
|
219
|
-
import { useNode } from '@janbox/storefront-builder';
|
|
201
|
+
import { defineNode, useNode } from '@janbox/storefront-builder';
|
|
220
202
|
|
|
221
203
|
type MyBadgeProps = { label: string; color?: string };
|
|
222
204
|
|
|
@@ -241,24 +223,20 @@ defineNode(MyBadge, {
|
|
|
241
223
|
});
|
|
242
224
|
```
|
|
243
225
|
|
|
244
|
-
### 2.
|
|
226
|
+
### 2. Truyền resolver vào editor
|
|
245
227
|
|
|
246
228
|
```tsx
|
|
247
229
|
import { MyBadge } from './my-badge.node';
|
|
248
230
|
|
|
249
231
|
<Editor
|
|
250
232
|
theme={myTheme}
|
|
251
|
-
handlers={{
|
|
252
|
-
upload: async () => '',
|
|
253
|
-
submit: () => {},
|
|
254
|
-
close: () => {},
|
|
255
|
-
}}
|
|
233
|
+
handlers={{ upload: async () => '', submit: () => {}, close: () => {} }}
|
|
256
234
|
resolver={{ MyBadge }}
|
|
257
|
-
insert={{
|
|
235
|
+
insert={{ groups: [] }}
|
|
258
236
|
/>
|
|
259
237
|
```
|
|
260
238
|
|
|
261
|
-
### 3.
|
|
239
|
+
### 3. Thêm toolbar (tùy chọn)
|
|
262
240
|
|
|
263
241
|
```tsx
|
|
264
242
|
// my-badge.toolbar.tsx
|
|
@@ -279,7 +257,7 @@ export function MyBadgeToolbar() {
|
|
|
279
257
|
}
|
|
280
258
|
```
|
|
281
259
|
|
|
282
|
-
|
|
260
|
+
Đăng ký toolbar trong `defineNode`:
|
|
283
261
|
|
|
284
262
|
```ts
|
|
285
263
|
defineNode(MyBadge, {
|
|
@@ -293,42 +271,42 @@ defineNode(MyBadge, {
|
|
|
293
271
|
|
|
294
272
|
## Hooks
|
|
295
273
|
|
|
296
|
-
|
|
274
|
+
Tất cả hooks phải được gọi bên trong cây `<Composer>`.
|
|
297
275
|
|
|
298
276
|
### `useComposer(collector?)`
|
|
299
277
|
|
|
300
|
-
|
|
278
|
+
Wrapper nâng cao của CraftJS `useEditor`. Bổ sung thêm `actions.duplicate()` và `actions.move()`.
|
|
301
279
|
|
|
302
280
|
```ts
|
|
303
281
|
const { query, actions } = useComposer();
|
|
304
282
|
|
|
305
|
-
// Serialize
|
|
283
|
+
// Serialize trạng thái canvas hiện tại
|
|
306
284
|
const json = query.serialize();
|
|
307
285
|
|
|
308
|
-
// Duplicate
|
|
286
|
+
// Duplicate một node
|
|
309
287
|
actions.duplicate(nodeId);
|
|
310
288
|
|
|
311
|
-
//
|
|
289
|
+
// Di chuyển một node
|
|
312
290
|
actions.move({ nodeId, sourceIndex: 0, destinationIndex: 2 });
|
|
313
291
|
```
|
|
314
292
|
|
|
315
293
|
### `useNodeProps<P>(options?)`
|
|
316
294
|
|
|
317
|
-
|
|
295
|
+
Đọc và ghi props của node hiện tại (hoặc node chỉ định qua `options.nodeId`). Hỗ trợ cập nhật responsive.
|
|
318
296
|
|
|
319
297
|
```ts
|
|
320
298
|
const { nodeProps, setNodeProps, setNodeResponsiveProps } = useNodeProps<MyProps>();
|
|
321
299
|
|
|
322
|
-
// Set
|
|
300
|
+
// Set prop thường
|
|
323
301
|
setNodeProps({ color: '#ff0000' });
|
|
324
302
|
|
|
325
|
-
// Set
|
|
303
|
+
// Set responsive prop cho breakpoint cụ thể
|
|
326
304
|
setNodeResponsiveProps({ fontSize: '18px' }, 'md');
|
|
327
305
|
```
|
|
328
306
|
|
|
329
307
|
### `useNode()`
|
|
330
308
|
|
|
331
|
-
|
|
309
|
+
Truy cập trực tiếp CraftJS node context (re-export từ `@craftjs/core`).
|
|
332
310
|
|
|
333
311
|
```ts
|
|
334
312
|
const { id, connectors, actions } = useNode();
|
|
@@ -336,9 +314,9 @@ const { id, connectors, actions } = useNode();
|
|
|
336
314
|
|
|
337
315
|
---
|
|
338
316
|
|
|
339
|
-
## TailwindCSS
|
|
317
|
+
## TailwindCSS
|
|
340
318
|
|
|
341
|
-
|
|
319
|
+
Thư viện dùng TailwindCSS v4 nội bộ với prefix `tw:`. Import stylesheet một lần ở entry của app:
|
|
342
320
|
|
|
343
321
|
```ts
|
|
344
322
|
import '@janbox/storefront-builder/style.css';
|
|
@@ -348,7 +326,7 @@ import '@janbox/storefront-builder/style.css';
|
|
|
348
326
|
|
|
349
327
|
## Theme Shape
|
|
350
328
|
|
|
351
|
-
|
|
329
|
+
Prop `theme` của `Editor` tuân theo kiểu `Theme` của `@janbox/storefront-ui`:
|
|
352
330
|
|
|
353
331
|
```ts
|
|
354
332
|
type Theme = {
|
|
@@ -356,14 +334,9 @@ type Theme = {
|
|
|
356
334
|
primary: Record<100 | 200 | 300 | 400 | 500 | 600 | 700 | 800, string>;
|
|
357
335
|
secondary: Record<...>;
|
|
358
336
|
red, orange, yellow, green, blue, violet, neutral: Record<...>;
|
|
359
|
-
|
|
360
|
-
white: string;
|
|
361
|
-
background: { subtle, default, emphasis: string };
|
|
337
|
+
background: { subtle: string; default: string; emphasis: string };
|
|
362
338
|
surface: { default: string };
|
|
363
339
|
border: { default: string };
|
|
364
|
-
inherit: string;
|
|
365
|
-
current: string;
|
|
366
|
-
transparent: string;
|
|
367
340
|
};
|
|
368
341
|
typography: Record<'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl', {
|
|
369
342
|
fontSize: string;
|
|
@@ -376,15 +349,15 @@ type Theme = {
|
|
|
376
349
|
|
|
377
350
|
## TypeScript
|
|
378
351
|
|
|
379
|
-
|
|
352
|
+
Package đi kèm đầy đủ file `.d.ts`. Các type chính:
|
|
380
353
|
|
|
381
354
|
```ts
|
|
382
355
|
import type {
|
|
383
|
-
SerializedNodes, //
|
|
384
|
-
NodeId, // string node
|
|
385
|
-
NodeTree, //
|
|
386
|
-
Resolver, // map
|
|
387
|
-
NodeConfig, // config
|
|
356
|
+
SerializedNodes, // JSON state của canvas
|
|
357
|
+
NodeId, // string định danh node
|
|
358
|
+
NodeTree, // cây node
|
|
359
|
+
Resolver, // map resolvedName → component
|
|
360
|
+
NodeConfig, // config truyền vào defineNode()
|
|
388
361
|
DisplayOnValue, // responsive visibility: Partial<Record<Screen, boolean>>
|
|
389
362
|
} from '@janbox/storefront-builder';
|
|
390
363
|
```
|
|
@@ -397,7 +370,7 @@ Chi tiết props, usage và rules cho từng node:
|
|
|
397
370
|
|
|
398
371
|
### Layout
|
|
399
372
|
|
|
400
|
-
- [RootNode](dist/lib/root/README.md) —
|
|
373
|
+
- [RootNode](dist/lib/root/README.md) — container gốc của canvas
|
|
401
374
|
- [BoxNode](dist/lib/box/README.md) — block container
|
|
402
375
|
- [FlexboxNode](dist/lib/flexbox/README.md) — flex container
|
|
403
376
|
- [FlexItemNode](dist/lib/flex-item/README.md) — flex item
|
|
@@ -412,7 +385,7 @@ Chi tiết props, usage và rules cho từng node:
|
|
|
412
385
|
|
|
413
386
|
### Media
|
|
414
387
|
|
|
415
|
-
- [ImageNode](dist/lib/image/README.md) —
|
|
388
|
+
- [ImageNode](dist/lib/image/README.md) — hình ảnh
|
|
416
389
|
- [VideoNode](dist/lib/video/README.md) — video player
|
|
417
390
|
- [IconNode](dist/lib/icon/README.md) — inline SVG icon
|
|
418
391
|
|
|
@@ -423,8 +396,8 @@ Chi tiết props, usage và rules cho từng node:
|
|
|
423
396
|
|
|
424
397
|
### Lists
|
|
425
398
|
|
|
426
|
-
- [UnorderedListNode](dist/lib/unordered-list/README.md) —
|
|
427
|
-
- [ListItemNode](dist/lib/list-item/README.md) —
|
|
399
|
+
- [UnorderedListNode](dist/lib/unordered-list/README.md) — danh sách không thứ tự
|
|
400
|
+
- [ListItemNode](dist/lib/list-item/README.md) — item trong danh sách
|
|
428
401
|
|
|
429
402
|
### Accordion
|
|
430
403
|
|
|
@@ -436,10 +409,10 @@ Chi tiết props, usage và rules cho từng node:
|
|
|
436
409
|
### Tabs
|
|
437
410
|
|
|
438
411
|
- [TabsNode](dist/lib/tabs/README.md) — tabs container
|
|
439
|
-
- [TabListNode](dist/lib/tab-list/README.md) — tab headers
|
|
412
|
+
- [TabListNode](dist/lib/tab-list/README.md) — container chứa tab headers
|
|
440
413
|
- [TabNode](dist/lib/tab/README.md) — tab header button
|
|
441
|
-
- [TabContentNode](dist/lib/tab-content/README.md) — tab panels
|
|
442
|
-
- [TabPanelNode](dist/lib/tab-panel/README.md) — tab panel
|
|
414
|
+
- [TabContentNode](dist/lib/tab-content/README.md) — container chứa tab panels
|
|
415
|
+
- [TabPanelNode](dist/lib/tab-panel/README.md) — nội dung tab panel
|
|
443
416
|
|
|
444
417
|
### Carousel
|
|
445
418
|
|
|
@@ -453,28 +426,28 @@ Chi tiết props, usage và rules cho từng node:
|
|
|
453
426
|
|
|
454
427
|
### Utilities
|
|
455
428
|
|
|
456
|
-
- [CountdownTimerNode](dist/lib/countdown-timer/README.md) —
|
|
429
|
+
- [CountdownTimerNode](dist/lib/countdown-timer/README.md) — đồng hồ đếm ngược
|
|
457
430
|
|
|
458
431
|
### Internal
|
|
459
432
|
|
|
460
|
-
- [UnknownNode](dist/lib/unknown/README.md) — fallback
|
|
433
|
+
- [UnknownNode](dist/lib/unknown/README.md) — fallback cho node không resolve được
|
|
461
434
|
|
|
462
435
|
---
|
|
463
436
|
|
|
464
|
-
## Monorepo
|
|
437
|
+
## Phát triển Monorepo
|
|
465
438
|
|
|
466
439
|
```bash
|
|
467
|
-
#
|
|
440
|
+
# Cài đặt dependencies
|
|
468
441
|
pnpm install
|
|
469
442
|
|
|
470
|
-
#
|
|
443
|
+
# Chạy demo app (React Router 7)
|
|
471
444
|
pnpm dev
|
|
472
445
|
|
|
473
|
-
# Build
|
|
446
|
+
# Build thư viện
|
|
474
447
|
pnpm build
|
|
475
448
|
|
|
476
449
|
# Type check
|
|
477
450
|
pnpm typecheck
|
|
478
451
|
```
|
|
479
452
|
|
|
480
|
-
|
|
453
|
+
Yêu cầu Node.js >= 20 và pnpm.
|