@janbox/storefront-ui 2.0.28 → 2.0.30
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 +681 -0
- package/dist/lib/accordion/README.md +81 -0
- package/dist/lib/avatar/README.md +74 -0
- package/dist/lib/badge/README.md +58 -0
- package/dist/lib/box/README.md +69 -0
- package/dist/lib/box/box.js +5 -21
- package/dist/lib/breadcrumbs/README.md +70 -0
- package/dist/lib/button/README.md +115 -0
- package/dist/lib/cascader/README.md +128 -0
- package/dist/lib/checkbox/README.md +74 -0
- package/dist/lib/checkbox/checkbox.js +107 -12
- package/dist/lib/checkbox/types.d.ts +2 -2
- package/dist/lib/chip/README.md +72 -0
- package/dist/lib/collapse/README.md +78 -0
- package/dist/lib/container/README.md +59 -0
- package/dist/lib/count-up/README.md +52 -0
- package/dist/lib/countdown-timer/README.md +77 -0
- package/dist/lib/date-picker/README.md +94 -0
- package/dist/lib/date-picker/date-picker.js +2 -1
- package/dist/lib/dialog/README.md +109 -0
- package/dist/lib/drawer/README.md +97 -0
- package/dist/lib/filter-panel/README.md +146 -0
- package/dist/lib/flag/README.md +58 -0
- package/dist/lib/flexbox/README.md +59 -0
- package/dist/lib/flexbox/flexbox/flexbox.d.ts +1 -1
- package/dist/lib/flexbox/flexbox/flexbox.js +16 -20
- package/dist/lib/floating/README.md +109 -0
- package/dist/lib/form-helper-text/README.md +54 -0
- package/dist/lib/form-label/README.md +50 -0
- package/dist/lib/grid/README.md +72 -0
- package/dist/lib/grid/grid/grid.d.ts +1 -1
- package/dist/lib/grid/grid/grid.js +20 -25
- package/dist/lib/highlight-words/README.md +64 -0
- package/dist/lib/highlight-words/highlight-words.js +1 -2
- package/dist/lib/icon/README.md +69 -0
- package/dist/lib/icon-button/README.md +92 -0
- package/dist/lib/image/README.md +80 -0
- package/dist/lib/input/README.md +118 -0
- package/dist/lib/input-mask/README.md +88 -0
- package/dist/lib/input-number/README.md +92 -0
- package/dist/lib/input-range/README.md +85 -0
- package/dist/lib/lightbox/README.md +107 -0
- package/dist/lib/linear-progress/README.md +54 -0
- package/dist/lib/link/README.md +67 -0
- package/dist/lib/loading/README.md +65 -0
- package/dist/lib/marquee/README.md +83 -0
- package/dist/lib/menu/README.md +92 -0
- package/dist/lib/multiple-select/README.md +108 -0
- package/dist/lib/nav-link/README.md +61 -0
- package/dist/lib/notifications/README.md +103 -0
- package/dist/lib/otp-input/README.md +71 -0
- package/dist/lib/pagination/README.md +84 -0
- package/dist/lib/phone-input/README.md +80 -0
- package/dist/lib/popover/README.md +93 -0
- package/dist/lib/price-label/README.md +78 -0
- package/dist/lib/primitive/README.md +80 -0
- package/dist/lib/progress/README.md +50 -0
- package/dist/lib/radio-button/README.md +89 -0
- package/dist/lib/radio-button/radio-button.js +98 -7
- package/dist/lib/ripple-effect/README.md +66 -0
- package/dist/lib/select/README.md +124 -0
- package/dist/lib/star-rating/README.md +67 -0
- package/dist/lib/stepper/README.md +99 -0
- package/dist/lib/suspense-query/README.md +78 -0
- package/dist/lib/swiper/README.md +99 -0
- package/dist/lib/switch/README.md +73 -0
- package/dist/lib/switch/switch.d.ts +1 -1
- package/dist/lib/switch/switch.js +110 -11
- package/dist/lib/table/README.md +115 -0
- package/dist/lib/table/table-row/table-row.d.ts +1 -1
- package/dist/lib/table/table-row/table-row.js +4 -4
- package/dist/lib/table/table-row/types.d.ts +2 -2
- package/dist/lib/tabs/README.md +103 -0
- package/dist/lib/text/README.md +59 -0
- package/dist/lib/textarea/README.md +76 -0
- package/dist/lib/time-picker/README.md +100 -0
- package/dist/lib/tooltip/README.md +106 -0
- package/dist/lib/unordered-list/README.md +85 -0
- package/dist/lib/unordered-list/list-item/list-item.d.ts +1 -1
- package/dist/lib/unordered-list/list-item/list-item.js +8 -10
- package/dist/lib/unordered-list/list-item/types.d.ts +2 -2
- package/dist/lib/video/README.md +88 -0
- package/package.json +5 -5
- package/dist/lib/checkbox/checkbox.module.scss.js +0 -23
- package/dist/lib/radio-button/radio-button.module.scss.js +0 -17
- package/dist/lib/switch/switch.module.scss.js +0 -14
- package/dist/style.css +0 -823
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Menu
|
|
2
|
+
|
|
3
|
+
Dropdown menu component hiển thị danh sách actions hoặc options khi được kích hoạt. Xây dựng trên Floating UI, hỗ trợ tương tác hover và click với safe polygon hover detection.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Menu } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `placement` | `Placement` | `'bottom'` | Vị trí của menu so với trigger (vd: `'top'`, `'bottom'`, `'left'`, `'right'`, và các biến thể như `'top-start'`) |
|
|
16
|
+
| `open` | `boolean` | - | Controlled open state của menu |
|
|
17
|
+
| `onOpenChange` | `(open: boolean, event?: Event, reason?: string) => void` | - | Callback khi trạng thái open thay đổi |
|
|
18
|
+
| `clickProps` | `UseClickProps` | - | Cấu hình tương tác click (bật mặc định) |
|
|
19
|
+
| `dismissProps` | `UseDismissProps` | - | Cấu hình dismiss khi click ra ngoài (bật mặc định) |
|
|
20
|
+
| `hoverProps` | `UseHoverProps` | - | Cấu hình tương tác hover (dùng `safePolygon` mặc định để tránh đóng nhầm) |
|
|
21
|
+
| `focusProps` | `UseFocusProps` | - | Cấu hình tương tác focus |
|
|
22
|
+
| `offsetOptions` | `OffsetOptions` | - | Khoảng cách giữa trigger và menu content |
|
|
23
|
+
| `sizeOptions` | `SizeOptions` | - | Ràng buộc kích thước của floating menu |
|
|
24
|
+
| `autoUpdateOptions` | `AutoUpdateOptions` | - | Tùy chọn tự động cập nhật vị trí menu |
|
|
25
|
+
| `children` * | `ReactNode` | - | Nội dung menu (thường là `MenuTrigger` và `MenuList`) |
|
|
26
|
+
|
|
27
|
+
*Bắt buộc
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
### Basic Menu
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<Menu>
|
|
35
|
+
<MenuTrigger>
|
|
36
|
+
<button>Open Menu ▼</button>
|
|
37
|
+
</MenuTrigger>
|
|
38
|
+
<MenuList>
|
|
39
|
+
<MenuItem>Profile</MenuItem>
|
|
40
|
+
<MenuItem>Settings</MenuItem>
|
|
41
|
+
<MenuItem>Help</MenuItem>
|
|
42
|
+
<MenuItem>Logout</MenuItem>
|
|
43
|
+
</MenuList>
|
|
44
|
+
</Menu>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Menu with Icons
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
<Menu>
|
|
51
|
+
<MenuTrigger>
|
|
52
|
+
<button>Actions ▼</button>
|
|
53
|
+
</MenuTrigger>
|
|
54
|
+
<MenuList>
|
|
55
|
+
<MenuItem>✏️ Edit</MenuItem>
|
|
56
|
+
<MenuItem>📋 Copy</MenuItem>
|
|
57
|
+
<MenuItem>🗑️ Delete</MenuItem>
|
|
58
|
+
</MenuList>
|
|
59
|
+
</Menu>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Top Placement Menu
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<Menu placement="top">
|
|
66
|
+
<MenuTrigger>
|
|
67
|
+
<button>Open Top ▲</button>
|
|
68
|
+
</MenuTrigger>
|
|
69
|
+
<MenuList>
|
|
70
|
+
<MenuItem>Option 1</MenuItem>
|
|
71
|
+
<MenuItem>Option 2</MenuItem>
|
|
72
|
+
<MenuItem>Option 3</MenuItem>
|
|
73
|
+
</MenuList>
|
|
74
|
+
</Menu>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Related Components
|
|
78
|
+
|
|
79
|
+
- [Floating](../floating/README.md)
|
|
80
|
+
- [FloatingTrigger](../floating-trigger/README.md)
|
|
81
|
+
- [FloatingContent](../floating-content/README.md)
|
|
82
|
+
- [Button](../button/README.md)
|
|
83
|
+
|
|
84
|
+
## Dependencies
|
|
85
|
+
|
|
86
|
+
- `@floating-ui/react`
|
|
87
|
+
|
|
88
|
+
## See Also
|
|
89
|
+
|
|
90
|
+
- [Component Source](./index.ts)
|
|
91
|
+
- [Storybook Stories](./menu.stories.tsx)
|
|
92
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# MultipleSelect
|
|
2
|
+
|
|
3
|
+
A generic multi-select dropdown component that renders selected values as tags inside an input trigger. It supports search filtering, virtualized option lists, controlled/uncontrolled state, and responsive sizing.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { MultipleSelect } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `options*` | `O[]` | - | Array of option objects to display in the dropdown list. |
|
|
16
|
+
| `value` | `Array<Partial<O> \| MultipleSelectOptionValue>` | - | Controlled selected values. Can be full option objects or primitive values (string \| number). |
|
|
17
|
+
| `defaultValue` | `Array<Partial<O> \| MultipleSelectOptionValue>` | - | Initial selected values for uncontrolled usage. |
|
|
18
|
+
| `onChange` | `(value: O[]) => void` | - | Callback fired when the selection changes, receiving the full array of selected option objects. |
|
|
19
|
+
| `optionValue` | `keyof O \| ((option: O) => MultipleSelectOptionValue)` | `'value'` | Key or function to derive the unique value from an option object. |
|
|
20
|
+
| `optionLabel` | `keyof O \| ((option: O) => React.ReactNode)` | `'label'` | Key or function to derive the display label from an option object. |
|
|
21
|
+
| `tagLabel` | `keyof O \| ((option: O) => React.ReactNode)` | - | Key or function to derive the label shown inside the selected tag chip. Falls back to `optionLabel` if not set. |
|
|
22
|
+
| `optionSearchLabel` | `keyof O \| Array<keyof O> \| ((option: O) => string \| string[])` | - | Field(s) or function used when filtering options by the search input. Defaults to `optionLabel`. |
|
|
23
|
+
| `searchable` | `boolean` | `true` | Whether to show a search input inside the dropdown for filtering options. |
|
|
24
|
+
| `displayCount` | `number` | `1` | Maximum number of tag chips shown in the trigger before collapsing into a `+N` badge. Use `Infinity` to show all. |
|
|
25
|
+
| `placeholder` | `string` | - | Placeholder text shown in the trigger when no values are selected. |
|
|
26
|
+
| `open` | `boolean` | - | Controlled open state of the dropdown. |
|
|
27
|
+
| `onOpenChange` | `UseFloatingOptions['onOpenChange']` | - | Callback fired when the open state changes. |
|
|
28
|
+
| `placement` | `Placement` | `'bottom-start'` | Floating UI placement for the dropdown panel. |
|
|
29
|
+
| `error` | `boolean` | - | When true, renders the trigger in an error/invalid visual state. |
|
|
30
|
+
| `helperText` | `string` | - | Helper or validation message rendered below the trigger via `FormHelperText`. |
|
|
31
|
+
| `containerProps` | `PrimitiveProps<JSX.IntrinsicElements['div']>` | - | Props forwarded to the outer container `Primitive` wrapper. |
|
|
32
|
+
| `inputProps` | `InputProps` | - | Props forwarded to the search `Input` rendered inside the dropdown panel. |
|
|
33
|
+
| `listProps` | `PropsWithoutRef<HTMLProps<HTMLDivElement>>` | - | Props forwarded to the `VirtualizedList` container element. |
|
|
34
|
+
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | `'md'` | Size variant controlling height, padding, and font size of the trigger and option rows. |
|
|
35
|
+
|
|
36
|
+
*Required props
|
|
37
|
+
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
### Basic usage
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
type Option = { label: string; value: string };
|
|
44
|
+
|
|
45
|
+
const fruits: Option[] = [
|
|
46
|
+
{ label: 'Apple', value: 'apple' },
|
|
47
|
+
{ label: 'Banana', value: 'banana' },
|
|
48
|
+
{ label: 'Cherry', value: 'cherry' },
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
<MultipleSelect<Option>
|
|
52
|
+
options={fruits}
|
|
53
|
+
placeholder="Select fruits..."
|
|
54
|
+
onChange={(selected) => console.log(selected)}
|
|
55
|
+
/>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Controlled with error state
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
const [selected, setSelected] = useState<string[]>([]);
|
|
62
|
+
|
|
63
|
+
<MultipleSelect
|
|
64
|
+
options={fruits}
|
|
65
|
+
value={selected}
|
|
66
|
+
onChange={(opts) => setSelected(opts.map((o) => o.value))}
|
|
67
|
+
error={selected.length === 0}
|
|
68
|
+
helperText={selected.length === 0 ? 'Please select at least one option' : undefined}
|
|
69
|
+
placeholder="Select fruits..."
|
|
70
|
+
/>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Display multiple tags with overflow badge
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
// Shows up to 2 tag chips, remaining selections collapse into '+N' badge
|
|
77
|
+
<MultipleSelect<Option>
|
|
78
|
+
options={fruits}
|
|
79
|
+
value={['apple', 'banana', 'cherry']}
|
|
80
|
+
displayCount={2}
|
|
81
|
+
placeholder="Select fruits..."
|
|
82
|
+
onChange={handleChange}
|
|
83
|
+
/>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Related Components
|
|
87
|
+
|
|
88
|
+
- [Input](../input/README.md)
|
|
89
|
+
- [InputMask](../inputmask/README.md)
|
|
90
|
+
- [Checkbox](../checkbox/README.md)
|
|
91
|
+
- [Floating](../floating/README.md)
|
|
92
|
+
- [FloatingTrigger](../floatingtrigger/README.md)
|
|
93
|
+
- [FloatingContent](../floatingcontent/README.md)
|
|
94
|
+
- [FormHelperText](../formhelpertext/README.md)
|
|
95
|
+
- [VirtualizedList](../virtualizedlist/README.md)
|
|
96
|
+
- [Primitive](../primitive/README.md)
|
|
97
|
+
|
|
98
|
+
## Dependencies
|
|
99
|
+
|
|
100
|
+
- @floating-ui/react
|
|
101
|
+
- @tanstack/react-virtual
|
|
102
|
+
- lodash-es
|
|
103
|
+
|
|
104
|
+
## See Also
|
|
105
|
+
|
|
106
|
+
- [Component Source](./index.ts)
|
|
107
|
+
- [Storybook Stories](./multipleselect.stories.tsx)
|
|
108
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# NavLink
|
|
2
|
+
|
|
3
|
+
A wrapper around React Router's NavLink component that adds safe handling for undefined `to` prop. When `to` is nil, the link prevents navigation and treats itself as inactive, making it safe to render navigation items that may not yet have a destination.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { NavLink } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `to` | `ReactRouterNavLinkProps['to'] \| undefined` | - | Đường dẫn hoặc location object. Khi `undefined` hoặc `null`, link sẽ ngăn navigation và được coi là inactive (`isActive = false`). |
|
|
16
|
+
| `children` | `React.ReactNode \| ((props: NavLinkRenderProps) => React.ReactNode)` | - | Nội dung bên trong link. Có thể là render function nhận NavLink render props gồm `isActive`, `isPending`, `isTransitioning`. Khi `to` là nil, `isActive` luôn là `false`. |
|
|
17
|
+
| `className` | `string \| ((props: NavLinkRenderProps) => string \| undefined)` | - | Class name hoặc function nhận render props để tính class động. `isActive` trong render props tuân theo nil-to override. |
|
|
18
|
+
| `style` | `React.CSSProperties \| ((props: NavLinkRenderProps) => React.CSSProperties \| undefined)` | - | Inline styles hoặc function nhận render props để tính styles động. `isActive` trong render props tuân theo nil-to override. |
|
|
19
|
+
| `end` | `boolean` | - | Khi `true`, active class/style chỉ được áp dụng khi URL hiện tại khớp chính xác với `to` (không partial matching). |
|
|
20
|
+
| `ref` | `Ref<HTMLAnchorElement>` | - | Forwarded ref đến anchor element bên dưới. |
|
|
21
|
+
| `onClick` | `(event: React.MouseEvent<HTMLAnchorElement>) => void` | - | Click handler. Navigation tự động bị ngăn khi `to` là nil hoặc khi `aria-disabled` là `true`. |
|
|
22
|
+
|
|
23
|
+
## Examples
|
|
24
|
+
|
|
25
|
+
### Basic navigation link
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
<NavLink to="/home">Home</NavLink>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Active state with exact match and dynamic class
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<NavLink
|
|
35
|
+
to="/dashboard"
|
|
36
|
+
end
|
|
37
|
+
className={({ isActive }) => isActive ? 'nav-item nav-item--active' : 'nav-item'}
|
|
38
|
+
>
|
|
39
|
+
Dashboard
|
|
40
|
+
</NavLink>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Placeholder link with no destination (disabled navigation)
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
<NavLink to={undefined} aria-disabled="true">
|
|
47
|
+
{({ isActive }) => (
|
|
48
|
+
<span style={{ opacity: isActive ? 1 : 0.5 }}>Coming Soon</span>
|
|
49
|
+
)}
|
|
50
|
+
</NavLink>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Dependencies
|
|
54
|
+
|
|
55
|
+
- react-router
|
|
56
|
+
|
|
57
|
+
## See Also
|
|
58
|
+
|
|
59
|
+
- [Component Source](./index.ts)
|
|
60
|
+
- [Storybook Stories](./navlink.stories.tsx)
|
|
61
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Notifications
|
|
2
|
+
|
|
3
|
+
A toast notification system that renders dismissible notification cards in a fixed portal overlay at the top-right of the screen. It uses an external store (`notificationStore`) and the `useNotifications` hook to push notifications imperatively from anywhere in the app.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Notifications } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
|
|
16
|
+
## Examples
|
|
17
|
+
|
|
18
|
+
### Basic usage — mount Notifications once and push via hook
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { Notifications, useNotifications } from '@janbox/storefront-ui';
|
|
22
|
+
|
|
23
|
+
const App = () => (
|
|
24
|
+
<>
|
|
25
|
+
{/* Mount once at the root level */}
|
|
26
|
+
<Notifications />
|
|
27
|
+
<MyPage />
|
|
28
|
+
</>
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const MyPage = () => {
|
|
32
|
+
const { pushNotifications } = useNotifications();
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<button
|
|
36
|
+
onClick={() =>
|
|
37
|
+
pushNotifications({
|
|
38
|
+
title: 'Success',
|
|
39
|
+
message: 'Your changes have been saved.',
|
|
40
|
+
color: 'green',
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
>
|
|
44
|
+
Save
|
|
45
|
+
</button>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Push multiple notifications with custom duration
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
const { pushNotifications } = useNotifications();
|
|
54
|
+
|
|
55
|
+
pushNotifications([
|
|
56
|
+
{
|
|
57
|
+
title: 'Item added',
|
|
58
|
+
message: 'Product has been added to your cart.',
|
|
59
|
+
color: 'primary',
|
|
60
|
+
duration: 4000,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
title: 'Stock low',
|
|
64
|
+
message: 'Only 2 items left in stock.',
|
|
65
|
+
color: 'orange',
|
|
66
|
+
duration: 6000,
|
|
67
|
+
},
|
|
68
|
+
]);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Error notification on API failure
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
const { pushNotifications } = useNotifications();
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
await submitOrder();
|
|
78
|
+
} catch (err) {
|
|
79
|
+
pushNotifications({
|
|
80
|
+
title: 'Order failed',
|
|
81
|
+
message: 'Something went wrong. Please try again.',
|
|
82
|
+
color: 'red',
|
|
83
|
+
duration: 5000,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Related Components
|
|
89
|
+
|
|
90
|
+
- [IconButton](../icon-button/README.md)
|
|
91
|
+
- [Primitive](../primitive/README.md)
|
|
92
|
+
|
|
93
|
+
## Dependencies
|
|
94
|
+
|
|
95
|
+
- @floating-ui/react
|
|
96
|
+
- lodash-es
|
|
97
|
+
- motion/react
|
|
98
|
+
|
|
99
|
+
## See Also
|
|
100
|
+
|
|
101
|
+
- [Component Source](./index.ts)
|
|
102
|
+
- [Storybook Stories](./notifications.stories.tsx)
|
|
103
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# OtpInput
|
|
2
|
+
|
|
3
|
+
A one-time password input component that renders multiple individual input fields for entering verification codes. Supports auto-focus, paste handling, keyboard navigation, and automatic progression between fields.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { OtpInput } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `length` | `number` | 6 | Number of OTP input fields to render |
|
|
16
|
+
| `onChange` | `(otp: string) => void` | - | Callback fired when any digit changes, receives the complete OTP string |
|
|
17
|
+
| `onFullfilled` | `(otp: string) => void` | - | Callback fired when all digits are filled, receives the complete OTP string |
|
|
18
|
+
| `disabled` | `boolean` | - | Disables all input fields |
|
|
19
|
+
| `autoFocus` | `boolean` | - | Auto-focuses the first input field on mount |
|
|
20
|
+
| `isLoading` | `boolean` | - | Makes all input fields read-only during loading state |
|
|
21
|
+
| `defaultValue` | `string` | - | Default OTP value (uncontrolled) |
|
|
22
|
+
| `value` | `string` | - | Controlled OTP value |
|
|
23
|
+
| `error` | `boolean` | - | Shows error state styling on all input fields |
|
|
24
|
+
| `size` | `InputSizeVariant` | - | Size variant for all input fields |
|
|
25
|
+
| `sm` | `InputResponsiveProps` | - | Responsive props for small breakpoint (768px+) |
|
|
26
|
+
| `md` | `InputResponsiveProps` | - | Responsive props for medium breakpoint (1280px+) |
|
|
27
|
+
| `lg` | `InputResponsiveProps` | - | Responsive props for large breakpoint (1680px+) |
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
### Basic 6-digit OTP
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<OtpInput length={6} onChange={(otp) => console.log(otp)} />
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 4-digit PIN with auto-submit
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
<OtpInput
|
|
41
|
+
length={4}
|
|
42
|
+
autoFocus
|
|
43
|
+
onFullfilled={(otp) => handleVerify(otp)}
|
|
44
|
+
/>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Controlled with error state
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
<OtpInput
|
|
51
|
+
length={6}
|
|
52
|
+
value={otpValue}
|
|
53
|
+
onChange={setOtpValue}
|
|
54
|
+
error={hasError}
|
|
55
|
+
disabled={isSubmitting}
|
|
56
|
+
/>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Related Components
|
|
60
|
+
|
|
61
|
+
- [Input](../input/README.md)
|
|
62
|
+
|
|
63
|
+
## Dependencies
|
|
64
|
+
|
|
65
|
+
- lodash-es
|
|
66
|
+
|
|
67
|
+
## See Also
|
|
68
|
+
|
|
69
|
+
- [Component Source](./index.ts)
|
|
70
|
+
- [Storybook Stories](./otpinput.stories.tsx)
|
|
71
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Pagination
|
|
2
|
+
|
|
3
|
+
A pagination component for navigating through multiple pages of content. Displays page numbers with ellipsis for large page counts, supports customizable navigation buttons, and provides responsive sizing.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Pagination } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `page` | `number` | 1 | Current active page number |
|
|
16
|
+
| `totalPages` | `number` | 1 | Total number of pages available |
|
|
17
|
+
| `onChange` | `(page: number) => void` | - | Callback function triggered when page changes |
|
|
18
|
+
| `disabled` | `boolean` | - | Disables all pagination interactions |
|
|
19
|
+
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | `sm` | Size variant for pagination buttons and text |
|
|
20
|
+
| `showPrevPageButton` | `boolean` | `true` | Show/hide the previous page navigation button |
|
|
21
|
+
| `showNextPageButton` | `boolean` | `true` | Show/hide the next page navigation button |
|
|
22
|
+
| `showFirstPageButton` | `boolean` | `false` | Show/hide the first page navigation button |
|
|
23
|
+
| `showLastPageButton` | `boolean` | `false` | Show/hide the last page navigation button |
|
|
24
|
+
| `siblingCount` | `number` | `2` | Number of pages to show on each side of the current page |
|
|
25
|
+
| `states` | `Partial<Record<'normal' \| 'active', { color?: IconButtonProps['color']; variant?: IconButtonProps['variant']; }>>` | `{ normal: { color: 'neutral', variant: 'outlined' }, active: { color: 'primary', variant: 'outlined' } }` | Customize color and variant for normal and active pagination button states |
|
|
26
|
+
| `sm` | `{ size?: SizeVariant }` | - | Responsive props for small breakpoint (768px) |
|
|
27
|
+
| `md` | `{ size?: SizeVariant }` | - | Responsive props for medium breakpoint (1280px) |
|
|
28
|
+
| `lg` | `{ size?: SizeVariant }` | - | Responsive props for large breakpoint (1680px) |
|
|
29
|
+
|
|
30
|
+
## Examples
|
|
31
|
+
|
|
32
|
+
### Basic pagination with 10 pages
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
<Pagination
|
|
36
|
+
page={5}
|
|
37
|
+
totalPages={10}
|
|
38
|
+
onChange={(page) => console.log('Navigate to page:', page)}
|
|
39
|
+
/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Pagination with first/last buttons and custom sibling count
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
<Pagination
|
|
46
|
+
page={7}
|
|
47
|
+
totalPages={50}
|
|
48
|
+
siblingCount={2}
|
|
49
|
+
showFirstPageButton
|
|
50
|
+
showLastPageButton
|
|
51
|
+
onChange={(page) => setCurrentPage(page)}
|
|
52
|
+
/>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Disabled pagination with custom button states
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
<Pagination
|
|
59
|
+
page={3}
|
|
60
|
+
totalPages={10}
|
|
61
|
+
disabled
|
|
62
|
+
states={{
|
|
63
|
+
normal: { color: 'neutral', variant: 'outlined' },
|
|
64
|
+
active: { color: 'blue', variant: 'contained' }
|
|
65
|
+
}}
|
|
66
|
+
onChange={(page) => handlePageChange(page)}
|
|
67
|
+
/>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Related Components
|
|
71
|
+
|
|
72
|
+
- [IconButton](../iconbutton/README.md)
|
|
73
|
+
- [Icon](../icon/README.md)
|
|
74
|
+
- [Text](../text/README.md)
|
|
75
|
+
|
|
76
|
+
## Dependencies
|
|
77
|
+
|
|
78
|
+
- @emotion/react
|
|
79
|
+
|
|
80
|
+
## See Also
|
|
81
|
+
|
|
82
|
+
- [Component Source](./index.ts)
|
|
83
|
+
- [Storybook Stories](./pagination.stories.tsx)
|
|
84
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# PhoneInput
|
|
2
|
+
|
|
3
|
+
A phone number input component that combines a country dial code selector with a national number text field. It supports controlled and uncontrolled usage, auto-parses country codes from dial codes, and displays formatted phone numbers when not focused.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { PhoneInput } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `value` | `PhoneInputValue` | - | Controlled value object containing countryCode, dialCode, and nationalNumber. |
|
|
16
|
+
| `defaultValue` | `PhoneInputValue` | - | Uncontrolled default value. Defaults to the first country in the countries list if not provided. |
|
|
17
|
+
| `onChange` | `(value: PhoneInputValue) => void` | - | Callback fired when either the country dial code or the national number changes. Receives a PhoneInputValue object. |
|
|
18
|
+
| `error` | `boolean` | `false` | Puts the input into an error state, rendering the border in red. |
|
|
19
|
+
| `helperText` | `string` | - | Helper or error message displayed below the input via FormHelperText. |
|
|
20
|
+
| `disabled` | `boolean` | `false` | Disables both the country select and the number input, applying a disabled surface color. |
|
|
21
|
+
| `containerProps` | `PrimitiveProps<JSX.IntrinsicElements['div']>` | - | Props forwarded to the outer container Primitive div, useful for layout overrides via sx. |
|
|
22
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size variant for the input. xs is excluded. Supports responsive values via sm/md/lg breakpoint keys. |
|
|
23
|
+
| `css` | `Interpolation` | - | Emotion CSS interpolation applied directly to the InputMask wrapper element. |
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### Default (uncontrolled)
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
<div style={{ width: 300 }}>
|
|
31
|
+
<PhoneInput onChange={(value) => console.log(value)} />
|
|
32
|
+
</div>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Controlled with initial value
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
const [phone, setPhone] = useState<PhoneInputValue>({
|
|
39
|
+
countryCode: 'JP',
|
|
40
|
+
dialCode: '+81',
|
|
41
|
+
nationalNumber: '9012345678',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
<PhoneInput
|
|
45
|
+
value={phone}
|
|
46
|
+
onChange={setPhone}
|
|
47
|
+
/>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Error state with helper text
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
<PhoneInput
|
|
54
|
+
error
|
|
55
|
+
helperText="Please enter a valid phone number."
|
|
56
|
+
defaultValue={{ countryCode: 'VN' }}
|
|
57
|
+
onChange={(value) => console.log(value)}
|
|
58
|
+
/>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Related Components
|
|
62
|
+
|
|
63
|
+
- [Input](../input/README.md)
|
|
64
|
+
- [InputMask](../inputmask/README.md)
|
|
65
|
+
- [Select](../select/README.md)
|
|
66
|
+
- [Flag](../flag/README.md)
|
|
67
|
+
- [FormHelperText](../formhelpertext/README.md)
|
|
68
|
+
- [Primitive](../primitive/README.md)
|
|
69
|
+
|
|
70
|
+
## Dependencies
|
|
71
|
+
|
|
72
|
+
- phone
|
|
73
|
+
- @floating-ui/react
|
|
74
|
+
- lodash-es
|
|
75
|
+
|
|
76
|
+
## See Also
|
|
77
|
+
|
|
78
|
+
- [Component Source](./index.ts)
|
|
79
|
+
- [Storybook Stories](./phoneinput.stories.tsx)
|
|
80
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Popover
|
|
2
|
+
|
|
3
|
+
A floating overlay component for displaying contextual content anchored to a trigger element. Built on top of @floating-ui/react, it supports click-to-open, dismiss-on-outside-click, and controlled/uncontrolled open state — composed via Popover, PopoverTrigger, PopoverContent, and PopoverClose sub-components.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Popover } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `open` | `boolean` | - | Controlled open state of the popover. |
|
|
16
|
+
| `onOpenChange` | `UseFloatingOptions['onOpenChange']` | - | Callback fired when the open state changes. Receives (open: boolean, event: Event | undefined, reason: OpenChangeReason | undefined). |
|
|
17
|
+
| `placement` | `Placement` | `bottom` | Preferred placement of the floating content relative to the trigger. Accepts all @floating-ui/react Placement values (e.g. `'top'`, `'bottom'`, `'left'`, `'right'` and their `'-start'`/`'-end'` variants). |
|
|
18
|
+
| `clickProps` | `UseClickProps` | `{ enabled: true }` | Options forwarded to @floating-ui/react useClick interaction hook. Enabled by default in Popover. |
|
|
19
|
+
| `dismissProps` | `UseDismissProps` | `{ enabled: true }` | Options forwarded to @floating-ui/react useDismiss interaction hook (close on outside click / Escape key). Enabled by default in Popover. |
|
|
20
|
+
| `hoverProps` | `UseHoverProps` | - | Options forwarded to @floating-ui/react useHover interaction hook. |
|
|
21
|
+
| `focusProps` | `UseFocusProps` | - | Options forwarded to @floating-ui/react useFocus interaction hook. |
|
|
22
|
+
| `offsetOptions` | `OffsetOptions` | - | Distance (in px) between the trigger and the floating content. |
|
|
23
|
+
| `sizeOptions` | `SizeOptions` | - | Options for the @floating-ui/react size middleware — constrain the floating element dimensions. |
|
|
24
|
+
| `autoUpdateOptions` | `AutoUpdateOptions` | - | Options passed to @floating-ui/react autoUpdate to control when the position recalculates. |
|
|
25
|
+
| `elements` | `UseFloatingOptions['elements']` | - | Override the reference or floating elements used by floating-ui. |
|
|
26
|
+
| `ref` | `React.Ref<FloatingRef>` | - | Ref forwarded to the underlying UseFloatingReturn object, exposing the full floating-ui context. |
|
|
27
|
+
| `children` | `React.ReactNode` | - | Should contain PopoverTrigger and PopoverContent (and optionally PopoverClose inside content). |
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
### Default (click to open, dismiss on outside click)
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<Popover>
|
|
35
|
+
<PopoverTrigger>
|
|
36
|
+
<button>Open Popover</button>
|
|
37
|
+
</PopoverTrigger>
|
|
38
|
+
<PopoverContent>
|
|
39
|
+
<p>Popover content here</p>
|
|
40
|
+
<PopoverClose>
|
|
41
|
+
<button>Close</button>
|
|
42
|
+
</PopoverClose>
|
|
43
|
+
</PopoverContent>
|
|
44
|
+
</Popover>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Top placement
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
<Popover placement="top">
|
|
51
|
+
<PopoverTrigger>
|
|
52
|
+
<button>Open Top</button>
|
|
53
|
+
</PopoverTrigger>
|
|
54
|
+
<PopoverContent>
|
|
55
|
+
<p>Popover anchored above the trigger</p>
|
|
56
|
+
</PopoverContent>
|
|
57
|
+
</Popover>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Controlled open state
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
const [open, setOpen] = useState(false);
|
|
64
|
+
|
|
65
|
+
<Popover open={open} onOpenChange={(next) => setOpen(next)}>
|
|
66
|
+
<PopoverTrigger>
|
|
67
|
+
<button>Toggle</button>
|
|
68
|
+
</PopoverTrigger>
|
|
69
|
+
<PopoverContent>
|
|
70
|
+
<p>Controlled popover</p>
|
|
71
|
+
<PopoverClose>
|
|
72
|
+
<button onClick={() => setOpen(false)}>Close</button>
|
|
73
|
+
</PopoverClose>
|
|
74
|
+
</PopoverContent>
|
|
75
|
+
</Popover>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Related Components
|
|
79
|
+
|
|
80
|
+
- [Floating](../floating/README.md)
|
|
81
|
+
- [FloatingTrigger](../floating-trigger/README.md)
|
|
82
|
+
- [FloatingContent](../floating-content/README.md)
|
|
83
|
+
- [FloatingClose](../floating-close/README.md)
|
|
84
|
+
|
|
85
|
+
## Dependencies
|
|
86
|
+
|
|
87
|
+
- @floating-ui/react
|
|
88
|
+
|
|
89
|
+
## See Also
|
|
90
|
+
|
|
91
|
+
- [Component Source](./index.ts)
|
|
92
|
+
- [Storybook Stories](./popover.stories.tsx)
|
|
93
|
+
- [Main README](../../README.md)
|