@janbox/storefront-ui 6.0.7 → 6.0.8

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 CHANGED
@@ -519,7 +519,6 @@ Mọi component đều có README riêng với API reference, examples, và usag
519
519
  - [Marquee](./dist/lib/marquee/README.md)
520
520
  - [Menu](./dist/lib/menu/README.md)
521
521
  - [MultipleSelect](./dist/lib/multiple-select/README.md)
522
- - [NavLink](./dist/lib/nav-link/README.md)
523
522
  - [Notifications](./dist/lib/notifications/README.md)
524
523
  - [OtpInput](./dist/lib/otp-input/README.md)
525
524
  - [Pagination](./dist/lib/pagination/README.md)
@@ -1,4 +1,5 @@
1
- const MinusIcon = '<svg fill="currentColor" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19,13H5a1,1,0,0,1,0-2H19a1,1,0,0,1,0,2Z"></path></svg>';
1
+ import * as React from "react";
2
+ const SvgMinus = (props) => /* @__PURE__ */ React.createElement("svg", { fill: "currentColor", width: 24, height: 24, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M19,13H5a1,1,0,0,1,0-2H19a1,1,0,0,1,0,2Z" }));
2
3
  export {
3
- MinusIcon as default
4
+ SvgMinus as default
4
5
  };
@@ -1,5 +1,4 @@
1
- import * as React from "react";
2
- const SvgMinus = (props) => /* @__PURE__ */ React.createElement("svg", { fill: "currentColor", width: 24, height: 24, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", ...props }, /* @__PURE__ */ React.createElement("path", { d: "M19,13H5a1,1,0,0,1,0-2H19a1,1,0,0,1,0,2Z" }));
1
+ const MinusIcon = '<svg fill="currentColor" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19,13H5a1,1,0,0,1,0-2H19a1,1,0,0,1,0,2Z"></path></svg>';
3
2
  export {
4
- SvgMinus as default
3
+ MinusIcon as default
5
4
  };
package/dist/index.js CHANGED
@@ -64,7 +64,6 @@ import { MenuList } from "./lib/menu/menu-list/menu-list.js";
64
64
  import { MenuListDataAttributes } from "./lib/menu/menu-list/types.js";
65
65
  import { MenuTrigger } from "./lib/menu/menu-trigger/menu-trigger.js";
66
66
  import { MultipleSelect } from "./lib/multiple-select/multiple-select.js";
67
- import { NavLink } from "./lib/nav-link/nav-link.js";
68
67
  import { Notifications } from "./lib/notifications/notifications.js";
69
68
  import { OtpInput } from "./lib/otp-input/otp-input.js";
70
69
  import { Pagination } from "./lib/pagination/pagination.js";
@@ -112,6 +111,8 @@ import { getAccordionContentProps } from "./lib/accordion/accordion-content/help
112
111
  import { getAccordionSummaryProps } from "./lib/accordion/accordion-summary/helpers.js";
113
112
  import { getBadgeProps } from "./lib/badge/helpers.js";
114
113
  import { getBoxProps } from "./lib/box/helpers.js";
114
+ import { getBreadcrumbItemProps } from "./lib/breadcrumbs/breadcrumb-item/helpers.js";
115
+ import { getBreadcrumbsProps } from "./lib/breadcrumbs/breadcrumbs/helpers.js";
115
116
  import { getButtonCssBySize, getButtonProps } from "./lib/button/helpers.js";
116
117
  import { getCellProps } from "./lib/grid/cell/helpers.js";
117
118
  import { getChipProps, getChipSizeState } from "./lib/chip/helpers.js";
@@ -214,7 +215,6 @@ export {
214
215
  MenuListDataAttributes,
215
216
  MenuTrigger,
216
217
  MultipleSelect,
217
- NavLink,
218
218
  Notifications,
219
219
  OtpInput,
220
220
  Pagination,
@@ -266,6 +266,8 @@ export {
266
266
  getAccordionSummaryProps,
267
267
  getBadgeProps,
268
268
  getBoxProps,
269
+ getBreadcrumbItemProps,
270
+ getBreadcrumbsProps,
269
271
  getButtonCssBySize,
270
272
  getButtonProps,
271
273
  getCellProps,
@@ -1,11 +1,11 @@
1
1
  # Breadcrumbs
2
2
 
3
- A navigation aid component that displays a hierarchy of links showing the user's current location within the app. It renders BreadcrumbItem children separated by a configurable separator and supports color theming for hover states.
3
+ A navigation aid component that displays a hierarchy of links showing the user's current location within the app. It renders `<nav><ol>` with `BreadcrumbItem` children (`<li>`) separated by a configurable separator, and supports color theming for link hover states.
4
4
 
5
5
  ## Import
6
6
 
7
7
  ```tsx
8
- import { Breadcrumbs } from '@janbox/storefront-ui';
8
+ import { Breadcrumbs, BreadcrumbItem } from '@janbox/storefront-ui';
9
9
  ```
10
10
 
11
11
  ## Props
@@ -13,12 +13,22 @@ import { Breadcrumbs } from '@janbox/storefront-ui';
13
13
  | Prop | Type | Default | Description |
14
14
  |------|------|---------|-------------|
15
15
  | `separator` | `string \| IconProps` | `'>'` | The separator rendered between each breadcrumb item. Can be a plain string (e.g. `'>'` or `'/'`) or an IconProps object to render an icon. |
16
- | `color` | `ColorScale` | `'primary'` | Controls the hover color of breadcrumb items. Accepts any ColorScale: `'primary' \| 'secondary' \| 'green' \| 'red' \| 'orange' \| 'blue' \| 'neutral'`. |
17
- | `children` | `React.ReactNode` | - | BreadcrumbItem elements to render as the navigation trail. Flattened automatically to support wrapping in Fragments. |
18
- | `BreadcrumbItem.to` | `ReactRouterLinkProps['to']` | - | (BreadcrumbItem prop) The route target passed to react-router Link. |
19
- | `BreadcrumbItem.icon` | `IconProps` | - | (BreadcrumbItem prop) An optional icon rendered before the item label. |
20
- | `BreadcrumbItem.underline` | `boolean` | - | (BreadcrumbItem prop, inherited from Link) Whether to show an underline on the link. |
21
- | `BreadcrumbItem.textVariant` | `TypographySizeVariant` | - | (BreadcrumbItem prop, inherited from Link) Typography size variant for the link text. |
16
+ | `color` | `ColorScale` | `'primary'` | Controls the hover color of links (`<a>`) inside breadcrumb items. Accepts any ColorScale: `'primary' \| 'secondary' \| 'green' \| 'red' \| 'orange' \| 'blue' \| 'neutral'`. |
17
+ | `children` | `React.ReactNode` | - | `BreadcrumbItem` elements to render as the navigation trail. Flattened automatically to support wrapping in Fragments. |
18
+ | `spaceBetween` | `number` | `8` | Gap (px) between items and separators. Responsive via `sm` / `md` / `lg` (e.g. `md={{ spaceBetween: 16 }}`). Takes precedence over `sx.gap`. |
19
+ | `sm` / `md` / `lg` | `{ spaceBetween?: number }` | - | Responsive overrides applied from that breakpoint up. |
20
+
21
+ ### BreadcrumbItem
22
+
23
+ `BreadcrumbItem` renders a plain `<li>` (via `Primitive`) and accepts all `<li>` attributes plus `sx`. Its content is free-form: put an `<a>` (or any link component, e.g. `Link`) inside for navigable items, or plain text for the current page.
24
+
25
+ | Prop | Type | Default | Description |
26
+ |------|------|---------|-------------|
27
+ | `children` | `React.ReactNode` | - | Item content, typically an `<a>` or plain text. |
28
+ | `sx` | `ToResponsiveProps<StyledCSS>` | - | Style overrides for the `<li>`. Base style: `display: flex; align-items: center; gap: 6px`. |
29
+ | `ref` | `Ref<HTMLLIElement>` | - | Ref to the `<li>` element. |
30
+
31
+ > ⚠️ **Breaking change**: `BreadcrumbItem` no longer renders a `Link` and no longer accepts `to`, `icon`, `underline`, or `textVariant`. Put an `<a>` (or `Link`) inside instead (see examples below).
22
32
 
23
33
  ## Examples
24
34
 
@@ -26,9 +36,13 @@ import { Breadcrumbs } from '@janbox/storefront-ui';
26
36
 
27
37
  ```tsx
28
38
  <Breadcrumbs>
29
- <BreadcrumbItem to="/">Home</BreadcrumbItem>
30
- <BreadcrumbItem to="/products">Products</BreadcrumbItem>
31
- <BreadcrumbItem to="/products/detail">Detail</BreadcrumbItem>
39
+ <BreadcrumbItem>
40
+ <a href="/">Home</a>
41
+ </BreadcrumbItem>
42
+ <BreadcrumbItem>
43
+ <a href="/products">Products</a>
44
+ </BreadcrumbItem>
45
+ <BreadcrumbItem aria-current="page">Detail</BreadcrumbItem>
32
46
  </Breadcrumbs>
33
47
  ```
34
48
 
@@ -36,31 +50,76 @@ import { Breadcrumbs } from '@janbox/storefront-ui';
36
50
 
37
51
  ```tsx
38
52
  <Breadcrumbs separator="/">
39
- <BreadcrumbItem to="/">Home</BreadcrumbItem>
40
- <BreadcrumbItem to="/products">Products</BreadcrumbItem>
41
- <BreadcrumbItem to="/products/detail">Detail</BreadcrumbItem>
53
+ <BreadcrumbItem>
54
+ <a href="/">Home</a>
55
+ </BreadcrumbItem>
56
+ <BreadcrumbItem>
57
+ <a href="/products">Products</a>
58
+ </BreadcrumbItem>
59
+ <BreadcrumbItem aria-current="page">Detail</BreadcrumbItem>
42
60
  </Breadcrumbs>
43
61
  ```
44
62
 
45
63
  ### WithColor
46
64
 
47
65
  ```tsx
48
- <Breadcrumbs color="primary">
49
- <BreadcrumbItem to="/">Home</BreadcrumbItem>
50
- <BreadcrumbItem to="/products">Products</BreadcrumbItem>
51
- <BreadcrumbItem to="/products/detail">Detail</BreadcrumbItem>
66
+ <Breadcrumbs color="red">
67
+ <BreadcrumbItem>
68
+ <a href="/">Home</a>
69
+ </BreadcrumbItem>
70
+ <BreadcrumbItem>
71
+ <a href="/products">Products</a>
72
+ </BreadcrumbItem>
73
+ <BreadcrumbItem aria-current="page">Detail</BreadcrumbItem>
74
+ </Breadcrumbs>
75
+ ```
76
+
77
+ ### WithSpaceBetween
78
+
79
+ ```tsx
80
+ <Breadcrumbs spaceBetween={4} md={{ spaceBetween: 16 }}>
81
+ <BreadcrumbItem>
82
+ <a href="/">Home</a>
83
+ </BreadcrumbItem>
84
+ <BreadcrumbItem>
85
+ <a href="/products">Products</a>
86
+ </BreadcrumbItem>
87
+ <BreadcrumbItem aria-current="page">Detail</BreadcrumbItem>
88
+ </Breadcrumbs>
89
+ ```
90
+
91
+ ### WithIcon
92
+
93
+ ```tsx
94
+ import HomeIcon from '@/assets/svg/earth-home-world.svg?raw';
95
+
96
+ <Breadcrumbs>
97
+ <BreadcrumbItem>
98
+ <a href="/" style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
99
+ <Icon source={HomeIcon} size={20} />
100
+ Home
101
+ </a>
102
+ </BreadcrumbItem>
103
+ <BreadcrumbItem>
104
+ <a href="/products">Products</a>
105
+ </BreadcrumbItem>
106
+ <BreadcrumbItem aria-current="page">Detail</BreadcrumbItem>
52
107
  </Breadcrumbs>
53
108
  ```
54
109
 
110
+ ## Accessibility
111
+
112
+ - Renders `<nav>` → `<ol>` → `<li>`. Pass `aria-label="Breadcrumb"` to `Breadcrumbs` to label the landmark.
113
+ - Separators are rendered as `<li aria-hidden="true">`, so screen readers skip them.
114
+ - Mark the current page with `aria-current="page"` (on the `BreadcrumbItem` or on its inner `<a>`).
115
+
55
116
  ## Related Components
56
117
 
57
- - [Link](../link/README.md)
58
118
  - [Icon](../icon/README.md)
59
119
 
60
120
  ## Dependencies
61
121
 
62
122
  - lodash-es
63
- - react-router
64
123
  - @emotion/react
65
124
 
66
125
  ## See Also
@@ -1,2 +1,2 @@
1
1
  import { BreadcrumbItemProps } from './types';
2
- export declare const BreadcrumbItem: ({ children, icon, ...props }: BreadcrumbItemProps) => import("react").JSX.Element;
2
+ export declare const BreadcrumbItem: ({ ref, children, ..._props }: BreadcrumbItemProps) => import("react").JSX.Element;
@@ -1,11 +1,9 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
2
- import { Link } from "../../link/link.js";
3
- import { Icon } from "../../icon/icon.js";
4
- const BreadcrumbItem = ({ children, icon, ...props }) => {
5
- return /* @__PURE__ */ jsxs(Link, { ...props, sx: { display: "flex", width: "fit-content", alignItems: "center", gap: 6, ...props.sx }, children: [
6
- icon && /* @__PURE__ */ jsx(Icon, { ...icon }),
7
- children
8
- ] });
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { getBreadcrumbItemProps } from "./helpers.js";
3
+ import { Primitive } from "../../primitive/primitive.js";
4
+ const BreadcrumbItem = ({ ref, children, ..._props }) => {
5
+ const props = getBreadcrumbItemProps(_props);
6
+ return /* @__PURE__ */ jsx(Primitive, { ...props, ref, as: "li", children });
9
7
  };
10
8
  export {
11
9
  BreadcrumbItem
@@ -0,0 +1,2 @@
1
+ import { BreadcrumbItemProps } from './types';
2
+ export declare const getBreadcrumbItemProps: (extended: BreadcrumbItemProps) => BreadcrumbItemProps;
@@ -0,0 +1,14 @@
1
+ import { mergeComponentProps } from "../../../utils/index.js";
2
+ const defaultProps = {
3
+ sx: {
4
+ display: "flex",
5
+ alignItems: "center",
6
+ gap: 6
7
+ }
8
+ };
9
+ const getBreadcrumbItemProps = (extended) => {
10
+ return mergeComponentProps(defaultProps, extended);
11
+ };
12
+ export {
13
+ getBreadcrumbItemProps
14
+ };
@@ -1,2 +1,3 @@
1
1
  export * from './breadcrumb-item';
2
2
  export * from './types';
3
+ export * from './helpers';
@@ -1,6 +1,3 @@
1
- import { IconProps } from '../../icon';
2
- import { LinkProps } from '../../link';
3
- import { ShallowMerge } from '../../../types';
4
- export type BreadcrumbItemProps = ShallowMerge<LinkProps, {
5
- icon?: IconProps;
6
- }>;
1
+ import { JSX } from 'react';
2
+ import { PrimitiveProps } from '../../primitive';
3
+ export type BreadcrumbItemProps = PrimitiveProps<JSX.IntrinsicElements['li']>;
@@ -1,2 +1,2 @@
1
1
  import { BreadcrumbsProps } from './types';
2
- export declare const Breadcrumbs: ({ separator, children, color, ...props }: BreadcrumbsProps) => import("react").JSX.Element;
2
+ export declare const Breadcrumbs: ({ separator, children, color, ..._props }: BreadcrumbsProps) => import("react").JSX.Element;
@@ -1,32 +1,45 @@
1
- import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Fragment } from "react";
3
- import { isString } from "lodash-es";
3
+ import { isString, isNumber } from "lodash-es";
4
+ import { getBreadcrumbsProps } from "./helpers.js";
4
5
  import { flattenChildren, getColorShadesByVariant } from "../../../utils/index.js";
5
6
  import { getColorVar } from "../../../theme/palette.js";
6
7
  import { Primitive } from "../../primitive/primitive.js";
7
8
  import { Icon } from "../../icon/icon.js";
8
- const Breadcrumbs = ({ separator = ">", children, color = "primary", ...props }) => {
9
+ const Breadcrumbs = ({ separator = ">", children, color = "primary", ..._props }) => {
10
+ var _a, _b, _c;
11
+ const { spaceBetween, sm, md, lg, ...props } = getBreadcrumbsProps(_props);
9
12
  const flattenedChildren = flattenChildren(children);
10
13
  const { main } = getColorShadesByVariant(color);
11
- return /* @__PURE__ */ jsx(Primitive, { ...props, sx: { display: "inline-flex", flexWrap: "wrap", gap: 8, ...props.sx }, children: flattenedChildren.map((child, index, array) => {
12
- const isLast = index === array.length - 1;
13
- return /* @__PURE__ */ jsxs(Fragment, { children: [
14
- /* @__PURE__ */ jsx(
15
- Primitive,
16
- {
17
- sx: {
18
- display: "contents",
19
- color: getColorVar("neutral.500"),
20
- ":hover": {
21
- color: main
22
- }
23
- },
24
- children: child
25
- }
26
- ),
27
- !isLast && /* @__PURE__ */ jsx(Fragment$1, { children: isString(separator) ? /* @__PURE__ */ jsx(Primitive, { as: "span", sx: { color: getColorVar("neutral.500") }, children: separator }) : /* @__PURE__ */ jsx(Icon, { ...separator }) })
28
- ] }, index);
29
- }) });
14
+ return /* @__PURE__ */ jsx(Primitive, { as: "nav", ...props, children: /* @__PURE__ */ jsx(
15
+ Primitive,
16
+ {
17
+ sx: {
18
+ display: "flex",
19
+ flexWrap: "wrap",
20
+ color: getColorVar("neutral.500"),
21
+ "& a:hover": {
22
+ color: main
23
+ },
24
+ ...props.sx,
25
+ ...createStyle({ spaceBetween }),
26
+ sm: { ...(_a = props.sx) == null ? void 0 : _a.sm, ...createStyle(sm) },
27
+ md: { ...(_b = props.sx) == null ? void 0 : _b.md, ...createStyle(md) },
28
+ lg: { ...(_c = props.sx) == null ? void 0 : _c.lg, ...createStyle(lg) }
29
+ },
30
+ as: "ol",
31
+ children: flattenedChildren.map((child, index, array) => {
32
+ const isLast = index === array.length - 1;
33
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
34
+ child,
35
+ !isLast && /* @__PURE__ */ jsx(Primitive, { as: "li", "aria-hidden": true, sx: { display: "flex", alignItems: "center" }, children: isString(separator) ? separator : /* @__PURE__ */ jsx(Icon, { ...separator }) })
36
+ ] }, index);
37
+ })
38
+ }
39
+ ) });
40
+ };
41
+ const createStyle = ({ spaceBetween } = {}) => {
42
+ return isNumber(spaceBetween) ? { gap: spaceBetween } : {};
30
43
  };
31
44
  export {
32
45
  Breadcrumbs
@@ -0,0 +1,2 @@
1
+ import { BreadcrumbsProps } from './types';
2
+ export declare const getBreadcrumbsProps: (extended: BreadcrumbsProps) => BreadcrumbsProps;
@@ -0,0 +1,10 @@
1
+ import { mergeComponentProps } from "../../../utils/index.js";
2
+ const defaultProps = {
3
+ spaceBetween: 8
4
+ };
5
+ const getBreadcrumbsProps = (extended) => {
6
+ return mergeComponentProps(defaultProps, extended);
7
+ };
8
+ export {
9
+ getBreadcrumbsProps
10
+ };
@@ -1 +1,3 @@
1
1
  export * from './breadcrumbs';
2
+ export * from './types';
3
+ export * from './helpers';
@@ -1,11 +1,14 @@
1
1
  import { JSX } from 'react';
2
2
  import { IconProps } from '../../icon';
3
3
  import { ColorScale } from '../../../theme';
4
- import { ShallowMerge } from '../../../types';
4
+ import { ShallowMerge, ToResponsiveProps } from '../../../types';
5
5
  import { PrimitiveProps } from '../../primitive';
6
6
  type BreadcrumbsSeparator = string | IconProps;
7
- export type BreadcrumbsProps = PrimitiveProps<ShallowMerge<JSX.IntrinsicElements['div'], {
7
+ export type BreadcrumbsResponsiveProps = {
8
+ spaceBetween?: number;
9
+ };
10
+ export type BreadcrumbsProps = PrimitiveProps<ShallowMerge<JSX.IntrinsicElements['nav'], {
8
11
  separator?: BreadcrumbsSeparator;
9
12
  color?: ColorScale;
10
- }>, 'div'>;
13
+ } & ToResponsiveProps<BreadcrumbsResponsiveProps>>, 'nav'>;
11
14
  export {};
@@ -2,7 +2,7 @@ import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { useRef, useEffect } from "react";
3
3
  import { useMergeRefs } from "@floating-ui/react";
4
4
  import SvgDoneCheck from "../../assets/svg/done-check.svg.js";
5
- import SvgMinus from "../../assets/svg/minus2.svg.js";
5
+ import SvgMinus from "../../assets/svg/minus.svg.js";
6
6
  import { getColorShadesByVariant } from "../../utils/index.js";
7
7
  import "lodash-es";
8
8
  import { getColorVar } from "../../theme/palette.js";
@@ -31,7 +31,6 @@ export * from './dialog';
31
31
  export * from './loading';
32
32
  export * from './link';
33
33
  export * from './count-up';
34
- export * from './nav-link';
35
34
  export * from './breadcrumbs';
36
35
  export * from './phone-input';
37
36
  export * from './form-helper-text';
@@ -4,7 +4,7 @@ import { useMergeRefs } from "@floating-ui/react";
4
4
  import { isNil } from "lodash-es";
5
5
  import { Input } from "../input/input.js";
6
6
  import { useControllableState } from "../../hooks/use-controllable-state.js";
7
- import MinusIcon from "../../assets/svg/minus.svg.js";
7
+ import MinusIcon from "../../assets/svg/minus2.svg.js";
8
8
  import PlusIcon from "../../assets/svg/plus.svg.js";
9
9
  import { IconButton } from "../icon-button/icon-button.js";
10
10
  const MAX_FRACTION_DIGITS = 10;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@janbox/storefront-ui",
3
- "version": "6.0.7",
3
+ "version": "6.0.8",
4
4
  "description": "Storefront UI component library for Janbox",
5
5
  "author": "Janbox",
6
6
  "keywords": [
@@ -1,61 +0,0 @@
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)
@@ -1,2 +0,0 @@
1
- export * from './nav-link';
2
- export * from './types';
@@ -1,2 +0,0 @@
1
- import { NavLinkProps } from './types';
2
- export declare const NavLink: ({ children, style, className, to, ref, ...props }: NavLinkProps) => import("react").JSX.Element;
@@ -1,37 +0,0 @@
1
- import { jsx, Fragment } from "react/jsx-runtime";
2
- import { isFunction, isNil } from "lodash-es";
3
- import { NavLink as NavLink$1 } from "react-router";
4
- import { Booleanish } from "../../constants/index.js";
5
- const NavLink = ({ children, style, className, to, ref, ...props }) => {
6
- const styleFn = (renderProps) => {
7
- return isFunction(style) ? style({
8
- ...renderProps,
9
- isActive: renderProps.isActive && !isNil(to)
10
- }) : style;
11
- };
12
- const classNameFn = (renderProps) => {
13
- return isFunction(className) ? className({
14
- ...renderProps,
15
- isActive: renderProps.isActive && !isNil(to)
16
- }) : className;
17
- };
18
- const onClick = (e) => {
19
- var _a;
20
- if (e.currentTarget.getAttribute("aria-disabled") === Booleanish.True) {
21
- e.preventDefault();
22
- }
23
- if (isNil(to)) {
24
- e.preventDefault();
25
- }
26
- (_a = props.onClick) == null ? void 0 : _a.call(props, e);
27
- };
28
- return /* @__PURE__ */ jsx(NavLink$1, { ...props, style: styleFn, className: classNameFn, to: to ?? "#", ref, onClick, children: (renderProps) => {
29
- return /* @__PURE__ */ jsx(Fragment, { children: isFunction(children) ? children({
30
- ...renderProps,
31
- isActive: renderProps.isActive && !isNil(to)
32
- }) : children });
33
- } });
34
- };
35
- export {
36
- NavLink
37
- };
@@ -1,7 +0,0 @@
1
- import { NavLinkProps as ReactRouterNavLinkProps } from 'react-router';
2
- import { ShallowMerge } from '../../types';
3
- import { Ref } from 'react';
4
- export type NavLinkProps = ShallowMerge<ReactRouterNavLinkProps, {
5
- to?: ReactRouterNavLinkProps['to'];
6
- ref?: Ref<HTMLAnchorElement>;
7
- }>;