@doubao-apps/template 0.0.31 → 0.0.32

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.
Files changed (50) hide show
  1. package/README.md +231 -109
  2. package/assets/order-card.png +0 -0
  3. package/assets/product-action-card.png +0 -0
  4. package/assets/ticket-order-card.png +0 -0
  5. package/assets/transport-card.png +0 -0
  6. package/assets/transport-list-card.png +0 -0
  7. package/dist/components/action-bar/index.d.ts +19 -0
  8. package/dist/components/action-bar/index.js +15 -0
  9. package/dist/components/action-bar/styles.css +30 -0
  10. package/dist/components/info-section/index.d.ts +47 -0
  11. package/dist/components/info-section/index.js +93 -0
  12. package/dist/components/info-section/styles.css +140 -0
  13. package/dist/components/product-summary/index.d.ts +24 -0
  14. package/dist/components/product-summary/index.js +51 -0
  15. package/dist/components/product-summary/styles.css +125 -0
  16. package/dist/components/route-section/index.d.ts +23 -0
  17. package/dist/components/route-section/index.js +38 -0
  18. package/dist/components/route-section/styles.css +58 -0
  19. package/dist/components/title-bar/index.d.ts +11 -0
  20. package/dist/components/title-bar/index.js +32 -0
  21. package/dist/components/title-bar/styles.css +69 -0
  22. package/dist/components/transport-summary/index.d.ts +31 -0
  23. package/dist/components/transport-summary/index.js +104 -0
  24. package/dist/components/transport-summary/styles.css +182 -0
  25. package/dist/index.d.ts +5 -0
  26. package/dist/index.js +4 -0
  27. package/dist/invalid-card/index.js +2 -20
  28. package/dist/invalid-card/styles.css +1 -65
  29. package/dist/list-card/index.d.ts +3 -2
  30. package/dist/list-card/index.js +2 -20
  31. package/dist/list-card/styles.css +0 -72
  32. package/dist/order-card/index.d.ts +7 -6
  33. package/dist/order-card/index.js +9 -106
  34. package/dist/order-card/styles.css +6 -368
  35. package/dist/product-action-card/index.d.ts +40 -0
  36. package/dist/product-action-card/index.js +17 -0
  37. package/dist/product-action-card/styles.css +20 -0
  38. package/dist/ticket-order-card/index.d.ts +78 -0
  39. package/dist/ticket-order-card/index.js +27 -0
  40. package/dist/ticket-order-card/styles.css +18 -0
  41. package/dist/transport-card/index.d.ts +36 -0
  42. package/dist/transport-card/index.js +15 -0
  43. package/dist/transport-card/styles.css +21 -0
  44. package/dist/transport-list-card/index.d.ts +56 -0
  45. package/dist/transport-list-card/index.js +32 -0
  46. package/dist/transport-list-card/styles.css +60 -0
  47. package/dist/types.d.ts +3 -0
  48. package/dist/types.js +0 -0
  49. package/dist/utils/app-info.js +1 -2
  50. package/package.json +2 -6
package/README.md CHANGED
@@ -5,41 +5,28 @@ Doubao Apps Widget 模板库,用于快速开发卡片类 widget。模板会把
5
5
  模板适合用在 widget 的 `render` 中。通常一个 widget 对应一张卡片,建议直接返回模板组件,不额外包裹无意义的 `view` / `scroll-view`:
6
6
 
7
7
  ```tsx
8
- import { defineWidget } from '@doubao-apps/framework';
9
8
  import { ListCard } from '@doubao-apps/template';
10
9
 
11
- export default defineWidget({
12
- aiMeta: {
13
- id: 'product-list',
14
- name: '商品列表',
15
- description: '展示商品列表卡片',
16
- border: true
17
- },
18
- render() {
19
- return (
20
- <ListCard
21
- items={[
22
- {
23
- title: '主标题',
24
- price: '4199',
25
- priceUnit: '元',
26
- description: '商品描述商品描述',
27
- imageSrc: 'https://example.com/product.png'
28
- },
29
- {
30
- title: '第二个商品',
31
- price: '299',
32
- priceUnit: '元',
33
- description: '商品描述商品描述'
34
- }
35
- ]}
36
- onViewMoreClick={() => {
37
- console.log('view more');
38
- }}
39
- />
40
- );
41
- }
42
- });
10
+ <ListCard
11
+ items={[
12
+ {
13
+ title: '主标题',
14
+ price: '4199',
15
+ priceUnit: '元',
16
+ description: '商品描述商品描述',
17
+ imageSrc: 'https://example.com/product.png'
18
+ },
19
+ {
20
+ title: '第二个商品',
21
+ price: '299',
22
+ priceUnit: '',
23
+ description: '商品描述商品描述'
24
+ }
25
+ ]}
26
+ onViewMoreClick={() => {
27
+ console.log('view more');
28
+ }}
29
+ />
43
30
  ```
44
31
 
45
32
  如果只是验证 UI 效果,也可以在普通页面里直接渲染模板组件;但真实卡片接入建议优先按 widget 方式组织。
@@ -51,34 +38,30 @@ export default defineWidget({
51
38
  ```tsx
52
39
  import { ListCard } from '@doubao-apps/template';
53
40
 
54
- export default function Page() {
55
- return (
56
- <ListCard
57
- items={[
58
- {
59
- title: '主标题',
60
- price: '4199',
61
- priceUnit: '',
62
- description: '商品描述商品描述',
63
- imageSrc: 'https://example.com/product.png',
64
- actionText: '下单'
65
- },
66
- {
67
- title: '第二个商品',
68
- price: '299',
69
- priceUnit: '元',
70
- description: '商品描述商品描述'
71
- }
72
- ]}
73
- onViewMoreClick={() => {
74
- console.log('view more');
75
- }}
76
- onMoreClick={() => {
77
- console.log('more');
78
- }}
79
- />
80
- );
81
- }
41
+ <ListCard
42
+ items={[
43
+ {
44
+ title: '主标题',
45
+ price: '4199',
46
+ priceUnit: '',
47
+ description: '商品描述商品描述',
48
+ imageSrc: 'https://example.com/product.png',
49
+ actionText: '下单'
50
+ },
51
+ {
52
+ title: '第二个商品',
53
+ price: '299',
54
+ priceUnit: '',
55
+ description: '商品描述商品描述'
56
+ }
57
+ ]}
58
+ onViewMoreClick={() => {
59
+ console.log('view more');
60
+ }}
61
+ onMoreClick={() => {
62
+ console.log('more');
63
+ }}
64
+ />
82
65
  ```
83
66
 
84
67
  说明:
@@ -93,41 +76,43 @@ export default function Page() {
93
76
 
94
77
  `OrderCard` 是提单卡模板,结构包含应用标题栏、商品摘要、提单信息、费用汇总和底部操作按钮,适合下单确认、支付确认等场景。
95
78
 
79
+ 效果图:
80
+
81
+ <img src="https://unpkg.com/@doubao-apps/template@latest/assets/order-card.png" alt="OrderCard 示例" width="400" />
82
+
83
+ <p />
84
+
96
85
  ```tsx
97
86
  import { OrderCard } from '@doubao-apps/template';
98
87
 
99
- export default function Page() {
100
- return (
101
- <OrderCard
102
- productTitle="主标题"
103
- productSpec="商品规格商品规格"
104
- productPrice="¥5.8"
105
- productQuantity="1"
106
- infoItems={[
107
- {
108
- label: '提单信息',
109
- value: '信息字段最多支持 2 行',
110
- valueExtra: '信息字段最多支持 2 行'
111
- },
112
- {
113
- label: '提单信息',
114
- value: '信息字段最多支持 2 行'
115
- }
116
- ]}
117
- feeItems={[
118
- { label: '运费', value: '¥3.0' },
119
- { label: '打包费', value: '¥1.0' }
120
- ]}
121
- totalPrice="¥9.8"
122
- onPrimaryActionClick={() => {
123
- console.log('pay');
124
- }}
125
- onSecondaryActionClick={() => {
126
- console.log('edit');
127
- }}
128
- />
129
- );
130
- }
88
+ <OrderCard
89
+ productTitle="主标题"
90
+ productSpec="商品规格商品规格"
91
+ productPrice="¥5.8"
92
+ productQuantity="1"
93
+ infoItems={[
94
+ {
95
+ label: '提单信息',
96
+ value: '信息字段最多支持 2 行',
97
+ valueExtra: '信息字段最多支持 2 行'
98
+ },
99
+ {
100
+ label: '提单信息',
101
+ value: '信息字段最多支持 2 行'
102
+ }
103
+ ]}
104
+ feeItems={[
105
+ { label: '运费', value: '¥3.0' },
106
+ { label: '打包费', value: '¥1.0' }
107
+ ]}
108
+ totalPrice="¥9.8"
109
+ onPrimaryActionClick={() => {
110
+ console.log('pay');
111
+ }}
112
+ onSecondaryActionClick={() => {
113
+ console.log('edit');
114
+ }}
115
+ />
131
116
  ```
132
117
 
133
118
  说明:
@@ -138,26 +123,163 @@ export default function Page() {
138
123
  - `primaryActionText` 和 `secondaryActionText` 可以自定义底部操作按钮文案。
139
124
  - 用在 widget 中时,推荐让 `render` 直接返回 `OrderCard`。
140
125
 
141
- ## InvalidCard
142
126
 
143
- `InvalidCard` 是失效卡模板,结构包含应用标题栏和失效状态内容行,适合任务状态变化、卡片过期、服务不可用等场景。
127
+ ## ProductActionCard
128
+
129
+ `ProductActionCard` 是商品操作卡模板,结构包含应用标题栏、商品摘要和底部主按钮,适合商品确认、下单入口等场景。
130
+
131
+ 效果图:
132
+
133
+ <img src="https://unpkg.com/@doubao-apps/template@latest/assets/product-action-card.png" alt="ProductActionCard 示例" width="400" />
134
+
135
+ <p />
136
+
137
+ ```tsx
138
+ import { ProductActionCard } from '@doubao-apps/template';
139
+
140
+ <ProductActionCard
141
+ productTitle="主标题"
142
+ productSpec="商品规格等描述信息"
143
+ productImageSrc="https://example.com/product.png"
144
+ productPrice="¥99"
145
+ productQuantity="1"
146
+ primaryActionText="主按钮"
147
+ onPrimaryActionClick={() => {
148
+ console.log('primary action');
149
+ }}
150
+ />
151
+ ```
152
+
153
+ 说明:
154
+
155
+ - `productTitle`、`productSpec`、`productImageSrc`、`productPrice`、`productQuantity` 用于配置商品摘要。
156
+ - `productImage` 可以传入自定义图片节点,优先级高于 `productImageSrc`。
157
+ - `primaryActionText` 用于配置底部主按钮文案。
158
+
159
+ ## TransportCard
160
+
161
+ `TransportCard` 是交通票务卡模板,结构包含应用标题栏、行程标题、出发/到达信息、中转信息和价格信息,适合机票、火车票、大巴等交通工具票务卡片。
162
+
163
+ 效果图:
164
+
165
+ <img src="https://unpkg.com/@doubao-apps/template@latest/assets/transport-card.png" alt="TransportCard 示例" width="400" />
166
+
167
+ <p />
168
+
169
+ ```tsx
170
+ import { TransportCard } from '@doubao-apps/template';
171
+
172
+ <TransportCard
173
+ title="北京南 - 上海虹桥"
174
+ departureMain="08:00"
175
+ departureSub="北京南"
176
+ transferTop="直达"
177
+ showTransferDot
178
+ arrivalMain="12:32"
179
+ arrivalDayOffset="+1"
180
+ arrivalSub="上海虹桥"
181
+ price="¥553"
182
+ onClick={() => {
183
+ console.log('transport card');
184
+ }}
185
+ />
186
+ ```
187
+
188
+ 说明:
189
+
190
+ - `departureMain`、`departureSub`、`transferTop`、`transferBottom`、`arrivalMain`、`arrivalDayOffset`、`arrivalSub` 仅接收字符串或数字。
191
+ - `title`、`transfer`、`price` 接收 `ReactNode`,用于需要自定义灰色块或整块区域的场景。
192
+ - `showTransferDot` 用于切换中转箭头的中间圆点样式。
193
+
194
+ ## TransportListCard
195
+
196
+ `TransportListCard` 是交通票务列表卡模板,结构包含应用标题栏、多条出发/到达信息和底部「查看更多」按钮,适合展示机票、火车票、大巴等交通工具推荐列表。
197
+
198
+ 效果图:
199
+
200
+ <img src="https://unpkg.com/@doubao-apps/template@latest/assets/transport-list-card.png" alt="TransportListCard 示例" width="400" />
201
+
202
+ <p />
203
+
144
204
 
145
205
  ```tsx
146
- import { InvalidCard } from '@doubao-apps/template';
147
-
148
- export default function Page() {
149
- return (
150
- <InvalidCard
151
- title="任务状态已更新"
152
- onClick={() => {
153
- console.log('invalid card');
154
- }}
155
- />
156
- );
157
- }
206
+ import { TransportListCard } from '@doubao-apps/template';
207
+
208
+ <TransportListCard
209
+ items={[
210
+ {
211
+ title: '北京南 - 上海虹桥',
212
+ departureMain: '11:20',
213
+ departureSub: '出发地',
214
+ arrivalMain: '16:00',
215
+ arrivalDayOffset: '+1',
216
+ arrivalSub: '到达地',
217
+ price: '¥553'
218
+ },
219
+ {
220
+ title: '北京南 - 上海虹桥',
221
+ departureMain: '11:20',
222
+ departureSub: '出发地',
223
+ arrivalMain: '16:00',
224
+ arrivalDayOffset: '+1',
225
+ arrivalSub: '到达地',
226
+ price: '¥553'
227
+ }
228
+ ]}
229
+ onViewMoreClick={() => {
230
+ console.log('view more');
231
+ }}
232
+ />
158
233
  ```
159
234
 
160
235
  说明:
161
236
 
162
- - `title` 用于配置失效状态文案。
163
- - 用在 widget 中时,推荐让 `render` 直接返回 `InvalidCard`。
237
+ - `items` 超过 4 条时,默认只展示前 4 条,并在底部展示「查看更多」按钮。
238
+ - 可以通过 `viewMoreText` `onViewMoreClick` 自定义「查看更多」按钮文案和点击行为。
239
+ - 每个列表项可以通过 `arrivalDayOffset` 展示到达时间右上角日期偏移,例如 `+1`。
240
+ - 每个列表项的 `title`、`transfer`、`price` 接收 `ReactNode`,用于需要自定义灰色块或整块区域的场景。
241
+
242
+ ## TicketOrderCard
243
+
244
+ `TicketOrderCard` 是提单卡模板,结构包含应用标题栏、往返航程、订单信息、费用汇总和底部操作按钮,适合机票预订、改签确认等场景。
245
+
246
+ 效果图:
247
+
248
+ <img src="https://unpkg.com/@doubao-apps/template@latest/assets/ticket-order-card.png" alt="TicketOrderCard 示例" width="400" />
249
+
250
+ <p />
251
+
252
+ ```tsx
253
+ import { TicketOrderCard } from '@doubao-apps/template';
254
+
255
+ <TicketOrderCard
256
+ routeItems={[
257
+ {
258
+ title: '出发地 - 到达地',
259
+ description: '6月1日 周六 20:50-23:50 CZ0000 经济舱'
260
+ },
261
+ {
262
+ title: '到达地 - 出发地',
263
+ description: '6月3日 周一 14:50-18:50 CZ0001 经济舱'
264
+ }
265
+ ]}
266
+ infoItems={[
267
+ { label: '订单信息1', value: '信息字段', valueExtra: '信息字段' },
268
+ { label: '订单信息2', value: '信息字段' }
269
+ ]}
270
+ feeItems={[
271
+ { label: '明细1', value: '¥1064' },
272
+ { label: '明细2', value: '¥440' }
273
+ ]}
274
+ totalLabel="合计"
275
+ totalPrice="¥1504"
276
+ secondaryActionText="次按钮"
277
+ primaryActionText="主按钮"
278
+ onSecondaryActionClick={() => {
279
+ console.log('secondary action');
280
+ }}
281
+ onPrimaryActionClick={() => {
282
+ console.log('primary action');
283
+ }}
284
+ />
285
+ ```
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,19 @@
1
+ import type { CSSProperties, TouchEvent } from '@lynx-js/types';
2
+ import type { ReactElement } from 'react';
3
+ import './styles.scss';
4
+ export interface TemplateActionBarProps {
5
+ /** 操作区根节点自定义类名。 */
6
+ className?: string;
7
+ /** 操作区根节点自定义样式。 */
8
+ style?: CSSProperties;
9
+ /** 主按钮文案。 */
10
+ primaryActionText?: string;
11
+ /** 次按钮文案。 */
12
+ secondaryActionText?: string;
13
+ /** 点击主按钮时触发。 */
14
+ onPrimaryActionClick?: (event?: TouchEvent) => void;
15
+ /** 点击次按钮时触发。 */
16
+ onSecondaryActionClick?: (event?: TouchEvent) => void;
17
+ }
18
+ export declare function TemplateActionBar(props: TemplateActionBarProps): ReactElement | null;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,15 @@
1
+ import { Button } from "@byted-doubao-apps/components";
2
+ import { clsx } from "clsx";
3
+ import "./styles.css";
4
+ function TemplateActionBar(props) {
5
+ const { className, style, primaryActionText, secondaryActionText, onPrimaryActionClick, onSecondaryActionClick } = props;
6
+ const hasPrimaryAction = null != primaryActionText && primaryActionText.length > 0;
7
+ const hasSecondaryAction = null != secondaryActionText && secondaryActionText.length > 0;
8
+ const hasDefaultActions = hasPrimaryAction || hasSecondaryAction;
9
+ if (!hasDefaultActions) return null;
10
+ return <view className={clsx('doubao-template-action-bar', className)} style={style}>
11
+ {hasSecondaryAction ? <Button className="doubao-template-action-bar__action" type="default" text={secondaryActionText} onClick={onSecondaryActionClick}/> : null}
12
+ {hasPrimaryAction ? <Button className="doubao-template-action-bar__action" type="primary" text={primaryActionText} onClick={onPrimaryActionClick}/> : null}
13
+ </view>;
14
+ }
15
+ export { TemplateActionBar };
@@ -0,0 +1,30 @@
1
+ .doubao-template-action-bar {
2
+ width: 100%;
3
+ padding: var(--doubao-template-action-bar-padding, 8px 12px 12px);
4
+ box-sizing: border-box;
5
+ flex-direction: row;
6
+ display: flex;
7
+ }
8
+
9
+ .doubao-template-action-bar__action {
10
+ width: auto;
11
+ height: var(--doubao-template-action-bar-button-height, 44px);
12
+ border-radius: var(--doubao-template-action-bar-button-radius, 8px);
13
+ --doubao-btn-border-radius: var(--doubao-template-action-bar-button-radius, 8px);
14
+ --doubao-btn-default-height: var(--doubao-template-action-bar-button-height, 44px);
15
+ --doubao-btn-default-padding-x: var(--doubao-template-action-bar-button-padding-x, 12px);
16
+ --doubao-btn-default-padding-y: 0;
17
+ --doubao-btn-default-font-size: var(--doubao-template-action-bar-button-font-size, 16px);
18
+ --doubao-btn-default-line-height: var(--doubao-template-action-bar-button-line-height, 22px);
19
+ --doubao-btn-primary-bg: var(--doubao-template-action-bar-primary-bg, var(--primary-50));
20
+ --doubao-btn-primary-text: var(--doubao-template-action-bar-primary-text, var(--static-white));
21
+ --doubao-btn-default-bg: var(--doubao-template-action-bar-secondary-bg, var(--bg-base-2-overlay));
22
+ --doubao-btn-default-text: var(--doubao-template-action-bar-secondary-text, var(--neutral-100));
23
+ flex: 1 1 0;
24
+ min-width: 0;
25
+ }
26
+
27
+ .doubao-template-action-bar__action + .doubao-template-action-bar__action {
28
+ margin-left: var(--doubao-template-action-bar-gap, 10px);
29
+ }
30
+
@@ -0,0 +1,47 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+ import type { TemplateKey, TemplateText } from '../../types.js';
3
+ import './styles.scss';
4
+ export interface TemplateInfoSectionProps {
5
+ /** 信息行列表。 */
6
+ infoItems?: TemplateInfoSectionInfoItem[];
7
+ /** 费用明细列表。 */
8
+ feeItems?: TemplateInfoSectionFeeItem[];
9
+ /** 优惠信息文案。 */
10
+ discountText?: TemplateText;
11
+ /** 合计价格前的标签文案。 */
12
+ totalLabel?: TemplateText;
13
+ /** 合计价格。 */
14
+ totalPrice?: TemplateText;
15
+ /** 合计区域自定义内容;优先级高于 totalLabel 和 totalPrice。 */
16
+ totalContent?: ReactNode;
17
+ /** 信息值排列方式。 */
18
+ valueLayout?: 'row' | 'column';
19
+ }
20
+ export interface TemplateInfoSectionInfoItem {
21
+ /** 信息项唯一标识;不传时使用数组下标。 */
22
+ key?: TemplateKey;
23
+ /** 信息项标签。 */
24
+ label?: TemplateText;
25
+ /** 信息项标签块内容;优先级高于 label。 */
26
+ labelContent?: ReactNode;
27
+ /** 信息项主内容。 */
28
+ value?: ReactNode;
29
+ /** 信息项主内容块内容;优先级高于 value。 */
30
+ valueContent?: ReactNode;
31
+ /** 信息项补充内容。 */
32
+ valueExtra?: ReactNode;
33
+ /** 信息项补充内容块内容;优先级高于 valueExtra。 */
34
+ valueExtraContent?: ReactNode;
35
+ }
36
+ export interface TemplateInfoSectionFeeItem {
37
+ /** 费用项唯一标识;不传时使用数组下标。 */
38
+ key?: TemplateKey;
39
+ /** 费用项标签。 */
40
+ label?: TemplateText;
41
+ /** 费用项金额或数值。 */
42
+ value?: TemplateText;
43
+ /** 费用项自定义内容;优先级高于 label 和 value。 */
44
+ content?: ReactNode;
45
+ }
46
+ export declare function TemplateInfoSection(props: TemplateInfoSectionProps): ReactElement | null;
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,93 @@
1
+ import { clsx } from "clsx";
2
+ import "./styles.css";
3
+ function isTemplateInfoSectionNodeEmpty(content) {
4
+ return null == content || 'boolean' == typeof content || '' === content;
5
+ }
6
+ function isTemplateInfoSectionTextEmpty(content) {
7
+ return null == content || '' === content;
8
+ }
9
+ function renderTemplateInfoSectionNode(textContent, nodeContent, textClassName, maxLines = 1) {
10
+ if (void 0 !== nodeContent) {
11
+ if (isTemplateInfoSectionNodeEmpty(nodeContent)) return null;
12
+ if ('string' == typeof nodeContent || 'number' == typeof nodeContent) return <text className={textClassName} text-maxline={maxLines}>
13
+ {nodeContent}
14
+ </text>;
15
+ return nodeContent;
16
+ }
17
+ if (isTemplateInfoSectionNodeEmpty(textContent)) return null;
18
+ if ('string' == typeof textContent || 'number' == typeof textContent) return <text className={textClassName} text-maxline={maxLines}>
19
+ {textContent}
20
+ </text>;
21
+ return textContent;
22
+ }
23
+ function hasTemplateInfoSectionInfoItemContent(item) {
24
+ return !isTemplateInfoSectionTextEmpty(item.label) || !isTemplateInfoSectionNodeEmpty(item.labelContent) || !isTemplateInfoSectionNodeEmpty(item.value) || !isTemplateInfoSectionNodeEmpty(item.valueContent) || !isTemplateInfoSectionNodeEmpty(item.valueExtra) || !isTemplateInfoSectionNodeEmpty(item.valueExtraContent);
25
+ }
26
+ function renderTemplateInfoSectionInfoItem(item, index) {
27
+ if (!hasTemplateInfoSectionInfoItemContent(item)) return null;
28
+ const labelNode = renderTemplateInfoSectionNode(item.label, item.labelContent, 'doubao-template-info-section__info-label');
29
+ const valueNode = renderTemplateInfoSectionNode(item.value, item.valueContent, 'doubao-template-info-section__info-value', 2);
30
+ const valueExtraNode = renderTemplateInfoSectionNode(item.valueExtra, item.valueExtraContent, 'doubao-template-info-section__info-value', 2);
31
+ return <view className="doubao-template-info-section__info-row" key={item.key ?? index}>
32
+ <view className="doubao-template-info-section__info-label-wrap">{labelNode}</view>
33
+ <view className="doubao-template-info-section__info-value-wrap">
34
+ {valueNode}
35
+ {valueExtraNode}
36
+ </view>
37
+ </view>;
38
+ }
39
+ function renderTemplateInfoSectionFeeItem(item, index) {
40
+ if (void 0 !== item.content) {
41
+ if (isTemplateInfoSectionNodeEmpty(item.content)) return null;
42
+ return <view className="doubao-template-info-section__fee" key={item.key ?? index}>
43
+ {item.content}
44
+ </view>;
45
+ }
46
+ if (isTemplateInfoSectionTextEmpty(item.label) && isTemplateInfoSectionTextEmpty(item.value)) return null;
47
+ return <text className="doubao-template-info-section__fee" text-maxline="1" key={item.key ?? index}>
48
+ {item.label}
49
+ {item.value}
50
+ </text>;
51
+ }
52
+ function renderTemplateInfoSectionTotal({ totalLabel, totalPrice, totalContent }) {
53
+ if (void 0 !== totalContent) {
54
+ if (isTemplateInfoSectionNodeEmpty(totalContent)) return null;
55
+ return <view className="doubao-template-info-section__total">{totalContent}</view>;
56
+ }
57
+ if (isTemplateInfoSectionTextEmpty(totalLabel) && isTemplateInfoSectionTextEmpty(totalPrice)) return null;
58
+ return <view className="doubao-template-info-section__total">
59
+ {!isTemplateInfoSectionTextEmpty(totalLabel) ? <text className="doubao-template-info-section__total-label" text-maxline="1">
60
+ {totalLabel}
61
+ </text> : null}
62
+ {!isTemplateInfoSectionTextEmpty(totalPrice) ? <text className="doubao-template-info-section__total-price" text-maxline="1">
63
+ {totalPrice}
64
+ </text> : null}
65
+ </view>;
66
+ }
67
+ function TemplateInfoSection(props) {
68
+ const { infoItems = [], feeItems = [], discountText, totalLabel, totalPrice, totalContent, valueLayout = 'row' } = props;
69
+ const infoNodes = infoItems.map(renderTemplateInfoSectionInfoItem).filter((node)=>null != node);
70
+ const feeNodes = feeItems.map(renderTemplateInfoSectionFeeItem).filter((node)=>null != node);
71
+ const hasDiscount = !isTemplateInfoSectionTextEmpty(discountText);
72
+ const totalNode = renderTemplateInfoSectionTotal({
73
+ totalLabel,
74
+ totalPrice,
75
+ totalContent
76
+ });
77
+ const hasInfo = infoNodes.length > 0;
78
+ const hasSummary = hasDiscount || feeNodes.length > 0 || null != totalNode;
79
+ if (!hasInfo && !hasSummary) return null;
80
+ return <view className={clsx('doubao-template-info-section', 'column' === valueLayout && 'doubao-template-info-section--value-column')}>
81
+ {hasInfo ? <view className="doubao-template-info-section__info">{infoNodes}</view> : null}
82
+ {hasSummary ? <view className="doubao-template-info-section__summary">
83
+ <view className="doubao-template-info-section__summary-content">
84
+ {hasDiscount ? <text className="doubao-template-info-section__fee" text-maxline="1">
85
+ {discountText}
86
+ </text> : null}
87
+ {feeNodes}
88
+ {totalNode}
89
+ </view>
90
+ </view> : null}
91
+ </view>;
92
+ }
93
+ export { TemplateInfoSection };