@janbox/storefront-builder 2.0.24 → 2.0.25

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 (37) hide show
  1. package/dist/components/composer/dataset.d.ts +2 -0
  2. package/dist/constants/index.d.ts +2 -0
  3. package/dist/editor.js +81 -77
  4. package/dist/{index-BBoR6Gy_.js → index-C9gD44fK.js} +1 -1
  5. package/dist/index-CglXRxzd.js +4 -0
  6. package/dist/index.js +82 -75
  7. package/dist/lib/count-up/README.md +129 -0
  8. package/dist/lib/count-up/count-up.inspector/count-up.inspector.d.ts +1 -0
  9. package/dist/lib/count-up/count-up.inspector/index.d.ts +1 -0
  10. package/dist/lib/count-up/count-up.node/count-up.node.d.ts +2 -0
  11. package/dist/lib/count-up/count-up.node/helpers.d.ts +3 -0
  12. package/dist/lib/count-up/count-up.node/index.d.ts +3 -0
  13. package/dist/lib/count-up/count-up.node/types.d.ts +2 -0
  14. package/dist/lib/count-up/index.d.ts +1 -0
  15. package/dist/lib/icon/README.md +9 -18
  16. package/dist/lib/index.d.ts +2 -0
  17. package/dist/lib/rating/README.md +126 -0
  18. package/dist/lib/rating/index.d.ts +2 -0
  19. package/dist/lib/rating/rating/helpers.d.ts +4 -0
  20. package/dist/lib/rating/rating/index.d.ts +3 -0
  21. package/dist/lib/rating/rating/rating.d.ts +2 -0
  22. package/dist/lib/rating/rating/types.d.ts +10 -0
  23. package/dist/lib/rating/rating.inspector/index.d.ts +1 -0
  24. package/dist/lib/rating/rating.inspector/rating.inspector.d.ts +1 -0
  25. package/dist/lib/rating/rating.node/helpers.d.ts +3 -0
  26. package/dist/lib/rating/rating.node/index.d.ts +3 -0
  27. package/dist/lib/rating/rating.node/rating.node.d.ts +2 -0
  28. package/dist/lib/rating/rating.node/types.d.ts +2 -0
  29. package/dist/templates/sections/brand-story/about-story.d.ts +2 -0
  30. package/dist/templates/sections/hero/notebook-hero.d.ts +2 -0
  31. package/dist/templates/sections/index.d.ts +1 -0
  32. package/dist/templates/sections/testimonial/before-after.d.ts +2 -0
  33. package/dist/templates/sections/testimonial/index.d.ts +2 -0
  34. package/dist/templates.js +826 -202
  35. package/dist/{toaster-DMjFxzB_.js → toaster-CzSp838P.js} +6465 -6172
  36. package/package.json +3 -3
  37. package/dist/index-BPG8gpQT.js +0 -4
package/dist/index.js CHANGED
@@ -1,20 +1,20 @@
1
- import { N as n, c as t } from "./toaster-DMjFxzB_.js";
2
- import { A as C, e as L, f as T, h as x, i as S, j as A, k as E, l as w, m as R, n as h, F, o as k, p as q, G as B, H as G, q as H, I as M, s as U, t as y, v as V, L as j, w as D, M as z, x as J, y as K, P as O, R as Q, S as X, z as Y, T as Z, E as _, J as $, K as W, O as ee, U as oe, Q as se, V as ae, X as re, Y as de, Z as te, _ as ne, $ as Ne, g as ue, a0 as ie, a1 as pe, a2 as me, a3 as Pe, a4 as ce, a5 as le, a6 as ge, a7 as be, a8 as fe, a9 as ve, u as Ie, aa as Ce, ab as Le, ac as Te, ad as xe, ae as Se, af as Ae, ag as Ee, ah as we, ai as Re, aj as he, ak as Fe, al as ke, am as qe, an as Be, ao as Ge, ap as He, aq as Me } from "./toaster-DMjFxzB_.js";
1
+ import { N as n, c as t } from "./toaster-CzSp838P.js";
2
+ import { A as I, e as L, f as x, h as T, i as R, j as S, k as w, l as A, m as E, n as h, o as F, F as U, p as k, q, G as B, H as G, s as H, I as M, t as y, v as V, w as j, L as D, x as z, M as J, y as K, z as O, P as Q, R as X, E as Y, J as Z, S as _, K as $, T as W, O as ee, Q as se, U as oe, V as ae, X as re, Y as de, Z as te, _ as ne, $ as Ne, a0 as ue, a1 as ie, a2 as pe, a3 as me, g as Pe, a4 as ce, a5 as le, a6 as ge, a7 as be, a8 as fe, a9 as ve, aa as Ce, ab as Ie, ac as Le, ad as xe, ae as Te, u as Re, af as Se, ag as we, ah as Ae, ai as Ee, aj as he, ak as Fe, al as Ue, am as ke, an as qe, ao as Be, ap as Ge, aq as He, ar as Me, as as ye, at as Ve, au as je, av as De, aw as ze, ax as Je } from "./toaster-CzSp838P.js";
3
3
  import "lodash-es";
4
4
  import { useRef as N, useEffect as u } from "react";
5
5
  import { getTabPanelProps as i, getListItemProps as p } from "@janbox/storefront-ui";
6
- import { C as ye, a as Ve } from "./index-BBoR6Gy_.js";
6
+ import { C as Oe, a as Qe } from "./index-C9gD44fK.js";
7
7
  const g = ({ enabled: a, onChange: r }) => {
8
- const { dom: e } = n((s) => ({ dom: s.dom })), o = N(void 0);
8
+ const { dom: e } = n((o) => ({ dom: o.dom })), s = N(void 0);
9
9
  u(() => {
10
10
  if (!a || !e) return;
11
- const s = () => {
12
- o.current = e.innerHTML;
11
+ const o = () => {
12
+ s.current = e.innerHTML;
13
13
  }, d = () => {
14
- o.current !== void 0 && (r(o.current), o.current = void 0);
14
+ s.current !== void 0 && (r(s.current), s.current = void 0);
15
15
  };
16
- return e.addEventListener("input", s), e.addEventListener("blur", d), () => {
17
- e.removeEventListener("input", s), e.removeEventListener("blur", d);
16
+ return e.addEventListener("input", o), e.addEventListener("blur", d), () => {
17
+ e.removeEventListener("input", o), e.removeEventListener("blur", d);
18
18
  };
19
19
  }, [a, e, r]);
20
20
  }, b = () => t({
@@ -23,82 +23,89 @@ const g = ({ enabled: a, onChange: r }) => {
23
23
  transform: p
24
24
  });
25
25
  export {
26
- C as AccordionContentNode,
26
+ I as AccordionContentNode,
27
27
  L as AccordionGroupNode,
28
- T as AccordionNode,
29
- x as AccordionSummaryNode,
30
- S as BoxNode,
31
- A as ButtonNode,
32
- ye as Canvas,
33
- E as CanvasPlaceholder,
34
- w as CellNode,
35
- Ve as Composer,
36
- R as ContainerNode,
37
- h as CountdownTimerNode,
38
- F as FlexItemNode,
28
+ x as AccordionNode,
29
+ T as AccordionSummaryNode,
30
+ R as BoxNode,
31
+ S as ButtonNode,
32
+ Oe as Canvas,
33
+ w as CanvasPlaceholder,
34
+ A as CellNode,
35
+ Qe as Composer,
36
+ E as ContainerNode,
37
+ h as CountUpNode,
38
+ F as CountdownTimerNode,
39
+ U as FlexItemNode,
39
40
  k as FlexboxNode,
40
41
  q as FragmentNode,
41
42
  B as GridNode,
42
43
  G as Heading,
43
44
  H as HeadingNode,
44
45
  M as IconNode,
45
- U as ImageNode,
46
- y as InlineInspector,
47
- V as InlineNode,
48
- j as LinkNode,
49
- D as ListItemNode,
50
- z as MarqueeItemNode,
51
- J as MarqueeNode,
52
- K as NodeElement,
53
- O as ParagraphNode,
54
- Q as RootNode,
55
- X as SwiperNode,
56
- Y as SwiperSlideNode,
57
- Z as TabContentNode,
58
- _ as TabListNode,
59
- $ as TabNode,
60
- W as TabPanelNode,
61
- ee as TabsNode,
62
- oe as UnknownNode,
63
- se as UnorderedListNode,
64
- ae as VideoNode,
65
- re as defineNode,
66
- de as getNodeCustom,
67
- te as getNodeDisplayName,
68
- ne as getNodeInfo,
69
- Ne as getNodeRelated,
70
- ue as getNodeResolved,
71
- ie as isNodeSelectable,
72
- pe as parseNumber,
73
- me as parseSvgString,
74
- Pe as registerNodeRelated,
75
- ce as toResponsiveCss,
76
- le as useAccordionGroupNodeProps,
77
- ge as useAccordionNodeProps,
78
- be as useBoxNodeProps,
79
- fe as useButtonNodeProps,
80
- ve as useCellNodeProps,
81
- Ie as useComposer,
82
- Ce as useContainerNodeProps,
83
- Le as useCountdownTimerNodeProps,
84
- Te as useFlexItemNodeProps,
85
- xe as useFlexboxNodeProps,
86
- Se as useGridNodeProps,
87
- Ae as useHeadingNodeProps,
88
- Ee as useIconNodeProps,
89
- we as useImageNodeProps,
90
- Re as useLinkNodeProps,
46
+ y as ImageNode,
47
+ V as InlineInspector,
48
+ j as InlineNode,
49
+ D as LinkNode,
50
+ z as ListItemNode,
51
+ J as MarqueeItemNode,
52
+ K as MarqueeNode,
53
+ O as NodeElement,
54
+ Q as ParagraphNode,
55
+ X as Rating,
56
+ Y as RatingNode,
57
+ Z as RootNode,
58
+ _ as SwiperNode,
59
+ $ as SwiperSlideNode,
60
+ W as TabContentNode,
61
+ ee as TabListNode,
62
+ se as TabNode,
63
+ oe as TabPanelNode,
64
+ ae as TabsNode,
65
+ re as UnknownNode,
66
+ de as UnorderedListNode,
67
+ te as VideoNode,
68
+ ne as defaultProps,
69
+ Ne as defineNode,
70
+ ue as getNodeCustom,
71
+ ie as getNodeDisplayName,
72
+ pe as getNodeInfo,
73
+ me as getNodeRelated,
74
+ Pe as getNodeResolved,
75
+ ce as getRatingProps,
76
+ le as isNodeSelectable,
77
+ ge as parseNumber,
78
+ be as parseSvgString,
79
+ fe as registerNodeRelated,
80
+ ve as toResponsiveCss,
81
+ Ce as useAccordionGroupNodeProps,
82
+ Ie as useAccordionNodeProps,
83
+ Le as useBoxNodeProps,
84
+ xe as useButtonNodeProps,
85
+ Te as useCellNodeProps,
86
+ Re as useComposer,
87
+ Se as useContainerNodeProps,
88
+ we as useCountUpNodeProps,
89
+ Ae as useCountdownTimerNodeProps,
90
+ Ee as useFlexItemNodeProps,
91
+ he as useFlexboxNodeProps,
92
+ Fe as useGridNodeProps,
93
+ Ue as useHeadingNodeProps,
94
+ ke as useIconNodeProps,
95
+ qe as useImageNodeProps,
96
+ Be as useLinkNodeProps,
91
97
  f as useListItemNodeProps,
92
- he as useMarqueeNodeProps,
98
+ Ge as useMarqueeNodeProps,
93
99
  n as useNode,
94
100
  g as useNodeContentEditable,
95
- Fe as useNodeDataAttributes,
101
+ He as useNodeDataAttributes,
96
102
  t as useNodeProps,
97
- ke as useParagraphNodeProps,
98
- qe as useSwiperNodeProps,
99
- Be as useTabNodeProps,
103
+ Me as useParagraphNodeProps,
104
+ ye as useRatingNodeProps,
105
+ Ve as useSwiperNodeProps,
106
+ je as useTabNodeProps,
100
107
  b as useTabPanelNodeProps,
101
- Ge as useTabsNodeProps,
102
- He as useUnorderedListNodeProps,
103
- Me as useVideoNodeProps
108
+ De as useTabsNodeProps,
109
+ ze as useUnorderedListNodeProps,
110
+ Je as useVideoNodeProps
104
111
  };
@@ -0,0 +1,129 @@
1
+ # CountUpNode
2
+
3
+ Hiển thị con số chạy tăng dần (animate từ `from` đến `to`) — render ra component `CountUp` của `@janbox/storefront-ui`. Dùng cho số liệu thống kê, thành tựu, KPI... Không phải canvas node — không chứa node con.
4
+
5
+ ## Resolved name
6
+
7
+ `CountUp` (displayName: `Count up`)
8
+
9
+ ## Cấu trúc
10
+
11
+ ```text
12
+ count-up/
13
+ ├── count-up.node/ # CraftJS node bọc quanh <CountUp />
14
+ │ ├── count-up.node.tsx
15
+ │ ├── types.ts # CountUpNodeProps
16
+ │ └── helpers.ts # useCountUpNodeProps (transform = getCountUpProps)
17
+ └── count-up.inspector/ # Panel chỉnh sửa trong editor
18
+ ```
19
+
20
+ `CountUpNode` lo phần CraftJS (connectors, data attributes) rồi delegate xuống `CountUp`. Trong editor (`enabled`) thì `startOnView` bị tắt để số luôn hiển thị giá trị cuối; ở trang thật thì animate khi cuộn tới.
21
+
22
+ ## Configurable props
23
+
24
+ ### Top-level props
25
+
26
+ | Prop | Type | Default | Description |
27
+ | --- | --- | --- | --- |
28
+ | `to` | `number` | — | Giá trị kết thúc. **Bắt buộc** |
29
+ | `from` | `number` | `0` | Giá trị bắt đầu |
30
+ | `duration` | `number` | `2` | Thời lượng animate (giây) |
31
+ | `prefix` | `ReactNode` | — | Nội dung hiển thị trước số (VD `+`, `$`) |
32
+ | `suffix` | `ReactNode` | — | Nội dung hiển thị sau số (VD `%`, `k`) |
33
+ | `startOnView` | `boolean` | `true` | Chỉ animate khi element cuộn vào viewport (tự tắt trong editor) |
34
+ | `formatNumberOptions` | `FormatNumberOptions` | — | Tùy chọn format số (phân tách hàng nghìn, số thập phân...) |
35
+ | `sizeVariant` | `TypographySizeVariant` | — | Cỡ chữ theo hệ typography. Hỗ trợ responsive qua `sm`, `md`, `lg` |
36
+
37
+ Ngoài ra kế thừa toàn bộ props của `motion.span` (`HTMLMotionProps<'span'>`) — có thể truyền `className`, `onClick`, animation props của Motion...
38
+
39
+ `sizeVariant` responsive: `sizeVariant="xl"` trên mobile, `md={{ sizeVariant: '2xl' }}` phóng to trên desktop.
40
+
41
+ ### `sx` props
42
+
43
+ ```ts
44
+ sx?: {
45
+ // typography
46
+ color?: string
47
+ fontWeight?: number | string
48
+ fontStyle?: string
49
+ textDecorationLine?: string
50
+ textAlign?: 'left' | 'center' | 'right'
51
+ textTransform?: 'none' | 'uppercase' | 'lowercase' | 'capitalize'
52
+
53
+ // border
54
+ borderStyle?: string
55
+ borderColor?: string
56
+ borderTopWidth?: number
57
+ borderRightWidth?: number
58
+ borderBottomWidth?: number
59
+ borderLeftWidth?: number
60
+ borderTopLeftRadius?: number | string
61
+ borderTopRightRadius?: number | string
62
+ borderBottomRightRadius?: number | string
63
+ borderBottomLeftRadius?: number | string
64
+
65
+ // background
66
+ backgroundColor?: string
67
+ backgroundImage?: string
68
+ backgroundPosition?: string
69
+ backgroundRepeat?: string
70
+ backgroundSize?: string
71
+ backgroundAttachment?: string
72
+ background?: string
73
+
74
+ // responsive overrides
75
+ sm?: { /* same keys above */ }
76
+ md?: { /* same keys above */ }
77
+ lg?: { /* same keys above */ }
78
+ }
79
+ ```
80
+
81
+ ## Usage
82
+
83
+ ```tsx
84
+ import { CountUpNode } from '@janbox/storefront-builder';
85
+
86
+ // Cơ bản — chạy từ 0 đến 100
87
+ <CountUpNode from={0} to={100} />
88
+
89
+ // Có prefix/suffix
90
+ <CountUpNode from={0} to={1000} prefix="+" suffix="k" />
91
+
92
+ // Tùy chỉnh thời lượng + cỡ chữ responsive
93
+ <CountUpNode
94
+ from={0}
95
+ to={98}
96
+ suffix="%"
97
+ duration={3}
98
+ sizeVariant="xl"
99
+ md={{ sizeVariant: '3xl' }}
100
+ />
101
+
102
+ // Style qua sx
103
+ <CountUpNode
104
+ from={0}
105
+ to={500}
106
+ sx={{
107
+ color: '#f59e0b',
108
+ fontWeight: 700,
109
+ textAlign: 'center',
110
+ }}
111
+ />
112
+ ```
113
+
114
+ ## Editor (Inspector)
115
+
116
+ ### Tab Settings
117
+
118
+ - **Config**: From, To, Duration (s), Prefix, Suffix
119
+ - **Text style**: Size variant, Color, Style (weight/italic/underline), Text align, Text transform, Font weight
120
+
121
+ ### Tab Advanced
122
+
123
+ - **Shape**: Border, Border radius
124
+ - **Background**: Background
125
+
126
+ ## Rules
127
+
128
+ - **Canvas**: no — không chứa node con.
129
+ - Các prop đều có default qua `getCountUpProps` của `@janbox/storefront-ui`.
@@ -0,0 +1 @@
1
+ export declare const CountUpInspector: () => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export * from './count-up.inspector';
@@ -0,0 +1,2 @@
1
+ import { CountUpNodeProps } from './types';
2
+ export declare const CountUpNode: (props: CountUpNodeProps) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import { CountUpNodeProps } from './types';
2
+ import { useNodeProps } from '../../../hooks';
3
+ export declare const useCountUpNodeProps: () => ReturnType<typeof useNodeProps<CountUpNodeProps>>;
@@ -0,0 +1,3 @@
1
+ export * from './count-up.node';
2
+ export * from './types';
3
+ export * from './helpers';
@@ -0,0 +1,2 @@
1
+ import { CountUpProps } from '@janbox/storefront-ui';
2
+ export type CountUpNodeProps = CountUpProps;
@@ -0,0 +1 @@
1
+ export * from './count-up.node';
@@ -10,10 +10,10 @@ SVG icon node. Render inline SVG từ raw string hoặc URL.
10
10
 
11
11
  ### Top-level props
12
12
 
13
- | Prop | Type | Description |
14
- | --- | --- | --- |
15
- | `source` | `string` | Raw SVG string hoặc URL tới file SVG |
16
- | `size` | `number` | Kích thước icon (px) — set cả `width` và `height` |
13
+ | Prop | Type | Description |
14
+ | -------- | -------- | ------------------------------------------------- |
15
+ | `source` | `string` | Raw SVG string hoặc URL tới file SVG |
16
+ | `size` | `number` | Kích thước icon (px) — set cả `width` và `height` |
17
17
 
18
18
  `size` hỗ trợ responsive: `size={24}` xs, `md={{ size: 32 }}` desktop.
19
19
 
@@ -25,10 +25,6 @@ sx?: {
25
25
  color?: string
26
26
 
27
27
  // spacing
28
- paddingTop?: number
29
- paddingRight?: number
30
- paddingBottom?: number
31
- paddingLeft?: number
32
28
  marginTop?: number
33
29
  marginRight?: number
34
30
  marginBottom?: number
@@ -73,21 +69,16 @@ import { IconNode } from '@janbox/storefront-builder';
73
69
  sx={{ color: '#fa8c16' }}
74
70
  />
75
71
 
76
- // Icon với background tròn
72
+ // Icon với border radius tròn
77
73
  <IconNode
78
74
  source='<svg>...</svg>'
79
75
  size={16}
80
76
  sx={{
81
77
  color: '#ffffff',
82
- paddingTop: 8,
83
- paddingBottom: 8,
84
- paddingLeft: 8,
85
- paddingRight: 8,
86
- backgroundColor: '#fa8c16',
87
- borderTopLeftRadius: '50%',
88
- borderTopRightRadius: '50%',
89
- borderBottomLeftRadius: '50%',
90
- borderBottomRightRadius: '50%',
78
+ borderTopLeftRadius: 9999,
79
+ borderTopRightRadius: 9999,
80
+ borderBottomLeftRadius: 9999,
81
+ borderBottomRightRadius: 9999,
91
82
  }}
92
83
  />
93
84
  ```
@@ -31,3 +31,5 @@ export * from './video';
31
31
  export * from './box';
32
32
  export * from './container';
33
33
  export * from './countdown-timer';
34
+ export * from './count-up';
35
+ export * from './rating';
@@ -0,0 +1,126 @@
1
+ # RatingNode
2
+
3
+ Hiển thị dải sao đánh giá (render ra chuỗi `StarRating` của `@janbox/storefront-ui`). Hỗ trợ rating thập phân (sao được fill một phần), số lượng sao tùy chỉnh, kích thước responsive và màu tùy ý. Không phải canvas node — không chứa node con.
4
+
5
+ ## Resolved name
6
+
7
+ `Rating` (displayName: `Rating`)
8
+
9
+ ## Cấu trúc
10
+
11
+ ```text
12
+ rating/
13
+ ├── rating/ # Component thuần túy (không phụ thuộc CraftJS)
14
+ │ ├── rating.tsx # <Rating /> — render Primitive + danh sách StarRating
15
+ │ ├── types.ts # RatingProps
16
+ │ └── helpers.ts # defaultProps + getRatingProps (merge default)
17
+ ├── rating.node/ # CraftJS node bọc quanh <Rating />
18
+ │ ├── rating.node.tsx
19
+ │ ├── types.ts # RatingNodeProps = RatingProps
20
+ │ └── helpers.ts # useRatingNodeProps (transform = getRatingProps)
21
+ └── rating.inspector/ # Panel chỉnh sửa trong editor
22
+ ```
23
+
24
+ `RatingNode` chỉ lo phần CraftJS (connectors, data attributes) rồi delegate xuống component `Rating`.
25
+
26
+ ## Configurable props
27
+
28
+ ### Top-level props
29
+
30
+ | Prop | Type | Default | Description |
31
+ | --- | --- | --- | --- |
32
+ | `rating` | `number` | `5` | Giá trị rating hiện tại, hỗ trợ thập phân (VD `3.5` fill nửa sao). **Bắt buộc** |
33
+ | `count` | `number` | `5` | Số lượng sao hiển thị |
34
+ | `size` | `number` | `24` | Kích thước mỗi sao (px). Hỗ trợ responsive qua `sm`, `md`, `lg` |
35
+ | `color` | `string` | `orange.600` | Màu áp dụng cho tất cả sao (CSS color string) |
36
+
37
+ `size` responsive: `size={20}` trên mobile, `md={{ size: 32 }}` phóng to trên desktop.
38
+
39
+ ### `sx` props
40
+
41
+ ```ts
42
+ sx?: {
43
+ // spacing giữa các sao
44
+ columnGap?: number
45
+
46
+ // spacing ngoài/trong
47
+ marginTop?: number
48
+ marginRight?: number
49
+ marginBottom?: number
50
+ marginLeft?: number
51
+ paddingTop?: number
52
+ paddingRight?: number
53
+ paddingBottom?: number
54
+ paddingLeft?: number
55
+
56
+ // border
57
+ borderStyle?: string
58
+ borderColor?: string
59
+ borderTopWidth?: number
60
+ borderRightWidth?: number
61
+ borderBottomWidth?: number
62
+ borderLeftWidth?: number
63
+ borderTopLeftRadius?: number | string
64
+ borderTopRightRadius?: number | string
65
+ borderBottomRightRadius?: number | string
66
+ borderBottomLeftRadius?: number | string
67
+
68
+ // background
69
+ backgroundColor?: string
70
+ backgroundImage?: string
71
+ backgroundPosition?: string
72
+ backgroundRepeat?: string
73
+ backgroundSize?: string
74
+ backgroundAttachment?: string
75
+ background?: string
76
+
77
+ // responsive overrides
78
+ sm?: { /* same keys above */ }
79
+ md?: { /* same keys above */ }
80
+ lg?: { /* same keys above */ }
81
+ }
82
+ ```
83
+
84
+ Container render `display: flex` với `width: fit-content`, nên `columnGap` là khoảng cách giữa các sao.
85
+
86
+ ## Usage
87
+
88
+ ```tsx
89
+ import { RatingNode } from '@janbox/storefront-builder';
90
+
91
+ // Cơ bản — 5 sao, rating 4.5
92
+ <RatingNode rating={4.5} />
93
+
94
+ // Tùy chỉnh số sao, kích thước, màu
95
+ <RatingNode rating={3} count={5} size={28} color="#f59e0b" />
96
+
97
+ // Size responsive
98
+ <RatingNode rating={4} size={20} md={{ size: 32 }} />
99
+
100
+ // Điều chỉnh khoảng cách giữa các sao + spacing ngoài
101
+ <RatingNode
102
+ rating={4.5}
103
+ sx={{
104
+ columnGap: 8,
105
+ marginTop: 12,
106
+ marginBottom: 12,
107
+ }}
108
+ />
109
+ ```
110
+
111
+ ## Editor (Inspector)
112
+
113
+ ### Tab Settings
114
+
115
+ - **Config**: Rating, Count, Size (responsive), Color (color picker), Column gap
116
+ - **Spacing (px)**: Margin, Padding (responsive)
117
+
118
+ ### Tab Advanced
119
+
120
+ - **Shape**: Border, Border radius
121
+ - **Background**: Background
122
+
123
+ ## Rules
124
+
125
+ - **Canvas**: no — không chứa node con.
126
+ - `rating` là prop bắt buộc; các prop còn lại có default qua `getRatingProps`.
@@ -0,0 +1,2 @@
1
+ export * from './rating';
2
+ export * from './rating.node';
@@ -0,0 +1,4 @@
1
+ import { RatingProps } from './types';
2
+ export declare const defaultProps: Partial<RatingProps>;
3
+ /** Gán giá trị mặc định cho các prop bị bỏ trống. */
4
+ export declare const getRatingProps: (props: RatingProps) => RatingProps;
@@ -0,0 +1,3 @@
1
+ export * from './rating';
2
+ export * from './types';
3
+ export * from './helpers';
@@ -0,0 +1,2 @@
1
+ import { RatingProps } from './types';
2
+ export declare const Rating: (_props: RatingProps) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { PrimitiveProps, StarRatingResponsiveProps } from '@janbox/storefront-ui';
2
+ import { ToResponsiveProps } from '@janbox/storefront-ui/types';
3
+ export type RatingProps = ToResponsiveProps<StarRatingResponsiveProps> & PrimitiveProps & {
4
+ /** Giá trị rating hiện tại (hỗ trợ số thập phân, VD: 3.5). */
5
+ rating: number;
6
+ /** Số lượng ngôi sao hiển thị. */
7
+ count?: number;
8
+ /** Màu áp dụng cho tất cả ngôi sao (CSS color string). */
9
+ color?: string;
10
+ };
@@ -0,0 +1 @@
1
+ export * from './rating.inspector';
@@ -0,0 +1 @@
1
+ export declare const RatingInspector: () => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import { RatingNodeProps } from './types';
2
+ import { useNodeProps } from '../../../hooks';
3
+ export declare const useRatingNodeProps: () => ReturnType<typeof useNodeProps<RatingNodeProps>>;
@@ -0,0 +1,3 @@
1
+ export * from './rating.node';
2
+ export * from './types';
3
+ export * from './helpers';
@@ -0,0 +1,2 @@
1
+ import { RatingNodeProps } from './types';
2
+ export declare const RatingNode: (props: RatingNodeProps) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { RatingProps } from '../rating/types';
2
+ export type RatingNodeProps = RatingProps;
@@ -0,0 +1,2 @@
1
+ import { InsertTemplate } from '../../../editor';
2
+ export declare const ABOUT_STORY_TEMPLATE: InsertTemplate;
@@ -0,0 +1,2 @@
1
+ import { InsertTemplate } from '../../../editor';
2
+ export declare const NOTEBOOK_HERO_TEMPLATE: InsertTemplate;
@@ -3,3 +3,4 @@ export * from './faqs';
3
3
  export * from './guarantee';
4
4
  export * from './brand-story';
5
5
  export * from './about';
6
+ export * from './testimonial';
@@ -0,0 +1,2 @@
1
+ import { InsertTemplate } from '../../../editor';
2
+ export declare const BEFORE_AFTER_TEMPLATE: InsertTemplate;
@@ -0,0 +1,2 @@
1
+ import { InsertTemplateGroup } from '../../../editor';
2
+ export declare const TESTIMONIAL_SECTION_GROUP: InsertTemplateGroup;