@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,54 @@
|
|
|
1
|
+
# FormHelperText
|
|
2
|
+
|
|
3
|
+
Component hiển thị text hỗ trợ nhỏ bên dưới các form field, dùng để hiển thị hướng dẫn bổ sung hoặc thông báo lỗi validation. Tự động ẩn khi không có nội dung và đổi màu đỏ khi prop `error` được set.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { FormHelperText } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `error` | `boolean` | `false` | Khi `true`, render helper text màu đỏ (`--color-red-600`) để chỉ trạng thái lỗi validation. |
|
|
16
|
+
| `children` | `React.ReactNode` | - | Nội dung helper text. Element tự ẩn (`display: none`) khi không có nội dung. |
|
|
17
|
+
| `sx` | `ToResponsiveProps<StyledCSS>` | - | Style override có responsive, truyền qua hệ thống `sx` prop của `Primitive`. |
|
|
18
|
+
| `as` | `React.ElementType` | `"p"` | Override element type (polymorphic), kế thừa từ `PrimitiveProps`. Mặc định là `p`. |
|
|
19
|
+
| `...rest` | `JSX.IntrinsicElements['p']` | - | Tất cả HTML attributes của thẻ `<p>` đều được forward xuống element bên dưới. |
|
|
20
|
+
|
|
21
|
+
## Examples
|
|
22
|
+
|
|
23
|
+
### Helper text mặc định
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
<FormHelperText>This is a helper text</FormHelperText>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Trạng thái lỗi
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
<FormHelperText error>This field is required</FormHelperText>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Kết hợp với input field
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
<div>
|
|
39
|
+
<input type="email" placeholder="Enter your email" />
|
|
40
|
+
<FormHelperText error={!isValid}>
|
|
41
|
+
{isValid ? 'We will never share your email.' : 'Please enter a valid email address.'}
|
|
42
|
+
</FormHelperText>
|
|
43
|
+
</div>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Related Components
|
|
47
|
+
|
|
48
|
+
- [Primitive](../primitive/README.md)
|
|
49
|
+
|
|
50
|
+
## See Also
|
|
51
|
+
|
|
52
|
+
- [Component Source](./index.ts)
|
|
53
|
+
- [Storybook Stories](./form-helper-text.stories.tsx)
|
|
54
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# FormLabel
|
|
2
|
+
|
|
3
|
+
A form label wrapper component that renders a label for form fields with optional required indicator. It accepts either a string (auto-wrapped in a `<label>` element) or custom React children, and displays a red asterisk when the field is required.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { FormLabel } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `required` | `boolean` | undefined | When true, appends a red asterisk (*) after the label to indicate the associated field is required. |
|
|
16
|
+
| `children` | `React.ReactNode` | undefined | Label content. If a plain string is passed, it is automatically wrapped in a `<label>` element. Custom React nodes are rendered as-is. |
|
|
17
|
+
| `...props` | `JSX.IntrinsicElements['div']` | - | All standard HTML div attributes (className, style, id, onClick, etc.) are forwarded to the root div element. |
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
### Default label
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
<FormLabel>Email address</FormLabel>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Required field label
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
<FormLabel required>Password</FormLabel>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### With custom children and className
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
<FormLabel required className="custom-label">
|
|
37
|
+
<label htmlFor="username">Username</label>
|
|
38
|
+
</FormLabel>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Dependencies
|
|
42
|
+
|
|
43
|
+
- lodash-es
|
|
44
|
+
- @emotion/react
|
|
45
|
+
|
|
46
|
+
## See Also
|
|
47
|
+
|
|
48
|
+
- [Component Source](./index.ts)
|
|
49
|
+
- [Storybook Stories](./formlabel.stories.tsx)
|
|
50
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Grid
|
|
2
|
+
|
|
3
|
+
A CSS Grid layout component that renders a responsive grid container with configurable column counts. It works in tandem with the Cell component, which supports colSpan for spanning multiple columns.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Grid } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `cols` | `number` | 1 | Number of equal-width columns in the grid. Generates `grid-template-columns: repeat(cols, minmax(0, 1fr))`. Supports responsive variants via sm/md/lg. |
|
|
16
|
+
| `sm` | `GridResponsiveProps` | - | Responsive overrides applied at the sm breakpoint (≥768px). Accepts `{ cols?: number }`. |
|
|
17
|
+
| `md` | `GridResponsiveProps` | - | Responsive overrides applied at the md breakpoint (≥1280px). Accepts `{ cols?: number }`. |
|
|
18
|
+
| `lg` | `GridResponsiveProps` | - | Responsive overrides applied at the lg breakpoint (≥1680px). Accepts `{ cols?: number }`. |
|
|
19
|
+
| `container` | `boolean` | false | When true, applies the shared responsive container styles (padding and max-width) from `containerStyle`. |
|
|
20
|
+
| `sx` | `ToResponsiveProps<StyledCSS>` | - | Escape-hatch for inline Emotion styles. Supports responsive keys (sm, md, lg) alongside base styles. |
|
|
21
|
+
| `children` | `React.ReactNode` | - | Grid children, typically Cell components. |
|
|
22
|
+
| `ref` | `React.Ref<HTMLDivElement>` | - | Forwarded ref to the underlying div element. |
|
|
23
|
+
|
|
24
|
+
## Examples
|
|
25
|
+
|
|
26
|
+
### Two-column grid
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
<Grid cols={2} style={{ width: 600 }}>
|
|
30
|
+
<Cell style={{ padding: 8, background: '#e0f0ff' }}>Cell 1</Cell>
|
|
31
|
+
<Cell style={{ padding: 8, background: '#f0ffe0' }}>Cell 2</Cell>
|
|
32
|
+
<Cell style={{ padding: 8, background: '#fff0e0' }}>Cell 3</Cell>
|
|
33
|
+
<Cell style={{ padding: 8, background: '#f0e0ff' }}>Cell 4</Cell>
|
|
34
|
+
</Grid>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Three-column grid with colSpan
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
<Grid cols={3} style={{ width: 600 }}>
|
|
41
|
+
<Cell colSpan={2} style={{ padding: 8, background: '#e0f0ff' }}>Span 2 columns</Cell>
|
|
42
|
+
<Cell style={{ padding: 8, background: '#f0ffe0' }}>Cell 2</Cell>
|
|
43
|
+
<Cell style={{ padding: 8, background: '#fff0e0' }}>Cell 3</Cell>
|
|
44
|
+
<Cell style={{ padding: 8, background: '#f0e0ff' }}>Cell 4</Cell>
|
|
45
|
+
</Grid>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Responsive columns (1 on mobile, 2 on tablet, 4 on desktop)
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<Grid cols={1} sm={{ cols: 2 }} md={{ cols: 4 }} container>
|
|
52
|
+
<Cell>Item 1</Cell>
|
|
53
|
+
<Cell>Item 2</Cell>
|
|
54
|
+
<Cell>Item 3</Cell>
|
|
55
|
+
<Cell>Item 4</Cell>
|
|
56
|
+
</Grid>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Related Components
|
|
60
|
+
|
|
61
|
+
- [Cell](./cell/README.md)
|
|
62
|
+
- [Primitive](../primitive/README.md)
|
|
63
|
+
|
|
64
|
+
## Dependencies
|
|
65
|
+
|
|
66
|
+
- lodash-es
|
|
67
|
+
|
|
68
|
+
## See Also
|
|
69
|
+
|
|
70
|
+
- [Component Source](./index.ts)
|
|
71
|
+
- [Storybook Stories](./grid.stories.tsx)
|
|
72
|
+
- [Main README](../../README.md)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { GridProps } from './types';
|
|
2
2
|
export declare const GRID_MINIMUM_COLS = 1;
|
|
3
3
|
export declare const GRID_MAXIMUM_COLS = 24;
|
|
4
|
-
export declare const Grid: ({ children, ref, ..._props }: GridProps) => import("
|
|
4
|
+
export declare const Grid: ({ children, ref, ..._props }: GridProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,38 +1,33 @@
|
|
|
1
|
-
import { jsx } from "
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { isNil } from "lodash-es";
|
|
3
3
|
import { getGridProps } from "./helpers.js";
|
|
4
|
-
import { mediaQuery } from "../../../theme/screens.js";
|
|
5
|
-
import "../../../theme/palette.js";
|
|
6
4
|
import { containerStyle } from "../../../constants/emotion.js";
|
|
5
|
+
import { Primitive } from "../../primitive/primitive.js";
|
|
7
6
|
const GRID_MINIMUM_COLS = 1;
|
|
8
7
|
const GRID_MAXIMUM_COLS = 24;
|
|
9
8
|
const Grid = ({ children, ref, ..._props }) => {
|
|
10
9
|
const { cols, sm, md, lg, container, sx = {}, ...rest } = getGridProps(_props);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
container && containerStyle,
|
|
14
|
-
createStyle({ cols }, sxXs),
|
|
10
|
+
return /* @__PURE__ */ jsx(
|
|
11
|
+
Primitive,
|
|
15
12
|
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
sx: {
|
|
14
|
+
display: "grid",
|
|
15
|
+
...container ? containerStyle : {},
|
|
16
|
+
...createStyle({ cols }),
|
|
17
|
+
...sx,
|
|
18
|
+
sm: { ...createStyle(sm), ...sx.sm },
|
|
19
|
+
md: { ...createStyle(md), ...sx.md },
|
|
20
|
+
lg: { ...createStyle(lg), ...sx.lg }
|
|
21
|
+
},
|
|
22
|
+
...rest,
|
|
23
|
+
ref,
|
|
24
|
+
children
|
|
19
25
|
}
|
|
20
|
-
|
|
21
|
-
return /* @__PURE__ */ jsx("div", { css, ...rest, ref, children: /* @__PURE__ */ jsx("div", { css: { display: "grid", width: "100%", height: "100%" }, children }) });
|
|
22
|
-
};
|
|
23
|
-
const createStyle = ({ cols } = {}, sx = {}) => {
|
|
24
|
-
const { width, height, ...css } = sx;
|
|
25
|
-
return [
|
|
26
|
-
{
|
|
27
|
-
width,
|
|
28
|
-
height,
|
|
29
|
-
"& > *": {
|
|
30
|
-
gridTemplateColumns: isNil(cols) ? void 0 : `repeat(${cols}, minmax(0, 1fr))`,
|
|
31
|
-
...css
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
];
|
|
26
|
+
);
|
|
35
27
|
};
|
|
28
|
+
const createStyle = ({ cols } = {}) => ({
|
|
29
|
+
gridTemplateColumns: isNil(cols) ? void 0 : `repeat(${cols}, minmax(0, 1fr))`
|
|
30
|
+
});
|
|
36
31
|
export {
|
|
37
32
|
GRID_MAXIMUM_COLS,
|
|
38
33
|
GRID_MINIMUM_COLS,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# HighlightWords
|
|
2
|
+
|
|
3
|
+
Renders a text string with specified search words highlighted using bold font weight. Built on top of `highlight-words-core`, it is useful for search result UIs where matched terms need to be visually distinguished within a body of text.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { HighlightWords } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `textToHighlight*` | `string` | - | The full text string to display and search within. |
|
|
16
|
+
| `searchWords*` | `string[]` | - | Array of words or phrases to highlight within the text. |
|
|
17
|
+
| `highlightClassName` | `string` | - | Optional CSS class name(s) applied to the highlighted `<span>` elements. Useful for custom highlight styling (e.g. background color). |
|
|
18
|
+
| `caseSensitive` | `boolean` | `false` | Whether the search matching should be case-sensitive. Defaults to false (case-insensitive). |
|
|
19
|
+
| `autoEscape` | `boolean` | `false` | Whether to escape special regex characters in the search words before matching. |
|
|
20
|
+
| `sanitize` | `(text: string) => string` | - | Optional function to sanitize/normalize text before matching (e.g. removing diacritics). |
|
|
21
|
+
| `findChunks` | `(args: FindChunksArgs) => Chunk[]` | - | Custom chunk-finding function to override the default highlight-words-core matching logic. |
|
|
22
|
+
|
|
23
|
+
*Required props
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### Basic usage
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
<HighlightWords
|
|
31
|
+
textToHighlight="The quick brown fox jumps over the lazy dog"
|
|
32
|
+
searchWords={["fox", "dog"]}
|
|
33
|
+
/>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Case-sensitive matching
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<HighlightWords
|
|
40
|
+
textToHighlight="Hello World hello world"
|
|
41
|
+
searchWords={["Hello"]}
|
|
42
|
+
caseSensitive
|
|
43
|
+
/>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Custom highlight class
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<HighlightWords
|
|
50
|
+
textToHighlight="React is a JavaScript library for building user interfaces"
|
|
51
|
+
searchWords={["React", "JavaScript"]}
|
|
52
|
+
highlightClassName="bg-yellow-200 font-bold"
|
|
53
|
+
/>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Dependencies
|
|
57
|
+
|
|
58
|
+
- highlight-words-core
|
|
59
|
+
|
|
60
|
+
## See Also
|
|
61
|
+
|
|
62
|
+
- [Component Source](./index.ts)
|
|
63
|
+
- [Storybook Stories](./highlightwords.stories.tsx)
|
|
64
|
+
- [Main README](../../README.md)
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { jsx } from "@emotion/react/jsx-runtime";
|
|
2
2
|
import { Fragment } from "react";
|
|
3
3
|
import { findAll } from "highlight-words-core";
|
|
4
|
-
import { clsx } from "clsx";
|
|
5
4
|
const HighlightWords = ({ highlightClassName, ...props }) => {
|
|
6
5
|
const chunks = findAll(props);
|
|
7
6
|
return /* @__PURE__ */ jsx(Fragment, { children: chunks.map((chunk, index) => {
|
|
8
7
|
const { end, highlight, start } = chunk;
|
|
9
8
|
const text = props.textToHighlight.substring(start, end);
|
|
10
|
-
return /* @__PURE__ */ jsx(Fragment, { children: highlight ? /* @__PURE__ */ jsx("span", { css: { fontWeight: 500 }, className:
|
|
9
|
+
return /* @__PURE__ */ jsx(Fragment, { children: highlight ? /* @__PURE__ */ jsx("span", { css: { fontWeight: 500 }, className: highlightClassName, children: text }) : text }, index);
|
|
11
10
|
}) });
|
|
12
11
|
};
|
|
13
12
|
export {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Icon
|
|
2
|
+
|
|
3
|
+
A responsive SVG icon component that renders raw SVG strings via the SvgLoader component. Supports numeric size control with responsive breakpoint overrides (sm/md/lg) and the sx prop for custom styling.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Icon } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `source*` | `string` | - | Raw SVG string to render. Typically imported via Vite's ?raw query (e.g. import MyIcon from '@/assets/svg/my-icon.svg?raw'). |
|
|
16
|
+
| `size` | `number` | 24 | Width and height of the icon in pixels. Applied as the base (mobile-first) size. |
|
|
17
|
+
| `sm` | `{ size?: number }` | - | Responsive overrides applied at the sm breakpoint (≥768px). Accepts an object with the same responsive props. |
|
|
18
|
+
| `md` | `{ size?: number }` | - | Responsive overrides applied at the md breakpoint (≥1280px). Accepts an object with the same responsive props. |
|
|
19
|
+
| `lg` | `{ size?: number }` | - | Responsive overrides applied at the lg breakpoint (≥1680px). Accepts an object with the same responsive props. |
|
|
20
|
+
| `sx` | `ToResponsiveProps<StyledCSS>` | - | Escape hatch for custom Emotion CSS. Supports responsive keys (sm/md/lg) for breakpoint-scoped styles. |
|
|
21
|
+
| `...svgProps` | `JSX.IntrinsicElements['svg']` | - | All native SVG element attributes (e.g. className, style, aria-label, onClick) are forwarded to the underlying svg element. |
|
|
22
|
+
|
|
23
|
+
*Required props
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### Default icon at 24px
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import HomeIcon from '@/assets/svg/home.svg?raw';
|
|
31
|
+
|
|
32
|
+
<Icon source={HomeIcon} />
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Custom size with accessible label
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import StarIcon from '@/assets/svg/star.svg?raw';
|
|
39
|
+
|
|
40
|
+
<Icon source={StarIcon} size={32} aria-label="Favourite" />
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Responsive size across breakpoints
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import SearchIcon from '@/assets/svg/search.svg?raw';
|
|
47
|
+
|
|
48
|
+
<Icon
|
|
49
|
+
source={SearchIcon}
|
|
50
|
+
size={20}
|
|
51
|
+
sm={{ size: 20 }}
|
|
52
|
+
md={{ size: 24 }}
|
|
53
|
+
lg={{ size: 28 }}
|
|
54
|
+
/>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Related Components
|
|
58
|
+
|
|
59
|
+
- [SvgLoader](../svgloader/README.md)
|
|
60
|
+
|
|
61
|
+
## Dependencies
|
|
62
|
+
|
|
63
|
+
- @emotion/react
|
|
64
|
+
|
|
65
|
+
## See Also
|
|
66
|
+
|
|
67
|
+
- [Component Source](./index.ts)
|
|
68
|
+
- [Storybook Stories](./icon.stories.tsx)
|
|
69
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# IconButton
|
|
2
|
+
|
|
3
|
+
A button component that renders an icon (and optionally children) with support for contained, outlined, and text variants. Designed for icon-only or icon-with-label actions, with built-in loading state, ripple effect, and responsive sizing.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { IconButton } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `icon` | `IconProps` | - | Icon to render inside the button. Accepts an SVG raw string via `source` plus any Icon component props (size, sx, responsive breakpoints). |
|
|
16
|
+
| `variant` | `'contained' \| 'outlined' \| 'text'` | `'text'` | Visual style of the button. |
|
|
17
|
+
| `color` | `'primary' \| 'secondary' \| 'green' \| 'red' \| 'orange' \| 'blue' \| 'neutral'` | `'primary'` | Color variant that controls background, border, and icon color based on the design token palette. |
|
|
18
|
+
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | `'md'` | Controls the minimum width/height of the button and icon size. |
|
|
19
|
+
| `isLoading` | `boolean` | `false` | When true, hides the icon and shows a spinning loading indicator. Disables pointer events. |
|
|
20
|
+
| `sx` | `ToResponsiveProps<StyledCSS>` | - | Escape hatch for custom Emotion CSS styles, including responsive overrides at sm/md/lg breakpoints. |
|
|
21
|
+
| `sm` | `IconButtonResponsiveProps` | - | Responsive size override applied at the sm breakpoint (≥768px). |
|
|
22
|
+
| `md` | `IconButtonResponsiveProps` | - | Responsive size override applied at the md breakpoint (≥1280px). |
|
|
23
|
+
| `lg` | `IconButtonResponsiveProps` | - | Responsive size override applied at the lg breakpoint (≥1680px). |
|
|
24
|
+
| `disabled` | `boolean` | `false` | Native HTML disabled attribute. Disables pointer events and applies neutral disabled colors. |
|
|
25
|
+
| `aria-disabled` | `boolean \| 'true' \| 'false'` | - | Aria-disabled state. Applies disabled styling without removing the element from the tab order. |
|
|
26
|
+
| `children` | `React.ReactNode` | - | Optional content rendered alongside the icon (e.g. a label). |
|
|
27
|
+
| `onClick` | `React.MouseEventHandler<HTMLButtonElement>` | - | Click handler forwarded from native button props. |
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
### Text variant (default) with a star icon
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<IconButton icon={{ source: starSvg }} onClick={handleClick} />
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Contained primary button with loading state
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
<IconButton
|
|
41
|
+
icon={{ source: searchSvg }}
|
|
42
|
+
variant="contained"
|
|
43
|
+
color="primary"
|
|
44
|
+
isLoading={isFetching}
|
|
45
|
+
/>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Outlined small close button with aria-disabled
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<IconButton
|
|
52
|
+
icon={{ source: closeSvg }}
|
|
53
|
+
variant="outlined"
|
|
54
|
+
color="red"
|
|
55
|
+
size="sm"
|
|
56
|
+
aria-disabled={!canClose}
|
|
57
|
+
/>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Responsive size — nhỏ trên mobile, lớn hơn trên desktop
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
<IconButton
|
|
64
|
+
icon={{ source: filterSvg }}
|
|
65
|
+
variant="outlined"
|
|
66
|
+
size="sm"
|
|
67
|
+
md={{ size: 'md' }}
|
|
68
|
+
/>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Icon button với label
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
<IconButton icon={{ source: editSvg }} variant="text" color="primary">
|
|
75
|
+
Chỉnh sửa
|
|
76
|
+
</IconButton>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Related Components
|
|
80
|
+
|
|
81
|
+
- [Icon](../icon/README.md)
|
|
82
|
+
- [RippleEffect](../ripple-effect/README.md)
|
|
83
|
+
|
|
84
|
+
## Dependencies
|
|
85
|
+
|
|
86
|
+
- `@emotion/react`
|
|
87
|
+
|
|
88
|
+
## See Also
|
|
89
|
+
|
|
90
|
+
- [Component Source](./index.ts)
|
|
91
|
+
- [Storybook Stories](./icon-button.stories.tsx)
|
|
92
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Image
|
|
2
|
+
|
|
3
|
+
A polymorphic image component that wraps the native `<img>` element with built-in fallback support and sensible defaults. It automatically handles broken image sources by swapping in a fallback URL or a default placeholder, and applies `loading="lazy"` and `object-fit: cover` out of the box.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Image } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `src` | `string` | - | The URL of the image to display. If empty or undefined, the fallback source is used instead. |
|
|
16
|
+
| `alt` | `string` | "" | Alternative text for the image. Defaults to an empty string if not provided. |
|
|
17
|
+
| `fallback` | `string \| boolean` | true | Controls fallback behavior when the image fails to load. Pass `true` to use the built-in IMAGE_PLACEHOLDER constant, a string URL to use a custom fallback image, or `false` to disable fallback entirely. |
|
|
18
|
+
| `loading` | `"lazy" \| "eager"` | "lazy" | Native img loading attribute. Defaults to 'lazy' for performance. |
|
|
19
|
+
| `sx` | `ToResponsiveProps<StyledCSS>` | { objectFit: 'cover' } | Responsive style overrides via the Emotion sx prop. Base styles apply `objectFit: 'cover'` and `maxHeight: '100%'`. |
|
|
20
|
+
| `width` | `number \| string` | - | Native img width attribute. |
|
|
21
|
+
| `height` | `number \| string` | - | Native img height attribute. |
|
|
22
|
+
| `onError` | `React.ReactEventHandler<HTMLImageElement>` | - | Called after the fallback logic runs when the image fails to load. The component handles src replacement internally before invoking this callback. |
|
|
23
|
+
| `as` | `React.ElementType` | "img" | Polymorphic tag override inherited from Primitive. Defaults to 'img'. |
|
|
24
|
+
| `ref` | `React.Ref<HTMLImageElement>` | - | Forwarded ref to the underlying img element. |
|
|
25
|
+
|
|
26
|
+
## Examples
|
|
27
|
+
|
|
28
|
+
### Default usage
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<Image
|
|
32
|
+
src="https://via.placeholder.com/300x200"
|
|
33
|
+
alt="Placeholder image"
|
|
34
|
+
width={300}
|
|
35
|
+
height={200}
|
|
36
|
+
/>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Custom fallback URL on error
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
<Image
|
|
43
|
+
src="https://invalid-url.example.com/image.jpg"
|
|
44
|
+
alt="Image with fallback"
|
|
45
|
+
fallback="https://via.placeholder.com/300x200?text=Fallback"
|
|
46
|
+
width={300}
|
|
47
|
+
height={200}
|
|
48
|
+
/>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Built-in placeholder fallback with responsive sx
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
<Image
|
|
55
|
+
src="https://cdn.example.com/product.jpg"
|
|
56
|
+
alt="Product thumbnail"
|
|
57
|
+
fallback={true}
|
|
58
|
+
width={120}
|
|
59
|
+
height={120}
|
|
60
|
+
sx={{
|
|
61
|
+
borderRadius: 8,
|
|
62
|
+
objectFit: 'contain',
|
|
63
|
+
md: { width: 160, height: 160 },
|
|
64
|
+
}}
|
|
65
|
+
/>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Related Components
|
|
69
|
+
|
|
70
|
+
- [Primitive](../primitive/README.md)
|
|
71
|
+
|
|
72
|
+
## Dependencies
|
|
73
|
+
|
|
74
|
+
- lodash-es
|
|
75
|
+
|
|
76
|
+
## See Also
|
|
77
|
+
|
|
78
|
+
- [Component Source](./index.ts)
|
|
79
|
+
- [Storybook Stories](./image.stories.tsx)
|
|
80
|
+
- [Main README](../../README.md)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Input
|
|
2
|
+
|
|
3
|
+
A flexible text input component with support for prefix/suffix slots, start/end icons, password visibility toggle, error state, helper text, debounced onChange, and responsive sizing. Designed for form fields across all sizes of the design system.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Input } from '@janbox/storefront-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `size` | `SizeVariant ('xs' \| 'sm' \| 'md' \| 'lg')` | `md` | Controls height, padding, and font size of the input via the size variant scale. |
|
|
16
|
+
| `sm` | `InputResponsiveProps ({ size?: SizeVariant })` | - | Responsive overrides applied at the sm breakpoint (≥768px). |
|
|
17
|
+
| `md` | `InputResponsiveProps ({ size?: SizeVariant })` | - | Responsive overrides applied at the md breakpoint (≥1280px). |
|
|
18
|
+
| `lg` | `InputResponsiveProps ({ size?: SizeVariant })` | - | Responsive overrides applied at the lg breakpoint (≥1680px). |
|
|
19
|
+
| `sx` | `ToResponsiveProps<StyledCSS>` | - | Escape-hatch for custom Emotion CSS styles, passed to the container element. |
|
|
20
|
+
| `error` | `boolean` | `false` | Puts the input into an error state, showing a red border and applying error styling to the helper text. |
|
|
21
|
+
| `helperText` | `string` | - | Descriptive or validation text rendered below the input via FormHelperText. Color changes when `error` is `true`. |
|
|
22
|
+
| `prefix` | `React.ReactNode` | - | Arbitrary node rendered at the far-left of the input wrapper, outside the icon slots (e.g. a country code badge). |
|
|
23
|
+
| `suffix` | `React.ReactNode` | - | Arbitrary node rendered at the far-right of the input wrapper, outside the icon slots. |
|
|
24
|
+
| `startIcon` | `IconProps` | - | Icon displayed on the left side of the input field, inside the wrapper. Size tracks the current size variant automatically. |
|
|
25
|
+
| `endIcon` | `IconProps` | - | Icon displayed on the right side of the input field, inside the wrapper. Size tracks the current size variant automatically. |
|
|
26
|
+
| `containerProps` | `PrimitiveProps<JSX.IntrinsicElements['div']>` | - | Props forwarded to the outermost wrapper div (position: relative, flex column container). |
|
|
27
|
+
| `mainProps` | `PrimitiveProps<JSX.IntrinsicElements['div']>` | - | Props forwarded to the inner wrapper div that renders the border, background, and layout for the input row. |
|
|
28
|
+
| `value` | `string` | - | Controlled value of the input. When provided alongside `debounce` or `mode='onBlur'`, the component buffers the typing value internally. |
|
|
29
|
+
| `defaultValue` | `string` | - | Uncontrolled default value for the input. |
|
|
30
|
+
| `transform` | `(value: string) => string` | - | Optional function applied to the raw input value on every change event before propagating it (e.g. uppercase, numeric-only filter). |
|
|
31
|
+
| `mode` | `'onChange' \| 'onBlur'` | `onChange` | Determines when `onChange` fires. `'onBlur'` defers the call until the user leaves the field; `'onChange'` fires on every keystroke (subject to `debounce`). |
|
|
32
|
+
| `debounce` | `number` | `0` | Milliseconds to debounce the `onChange` callback. Set to `0` to disable debouncing. |
|
|
33
|
+
| `type` | `string (HTML input type)` | - | Standard HTML input type. When set to `'password'`, a visibility toggle icon is automatically appended. |
|
|
34
|
+
| `disabled` | `boolean` | - | Disables the input and applies a neutral muted style to the wrapper via CSS `:has` selector. |
|
|
35
|
+
| `placeholder` | `string` | - | Placeholder text shown when the input is empty. |
|
|
36
|
+
| `onChange` | `React.ChangeEventHandler<HTMLInputElement>` | - | Change handler. May be deferred depending on `mode` and `debounce` settings. |
|
|
37
|
+
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
### Default input with placeholder
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
<Input placeholder="Enter text..." onChange={handleChange} />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Error state with helper text
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<Input
|
|
50
|
+
placeholder="Enter email..."
|
|
51
|
+
error={true}
|
|
52
|
+
helperText="Invalid email address"
|
|
53
|
+
onChange={handleChange}
|
|
54
|
+
/>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Password input with debounced onChange
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
<Input
|
|
61
|
+
type="password"
|
|
62
|
+
placeholder="Enter password..."
|
|
63
|
+
mode="onChange"
|
|
64
|
+
debounce={300}
|
|
65
|
+
value={password}
|
|
66
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
67
|
+
/>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Input với icon và prefix/suffix
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<Input
|
|
74
|
+
placeholder="Tìm kiếm..."
|
|
75
|
+
startIcon={{ source: SearchIcon }}
|
|
76
|
+
suffix={<span>VND</span>}
|
|
77
|
+
size="lg"
|
|
78
|
+
/>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Responsive sizing
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
<Input
|
|
85
|
+
size="sm"
|
|
86
|
+
sm={{ size: 'md' }}
|
|
87
|
+
md={{ size: 'lg' }}
|
|
88
|
+
placeholder="Responsive input"
|
|
89
|
+
/>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### onBlur mode với transform
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
<Input
|
|
96
|
+
mode="onBlur"
|
|
97
|
+
transform={(val) => val.toUpperCase()}
|
|
98
|
+
placeholder="Uppercase on blur"
|
|
99
|
+
onChange={(e) => console.log(e.target.value)}
|
|
100
|
+
/>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Related Components
|
|
104
|
+
|
|
105
|
+
- [Icon](../icon/README.md)
|
|
106
|
+
- [FormHelperText](../formhelpertext/README.md)
|
|
107
|
+
- [Primitive](../primitive/README.md)
|
|
108
|
+
|
|
109
|
+
## Dependencies
|
|
110
|
+
|
|
111
|
+
- `@floating-ui/react`
|
|
112
|
+
- `lodash-es`
|
|
113
|
+
|
|
114
|
+
## See Also
|
|
115
|
+
|
|
116
|
+
- [Component Source](./index.ts)
|
|
117
|
+
- [Storybook Stories](./input.stories.tsx)
|
|
118
|
+
- [Main README](../../README.md)
|