flex-html-render 1.0.2 → 1.1.0

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
@@ -41,6 +41,12 @@ console.log(JSON.stringify(flexMessage, null, 2));
41
41
  ### `convertHtmlToFlexMessage(htmlString)`
42
42
  - **參數**:`htmlString` (string) - Flex Message 對應的 HTML 字串
43
43
  - **回傳**:Flex Message JSON 物件陣列
44
+ - **說明**:此函數將 Flex Message HTML 字串轉為 JSON 結構,可用於編輯或顯示目的
45
+
46
+ ### `convertJsonToHtml(json)`
47
+ - **參數**:`json` (object) - Flex Message JSON 物件
48
+ - **回傳**:對應的格式化 HTML 字串
49
+ - **說明**:此函數將 Flex Message JSON 結構轉為 HTML 字串,可用於編輯或顯示目的
44
50
 
45
51
 
46
52
  ## 支援的 Flex Message 元素
@@ -1 +1,6 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const f=require("htmlparser2"),h={ELEMENT:"element",TEXT:"text"},e={CAROUSEL:"carousel",BUBBLE:"bubble",HEADER:"header",HERO:"hero",BODY:"body",FOOTER:"footer",BOX:"box",TEXT:"text",SPAN:"span",IMAGE:"image",VIDEO:"video",ICON:"icon",SEPARATOR:"separator",BUTTON:"button",SPACE:"space",STRONG:"strong",BASELINE:"baseline",ROW:"row",VERTICAL:"vertical",DIV:"div",ARTICLE:"article",ACTION:"action",BACKGROUND:"background"},b=[e.HEADER,e.HERO,e.BODY,e.FOOTER],p=[e.BOX,e.VERTICAL,e.ROW,e.BASELINE,e.DIV,e.ARTICLE],E=[e.TEXT,e.STRONG];function T(t){const r=Number(t);return isNaN(r)?t:r}function O(t){return t==="true"?!0:t==="false"?!1:t}function A(t){return[T,O].reduce((a,l)=>l(a),t)}function d(t){const r={type:"root",children:[]},a=[r],l=new f.Parser({onopentag(n,u){const g={type:h.ELEMENT,tagName:n,attributes:Object.fromEntries(Object.entries(u).map(([m,N])=>[m,A(N)])),children:[]};a[a.length-1].children.push(g),a.push(g)},ontext(n){n.trim()&&a[a.length-1].children.push({type:h.TEXT,content:n.replace(/\n/g,"").trim()})},onclosetag(){a.pop()},onerror(n){console.error("解析錯誤:",n)}},{xmlMode:!0,lowerCaseTags:!1,lowerCaseAttributeNames:!1});return l.write(t),l.end(),r.children}const s=t=>{throw Error(`[Flex Html Render]: ${t}`)},c={carousel:t=>({type:"carousel",contents:t}),bubble:(t={})=>({type:"bubble",...t}),box:(t,r={})=>({type:"box",contents:t,...r}),text:(t,r={})=>({type:"text",...typeof t=="string"?{text:t}:{contents:t},...r}),span:(t,r={})=>({type:"span",text:t,...r}),image:(t={})=>({type:"image",...t}),video:(t={})=>({type:"video",...t}),icon:(t={})=>({type:"icon",...t}),button:(t={})=>({type:"button",...t}),separator:(t={color:"#E0E3EA"})=>({type:"separator",...t}),uri:(t={})=>({type:"uri",altUri:t.altUri?{desktop:t.altUri}:void 0,...t})};function y(t){if(t.tagName!==e.BACKGROUND&&t.children&&t.children.length>0){const r=t.children.filter(a=>a.tagName===e.BACKGROUND);return r.length>1&&s("A box node can only allowed with one background node inside"),t.children=t.children.filter(a=>a.tagName!==e.BACKGROUND),r[0]}return null}function B(t){if(t.tagName!==e.ACTION&&t.children&&t.children.length>0){const r=t.children.filter(a=>a.tagName===e.ACTION);return r.length>1&&s("A node can only allowed with one action node inside"),t.children=t.children.filter(a=>a.tagName!==e.ACTION),r[0]}return null}function C(t){!E.includes(t.tagName)&&t.children?.some(n=>n.type===h.TEXT)&&s("Span component only allowed inside Text component"),t.tagName===e.VIDEO&&t.children?.some(n=>![e.BOX,e.IMAGE].includes(n.tagName))&&s("Video component only allowed Box or Image as altContent child"),!p.includes(t.tagName)&&t.children?.some(n=>n.tagName===e.BACKGROUND)&&s("Only Box component allowed to have Background child")}function i(t){t.attributes=t.attributes||{},C(t);const r=B(t);r&&(t.attributes.action=i(r));const a=y(t);if(a&&(t.attributes.background=i(a)),t.type===h.TEXT)return c.span(t.content,t.attributes);if(t.tagName===e.BUBBLE){const l=t.children.find(o=>o.tagName===e.HEADER),n=t.children.find(o=>o.tagName===e.HERO),u=t.children.find(o=>o.tagName===e.BODY),g=t.children.find(o=>o.tagName===e.FOOTER);return c.bubble({...t.attributes,header:l?i(l):void 0,hero:n?i(n):void 0,body:u?i(u):void 0,footer:g?i(g):void 0})}if(t.tagName===e.CAROUSEL)return t.children.some(l=>l.tagName!==e.BUBBLE)&&s("Carousel can only have Bubble as children"),t.children.length>12&&s("Carousel can have maximum 12 bubbles"),c.carousel(t.children.map(i));if(b.includes(t.tagName))return t.children.length!==1&&s(`${t.tagName} should have exactly one child node`),i(t.children[0]);if(t.tagName===e.BUTTON)return t.attributes.action||s("Button component should contain an action node"),c.button(t.attributes);if(t.tagName===e.SPAN){t.children.length>1&&s("Span component can only have one text child");const l=t.children[0];if(l&&l.type===h.TEXT)return c.span(l.content,t.attributes);s("Span component only allowed text child")}if(t.tagName===e.TEXT)return c.text(t.children.map(i),t.attributes);if(t.tagName===e.SEPARATOR)return c.separator(t.attributes);if(t.tagName===e.IMAGE)return c.image(t.attributes);if(t.tagName===e.VIDEO)return t.children.length!==1&&s("Video component should only has one Box or Image as altContent"),t.attributes.altContent=i(t.children[0]),c.video(t.attributes);if(t.tagName===e.ICON)return c.icon(t.attributes);if(t.tagName===e.BOX||t.tagName===e.DIV||t.tagName===e.ARTICLE)return t.attributes.layout||(t.attributes.layout="vertical"),c.box(t.children.map(i),t.attributes);if(t.tagName===e.SPACE)return c.span(" ".repeat(t.attributes.size||1));if(t.tagName===e.STRONG)return t.tagName=e.TEXT,t.attributes.weight="bold",i(t);if(t.tagName===e.BASELINE)return t.tagName=e.BOX,t.attributes.layout="baseline",i(t);if(t.tagName===e.ROW)return t.tagName=e.BOX,t.attributes.layout="horizontal",i(t);if(t.tagName===e.VERTICAL)return t.tagName=e.BOX,t.attributes.layout="vertical",i(t);if(t.tagName===e.ACTION&&t.attributes.type==="uri")return c.uri(t.attributes);if(t.tagName===e.BACKGROUND)return t.attributes}function R(t){try{return d(t).map(i)}catch(r){throw console.error("Error converting HTML to Flex Message:",r),r}}exports.default=R;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const J=require("htmlparser2"),E={ELEMENT:"element",TEXT:"text"},e={CAROUSEL:"carousel",BUBBLE:"bubble",HEADER:"header",HERO:"hero",BODY:"body",FOOTER:"footer",BOX:"box",TEXT:"text",SPAN:"span",IMAGE:"image",VIDEO:"video",ICON:"icon",SEPARATOR:"separator",BUTTON:"button",FILLER:"filler",SPACE:"space",STRONG:"strong",BASELINE:"baseline",ROW:"row",VERTICAL:"vertical",DIV:"div",ARTICLE:"article",ACTION:"action",BACKGROUND:"background"},Y=[e.HEADER,e.HERO,e.BODY,e.FOOTER],W=[e.BOX,e.VERTICAL,e.ROW,e.BASELINE,e.DIV,e.ARTICLE],q=[e.TEXT,e.STRONG];function z(t){const r=Number(t);return isNaN(r)?t:r}function _(t){return t==="true"?!0:t==="false"?!1:t}function Q(t){return[z,_].reduce((n,s)=>s(n),t)}function Z(t){const r={type:"root",children:[]},n=[r],s=new J.Parser({onopentag(l,i){const a={type:E.ELEMENT,tagName:l,attributes:Object.fromEntries(Object.entries(i).map(([p,f])=>[p,Q(f)])),children:[]};n[n.length-1].children.push(a),n.push(a)},ontext(l){const i=n[n.length-1];if(i.tagName==="span"){i.children.push({type:E.TEXT,content:l});return}l.trim()&&i.children.push({type:E.TEXT,content:l.replace(/\n/g,"").trim()})},onclosetag(){n.pop()},onerror(l){console.error("解析錯誤:",l)}},{xmlMode:!0,lowerCaseTags:!1,lowerCaseAttributeNames:!1});return s.write(t),s.end(),r.children}const h=t=>{throw Error(`[Flex Html Render]: ${t}`)},c={carousel:t=>({type:"carousel",contents:t}),bubble:(t={})=>({type:"bubble",...t}),box:(t,r={})=>({type:"box",contents:t,...r}),text:(t,r={})=>({type:"text",...typeof t=="string"?{text:t}:{contents:t},...r}),span:(t,r={})=>({type:"span",text:t,...r}),image:(t={})=>({type:"image",...t}),video:(t={})=>({type:"video",...t}),icon:(t={})=>({type:"icon",...t}),button:(t={})=>({type:"button",...t}),separator:(t={color:"#E0E3EA"})=>({type:"separator",...t}),filler:(t={})=>({type:"filler",...t}),uri:(t={})=>({type:"uri",altUri:t.altUri?{desktop:t.altUri}:void 0,...t}),postback:(t={})=>({type:"postback",...t}),message:(t={})=>({type:"message",...t}),datetimepicker:(t={})=>({type:"datetimepicker",...t}),camera:(t={})=>({type:"camera",...t}),cameraRoll:(t={})=>({type:"cameraRoll",...t}),location:(t={})=>({type:"location",...t}),richmenuswitch:(t={})=>({type:"richmenuswitch",...t}),clipboard:(t={})=>({type:"clipboard",...t})};function tt(t){if(t.tagName!==e.BACKGROUND&&t.children&&t.children.length>0){const r=t.children.filter(n=>n.tagName===e.BACKGROUND);return r.length>1&&h("A box node can only allowed with one background node inside"),t.children=t.children.filter(n=>n.tagName!==e.BACKGROUND),r[0]}return null}function et(t){if(t.tagName!==e.ACTION&&t.children&&t.children.length>0){const r=t.children.filter(n=>n.tagName===e.ACTION);return r.length>1&&h("A node can only allowed with one action node inside"),t.children=t.children.filter(n=>n.tagName!==e.ACTION),r[0]}return null}function rt(t){![...q,e.SPAN].includes(t.tagName)&&t.children?.some(l=>l.type===E.TEXT)&&(console.log(t),h("Span component only allowed inside Text component")),t.tagName===e.VIDEO&&t.children?.some(l=>![e.BOX,e.IMAGE].includes(l.tagName))&&h("Video component only allowed Box or Image as altContent child"),!W.includes(t.tagName)&&t.children?.some(l=>l.tagName===e.BACKGROUND)&&h("Only Box component allowed to have Background child")}function m(t){t.attributes=t.attributes||{},rt(t);const r=et(t);r&&(t.attributes.action=m(r));const n=tt(t);if(n&&(t.attributes.background=m(n)),t.type===E.TEXT)return c.span(t.content,t.attributes);if(t.tagName===e.BUBBLE){const s=t.children.find(u=>u.tagName===e.HEADER),l=t.children.find(u=>u.tagName===e.HERO),i=t.children.find(u=>u.tagName===e.BODY),a=t.children.find(u=>u.tagName===e.FOOTER);return c.bubble({...t.attributes,header:s?m(s):void 0,hero:l?m(l):void 0,body:i?m(i):void 0,footer:a?m(a):void 0})}if(t.tagName===e.CAROUSEL)return t.children.some(s=>s.tagName!==e.BUBBLE)&&h("Carousel can only have Bubble as children"),t.children.length>12&&h("Carousel can have maximum 12 bubbles"),c.carousel(t.children.map(m));if(Y.includes(t.tagName))return t.children.length!==1&&h(`${t.tagName} should have exactly one child node`),m(t.children[0]);if(t.tagName===e.BUTTON)return t.attributes.action||h("Button component should contain an action node"),c.button(t.attributes);if(t.tagName===e.SPAN){t.children.length>1&&h("Span component can only have one text child");const s=t.children[0];if(s&&s.type===E.TEXT)return c.span(s.content,t.attributes);h(s?"Span component only allowed text child":"Span component can not be empty")}if(t.tagName===e.TEXT)return c.text(t.children.map(m),t.attributes);if(t.tagName===e.SEPARATOR)return c.separator(t.attributes);if(t.tagName===e.IMAGE)return c.image(t.attributes);if(t.tagName===e.VIDEO)return t.children.length!==1&&h("Video component should only has one Box or Image as altContent"),t.attributes.altContent=m(t.children[0]),c.video(t.attributes);if(t.tagName===e.ICON)return c.icon(t.attributes);if(t.tagName===e.FILLER)return c.filler(t.attributes);if(t.tagName===e.BOX||t.tagName===e.DIV||t.tagName===e.ARTICLE)return t.attributes.layout||(t.attributes.layout="vertical"),c.box(t.children.map(m),t.attributes);if(t.tagName===e.SPACE)return c.span(" ".repeat(t.attributes.size||1));if(t.tagName===e.STRONG)return t.tagName=e.TEXT,t.attributes.weight="bold",m(t);if(t.tagName===e.BASELINE)return t.tagName=e.BOX,t.attributes.layout="baseline",m(t);if(t.tagName===e.ROW)return t.tagName=e.BOX,t.attributes.layout="horizontal",m(t);if(t.tagName===e.VERTICAL)return t.tagName=e.BOX,t.attributes.layout="vertical",m(t);if(t.tagName===e.ACTION){const s=t.attributes.type;switch(s){case"uri":return c.uri(t.attributes);case"postback":return c.postback(t.attributes);case"message":return c.message(t.attributes);case"datetimepicker":return c.datetimepicker(t.attributes);case"camera":return c.camera(t.attributes);case"cameraRoll":return c.cameraRoll(t.attributes);case"location":return c.location(t.attributes);case"richmenuswitch":return c.richmenuswitch(t.attributes);case"clipboard":return c.clipboard(t.attributes);default:h(`Unsupported action type: ${s}`)}}if(t.tagName===e.BACKGROUND)return t.attributes}const o={createElement:(t,r={},n=[],s=0)=>{const i=Object.entries(r).filter(([u,p])=>p!=null).map(([u,p])=>typeof p=="object"?`${u}="${JSON.stringify(p).replace(/"/g,"&quot;")}"`:`${u}="${p}"`).join(" "),a=i?` ${i}`:"";if(n.length===0)return` <${t}${a} />`;{const u=n.map(p=>typeof p=="string"?p.split(`
2
+ `).map(f=>f?" "+f:"").join(`
3
+ `):p).join(`
4
+ `);return` <${t}${a}>
5
+ ${u}
6
+ </${t}>`}},createText:t=>t};function b(t,r=0){if(!t||typeof t!="object")return"";const{type:n,...s}=t,{action:l,...i}=s,a=l?b(l,r+1):"";switch(n){case"carousel":const{contents:u,...p}=i,f=u.map(N=>b(N,r+1));return a&&f.unshift(a),o.createElement(e.CAROUSEL,p,f,r);case"bubble":const{header:A,hero:C,body:R,footer:B,...L}=i,g=[];return a&&g.push(a),A&&g.push(o.createElement(e.HEADER,{},[b(A,r+1)],r+1)),C&&g.push(o.createElement(e.HERO,{},[b(C,r+1)],r+1)),R&&g.push(o.createElement(e.BODY,{},[b(R,r+1)],r+1)),B&&g.push(o.createElement(e.FOOTER,{},[b(B,r+1)],r+1)),o.createElement(e.BUBBLE,L,g,r);case"box":const{contents:w,background:d,...O}=i;O.layout||(O.layout="vertical");const T=[];return a&&T.push(a),d&&T.push(b({type:"background",...d},r+1)),T.push(...(w||[]).map(N=>b(N,r+1))),o.createElement(e.BOX,O,T,r);case"text":const{text:U,contents:y,...k}=i,x=y&&y.length>0?y.map(N=>b(N,r+1)):[U||""];return a&&x.unshift(a),o.createElement(e.TEXT,k,x,r);case"span":const{text:D,...X}=i,S=[D||""];return a&&S.unshift(a),o.createElement(e.SPAN,X,S,r);case"image":const{...$}=i,H=a?[a]:[];return o.createElement(e.IMAGE,$,H,r);case"video":const{altContent:I,...G}=i,v=I?[b(I,r+1)]:[];return a&&v.unshift(a),o.createElement(e.VIDEO,G,v,r);case"icon":const{...M}=i,F=a?[a]:[];return o.createElement(e.ICON,M,F,r);case"button":const{...P}=i,V=a?[a]:[];return o.createElement(e.BUTTON,P,V,r);case"separator":const j=a?[a]:[];return o.createElement(e.SEPARATOR,i,j,r);case"filler":const K=a?[a]:[];return o.createElement(e.FILLER,i,K,r);case"uri":case"message":case"postback":case"datetimepicker":case"camera":case"cameraRoll":case"location":case"richmenuswitch":case"clipboard":return o.createElement(e.ACTION,{type:n,...i},[],r);case"background":return o.createElement(e.BACKGROUND,i,[],r);default:return""}}function at(t){try{return Z(t).map(m)}catch(r){throw console.error("Error converting HTML to Flex Message:",r),r}}exports.convertJsonToHtml=b;exports.default=at;
@@ -1,5 +1,5 @@
1
- import { Parser as f } from "htmlparser2";
2
- const m = {
1
+ import { Parser as Y } from "htmlparser2";
2
+ const E = {
3
3
  ELEMENT: "element",
4
4
  TEXT: "text"
5
5
  }, e = {
@@ -20,6 +20,7 @@ const m = {
20
20
  ICON: "icon",
21
21
  SEPARATOR: "separator",
22
22
  BUTTON: "button",
23
+ FILLER: "filler",
23
24
  // custom render tags
24
25
  SPACE: "space",
25
26
  STRONG: "strong",
@@ -32,60 +33,68 @@ const m = {
32
33
  // custom utils tags
33
34
  ACTION: "action",
34
35
  BACKGROUND: "background"
35
- }, p = [
36
+ }, J = [
36
37
  e.HEADER,
37
38
  e.HERO,
38
39
  e.BODY,
39
40
  e.FOOTER
40
- ], b = [
41
+ ], W = [
41
42
  e.BOX,
42
43
  e.VERTICAL,
43
44
  e.ROW,
44
45
  e.BASELINE,
45
46
  e.DIV,
46
47
  e.ARTICLE
47
- ], E = [
48
+ ], z = [
48
49
  e.TEXT,
49
50
  e.STRONG
50
51
  ];
51
- function T(t) {
52
- const a = Number(t);
53
- return isNaN(a) ? t : a;
52
+ function q(t) {
53
+ const r = Number(t);
54
+ return isNaN(r) ? t : r;
54
55
  }
55
- function O(t) {
56
+ function Q(t) {
56
57
  return t === "true" ? !0 : t === "false" ? !1 : t;
57
58
  }
58
- function A(t) {
59
+ function Z(t) {
59
60
  return [
60
- T,
61
- O
62
- ].reduce((r, l) => l(r), t);
61
+ q,
62
+ Q
63
+ ].reduce((n, s) => s(n), t);
63
64
  }
64
- function B(t) {
65
- const a = { type: "root", children: [] }, r = [a], l = new f(
65
+ function _(t) {
66
+ const r = { type: "root", children: [] }, n = [r], s = new Y(
66
67
  {
67
- onopentag(n, u) {
68
- const g = {
69
- type: m.ELEMENT,
70
- tagName: n,
68
+ onopentag(l, i) {
69
+ const a = {
70
+ type: E.ELEMENT,
71
+ tagName: l,
71
72
  attributes: Object.fromEntries(
72
- Object.entries(u).map(([h, N]) => [h, A(N)])
73
+ Object.entries(i).map(([p, f]) => [p, Z(f)])
73
74
  ),
74
75
  children: []
75
76
  };
76
- r[r.length - 1].children.push(g), r.push(g);
77
+ n[n.length - 1].children.push(a), n.push(a);
77
78
  },
78
- ontext(n) {
79
- n.trim() && r[r.length - 1].children.push({
80
- type: m.TEXT,
81
- content: n.replace(/\n/g, "").trim()
79
+ ontext(l) {
80
+ const i = n[n.length - 1];
81
+ if (i.tagName === "span") {
82
+ i.children.push({
83
+ type: E.TEXT,
84
+ content: l
85
+ });
86
+ return;
87
+ }
88
+ l.trim() && i.children.push({
89
+ type: E.TEXT,
90
+ content: l.replace(/\n/g, "").trim()
82
91
  });
83
92
  },
84
93
  onclosetag() {
85
- r.pop();
94
+ n.pop();
86
95
  },
87
- onerror(n) {
88
- console.error("解析錯誤:", n);
96
+ onerror(l) {
97
+ console.error("解析錯誤:", l);
89
98
  }
90
99
  },
91
100
  {
@@ -96,9 +105,9 @@ function B(t) {
96
105
  lowerCaseAttributeNames: !1
97
106
  }
98
107
  );
99
- return l.write(t), l.end(), a.children;
108
+ return s.write(t), s.end(), r.children;
100
109
  }
101
- const o = (t) => {
110
+ const h = (t) => {
102
111
  throw Error(`[Flex Html Render]: ${t}`);
103
112
  }, c = {
104
113
  carousel: (t) => ({
@@ -109,22 +118,22 @@ const o = (t) => {
109
118
  type: "bubble",
110
119
  ...t
111
120
  }),
112
- box: (t, a = {}) => ({
121
+ box: (t, r = {}) => ({
113
122
  type: "box",
114
123
  contents: t,
115
- ...a
124
+ ...r
116
125
  }),
117
- text: (t, a = {}) => ({
126
+ text: (t, r = {}) => ({
118
127
  type: "text",
119
128
  ...typeof t == "string" ? { text: t } : {
120
129
  contents: t
121
130
  },
122
- ...a
131
+ ...r
123
132
  }),
124
- span: (t, a = {}) => ({
133
+ span: (t, r = {}) => ({
125
134
  type: "span",
126
135
  text: t,
127
- ...a
136
+ ...r
128
137
  }),
129
138
  image: (t = {}) => ({
130
139
  type: "image",
@@ -146,69 +155,105 @@ const o = (t) => {
146
155
  type: "separator",
147
156
  ...t
148
157
  }),
158
+ filler: (t = {}) => ({
159
+ type: "filler",
160
+ ...t
161
+ }),
149
162
  uri: (t = {}) => ({
150
163
  type: "uri",
151
164
  altUri: t.altUri ? {
152
165
  desktop: t.altUri
153
166
  } : void 0,
154
167
  ...t
168
+ }),
169
+ postback: (t = {}) => ({
170
+ type: "postback",
171
+ ...t
172
+ }),
173
+ message: (t = {}) => ({
174
+ type: "message",
175
+ ...t
176
+ }),
177
+ datetimepicker: (t = {}) => ({
178
+ type: "datetimepicker",
179
+ ...t
180
+ }),
181
+ camera: (t = {}) => ({
182
+ type: "camera",
183
+ ...t
184
+ }),
185
+ cameraRoll: (t = {}) => ({
186
+ type: "cameraRoll",
187
+ ...t
188
+ }),
189
+ location: (t = {}) => ({
190
+ type: "location",
191
+ ...t
192
+ }),
193
+ richmenuswitch: (t = {}) => ({
194
+ type: "richmenuswitch",
195
+ ...t
196
+ }),
197
+ clipboard: (t = {}) => ({
198
+ type: "clipboard",
199
+ ...t
155
200
  })
156
201
  };
157
- function d(t) {
202
+ function tt(t) {
158
203
  if (t.tagName !== e.BACKGROUND && t.children && t.children.length > 0) {
159
- const a = t.children.filter((r) => r.tagName === e.BACKGROUND);
160
- return a.length > 1 && o("A box node can only allowed with one background node inside"), t.children = t.children.filter((r) => r.tagName !== e.BACKGROUND), a[0];
204
+ const r = t.children.filter((n) => n.tagName === e.BACKGROUND);
205
+ return r.length > 1 && h("A box node can only allowed with one background node inside"), t.children = t.children.filter((n) => n.tagName !== e.BACKGROUND), r[0];
161
206
  }
162
207
  return null;
163
208
  }
164
- function y(t) {
209
+ function et(t) {
165
210
  if (t.tagName !== e.ACTION && t.children && t.children.length > 0) {
166
- const a = t.children.filter((r) => r.tagName === e.ACTION);
167
- return a.length > 1 && o("A node can only allowed with one action node inside"), t.children = t.children.filter((r) => r.tagName !== e.ACTION), a[0];
211
+ const r = t.children.filter((n) => n.tagName === e.ACTION);
212
+ return r.length > 1 && h("A node can only allowed with one action node inside"), t.children = t.children.filter((n) => n.tagName !== e.ACTION), r[0];
168
213
  }
169
214
  return null;
170
215
  }
171
- function C(t) {
172
- !E.includes(t.tagName) && t.children?.some((n) => n.type === m.TEXT) && o("Span component only allowed inside Text component"), t.tagName === e.VIDEO && t.children?.some((n) => ![e.BOX, e.IMAGE].includes(n.tagName)) && o("Video component only allowed Box or Image as altContent child"), !b.includes(t.tagName) && t.children?.some((n) => n.tagName === e.BACKGROUND) && o("Only Box component allowed to have Background child");
216
+ function rt(t) {
217
+ ![...z, e.SPAN].includes(t.tagName) && t.children?.some((l) => l.type === E.TEXT) && (console.log(t), h("Span component only allowed inside Text component")), t.tagName === e.VIDEO && t.children?.some((l) => ![e.BOX, e.IMAGE].includes(l.tagName)) && h("Video component only allowed Box or Image as altContent child"), !W.includes(t.tagName) && t.children?.some((l) => l.tagName === e.BACKGROUND) && h("Only Box component allowed to have Background child");
173
218
  }
174
- function i(t) {
175
- t.attributes = t.attributes || {}, C(t);
176
- const a = y(t);
177
- a && (t.attributes.action = i(a));
178
- const r = d(t);
179
- if (r && (t.attributes.background = i(r)), t.type === m.TEXT)
219
+ function m(t) {
220
+ t.attributes = t.attributes || {}, rt(t);
221
+ const r = et(t);
222
+ r && (t.attributes.action = m(r));
223
+ const n = tt(t);
224
+ if (n && (t.attributes.background = m(n)), t.type === E.TEXT)
180
225
  return c.span(t.content, t.attributes);
181
226
  if (t.tagName === e.BUBBLE) {
182
- const l = t.children.find((s) => s.tagName === e.HEADER), n = t.children.find((s) => s.tagName === e.HERO), u = t.children.find((s) => s.tagName === e.BODY), g = t.children.find((s) => s.tagName === e.FOOTER);
227
+ const s = t.children.find((u) => u.tagName === e.HEADER), l = t.children.find((u) => u.tagName === e.HERO), i = t.children.find((u) => u.tagName === e.BODY), a = t.children.find((u) => u.tagName === e.FOOTER);
183
228
  return c.bubble({
184
229
  ...t.attributes,
185
- header: l ? i(l) : void 0,
186
- hero: n ? i(n) : void 0,
187
- body: u ? i(u) : void 0,
188
- footer: g ? i(g) : void 0
230
+ header: s ? m(s) : void 0,
231
+ hero: l ? m(l) : void 0,
232
+ body: i ? m(i) : void 0,
233
+ footer: a ? m(a) : void 0
189
234
  });
190
235
  }
191
236
  if (t.tagName === e.CAROUSEL)
192
- return t.children.some((l) => l.tagName !== e.BUBBLE) && o("Carousel can only have Bubble as children"), t.children.length > 12 && o("Carousel can have maximum 12 bubbles"), c.carousel(
193
- t.children.map(i)
237
+ return t.children.some((s) => s.tagName !== e.BUBBLE) && h("Carousel can only have Bubble as children"), t.children.length > 12 && h("Carousel can have maximum 12 bubbles"), c.carousel(
238
+ t.children.map(m)
194
239
  );
195
- if (p.includes(t.tagName))
196
- return t.children.length !== 1 && o(`${t.tagName} should have exactly one child node`), i(t.children[0]);
240
+ if (J.includes(t.tagName))
241
+ return t.children.length !== 1 && h(`${t.tagName} should have exactly one child node`), m(t.children[0]);
197
242
  if (t.tagName === e.BUTTON)
198
- return t.attributes.action || o("Button component should contain an action node"), c.button(t.attributes);
243
+ return t.attributes.action || h("Button component should contain an action node"), c.button(t.attributes);
199
244
  if (t.tagName === e.SPAN) {
200
- t.children.length > 1 && o("Span component can only have one text child");
201
- const l = t.children[0];
202
- if (l && l.type === m.TEXT)
245
+ t.children.length > 1 && h("Span component can only have one text child");
246
+ const s = t.children[0];
247
+ if (s && s.type === E.TEXT)
203
248
  return c.span(
204
- l.content,
249
+ s.content,
205
250
  t.attributes
206
251
  );
207
- o("Span component only allowed text child");
252
+ h(s ? "Span component only allowed text child" : "Span component can not be empty");
208
253
  }
209
254
  if (t.tagName === e.TEXT)
210
255
  return c.text(
211
- t.children.map(i),
256
+ t.children.map(m),
212
257
  t.attributes
213
258
  );
214
259
  if (t.tagName === e.SEPARATOR)
@@ -216,36 +261,136 @@ function i(t) {
216
261
  if (t.tagName === e.IMAGE)
217
262
  return c.image(t.attributes);
218
263
  if (t.tagName === e.VIDEO)
219
- return t.children.length !== 1 && o("Video component should only has one Box or Image as altContent"), t.attributes.altContent = i(t.children[0]), c.video(t.attributes);
264
+ return t.children.length !== 1 && h("Video component should only has one Box or Image as altContent"), t.attributes.altContent = m(t.children[0]), c.video(t.attributes);
220
265
  if (t.tagName === e.ICON)
221
266
  return c.icon(t.attributes);
267
+ if (t.tagName === e.FILLER)
268
+ return c.filler(t.attributes);
222
269
  if (t.tagName === e.BOX || t.tagName === e.DIV || t.tagName === e.ARTICLE)
223
270
  return t.attributes.layout || (t.attributes.layout = "vertical"), c.box(
224
- t.children.map(i),
271
+ t.children.map(m),
225
272
  t.attributes
226
273
  );
227
274
  if (t.tagName === e.SPACE)
228
275
  return c.span(" ".repeat(t.attributes.size || 1));
229
276
  if (t.tagName === e.STRONG)
230
- return t.tagName = e.TEXT, t.attributes.weight = "bold", i(t);
277
+ return t.tagName = e.TEXT, t.attributes.weight = "bold", m(t);
231
278
  if (t.tagName === e.BASELINE)
232
- return t.tagName = e.BOX, t.attributes.layout = "baseline", i(t);
279
+ return t.tagName = e.BOX, t.attributes.layout = "baseline", m(t);
233
280
  if (t.tagName === e.ROW)
234
- return t.tagName = e.BOX, t.attributes.layout = "horizontal", i(t);
281
+ return t.tagName = e.BOX, t.attributes.layout = "horizontal", m(t);
235
282
  if (t.tagName === e.VERTICAL)
236
- return t.tagName = e.BOX, t.attributes.layout = "vertical", i(t);
237
- if (t.tagName === e.ACTION && t.attributes.type === "uri")
238
- return c.uri(t.attributes);
283
+ return t.tagName = e.BOX, t.attributes.layout = "vertical", m(t);
284
+ if (t.tagName === e.ACTION) {
285
+ const s = t.attributes.type;
286
+ switch (s) {
287
+ case "uri":
288
+ return c.uri(t.attributes);
289
+ case "postback":
290
+ return c.postback(t.attributes);
291
+ case "message":
292
+ return c.message(t.attributes);
293
+ case "datetimepicker":
294
+ return c.datetimepicker(t.attributes);
295
+ case "camera":
296
+ return c.camera(t.attributes);
297
+ case "cameraRoll":
298
+ return c.cameraRoll(t.attributes);
299
+ case "location":
300
+ return c.location(t.attributes);
301
+ case "richmenuswitch":
302
+ return c.richmenuswitch(t.attributes);
303
+ case "clipboard":
304
+ return c.clipboard(t.attributes);
305
+ default:
306
+ h(`Unsupported action type: ${s}`);
307
+ }
308
+ }
239
309
  if (t.tagName === e.BACKGROUND)
240
310
  return t.attributes;
241
311
  }
242
- function x(t) {
312
+ const o = {
313
+ createElement: (t, r = {}, n = [], s = 0) => {
314
+ const i = Object.entries(r).filter(([u, p]) => p != null).map(([u, p]) => typeof p == "object" ? `${u}="${JSON.stringify(p).replace(/"/g, "&quot;")}"` : `${u}="${p}"`).join(" "), a = i ? ` ${i}` : "";
315
+ if (n.length === 0)
316
+ return ` <${t}${a} />`;
317
+ {
318
+ const u = n.map((p) => typeof p == "string" ? p.split(`
319
+ `).map((f) => f ? " " + f : "").join(`
320
+ `) : p).join(`
321
+ `);
322
+ return ` <${t}${a}>
323
+ ${u}
324
+ </${t}>`;
325
+ }
326
+ },
327
+ createText: (t) => t
328
+ };
329
+ function b(t, r = 0) {
330
+ if (!t || typeof t != "object")
331
+ return "";
332
+ const { type: n, ...s } = t, { action: l, ...i } = s, a = l ? b(l, r + 1) : "";
333
+ switch (n) {
334
+ case "carousel":
335
+ const { contents: u, ...p } = i, f = u.map((N) => b(N, r + 1));
336
+ return a && f.unshift(a), o.createElement(e.CAROUSEL, p, f, r);
337
+ case "bubble":
338
+ const { header: y, hero: C, body: R, footer: B, ...L } = i, g = [];
339
+ return a && g.push(a), y && g.push(o.createElement(e.HEADER, {}, [b(y, r + 1)], r + 1)), C && g.push(o.createElement(e.HERO, {}, [b(C, r + 1)], r + 1)), R && g.push(o.createElement(e.BODY, {}, [b(R, r + 1)], r + 1)), B && g.push(o.createElement(e.FOOTER, {}, [b(B, r + 1)], r + 1)), o.createElement(e.BUBBLE, L, g, r);
340
+ case "box":
341
+ const { contents: w, background: d, ...O } = i;
342
+ O.layout || (O.layout = "vertical");
343
+ const T = [];
344
+ return a && T.push(a), d && T.push(b({ type: "background", ...d }, r + 1)), T.push(...(w || []).map((N) => b(N, r + 1))), o.createElement(e.BOX, O, T, r);
345
+ case "text":
346
+ const { text: U, contents: A, ...k } = i, x = A && A.length > 0 ? A.map((N) => b(N, r + 1)) : [U || ""];
347
+ return a && x.unshift(a), o.createElement(e.TEXT, k, x, r);
348
+ case "span":
349
+ const { text: D, ...X } = i, I = [D || ""];
350
+ return a && I.unshift(a), o.createElement(e.SPAN, X, I, r);
351
+ case "image":
352
+ const { ...$ } = i, G = a ? [a] : [];
353
+ return o.createElement(e.IMAGE, $, G, r);
354
+ case "video":
355
+ const { altContent: S, ...H } = i, v = S ? [b(S, r + 1)] : [];
356
+ return a && v.unshift(a), o.createElement(e.VIDEO, H, v, r);
357
+ case "icon":
358
+ const { ...F } = i, V = a ? [a] : [];
359
+ return o.createElement(e.ICON, F, V, r);
360
+ case "button":
361
+ const { ...M } = i, P = a ? [a] : [];
362
+ return o.createElement(e.BUTTON, M, P, r);
363
+ case "separator":
364
+ const K = a ? [a] : [];
365
+ return o.createElement(e.SEPARATOR, i, K, r);
366
+ case "filler":
367
+ const j = a ? [a] : [];
368
+ return o.createElement(e.FILLER, i, j, r);
369
+ // Action types
370
+ case "uri":
371
+ case "message":
372
+ case "postback":
373
+ case "datetimepicker":
374
+ case "camera":
375
+ case "cameraRoll":
376
+ case "location":
377
+ case "richmenuswitch":
378
+ case "clipboard":
379
+ return o.createElement(e.ACTION, { type: n, ...i }, [], r);
380
+ case "background":
381
+ return o.createElement(e.BACKGROUND, i, [], r);
382
+ default:
383
+ return "";
384
+ }
385
+ }
386
+ function nt(t) {
243
387
  try {
244
- return B(t).map(i);
245
- } catch (a) {
246
- throw console.error("Error converting HTML to Flex Message:", a), a;
388
+ return _(t).map(m);
389
+ } catch (r) {
390
+ throw console.error("Error converting HTML to Flex Message:", r), r;
247
391
  }
248
392
  }
249
393
  export {
250
- x as default
394
+ b as convertJsonToHtml,
395
+ nt as default
251
396
  };
@@ -1 +1,6 @@
1
- (function(u,h){typeof exports=="object"&&typeof module<"u"?h(exports,require("htmlparser2")):typeof define=="function"&&define.amd?define(["exports","htmlparser2"],h):(u=typeof globalThis<"u"?globalThis:u||self,h(u.FlexHtmlRender={},u.htmlparser2))})(this,(function(u,h){"use strict";const m={ELEMENT:"element",TEXT:"text"},e={CAROUSEL:"carousel",BUBBLE:"bubble",HEADER:"header",HERO:"hero",BODY:"body",FOOTER:"footer",BOX:"box",TEXT:"text",SPAN:"span",IMAGE:"image",VIDEO:"video",ICON:"icon",SEPARATOR:"separator",BUTTON:"button",SPACE:"space",STRONG:"strong",BASELINE:"baseline",ROW:"row",VERTICAL:"vertical",DIV:"div",ARTICLE:"article",ACTION:"action",BACKGROUND:"background"},N=[e.HEADER,e.HERO,e.BODY,e.FOOTER],p=[e.BOX,e.VERTICAL,e.ROW,e.BASELINE,e.DIV,e.ARTICLE],b=[e.TEXT,e.STRONG];function E(t){const r=Number(t);return isNaN(r)?t:r}function T(t){return t==="true"?!0:t==="false"?!1:t}function d(t){return[E,T].reduce((a,l)=>l(a),t)}function O(t){const r={type:"root",children:[]},a=[r],l=new h.Parser({onopentag(n,f){const g={type:m.ELEMENT,tagName:n,attributes:Object.fromEntries(Object.entries(f).map(([R,x])=>[R,d(x)])),children:[]};a[a.length-1].children.push(g),a.push(g)},ontext(n){n.trim()&&a[a.length-1].children.push({type:m.TEXT,content:n.replace(/\n/g,"").trim()})},onclosetag(){a.pop()},onerror(n){console.error("解析錯誤:",n)}},{xmlMode:!0,lowerCaseTags:!1,lowerCaseAttributeNames:!1});return l.write(t),l.end(),r.children}const s=t=>{throw Error(`[Flex Html Render]: ${t}`)},c={carousel:t=>({type:"carousel",contents:t}),bubble:(t={})=>({type:"bubble",...t}),box:(t,r={})=>({type:"box",contents:t,...r}),text:(t,r={})=>({type:"text",...typeof t=="string"?{text:t}:{contents:t},...r}),span:(t,r={})=>({type:"span",text:t,...r}),image:(t={})=>({type:"image",...t}),video:(t={})=>({type:"video",...t}),icon:(t={})=>({type:"icon",...t}),button:(t={})=>({type:"button",...t}),separator:(t={color:"#E0E3EA"})=>({type:"separator",...t}),uri:(t={})=>({type:"uri",altUri:t.altUri?{desktop:t.altUri}:void 0,...t})};function A(t){if(t.tagName!==e.BACKGROUND&&t.children&&t.children.length>0){const r=t.children.filter(a=>a.tagName===e.BACKGROUND);return r.length>1&&s("A box node can only allowed with one background node inside"),t.children=t.children.filter(a=>a.tagName!==e.BACKGROUND),r[0]}return null}function y(t){if(t.tagName!==e.ACTION&&t.children&&t.children.length>0){const r=t.children.filter(a=>a.tagName===e.ACTION);return r.length>1&&s("A node can only allowed with one action node inside"),t.children=t.children.filter(a=>a.tagName!==e.ACTION),r[0]}return null}function B(t){!b.includes(t.tagName)&&t.children?.some(n=>n.type===m.TEXT)&&s("Span component only allowed inside Text component"),t.tagName===e.VIDEO&&t.children?.some(n=>![e.BOX,e.IMAGE].includes(n.tagName))&&s("Video component only allowed Box or Image as altContent child"),!p.includes(t.tagName)&&t.children?.some(n=>n.tagName===e.BACKGROUND)&&s("Only Box component allowed to have Background child")}function i(t){t.attributes=t.attributes||{},B(t);const r=y(t);r&&(t.attributes.action=i(r));const a=A(t);if(a&&(t.attributes.background=i(a)),t.type===m.TEXT)return c.span(t.content,t.attributes);if(t.tagName===e.BUBBLE){const l=t.children.find(o=>o.tagName===e.HEADER),n=t.children.find(o=>o.tagName===e.HERO),f=t.children.find(o=>o.tagName===e.BODY),g=t.children.find(o=>o.tagName===e.FOOTER);return c.bubble({...t.attributes,header:l?i(l):void 0,hero:n?i(n):void 0,body:f?i(f):void 0,footer:g?i(g):void 0})}if(t.tagName===e.CAROUSEL)return t.children.some(l=>l.tagName!==e.BUBBLE)&&s("Carousel can only have Bubble as children"),t.children.length>12&&s("Carousel can have maximum 12 bubbles"),c.carousel(t.children.map(i));if(N.includes(t.tagName))return t.children.length!==1&&s(`${t.tagName} should have exactly one child node`),i(t.children[0]);if(t.tagName===e.BUTTON)return t.attributes.action||s("Button component should contain an action node"),c.button(t.attributes);if(t.tagName===e.SPAN){t.children.length>1&&s("Span component can only have one text child");const l=t.children[0];if(l&&l.type===m.TEXT)return c.span(l.content,t.attributes);s("Span component only allowed text child")}if(t.tagName===e.TEXT)return c.text(t.children.map(i),t.attributes);if(t.tagName===e.SEPARATOR)return c.separator(t.attributes);if(t.tagName===e.IMAGE)return c.image(t.attributes);if(t.tagName===e.VIDEO)return t.children.length!==1&&s("Video component should only has one Box or Image as altContent"),t.attributes.altContent=i(t.children[0]),c.video(t.attributes);if(t.tagName===e.ICON)return c.icon(t.attributes);if(t.tagName===e.BOX||t.tagName===e.DIV||t.tagName===e.ARTICLE)return t.attributes.layout||(t.attributes.layout="vertical"),c.box(t.children.map(i),t.attributes);if(t.tagName===e.SPACE)return c.span(" ".repeat(t.attributes.size||1));if(t.tagName===e.STRONG)return t.tagName=e.TEXT,t.attributes.weight="bold",i(t);if(t.tagName===e.BASELINE)return t.tagName=e.BOX,t.attributes.layout="baseline",i(t);if(t.tagName===e.ROW)return t.tagName=e.BOX,t.attributes.layout="horizontal",i(t);if(t.tagName===e.VERTICAL)return t.tagName=e.BOX,t.attributes.layout="vertical",i(t);if(t.tagName===e.ACTION&&t.attributes.type==="uri")return c.uri(t.attributes);if(t.tagName===e.BACKGROUND)return t.attributes}function C(t){try{return O(t).map(i)}catch(r){throw console.error("Error converting HTML to Flex Message:",r),r}}u.default=C,Object.defineProperties(u,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
1
+ (function(b,T){typeof exports=="object"&&typeof module<"u"?T(exports,require("htmlparser2")):typeof define=="function"&&define.amd?define(["exports","htmlparser2"],T):(b=typeof globalThis<"u"?globalThis:b||self,T(b.FlexHtmlRender={},b.htmlparser2))})(this,(function(b,T){"use strict";const E={ELEMENT:"element",TEXT:"text"},e={CAROUSEL:"carousel",BUBBLE:"bubble",HEADER:"header",HERO:"hero",BODY:"body",FOOTER:"footer",BOX:"box",TEXT:"text",SPAN:"span",IMAGE:"image",VIDEO:"video",ICON:"icon",SEPARATOR:"separator",BUTTON:"button",FILLER:"filler",SPACE:"space",STRONG:"strong",BASELINE:"baseline",ROW:"row",VERTICAL:"vertical",DIV:"div",ARTICLE:"article",ACTION:"action",BACKGROUND:"background"},U=[e.HEADER,e.HERO,e.BODY,e.FOOTER],k=[e.BOX,e.VERTICAL,e.ROW,e.BASELINE,e.DIV,e.ARTICLE],D=[e.TEXT,e.STRONG];function X(t){const r=Number(t);return isNaN(r)?t:r}function $(t){return t==="true"?!0:t==="false"?!1:t}function H(t){return[X,$].reduce((n,s)=>s(n),t)}function G(t){const r={type:"root",children:[]},n=[r],s=new T.Parser({onopentag(l,i){const a={type:E.ELEMENT,tagName:l,attributes:Object.fromEntries(Object.entries(i).map(([h,g])=>[h,H(g)])),children:[]};n[n.length-1].children.push(a),n.push(a)},ontext(l){const i=n[n.length-1];if(i.tagName==="span"){i.children.push({type:E.TEXT,content:l});return}l.trim()&&i.children.push({type:E.TEXT,content:l.replace(/\n/g,"").trim()})},onclosetag(){n.pop()},onerror(l){console.error("解析錯誤:",l)}},{xmlMode:!0,lowerCaseTags:!1,lowerCaseAttributeNames:!1});return s.write(t),s.end(),r.children}const p=t=>{throw Error(`[Flex Html Render]: ${t}`)},c={carousel:t=>({type:"carousel",contents:t}),bubble:(t={})=>({type:"bubble",...t}),box:(t,r={})=>({type:"box",contents:t,...r}),text:(t,r={})=>({type:"text",...typeof t=="string"?{text:t}:{contents:t},...r}),span:(t,r={})=>({type:"span",text:t,...r}),image:(t={})=>({type:"image",...t}),video:(t={})=>({type:"video",...t}),icon:(t={})=>({type:"icon",...t}),button:(t={})=>({type:"button",...t}),separator:(t={color:"#E0E3EA"})=>({type:"separator",...t}),filler:(t={})=>({type:"filler",...t}),uri:(t={})=>({type:"uri",altUri:t.altUri?{desktop:t.altUri}:void 0,...t}),postback:(t={})=>({type:"postback",...t}),message:(t={})=>({type:"message",...t}),datetimepicker:(t={})=>({type:"datetimepicker",...t}),camera:(t={})=>({type:"camera",...t}),cameraRoll:(t={})=>({type:"cameraRoll",...t}),location:(t={})=>({type:"location",...t}),richmenuswitch:(t={})=>({type:"richmenuswitch",...t}),clipboard:(t={})=>({type:"clipboard",...t})};function F(t){if(t.tagName!==e.BACKGROUND&&t.children&&t.children.length>0){const r=t.children.filter(n=>n.tagName===e.BACKGROUND);return r.length>1&&p("A box node can only allowed with one background node inside"),t.children=t.children.filter(n=>n.tagName!==e.BACKGROUND),r[0]}return null}function M(t){if(t.tagName!==e.ACTION&&t.children&&t.children.length>0){const r=t.children.filter(n=>n.tagName===e.ACTION);return r.length>1&&p("A node can only allowed with one action node inside"),t.children=t.children.filter(n=>n.tagName!==e.ACTION),r[0]}return null}function P(t){![...D,e.SPAN].includes(t.tagName)&&t.children?.some(l=>l.type===E.TEXT)&&(console.log(t),p("Span component only allowed inside Text component")),t.tagName===e.VIDEO&&t.children?.some(l=>![e.BOX,e.IMAGE].includes(l.tagName))&&p("Video component only allowed Box or Image as altContent child"),!k.includes(t.tagName)&&t.children?.some(l=>l.tagName===e.BACKGROUND)&&p("Only Box component allowed to have Background child")}function u(t){t.attributes=t.attributes||{},P(t);const r=M(t);r&&(t.attributes.action=u(r));const n=F(t);if(n&&(t.attributes.background=u(n)),t.type===E.TEXT)return c.span(t.content,t.attributes);if(t.tagName===e.BUBBLE){const s=t.children.find(m=>m.tagName===e.HEADER),l=t.children.find(m=>m.tagName===e.HERO),i=t.children.find(m=>m.tagName===e.BODY),a=t.children.find(m=>m.tagName===e.FOOTER);return c.bubble({...t.attributes,header:s?u(s):void 0,hero:l?u(l):void 0,body:i?u(i):void 0,footer:a?u(a):void 0})}if(t.tagName===e.CAROUSEL)return t.children.some(s=>s.tagName!==e.BUBBLE)&&p("Carousel can only have Bubble as children"),t.children.length>12&&p("Carousel can have maximum 12 bubbles"),c.carousel(t.children.map(u));if(U.includes(t.tagName))return t.children.length!==1&&p(`${t.tagName} should have exactly one child node`),u(t.children[0]);if(t.tagName===e.BUTTON)return t.attributes.action||p("Button component should contain an action node"),c.button(t.attributes);if(t.tagName===e.SPAN){t.children.length>1&&p("Span component can only have one text child");const s=t.children[0];if(s&&s.type===E.TEXT)return c.span(s.content,t.attributes);p(s?"Span component only allowed text child":"Span component can not be empty")}if(t.tagName===e.TEXT)return c.text(t.children.map(u),t.attributes);if(t.tagName===e.SEPARATOR)return c.separator(t.attributes);if(t.tagName===e.IMAGE)return c.image(t.attributes);if(t.tagName===e.VIDEO)return t.children.length!==1&&p("Video component should only has one Box or Image as altContent"),t.attributes.altContent=u(t.children[0]),c.video(t.attributes);if(t.tagName===e.ICON)return c.icon(t.attributes);if(t.tagName===e.FILLER)return c.filler(t.attributes);if(t.tagName===e.BOX||t.tagName===e.DIV||t.tagName===e.ARTICLE)return t.attributes.layout||(t.attributes.layout="vertical"),c.box(t.children.map(u),t.attributes);if(t.tagName===e.SPACE)return c.span(" ".repeat(t.attributes.size||1));if(t.tagName===e.STRONG)return t.tagName=e.TEXT,t.attributes.weight="bold",u(t);if(t.tagName===e.BASELINE)return t.tagName=e.BOX,t.attributes.layout="baseline",u(t);if(t.tagName===e.ROW)return t.tagName=e.BOX,t.attributes.layout="horizontal",u(t);if(t.tagName===e.VERTICAL)return t.tagName=e.BOX,t.attributes.layout="vertical",u(t);if(t.tagName===e.ACTION){const s=t.attributes.type;switch(s){case"uri":return c.uri(t.attributes);case"postback":return c.postback(t.attributes);case"message":return c.message(t.attributes);case"datetimepicker":return c.datetimepicker(t.attributes);case"camera":return c.camera(t.attributes);case"cameraRoll":return c.cameraRoll(t.attributes);case"location":return c.location(t.attributes);case"richmenuswitch":return c.richmenuswitch(t.attributes);case"clipboard":return c.clipboard(t.attributes);default:p(`Unsupported action type: ${s}`)}}if(t.tagName===e.BACKGROUND)return t.attributes}const o={createElement:(t,r={},n=[],s=0)=>{const i=Object.entries(r).filter(([m,h])=>h!=null).map(([m,h])=>typeof h=="object"?`${m}="${JSON.stringify(h).replace(/"/g,"&quot;")}"`:`${m}="${h}"`).join(" "),a=i?` ${i}`:"";if(n.length===0)return` <${t}${a} />`;{const m=n.map(h=>typeof h=="string"?h.split(`
2
+ `).map(g=>g?" "+g:"").join(`
3
+ `):h).join(`
4
+ `);return` <${t}${a}>
5
+ ${m}
6
+ </${t}>`}},createText:t=>t};function f(t,r=0){if(!t||typeof t!="object")return"";const{type:n,...s}=t,{action:l,...i}=s,a=l?f(l,r+1):"";switch(n){case"carousel":const{contents:m,...h}=i,g=m.map(O=>f(O,r+1));return a&&g.unshift(a),o.createElement(e.CAROUSEL,h,g,r);case"bubble":const{header:d,hero:R,body:B,footer:x,...j}=i,N=[];return a&&N.push(a),d&&N.push(o.createElement(e.HEADER,{},[f(d,r+1)],r+1)),R&&N.push(o.createElement(e.HERO,{},[f(R,r+1)],r+1)),B&&N.push(o.createElement(e.BODY,{},[f(B,r+1)],r+1)),x&&N.push(o.createElement(e.FOOTER,{},[f(x,r+1)],r+1)),o.createElement(e.BUBBLE,j,N,r);case"box":const{contents:K,background:S,...A}=i;A.layout||(A.layout="vertical");const y=[];return a&&y.push(a),S&&y.push(f({type:"background",...S},r+1)),y.push(...(K||[]).map(O=>f(O,r+1))),o.createElement(e.BOX,A,y,r);case"text":const{text:J,contents:C,...Y}=i,I=C&&C.length>0?C.map(O=>f(O,r+1)):[J||""];return a&&I.unshift(a),o.createElement(e.TEXT,Y,I,r);case"span":const{text:W,...q}=i,v=[W||""];return a&&v.unshift(a),o.createElement(e.SPAN,q,v,r);case"image":const{...z}=i,_=a?[a]:[];return o.createElement(e.IMAGE,z,_,r);case"video":const{altContent:L,...Q}=i,w=L?[f(L,r+1)]:[];return a&&w.unshift(a),o.createElement(e.VIDEO,Q,w,r);case"icon":const{...Z}=i,tt=a?[a]:[];return o.createElement(e.ICON,Z,tt,r);case"button":const{...et}=i,rt=a?[a]:[];return o.createElement(e.BUTTON,et,rt,r);case"separator":const at=a?[a]:[];return o.createElement(e.SEPARATOR,i,at,r);case"filler":const nt=a?[a]:[];return o.createElement(e.FILLER,i,nt,r);case"uri":case"message":case"postback":case"datetimepicker":case"camera":case"cameraRoll":case"location":case"richmenuswitch":case"clipboard":return o.createElement(e.ACTION,{type:n,...i},[],r);case"background":return o.createElement(e.BACKGROUND,i,[],r);default:return""}}function V(t){try{return G(t).map(u)}catch(r){throw console.error("Error converting HTML to Flex Message:",r),r}}b.convertJsonToHtml=f,b.default=V,Object.defineProperties(b,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
package/index.d.ts CHANGED
@@ -3,9 +3,4 @@
3
3
  * @param htmlString - Flex Message 對應的 HTML 字串
4
4
  * @returns Flex Message JSON 物件陣列
5
5
  */
6
- export default function convertHtmlToFlexMessage(htmlString: string): any[];
7
-
8
- /**
9
- * 官方範例 HTML 字串
10
- */
11
- export const officialDemoString: string;
6
+ export default function convertHtmlToFlexMessage(htmlString: string): any[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flex-html-render",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "將 HTML 字串轉換為 LINE Flex Message JSON 結構的工具",
5
5
  "type": "module",
6
6
  "main": "dist/flex-html-render.cjs.js",