# LinkNode

Anchor node render ra `<a>` qua component Link do consumer cấp (`nodeResources.link.component`), mặc định là thẻ `<a>`. Là canvas node — có thể chứa text hoặc các node con khác làm nội dung link.

## Resolved name

`link`

## Configurable props

### Top-level props

| Prop | Type | Description |
| --- | --- | --- |
| `href` | `string` | Đường dẫn điều hướng |
| `target` | `'_self' \| '_blank' \| '_parent' \| '_top'` | Cách mở link |
| `rel` | `string` | SEO attribute, ví dụ `'nofollow noreferrer'` |

### `sx` props

```ts
sx?: {
  // typography — inspector chỉ ghi các key này ở xs
  color?: string
  fontStyle?: 'normal' | 'italic'
  fontWeight?: number | string
  textDecorationLine?: 'none' | 'underline' | 'line-through'
  textAlign?: 'left' | 'center' | 'right' | 'justify'
  textTransform?: 'none' | 'uppercase' | 'lowercase' | 'capitalize'

  // typography từ preset — responsive (sx.sm/md/lg)
  fontSize?: number | string // chọn qua preset trong inspector
  lineHeight?: number | string // chọn qua preset trong inspector

  // spacing
  paddingTop?: number
  paddingRight?: number
  paddingBottom?: number
  paddingLeft?: number
  marginTop?: number
  marginRight?: number
  marginBottom?: number
  marginLeft?: number

  // border
  borderStyle?: string
  borderColor?: string
  borderTopWidth?: number
  borderRightWidth?: number
  borderBottomWidth?: number
  borderLeftWidth?: number
  borderTopLeftRadius?: number | string
  borderTopRightRadius?: number | string
  borderBottomRightRadius?: number | string
  borderBottomLeftRadius?: number | string

  // responsive overrides
  sm?: { /* same keys above */ }
  md?: { /* same keys above */ }
  lg?: { /* same keys above */ }
}
```

## Usage

```tsx
import { LinkNode } from '@janbox/storefront-builder';

// Link đơn giản
<LinkNode href="/products">View all products</LinkNode>

// Mở tab mới, no-follow
<LinkNode href="https://example.com" target="_blank" rel="nofollow noreferrer">
  External link
</LinkNode>

// Link dạng button (có border, padding)
<LinkNode
  href="/checkout"
  sx={{
    paddingTop: 12,
    paddingBottom: 12,
    paddingLeft: 24,
    paddingRight: 24,
    borderTopLeftRadius: 6,
    borderTopRightRadius: 6,
    borderBottomLeftRadius: 6,
    borderBottomRightRadius: 6,
    backgroundColor: '#fa8c16',
    color: '#ffffff',
  }}
>
  Checkout
</LinkNode>

// Cỡ chữ responsive
<LinkNode
  href="/sale"
  sx={{
    fontSize: 'var(--text-sm--font-size)',
    lineHeight: 'var(--text-sm--line-height)',
    md: {
      fontSize: 'var(--text-base--font-size)',
      lineHeight: 'var(--text-base--line-height)',
    },
  }}
>
  Sale items
</LinkNode>
```

## Link component

Consumer cấp component render link qua `nodeResources`. Không cấp thì `LinkNode` render thẻ `<a>`.

```ts
type LinkComponentProps = ComponentPropsWithRef<'a'>; // props native của <a>, href optional
type LinkComponent = ComponentType<LinkComponentProps>;
```

Yêu cầu với component được inject:

- Forward `ref` tới thẻ `<a>`. Nếu không, node không chọn hay kéo được trong editor.
- Truyền tiếp `className`, `onClick`, các thuộc tính `data-*` và `contentEditable` xuống thẻ `<a>`.

```tsx
import { Link } from 'react-router';
import NextLink from 'next/link';
import type { LinkComponentProps } from '@janbox/storefront-builder';

// React Router
const AppLink = ({ href, ...props }: LinkComponentProps) =>
  href ? <Link {...props} to={href} /> : <a {...props} />;

// Next.js
const AppLink = ({ href, ...props }: LinkComponentProps) =>
  href ? <NextLink {...props} href={href} /> : <a {...props} />;

<Composer nodeResources={{ link: { component: AppLink } }}>…</Composer>
```

> `next/link` prefetch các link thấy được trên màn hình, kể cả trong canvas editor. Muốn tắt thì truyền `prefetch={false}` trong adapter.

## Nâng cấp từ 4.x

| 4.x | 5.0.0 |
| --- | --- |
| `to` | `href` |
| `textVariant: 'X'` | `sx.fontSize: 'var(--text-X--font-size)'` + `sx.lineHeight: 'var(--text-X--line-height)'` |
| `underline: true` | `sx.textDecorationLine: 'underline'` |
| `sm`/`md`/`lg` cấp trên cùng | `sx.sm`/`sx.md`/`sx.lg` |
| (không có) | Inject `nodeResources.link.component`, mặc định `<a>` |

Thứ tự: thêm key mới trước, chỉ xoá `to` / `textVariant` / `underline` sau khi mọi nơi render đã chạy 5.0.0.

## Rules

- **Canvas**: yes — chứa node con.
- **canMoveIn**: bị block khi prop `children` đang có nội dung inline.
- Editor preview: click bị `preventDefault` khi editor đang bật để tránh navigate.

## Related nodes

- [`ButtonNode`](../button/README.md) — dùng khi cần CTA có style button từ theme
