# flex-html-render

`flex-html-render` 是一個將 HTML 字串轉換為 LINE Flex Message JSON 結構的工具，方便開發者以 HTML 標記語法設計 Flex Message，並自動轉換為 LINE Messaging API 所需的格式。

## Demo 頁面
- [Flex Message HTML Simulator](https://spa.maju-web.club/flex-message-html-simulator/)

## 特色
- 以 HTML 字串描述 Flex Message 結構
- 自動解析 HTML 並轉換為 Flex Message JSON
- 支援多種 Flex Message 元素
- 易於整合於 Node.js 或前端專案

## 安裝

```bash
npm install flex-html-render
```

## 使用方式

```js
import convertHtmlToFlexMessage from 'flex-html-render';

const htmlString = `
  <bubble>
    <body>
      <box layout="vertical">
        <text>這是一個 Flex Message</text>
      </box>
    </body>
  </bubble>
`;

const flexMessage = convertHtmlToFlexMessage(htmlString);
console.log(JSON.stringify(flexMessage, null, 2));

// 將產生的 JSON 放入 LINE Messaging API 的訊息結構中
const message = {
  type: 'flex',
  altText: 'Flex Message',
  contents: flexMessage[0]  // 因為 convertHtmlToFlexMessage 回傳陣列，取第一個元素
};
```

**注意**：此套件產生的 JSON 物件應放置在 LINE Messaging API 中 `type` 為 `flex` 的訊息物件的 `contents` 區塊內。詳細請參考 [LINE Flex Message 官方文件](https://developers.line.biz/en/reference/messaging-api/#flex-message)。

## API

### `convertHtmlToFlexMessage(htmlString)`
- **參數**：`htmlString` (string) - Flex Message 對應的 HTML 字串
- **回傳**：Flex Message JSON 物件陣列
- **說明**：此函數將 Flex Message HTML 字串轉為 JSON 結構，可用於編輯或顯示目的

### `convertJsonToHtml(json)`
- **參數**：`json` (object) - Flex Message JSON 物件
- **回傳**：對應的格式化 HTML 字串
- **說明**：此函數將 Flex Message JSON 結構轉為 HTML 字串，可用於編輯或顯示目的


## 支援的 Flex Message 元素
本工具支援大部分 [LINE Flex Message](https://developers.line.biz/en/reference/messaging-api/#flex-message) 元素，包括：
- bubble
- carousel
- box
- text
- image
- video
- button
- icon
- separator

詳細 Flex Message 元素與屬性請參考 [LINE 官方文件](https://developers.line.biz/en/reference/messaging-api/#flex-message)。

## 標籤類型說明 (types.js)

### 容器標籤 (Container Tags)
- `<bubble>` - Flex Message 的基本容器，只能包含 top-level 區塊標籤
- `<carousel>` - 輪播容器，只能包含 `<bubble>` 標籤，最多 12 個

### 頂層區塊標籤 (Top-level Section Tags)
這些標籤只能直接放在 `<bubble>` 內，且每個只能有一個子元素：
- `<header>` - 標題區塊
- `<hero>` - 英雄圖區塊
- `<body>` - 主體內容區塊
- `<footer>` - 頁尾區塊

### 元件標籤 (Component Tags)
- `<box>` - 容器元件，需指定 `layout` 屬性（vertical、horizontal、baseline）
- `<text>` - 文字元件，可包含多個 `<span>` 子元素
- `<span>` - 文字片段元件，只能有一個文字子節點
- `<image>` - 圖片元件，需指定 `url` 屬性
- `<video>` - 影片元件，必須包含一個 `<box>` 或 `<image>` 作為 `altContent`
- `<icon>` - 圖示元件，需指定 `url` 屬性
- `<separator>` - 分隔線元件
- `<button>` - 按鈕元件，必須包含一個 `<action>` 子元素

### 便捷標籤 (Convenience Tags)
這些是對常用設定的簡寫標籤：
- `<div>`, `<article>` - 等同於 `<box>`
- `<baseline>` - 等同於 `<box layout="baseline">`
- `<row>` - 等同於 `<box layout="horizontal">`
- `<vertical>` - 等同於 `<box layout="vertical">`
- `<strong>` - 自動設定 `weight="bold"` 的文字標籤
- `<space size="n">` - 產生 n 個空格的 span 元件（預設 size=1）

### 特殊功能標籤
- `<action>` - 動作設定標籤，必須放在需要添加動作的元件內（如 `<button>`、`<box>`、`<image>` 等）
- `<background>` - 背景設定標籤，只能放在 Box 相關標籤內（`<box>`、`<baseline>`、`<row>`、`<vertical>`）
- `<style>` - 樣式設定標籤，只能放在 top-level 區塊標籤內（`<header>`、`<hero>`、`<body>`、`<footer>`）

## 特殊標籤使用規則

### 1. `<bubble>` 容器規則
`<bubble>` 只能包含 top-level 區塊標籤（header、hero、body、footer），不能直接包含其他元件。

```html
<!-- ✅ 正確 -->
<bubble>
  <header>
    <box layout="vertical">
      <text>標題</text>
    </box>
  </header>
  <body>
    <box layout="vertical">
      <text>內容</text>
    </box>
  </body>
</bubble>

<!-- ❌ 錯誤 - 不能直接包含 box -->
<bubble>
  <box layout="vertical">
    <text>內容</text>
  </box>
</bubble>
```

### 2. `<action>` 使用規則
`<action>` 標籤必須放在需要添加互動行為的元件內部，會自動從子元素中提取並設定為該元件的 action 屬性。

```html
<!-- 按鈕必須包含 action -->
<button>
  <action type="uri" uri="https://example.com" />
</button>

<!-- Box 元件添加點擊動作 -->
<box layout="vertical">
  <text>點擊這個 Box</text>
  <action type="uri" uri="https://example.com" />
</box>

<!-- Image 元件添加點擊動作 -->
<image url="https://example.com/image.png">
  <action type="uri" uri="https://example.com" />
</image>
```

### 3. `<background>` 使用規則
`<background>` 標籤只能放在 Box 相關標籤內（`<box>`、`<baseline>`、`<row>`、`<vertical>`），用於設定背景。

```html
<!-- ✅ 正確 - 在 box 內使用 -->
<box layout="vertical">
  <background type="linearGradient" angle="90deg" startColor="#ff0000" endColor="#0000ff" />
  <text>有漸層背景的 Box</text>
</box>

<!-- ✅ 正確 - 在 vertical 內使用 -->
<vertical>
  <background type="linearGradient" angle="0deg" startColor="#ffff00" endColor="#00ff00" />
  <text>有背景的垂直容器</text>
</vertical>

<!-- ❌ 錯誤 - 不能在 text 內使用 -->
<text>
  <background type="linearGradient" angle="0deg" startColor="#ffff00" endColor="#00ff00" />
  文字
</text>
```

### 4. `<style>` 使用規則
`<style>` 標籤只能放在 top-level 區塊標籤內（`<header>`、`<hero>`、`<body>`、`<footer>`），用於設定該區塊的樣式屬性，如背景色等。各區塊標籤只能有一個 `<style>` 子元素。最終會整合為一個 styles 屬性到 bubble 的 JSON 結構中。

```xml
<!-- ✅ 正確 - 在 header 內使用 -->
<header>
  <style backgroundColor="#ff0000" />
  <box layout="vertical">
    <text>有背景色的標題</text>
  </box>
</header>

<!-- ❌ 錯誤 - 不能在 box 內使用 -->
<box layout="vertical">
  <style backgroundColor="#ff0000" />
  <text>文字</text>
</box>
```

### 5. `<strong>` 使用方式
`<strong>` 標籤會自動轉換為 `<text weight="bold">`，用於顯示粗體文字。

```html
<box layout="vertical">
  <strong>這是粗體文字</strong>
  <text>這是一般文字</text>
</box>
```

### 6. `<space>` 使用方式
`<space>` 標籤用於在文字中插入空格，可透過 `size` 屬性指定空格數量。

```html
<text>
  <span>Hello</span>
  <space size="3" />
  <span>World</span>
</text>
```

### 7. 便捷 Box 標籤（`<baseline>`、`<row>`、`<vertical>`）
這些標籤是 `<box>` 的簡寫形式，省去了 `layout` 屬性的設定。

```html
<!-- baseline: 基線對齊佈局 -->
<baseline>
  <text>左側文字</text>
  <text>右側文字</text>
</baseline>

<!-- row: 水平佈局 -->
<row>
  <image url="https://example.com/icon.png" />
  <text>橫向排列</text>
</row>

<!-- vertical: 垂直佈局 -->
<vertical>
  <text>第一行</text>
  <text>第二行</text>
</vertical>
```

### 8. `<carousel>` 使用規則
`<carousel>` 只能包含 `<bubble>` 子元素，且最多 12 個。

```html
<carousel>
  <bubble>
    <body>
      <box layout="vertical">
        <text>第一個 Bubble</text>
      </box>
    </body>
  </bubble>
  <bubble>
    <body>
      <box layout="vertical">
        <text>第二個 Bubble</text>
      </box>
    </body>
  </bubble>
</carousel>
```

### 9. `<video>` 使用規則
`<video>` 必須包含一個 `<box>` 或 `<image>` 作為 altContent（影片無法播放時的替代內容）。

```html
<video url="https://example.com/video.mp4" previewUrl="https://example.com/preview.jpg">
  <image url="https://example.com/alt-image.jpg" />
</video>
```

## 完整範例

```xml
<bubble>
  <header>
    <style backgroundColor="#f0f0f0" />
    <vertical>
      <background type="linearGradient" angle="90deg" startColor="#667eea" endColor="#764ba2" />
      <strong>商品資訊</strong>
    </vertical>
  </header>
  <body>
    <vertical>
      <image url="https://example.com/product.jpg" aspectRatio="4:3" size="full" />
      <baseline>
        <text>價格：</text>
        <space size="2" />
        <strong>NT$ 1,000</strong>
      </baseline>
      <separator />
      <text>這是商品的詳細說明文字</text>
    </vertical>
  </body>
  <footer>
    <row>
      <button>
        <action type="uri" uri="https://example.com/buy" label="立即購買" />
      </button>
    </row>
  </footer>
</bubble>
```

## 範例

```js
const html = `
  <bubble>
    <body>
      <box layout="vertical">
        <text color="#ff0000">Hello, Flex!</text>
        <image url="https://example.com/image.png" />
      </box>
    </body>
  </bubble>
`;

const result = convertHtmlToFlexMessage(html);
console.log(result);
```

## 注意事項
- 請確保 HTML 結構正確，否則可能無法正確轉換。
- 轉換後的 JSON 結構請依照 [LINE Flex Message 規範](https://developers.line.biz/en/reference/messaging-api/#flex-message) 使用。

## 授權
MIT License
