@doubao-dev/template 0.0.38 → 0.0.39
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 +116 -44
- package/dist/ask-human-card/index.d.ts +1 -3
- package/dist/ask-human-card/index.js +4 -8
- package/dist/checkout-card/index.d.ts +3 -5
- package/dist/checkout-card/index.js +2 -2
- package/dist/components/info-section/index.d.ts +0 -2
- package/dist/components/info-section/index.js +4 -7
- package/dist/components/info-section/styles.css +28 -18
- package/dist/components/product-summary/index.d.ts +5 -1
- package/dist/components/product-summary/index.js +9 -7
- package/dist/components/product-summary/styles.css +25 -16
- package/dist/components/route-section/index.d.ts +5 -1
- package/dist/components/route-section/index.js +2 -0
- package/dist/components/route-section/styles.css +24 -0
- package/dist/content-card/index.d.ts +13 -3
- package/dist/content-card/index.js +12 -6
- package/dist/content-card/styles.css +9 -5
- package/dist/index.d.ts +1 -1
- package/dist/price-action-card/index.d.ts +8 -2
- package/dist/price-action-card/index.js +2 -8
- package/dist/price-action-card/styles.css +15 -29
- package/dist/primitives/index.d.ts +4 -0
- package/dist/primitives/index.js +3 -0
- package/dist/primitives/price/index.d.ts +5 -0
- package/dist/primitives/price/index.js +56 -0
- package/dist/primitives/price/styles.css +130 -0
- package/dist/primitives/price/types.d.ts +26 -0
- package/dist/primitives/price/types.js +0 -0
- package/dist/primitives/tag/index.d.ts +5 -0
- package/dist/primitives/tag/index.js +10 -0
- package/dist/primitives/tag/styles.css +70 -0
- package/dist/primitives/tag/types.d.ts +14 -0
- package/dist/primitives/tag/types.js +0 -0
- package/dist/primitives/title/index.d.ts +5 -0
- package/dist/primitives/title/index.js +18 -0
- package/dist/primitives/title/styles.css +63 -0
- package/dist/primitives/title/types.d.ts +18 -0
- package/dist/primitives/title/types.js +0 -0
- package/dist/ticket-order-card/index.d.ts +20 -1
- package/dist/types.d.ts +1 -0
- package/package.json +6 -1
- package/dist/components/action-bar/index.d.ts +0 -31
- package/dist/components/action-bar/index.js +0 -15
- package/dist/components/action-bar/styles.css +0 -27
- package/dist/components/title-bar/index.d.ts +0 -11
- package/dist/components/title-bar/index.js +0 -33
- package/dist/components/title-bar/styles.css +0 -66
package/README.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# @doubao-dev/template
|
|
2
2
|
|
|
3
|
-
Doubao Apps Widget 模板库,用于快速开发卡片类 widget。模板把标题栏、内容区、信息区和操作区组合成稳定的卡片结构,开发者在
|
|
3
|
+
Doubao Apps Widget 模板库,用于快速开发卡片类 widget。模板把标题栏、内容区、信息区和操作区组合成稳定的卡片结构,开发者在 Widget 函数组件里选择模板并传入业务数据即可。
|
|
4
4
|
|
|
5
5
|
推荐一个 widget 直接返回一张模板卡片,不额外包裹无意义的 `view` / `scroll-view`:
|
|
6
6
|
|
|
7
7
|
```tsx
|
|
8
|
-
import { defineWidget } from '@doubao-dev/framework';
|
|
9
8
|
import { ContentCard, type ContentCardItem } from '@doubao-dev/template';
|
|
10
9
|
|
|
11
10
|
const items: ContentCardItem[] = [
|
|
@@ -13,33 +12,32 @@ const items: ContentCardItem[] = [
|
|
|
13
12
|
key: 'a',
|
|
14
13
|
title: '主标题',
|
|
15
14
|
subtitle: '4199 元 | 商品描述',
|
|
16
|
-
|
|
15
|
+
description: '补充描述',
|
|
16
|
+
thumbnailSrc: 'https://example.com/product.png'
|
|
17
17
|
}
|
|
18
18
|
];
|
|
19
19
|
|
|
20
|
-
export default
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
});
|
|
20
|
+
export default function ProductCard() {
|
|
21
|
+
return (
|
|
22
|
+
<ContentCard
|
|
23
|
+
items={items}
|
|
24
|
+
header={{
|
|
25
|
+
actionText: '更多',
|
|
26
|
+
onActionClick: () => console.log('more')
|
|
27
|
+
}}
|
|
28
|
+
footer={{
|
|
29
|
+
secondaryActionButton: {
|
|
30
|
+
text: '查看更多',
|
|
31
|
+
onClick: () => console.log('view more')
|
|
32
|
+
},
|
|
33
|
+
primaryActionButton: {
|
|
34
|
+
text: '立即下单',
|
|
35
|
+
onClick: () => console.log('submit')
|
|
36
|
+
}
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
43
41
|
```
|
|
44
42
|
|
|
45
43
|
## 通用约定
|
|
@@ -47,13 +45,80 @@ export default defineWidget({
|
|
|
47
45
|
- `header` 配置标题栏右侧操作,类型为 `TemplateCardHeaderProps`,包含 `actionText` / `showAction` / `onActionClick`。
|
|
48
46
|
- `footer` 配置底部操作区,类型为 `TemplateCardFooterProps`,包含 `primaryActionButton` / `secondaryActionButton`。只传一个按钮时占据整行。
|
|
49
47
|
- `header`、`footer` 和内容区相互独立。footer 不会影响 `items` 展示数量,内容区也不负责渲染 header/footer。
|
|
50
|
-
- `children`
|
|
48
|
+
- 优先使用模板公开的结构化 Props;部分模板保留的 `children` 已废弃,只用于兼容旧代码。
|
|
51
49
|
- `className` / `style` / `onClick` 作用在卡片根节点。
|
|
52
|
-
-
|
|
50
|
+
- 模板和 primitives 不声明或暴露组件级 CSS 变量;颜色可以直接消费已有的全局主题 token。
|
|
51
|
+
|
|
52
|
+
## Primitives
|
|
53
|
+
|
|
54
|
+
`primitives` 是模板体系中的可组合业务单元,不包含完整卡片外壳。`Title`、`Tag`、`Price`、后续的 `Play` 等单元统一通过该子入口导入。
|
|
55
|
+
|
|
56
|
+
### Title
|
|
57
|
+
|
|
58
|
+
标题展示组件,默认单行省略,可显式切换为最多两行,并可控制右侧箭头。
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { Title } from '@doubao-dev/template/primitives';
|
|
62
|
+
|
|
63
|
+
<Title text="默认单行标题" />
|
|
64
|
+
|
|
65
|
+
<Title text="需要展示更多信息的两行标题" maxLines={2} />
|
|
66
|
+
|
|
67
|
+
<Title text="不展示箭头的标题" showArrow={false} />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
说明:
|
|
71
|
+
|
|
72
|
+
- `text` 支持 `string | number`。
|
|
73
|
+
- `maxLines` 支持 `1 | 2`,默认是 `1`;超出对应行数后省略。
|
|
74
|
+
- `showArrow` 默认是 `true`。
|
|
75
|
+
- `loading` 展示最大宽度为 40% 的扫光占位。
|
|
76
|
+
- 组件宽度由外部业务容器决定。
|
|
77
|
+
|
|
78
|
+
### Tag
|
|
79
|
+
|
|
80
|
+
标签展示组件,用于突出营销、权威或常规辅助信息。标签固定高度为 20px;多个标签横向排列时,标签间距为 4px,容器高度为 26px。
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
import { Tag } from '@doubao-dev/template/primitives';
|
|
84
|
+
|
|
85
|
+
<Tag text="营销标签" tone="marketing" />
|
|
86
|
+
|
|
87
|
+
<Tag text="权威标签" />
|
|
88
|
+
|
|
89
|
+
<Tag text="普通标签" tone="neutral" />
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
说明:
|
|
93
|
+
|
|
94
|
+
- `text` 支持 `string | number`。
|
|
95
|
+
- `tone` 支持 `marketing | authority | neutral`,默认是 `authority`。
|
|
96
|
+
- 标签内容不会收缩或截断;业务容器负责测量或通过换行裁切隐藏放不下的整枚标签,不能只裁切标签文字。
|
|
97
|
+
- `className` 和 `style` 可用于样式定制。
|
|
98
|
+
|
|
99
|
+
### Price
|
|
100
|
+
|
|
101
|
+
价格展示组件,用于卡片内容中的金额、币种、前后缀、辅助信息和原价排版。`Price` 是业务展示组件,不包含卡片外壳。
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { Price } from '@doubao-dev/template/primitives';
|
|
105
|
+
|
|
106
|
+
<Price value="1636.92" prefix="均" suffix="券后价" description="销量100+" />
|
|
107
|
+
|
|
108
|
+
<Price value={1636.92} tone="highlight" originalPrice={2000} />
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
说明:
|
|
112
|
+
|
|
113
|
+
- `value` 支持 `string | number`;需要保留前导零或末尾小数位时传字符串。
|
|
114
|
+
- `currency` 默认是 `¥`,传空字符串可隐藏币种符号。
|
|
115
|
+
- `tone="highlight"` 使用营销强调色;默认色跟随当前主题。
|
|
116
|
+
- `loading` 展示最大宽度为 60% 的扫光占位。
|
|
117
|
+
- `className` 和 `style` 可用于样式定制。
|
|
53
118
|
|
|
54
119
|
## ContentCard
|
|
55
120
|
|
|
56
|
-
<img src="https://unpkg.com/@doubao-dev/template@0.0.
|
|
121
|
+
<img src="https://unpkg.com/@doubao-dev/template@0.0.39/assets/content-card.png" alt="ContentCard 示例" width="400" />
|
|
57
122
|
|
|
58
123
|
通用列表卡,由标题栏、列表内容和底部操作区组成,适合商品、服务、内容入口等可重复条目。
|
|
59
124
|
|
|
@@ -65,7 +130,8 @@ import { ContentCard } from '@doubao-dev/template';
|
|
|
65
130
|
{
|
|
66
131
|
title: '蓝牙降噪耳机 Pro',
|
|
67
132
|
subtitle: '799 元 | 主动降噪 | 现货',
|
|
68
|
-
|
|
133
|
+
description: '支持空间音频与多设备连接',
|
|
134
|
+
thumbnailSrc: 'https://example.com/product.png',
|
|
69
135
|
action: {
|
|
70
136
|
type: 'button',
|
|
71
137
|
text: '下单',
|
|
@@ -87,14 +153,14 @@ import { ContentCard } from '@doubao-dev/template';
|
|
|
87
153
|
|
|
88
154
|
说明:
|
|
89
155
|
|
|
90
|
-
- `title` / `subtitle`
|
|
91
|
-
- `thumbnail`
|
|
156
|
+
- `title` / `subtitle` / `description` 支持字符串、数字或自定义节点。字符串和数字使用模板默认样式且最多一行;需要两行标题时传入 `<Title maxLines={2} />`。各行高度由内容决定,行间距为 2px。
|
|
157
|
+
- `thumbnailSrc` 是列表项左侧缩略图地址;`thumbnail` 可传原生媒体节点或 primitive,同时传入时 `thumbnail` 优先。
|
|
92
158
|
- `action` 是列表项右侧操作区,支持 `{ type: 'button' }`、`{ type: 'switch' }`、`{ type: 'playback' }` 或自定义节点。
|
|
93
|
-
- `children`
|
|
159
|
+
- 标题、描述、缩略内容和操作区分别使用对应的明确字段配置。卡片和列表项的 `children` 已废弃,只用于兼容旧代码。
|
|
94
160
|
|
|
95
161
|
## PriceActionCard
|
|
96
162
|
|
|
97
|
-
<img src="https://unpkg.com/@doubao-dev/template@0.0.
|
|
163
|
+
<img src="https://unpkg.com/@doubao-dev/template@0.0.39/assets/price-action-card.png" alt="PriceActionCard 示例" width="400" />
|
|
98
164
|
|
|
99
165
|
价格操作卡,由多条"价格 + 信息 + 右侧按钮"组成,适合报价、权益、服务方案等结果列表。
|
|
100
166
|
|
|
@@ -127,7 +193,7 @@ import { PriceActionCard } from '@doubao-dev/template';
|
|
|
127
193
|
|
|
128
194
|
## CheckoutCard
|
|
129
195
|
|
|
130
|
-
<img src="https://unpkg.com/@doubao-dev/template@0.0.
|
|
196
|
+
<img src="https://unpkg.com/@doubao-dev/template@0.0.39/assets/checkout-card.png" alt="CheckoutCard 示例" width="400" />
|
|
131
197
|
|
|
132
198
|
通用提单卡,由商品摘要、提单信息、费用汇总和底部操作区组成,适合下单确认、支付确认等场景。
|
|
133
199
|
|
|
@@ -138,6 +204,8 @@ import { CheckoutCard } from '@doubao-dev/template';
|
|
|
138
204
|
productItems={[
|
|
139
205
|
{
|
|
140
206
|
title: '双人下午茶套餐',
|
|
207
|
+
tagText: '新',
|
|
208
|
+
tagTone: 'highlight',
|
|
141
209
|
spec: '含 2 杯饮品 + 2 款甜点',
|
|
142
210
|
price: '¥68',
|
|
143
211
|
quantity: '1'
|
|
@@ -155,10 +223,10 @@ import { CheckoutCard } from '@doubao-dev/template';
|
|
|
155
223
|
{ label: '预计时间', value: '今天 15:30', valueExtra: '请到店自取' }
|
|
156
224
|
]}
|
|
157
225
|
feeItems={[
|
|
226
|
+
{ label: '优惠', value: '-¥12' },
|
|
158
227
|
{ label: '包装费', value: '¥2' },
|
|
159
228
|
{ label: '服务费', value: '¥0' }
|
|
160
229
|
]}
|
|
161
|
-
discountText="共优惠 ¥12"
|
|
162
230
|
totalPrice="¥126"
|
|
163
231
|
footer={{
|
|
164
232
|
secondaryActionButton: { text: '修改' },
|
|
@@ -169,14 +237,16 @@ import { CheckoutCard } from '@doubao-dev/template';
|
|
|
169
237
|
|
|
170
238
|
说明:
|
|
171
239
|
|
|
172
|
-
- `productItems` 支持单个或多个商品。单项字段复用商品摘要能力,包括 `title`、`spec`、`imageSrc`、`image`、`pricePrefix`、`price`、`quantity`、`showChevron`、`onClick
|
|
173
|
-
- `infoItems`
|
|
174
|
-
- `feeItems`、`
|
|
240
|
+
- `productItems` 支持单个或多个商品。单项字段复用商品摘要能力,包括 `title`、`tagText`、`tagTone`、`spec`、`imageSrc`、`image`、`pricePrefix`、`price`、`quantity`、`showChevron`、`onClick`;`tagText` 展示在标题前,`tagTone="highlight"` 使用强调色。
|
|
241
|
+
- `infoItems` 配置提单信息列表;`value` 和 `valueExtra` 均为 `TemplateText`,使用相同样式并与左侧 label 的首行对齐。
|
|
242
|
+
- `feeItems`、`totalLabel`、`totalPrice` 作为一个整体配置费用汇总,最多展示两行;优惠信息也通过 `feeItems` 传入。
|
|
175
243
|
- 底部按钮使用 `footer.primaryActionButton` / `footer.secondaryActionButton`。
|
|
176
244
|
|
|
177
245
|
## TicketOrderCard
|
|
178
246
|
|
|
179
|
-
<img src="https://unpkg.com/@doubao-dev/template@0.0.
|
|
247
|
+
<img src="https://unpkg.com/@doubao-dev/template@0.0.39/assets/ticket-checkout-card.png" alt="TicketOrderCard 示例" width="400" />
|
|
248
|
+
|
|
249
|
+
> **已废弃:** 请使用 `CheckoutCard`。`TicketOrderCard` 仅为兼容现有代码保留。
|
|
180
250
|
|
|
181
251
|
票务提单卡,由航程信息、订单信息、费用汇总和底部操作区组成,适合机票、火车票等出行确认场景。
|
|
182
252
|
|
|
@@ -187,6 +257,8 @@ import { TicketOrderCard } from '@doubao-dev/template';
|
|
|
187
257
|
routeItems={[
|
|
188
258
|
{
|
|
189
259
|
title: '北京 - 上海',
|
|
260
|
+
tagText: '直飞',
|
|
261
|
+
tagTone: 'highlight',
|
|
190
262
|
description: '7月1日 周三 08:00-10:10 MU5101 经济舱'
|
|
191
263
|
},
|
|
192
264
|
{
|
|
@@ -213,13 +285,13 @@ import { TicketOrderCard } from '@doubao-dev/template';
|
|
|
213
285
|
|
|
214
286
|
说明:
|
|
215
287
|
|
|
216
|
-
- `routeItems`
|
|
288
|
+
- `routeItems` 配置航程列表,`tagText` 展示在标题前,`tagTone="highlight"` 使用强调色,单项可通过 `showChevron={false}` 隐藏标题右侧箭头。
|
|
217
289
|
- `totalContent` 可以接管合计区域,优先级高于 `totalLabel` / `totalPrice`。
|
|
218
290
|
- 底部按钮使用通用 `footer`。
|
|
219
291
|
|
|
220
292
|
## TransitCard
|
|
221
293
|
|
|
222
|
-
<img src="https://unpkg.com/@doubao-dev/template@0.0.
|
|
294
|
+
<img src="https://unpkg.com/@doubao-dev/template@0.0.39/assets/transit-card.png" alt="TransitCard 示例" width="400" />
|
|
223
295
|
|
|
224
296
|
交通票务列表卡,由多条出发、中转、到达和价格信息组成,适合展示机票、火车票、大巴等推荐列表。
|
|
225
297
|
|
|
@@ -255,7 +327,7 @@ import { TransitCard } from '@doubao-dev/template';
|
|
|
255
327
|
|
|
256
328
|
## AskHumanCard
|
|
257
329
|
|
|
258
|
-
<img src="https://unpkg.com/@doubao-dev/template@0.0.
|
|
330
|
+
<img src="https://unpkg.com/@doubao-dev/template@0.0.39/assets/ask-human-card.png" alt="AskHumanCard 示例" width="400" />
|
|
259
331
|
|
|
260
332
|
人工确认选项卡,由一组选项组成,适合让用户在多个候选项中确认选择。
|
|
261
333
|
|
|
@@ -278,5 +350,5 @@ import { AskHumanCard } from '@doubao-dev/template';
|
|
|
278
350
|
|
|
279
351
|
说明:
|
|
280
352
|
|
|
281
|
-
- `items`
|
|
353
|
+
- `items` 配置选项列表,选项文案通过 `text` 设置。
|
|
282
354
|
- `items[].showArrow` 支持 `'left'`、`'right'`、`'none'`,默认不展示;跳过、固定跳转等入口也通过 `items` 表达。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CSSProperties, TouchEvent } from '@lynx-js/types';
|
|
2
|
-
import { type ReactElement
|
|
2
|
+
import { type ReactElement } from 'react';
|
|
3
3
|
import type { TemplateKey, TemplateText } from '../types.js';
|
|
4
4
|
import './styles.scss';
|
|
5
5
|
/** 卡片行为语义。 */
|
|
@@ -27,8 +27,6 @@ export interface AskHumanCardItem {
|
|
|
27
27
|
key?: TemplateKey;
|
|
28
28
|
/** 选项文案。 */
|
|
29
29
|
text?: TemplateText;
|
|
30
|
-
/** 选项自定义内容;优先级高于 text。 */
|
|
31
|
-
children?: ReactNode;
|
|
32
30
|
/** 是否显示加载状态;为 true 时选项内展示 loading 动画并禁用点击。 */
|
|
33
31
|
loading?: boolean;
|
|
34
32
|
/** 箭头展示位置;默认 `'none'` 不展示。 */
|
|
@@ -23,15 +23,11 @@ function getAskHumanCardArrowIconContent(color) {
|
|
|
23
23
|
function isAskHumanCardTextEmpty(content) {
|
|
24
24
|
return null == content || '' === content;
|
|
25
25
|
}
|
|
26
|
-
function isAskHumanCardNodeEmpty(content) {
|
|
27
|
-
return null == content || 'boolean' == typeof content || '' === content;
|
|
28
|
-
}
|
|
29
26
|
function renderAskHumanCardItem({ item, index, optionBg, arrowColor }) {
|
|
30
27
|
const isLoading = true === item.loading;
|
|
31
|
-
const hasCustomContent = !isAskHumanCardNodeEmpty(item.children);
|
|
32
28
|
const arrowPosition = 'left' === item.showArrow || 'right' === item.showArrow ? item.showArrow : void 0;
|
|
33
29
|
const arrowNode = arrowPosition ? <svg className="doubao-ask-human-card__option-icon" content={getAskHumanCardArrowIconContent(arrowColor)}/> : null;
|
|
34
|
-
if (!isLoading &&
|
|
30
|
+
if (!isLoading && isAskHumanCardTextEmpty(item.text)) return null;
|
|
35
31
|
return <Button key={item.key ?? index} className={clsx('doubao-ask-human-card__option', {
|
|
36
32
|
'doubao-ask-human-card__option--with-arrow': null != arrowPosition
|
|
37
33
|
}, item.className)} style={{
|
|
@@ -42,9 +38,9 @@ function renderAskHumanCardItem({ item, index, optionBg, arrowColor }) {
|
|
|
42
38
|
item.onClick?.(event);
|
|
43
39
|
}}>
|
|
44
40
|
{'left' === arrowPosition && arrowNode}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
<text className="doubao-ask-human-card__option-text" text-maxline="1">
|
|
42
|
+
{item.text}
|
|
43
|
+
</text>
|
|
48
44
|
{'right' === arrowPosition && arrowNode}
|
|
49
45
|
</Button>;
|
|
50
46
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CSSProperties, TouchEvent } from '@lynx-js/types';
|
|
2
|
-
import type { ReactElement
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
3
|
import { type TemplateCardFooterProps } from '../components/footer/index.js';
|
|
4
4
|
import { type TemplateCardHeaderProps } from '../components/header/index.js';
|
|
5
5
|
import { type TemplateProductSummaryProps } from '../components/product-summary/index.js';
|
|
@@ -14,8 +14,6 @@ export interface CheckoutCardProps {
|
|
|
14
14
|
infoItems?: CheckoutCardInfoItem[];
|
|
15
15
|
/** 费用明细列表。 */
|
|
16
16
|
feeItems?: CheckoutCardFeeItem[];
|
|
17
|
-
/** 优惠信息文案;传空字符串时不展示。 */
|
|
18
|
-
discountText?: string;
|
|
19
17
|
/** 合计价格前的标签文案。 */
|
|
20
18
|
totalLabel?: string;
|
|
21
19
|
/** 合计价格。 */
|
|
@@ -39,9 +37,9 @@ export interface CheckoutCardInfoItem {
|
|
|
39
37
|
/** 信息项标签。 */
|
|
40
38
|
label: string;
|
|
41
39
|
/** 信息项主内容。 */
|
|
42
|
-
value:
|
|
40
|
+
value: TemplateText;
|
|
43
41
|
/** 信息项补充内容。 */
|
|
44
|
-
valueExtra?:
|
|
42
|
+
valueExtra?: TemplateText;
|
|
45
43
|
}
|
|
46
44
|
export interface CheckoutCardFeeItem {
|
|
47
45
|
/** 费用项唯一标识;不传时使用数组下标。 */
|
|
@@ -22,7 +22,7 @@ function renderCheckoutCardProductItem({ item, index }) {
|
|
|
22
22
|
</view>;
|
|
23
23
|
}
|
|
24
24
|
function CheckoutCard(props) {
|
|
25
|
-
const { header, productItems = [], infoItems = [], feeItems = [],
|
|
25
|
+
const { header, productItems = [], infoItems = [], feeItems = [], totalLabel, totalPrice, footer, className, style, onClick } = props;
|
|
26
26
|
const productNodes = productItems.map((item, index)=>renderCheckoutCardProductItem({
|
|
27
27
|
item,
|
|
28
28
|
index
|
|
@@ -32,7 +32,7 @@ function CheckoutCard(props) {
|
|
|
32
32
|
|
|
33
33
|
{productNodes.length > 0 && <view className="doubao-checkout-card__products">{productNodes}</view>}
|
|
34
34
|
|
|
35
|
-
<TemplateInfoSection infoItems={infoItems} feeItems={feeItems}
|
|
35
|
+
<TemplateInfoSection infoItems={infoItems} feeItems={feeItems} totalLabel={totalLabel} totalPrice={totalPrice} valueLayout="column"/>
|
|
36
36
|
|
|
37
37
|
<TemplateCardFooter secondaryActionButton={footer?.secondaryActionButton} primaryActionButton={footer?.primaryActionButton}/>
|
|
38
38
|
</view>;
|
|
@@ -65,26 +65,23 @@ function renderTemplateInfoSectionTotal({ totalLabel, totalPrice, totalContent }
|
|
|
65
65
|
</view>;
|
|
66
66
|
}
|
|
67
67
|
function TemplateInfoSection(props) {
|
|
68
|
-
const { infoItems = [], feeItems = [],
|
|
68
|
+
const { infoItems = [], feeItems = [], totalLabel, totalPrice, totalContent, valueLayout = 'row' } = props;
|
|
69
69
|
const infoNodes = infoItems.map(renderTemplateInfoSectionInfoItem).filter((node)=>null != node);
|
|
70
70
|
const feeNodes = feeItems.map(renderTemplateInfoSectionFeeItem).filter((node)=>null != node);
|
|
71
|
-
const hasDiscount = !isTemplateInfoSectionTextEmpty(discountText);
|
|
72
71
|
const totalNode = renderTemplateInfoSectionTotal({
|
|
73
72
|
totalLabel,
|
|
74
73
|
totalPrice,
|
|
75
74
|
totalContent
|
|
76
75
|
});
|
|
77
76
|
const hasInfo = infoNodes.length > 0;
|
|
78
|
-
const hasSummary =
|
|
77
|
+
const hasSummary = feeNodes.length > 0 || null != totalNode;
|
|
79
78
|
if (!hasInfo && !hasSummary) return null;
|
|
80
79
|
return <view className={clsx('doubao-template-info-section', 'column' === valueLayout && 'doubao-template-info-section--value-column')}>
|
|
81
80
|
{hasInfo && <view className="doubao-template-info-section__info">{infoNodes}</view>}
|
|
82
81
|
{hasSummary && <view className="doubao-template-info-section__summary">
|
|
83
82
|
<view className="doubao-template-info-section__summary-content">
|
|
84
|
-
{
|
|
85
|
-
|
|
86
|
-
</text>}
|
|
87
|
-
{feeNodes}
|
|
83
|
+
{}
|
|
84
|
+
{feeNodes.length > 0 && <view className="doubao-template-info-section__fees">{feeNodes}</view>}
|
|
88
85
|
{totalNode}
|
|
89
86
|
</view>
|
|
90
87
|
</view>}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
.doubao-template-info-section__info-row {
|
|
17
17
|
flex-direction: row;
|
|
18
|
+
align-items: flex-start;
|
|
18
19
|
width: 100%;
|
|
19
20
|
display: flex;
|
|
20
21
|
}
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
|
|
63
64
|
.doubao-template-info-section__info-value {
|
|
64
65
|
min-width: 0;
|
|
65
|
-
color: var(--neutral-
|
|
66
|
+
color: var(--neutral-70);
|
|
66
67
|
text-align: right;
|
|
67
68
|
margin-left: 6px;
|
|
68
69
|
font-size: 13px;
|
|
@@ -93,9 +94,24 @@
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
.doubao-template-info-section__summary-content {
|
|
96
|
-
flex-
|
|
97
|
+
flex-flow: wrap;
|
|
98
|
+
flex: 1 1 0;
|
|
97
99
|
justify-content: flex-end;
|
|
98
100
|
align-items: center;
|
|
101
|
+
gap: 0 6px;
|
|
102
|
+
min-width: 0;
|
|
103
|
+
max-width: 100%;
|
|
104
|
+
max-height: 42px;
|
|
105
|
+
display: flex;
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.doubao-template-info-section__fees {
|
|
110
|
+
flex-direction: row;
|
|
111
|
+
flex: 0 auto;
|
|
112
|
+
align-items: center;
|
|
113
|
+
gap: 0 6px;
|
|
114
|
+
min-width: 0;
|
|
99
115
|
max-width: 100%;
|
|
100
116
|
display: flex;
|
|
101
117
|
overflow: hidden;
|
|
@@ -103,46 +119,40 @@
|
|
|
103
119
|
|
|
104
120
|
.doubao-template-info-section__fee {
|
|
105
121
|
min-width: 0;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
max-width: 100%;
|
|
123
|
+
color: var(--neutral-70);
|
|
124
|
+
flex: 0 auto;
|
|
109
125
|
font-size: 13px;
|
|
110
126
|
font-weight: 400;
|
|
111
127
|
line-height: 20px;
|
|
112
128
|
}
|
|
113
129
|
|
|
114
|
-
.doubao-template-info-section__fee:first-child {
|
|
115
|
-
margin-left: 0;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
130
|
.doubao-template-info-section__total {
|
|
119
|
-
flex-
|
|
120
|
-
flex
|
|
131
|
+
flex-direction: row;
|
|
132
|
+
flex: 0 auto;
|
|
121
133
|
justify-content: flex-end;
|
|
122
134
|
align-items: center;
|
|
123
135
|
min-width: 0;
|
|
124
136
|
max-width: 100%;
|
|
125
|
-
margin-left: 6px;
|
|
126
137
|
display: flex;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
.doubao-template-info-section__total:first-child {
|
|
130
|
-
margin-left: 0;
|
|
138
|
+
overflow: hidden;
|
|
131
139
|
}
|
|
132
140
|
|
|
133
141
|
.doubao-template-info-section__total-label {
|
|
142
|
+
min-width: 0;
|
|
134
143
|
max-width: 100%;
|
|
135
144
|
color: var(--neutral-100);
|
|
136
|
-
flex
|
|
145
|
+
flex: 0 auto;
|
|
137
146
|
font-size: 13px;
|
|
138
147
|
font-weight: 500;
|
|
139
148
|
line-height: 20px;
|
|
140
149
|
}
|
|
141
150
|
|
|
142
151
|
.doubao-template-info-section__total-price {
|
|
152
|
+
min-width: 0;
|
|
143
153
|
max-width: 100%;
|
|
144
154
|
color: var(--neutral-100);
|
|
145
|
-
flex
|
|
155
|
+
flex: 0 auto;
|
|
146
156
|
margin-left: 2px;
|
|
147
157
|
font-size: 15px;
|
|
148
158
|
font-weight: 500;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { TouchEvent } from '@lynx-js/types';
|
|
2
2
|
import type { ReactElement, ReactNode } from 'react';
|
|
3
|
-
import type { TemplateText } from '../../types.js';
|
|
3
|
+
import type { TemplateTagTone, TemplateText } from '../../types.js';
|
|
4
4
|
import './styles.scss';
|
|
5
5
|
export interface TemplateProductSummaryProps {
|
|
6
6
|
/** 商品标题。 */
|
|
7
7
|
title?: string;
|
|
8
|
+
/** 商品标题前的标签文案。 */
|
|
9
|
+
tagText?: TemplateText;
|
|
10
|
+
/** 商品标题标签的色调。 */
|
|
11
|
+
tagTone?: TemplateTagTone;
|
|
8
12
|
/** 商品规格说明。 */
|
|
9
13
|
spec?: string;
|
|
10
14
|
/** 商品图片地址。 */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Title } from "../../primitives/title/index.js";
|
|
2
2
|
import "./styles.css";
|
|
3
3
|
function isTemplateProductSummaryTextEmpty(content) {
|
|
4
4
|
return null == content || '' === content;
|
|
@@ -13,9 +13,11 @@ function TemplateProductSummaryImage(props) {
|
|
|
13
13
|
return <view className="doubao-template-product-summary__image"/>;
|
|
14
14
|
}
|
|
15
15
|
function TemplateProductSummary(props) {
|
|
16
|
-
const { title, spec, imageSrc, image: image1, pricePrefix, price, quantity, showChevron = true, onClick } = props;
|
|
16
|
+
const { title, tagText, tagTone = 'default', spec, imageSrc, image: image1, pricePrefix, price, quantity, showChevron = true, onClick } = props;
|
|
17
17
|
const hasImage = !isTemplateProductSummaryNodeEmpty(image1) || null != imageSrc && imageSrc.length > 0;
|
|
18
|
-
const
|
|
18
|
+
const titleText = title ?? '';
|
|
19
|
+
const hasTitle = titleText.length > 0;
|
|
20
|
+
const hasTag = !isTemplateProductSummaryTextEmpty(tagText);
|
|
19
21
|
const hasPrice = null != pricePrefix && pricePrefix.length > 0 || !isTemplateProductSummaryTextEmpty(price);
|
|
20
22
|
const hasMainLine = hasTitle || hasPrice;
|
|
21
23
|
const hasSpec = null != spec && spec.length > 0;
|
|
@@ -27,10 +29,10 @@ function TemplateProductSummary(props) {
|
|
|
27
29
|
<view className={hasImage ? 'doubao-template-product-summary__content doubao-template-product-summary__content--with-image' : 'doubao-template-product-summary__content'}>
|
|
28
30
|
{hasMainLine && <view className="doubao-template-product-summary__line-main">
|
|
29
31
|
{hasTitle && <view className="doubao-template-product-summary__title-wrap">
|
|
30
|
-
<text className=
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
{hasTag && <text className={'highlight' === tagTone ? 'doubao-template-product-summary__tag doubao-template-product-summary__tag--highlight' : 'doubao-template-product-summary__tag'} text-maxline="1">
|
|
33
|
+
{tagText}
|
|
34
|
+
</text>}
|
|
35
|
+
<Title text={titleText} showArrow={showChevron}/>
|
|
34
36
|
</view>}
|
|
35
37
|
{hasPrice && <view className="doubao-template-product-summary__price">
|
|
36
38
|
{null != pricePrefix && pricePrefix.length > 0 && <text className="doubao-template-product-summary__price-prefix" text-maxline="1">
|
|
@@ -49,32 +49,41 @@
|
|
|
49
49
|
flex-direction: row;
|
|
50
50
|
flex: 1 1 0;
|
|
51
51
|
align-items: center;
|
|
52
|
+
gap: 4px;
|
|
52
53
|
min-width: 0;
|
|
53
54
|
margin-right: 8px;
|
|
54
55
|
display: flex;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
.doubao-template-product-
|
|
58
|
+
.doubao-template-product-summary__tag {
|
|
59
|
+
box-sizing: border-box;
|
|
60
|
+
height: 18px;
|
|
61
|
+
color: var(--neutral-70);
|
|
58
62
|
text-overflow: ellipsis;
|
|
59
63
|
white-space: nowrap;
|
|
64
|
+
background-color: var(--bg-base-2-overlay);
|
|
65
|
+
border-radius: 4px;
|
|
66
|
+
flex-shrink: 0;
|
|
67
|
+
padding: 2px 4px;
|
|
60
68
|
font-family: PingFang SC, sans-serif;
|
|
69
|
+
font-size: 12px;
|
|
61
70
|
font-style: normal;
|
|
71
|
+
font-weight: 400;
|
|
72
|
+
line-height: 14px;
|
|
62
73
|
overflow: hidden;
|
|
63
74
|
}
|
|
64
75
|
|
|
65
|
-
.doubao-template-product-
|
|
66
|
-
|
|
67
|
-
color: var(--
|
|
68
|
-
font-size: 16px;
|
|
69
|
-
font-weight: 500;
|
|
70
|
-
line-height: 24px;
|
|
76
|
+
.doubao-template-product-summary__tag--highlight {
|
|
77
|
+
color: var(--primary-60);
|
|
78
|
+
background-color: var(--primary-transparent-1);
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
.doubao-template-product-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
.doubao-template-product-summary__price-prefix, .doubao-template-product-summary__price-value, .doubao-template-product-summary__spec, .doubao-template-product-summary__quantity {
|
|
82
|
+
text-overflow: ellipsis;
|
|
83
|
+
white-space: nowrap;
|
|
84
|
+
font-family: PingFang SC, sans-serif;
|
|
85
|
+
font-style: normal;
|
|
86
|
+
overflow: hidden;
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
.doubao-template-product-summary__price {
|
|
@@ -103,15 +112,15 @@
|
|
|
103
112
|
|
|
104
113
|
.doubao-template-product-summary__spec {
|
|
105
114
|
min-width: 0;
|
|
106
|
-
color: var(--neutral-
|
|
115
|
+
color: var(--neutral-70);
|
|
107
116
|
flex: 1 1 0;
|
|
108
|
-
font-size:
|
|
117
|
+
font-size: 13px;
|
|
109
118
|
font-weight: 400;
|
|
110
|
-
line-height:
|
|
119
|
+
line-height: 20px;
|
|
111
120
|
}
|
|
112
121
|
|
|
113
122
|
.doubao-template-product-summary__quantity {
|
|
114
|
-
color: var(--neutral-
|
|
123
|
+
color: var(--neutral-70);
|
|
115
124
|
flex-shrink: 0;
|
|
116
125
|
margin-left: 8px;
|
|
117
126
|
font-size: 13px;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TouchEvent } from '@lynx-js/types';
|
|
2
2
|
import type { ReactElement } from 'react';
|
|
3
|
-
import type { TemplateKey, TemplateText } from '../../types.js';
|
|
3
|
+
import type { TemplateKey, TemplateTagTone, TemplateText } from '../../types.js';
|
|
4
4
|
import './styles.scss';
|
|
5
5
|
export interface TemplateRouteSectionProps {
|
|
6
6
|
/** 航程信息列表。 */
|
|
@@ -13,6 +13,10 @@ export interface TemplateRouteSectionItem {
|
|
|
13
13
|
title?: TemplateText;
|
|
14
14
|
/** 航程描述,例如「6月1日 周六 20:50-23:50 CZ0000 经济舱」。 */
|
|
15
15
|
description?: TemplateText;
|
|
16
|
+
/** 航程标题前的标签文案。 */
|
|
17
|
+
tagText?: TemplateText;
|
|
18
|
+
/** 航程标题标签的色调。 */
|
|
19
|
+
tagTone?: TemplateTagTone;
|
|
16
20
|
/** 是否展示标题右侧箭头。 */
|
|
17
21
|
showChevron?: boolean;
|
|
18
22
|
/** 点击航程项时触发。 */
|