@doubao-apps/template 0.0.32 → 0.0.33

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
@@ -31,6 +31,52 @@ import { ListCard } from '@doubao-apps/template';
31
31
 
32
32
  如果只是验证 UI 效果,也可以在普通页面里直接渲染模板组件;但真实卡片接入建议优先按 widget 方式组织。
33
33
 
34
+ ## AskHumanCard
35
+
36
+ `AskHumanCard` 是人工确认选项卡模板,结构包含一组可点击选项和可选的「跳过」入口,适合需要让用户在多个候选项中确认选择的场景。
37
+
38
+ 效果图:
39
+
40
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.33/assets/ask_human.png" alt="AskHumanCard 示例" width="400" />
41
+
42
+ <p />
43
+
44
+ ```tsx
45
+ import { AskHumanCard } from '@doubao-apps/template';
46
+
47
+ <AskHumanCard
48
+ items={[
49
+ {
50
+ text: '中关村创业大街店 · 0.6km',
51
+ onClick: () => {
52
+ console.log('select store 1');
53
+ }
54
+ },
55
+ {
56
+ text: '北京中关村·在握旗舰店 · 1.8km',
57
+ onClick: () => {
58
+ console.log('select store 2');
59
+ }
60
+ },
61
+ {
62
+ text: '中关村城委店 · 3.5km',
63
+ onClick: () => {
64
+ console.log('select store 3');
65
+ }
66
+ }
67
+ ]}
68
+ onSkipClick={() => {
69
+ console.log('skip');
70
+ }}
71
+ />
72
+ ```
73
+
74
+ 说明:
75
+
76
+ - `items` 用于配置选项列表,每个选项可以通过 `text` 或 `children` 自定义内容。
77
+ - 默认展示「跳过」入口,可以通过 `showSkip={false}` 隐藏,也可以通过 `skipText` 或 `skipContent` 自定义内容。
78
+ - 用在 widget 中时,推荐让 `render` 直接返回 `AskHumanCard`。
79
+
34
80
  ## ListCard
35
81
 
36
82
  `ListCard` 是列表卡模板,结构包含应用标题栏和一组商品/内容列表项,适合展示商品、服务、行程等可重复内容。
@@ -72,13 +118,133 @@ import { ListCard } from '@doubao-apps/template';
72
118
  - 如果需要完全自定义内容区域,可以传入 `children`,模板会保留标题栏和卡片外壳。
73
119
  - 用在 widget 中时,推荐让 `render` 直接返回 `ListCard`。
74
120
 
121
+ ## SingleItemCard
122
+
123
+ `SingleItemCard` 是单项卡模板,结构包含应用标题栏、内容图片、主标题和两行信息字段,适合展示单个商品、服务或内容入口。
124
+
125
+ 效果图:
126
+
127
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.33/assets/single-item-card.png" alt="SingleItemCard 示例" width="400" />
128
+
129
+ <p />
130
+
131
+ ```tsx
132
+ import { SingleItemCard } from '@doubao-apps/template';
133
+
134
+ <SingleItemCard
135
+ moreText="查看更多"
136
+ title="主标题"
137
+ imageSrc="https://example.com/product.png"
138
+ price="¥99"
139
+ quantity="1"
140
+ infoRows={[
141
+ { text: '信息字段1' },
142
+ {
143
+ items: [{ text: '信息字段2' }, { text: '信息字段3' }]
144
+ }
145
+ ]}
146
+ primaryActionText="主按钮"
147
+ onContentClick={() => {
148
+ console.log('content');
149
+ }}
150
+ onMoreClick={() => {
151
+ console.log('more');
152
+ }}
153
+ onPrimaryActionClick={() => {
154
+ console.log('primary action');
155
+ }}
156
+ />
157
+ ```
158
+
159
+ 说明:
160
+
161
+ - `infoRows` 最多展示前 2 行,每行可以通过 `text` 配置单字段,或通过 `items` 配置多个字段并自动用圆点分隔。
162
+ - `title` 支持字符串、数字或自定义节点;需要标签等复杂标题时传入自定义节点。
163
+ - `pricePrefix`、`price` 和 `quantity` 用于配置商品操作态;不传时展示基础单项态。
164
+ - `image` 可以传入自定义图片节点,优先级高于 `imageSrc`。
165
+ - `primaryActionText` 和 `secondaryActionText` 可以配置底部操作按钮,不传时不展示操作区。
166
+ - 如果需要完全自定义内容区域,可以传入 `children`,模板会保留标题栏和卡片外壳。
167
+
168
+ ## PriceActionListCard
169
+
170
+ `PriceActionListCard` 是价格操作列表卡模板,结构包含应用标题栏、多条价格信息和底部操作按钮,适合展示多个可操作的报价、权益或结果项。
171
+
172
+ 效果图:
173
+
174
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.33/assets/price-action-list-card.png" alt="PriceActionListCard 示例" width="400" />
175
+
176
+ <p />
177
+
178
+ ```tsx
179
+ import { PriceActionListCard } from '@doubao-apps/template';
180
+
181
+ <PriceActionListCard
182
+ items={[
183
+ {
184
+ price: '¥000',
185
+ badgeText: '辅助信息',
186
+ infoRows: [{ text: '信息字段 1' }, { text: '信息字段 2' }],
187
+ actionText: '次按钮'
188
+ },
189
+ {
190
+ price: '¥000',
191
+ badgeText: '辅助信息',
192
+ infoRows: [{ text: '信息字段 1' }, { text: '信息字段 2' }],
193
+ actionText: '次按钮'
194
+ },
195
+ {
196
+ price: '¥000',
197
+ badgeText: '辅助信息',
198
+ infoRows: [{ text: '信息字段 1' }, { text: '信息字段 2' }],
199
+ actionText: '次按钮'
200
+ }
201
+ ]}
202
+ footerActionText="次按钮"
203
+ onFooterActionClick={() => {
204
+ console.log('footer action');
205
+ }}
206
+ />
207
+ ```
208
+
209
+ 说明:
210
+
211
+ - `items` 用于配置价格列表,每条最多展示前 2 行 `infoRows`。
212
+ - 每条列表项可以通过 `actionText` 和 `onActionClick` 自行决定是否展示右侧按钮。
213
+ - `footerActionText` 用于配置底部全宽按钮;不传或传空字符串时不展示。
214
+ - 如果需要完全自定义内容区域,可以传入 `children`,模板会保留标题栏和卡片外壳。
215
+
216
+ ## TaskActionCard
217
+
218
+ `TaskActionCard` 是任务操作按钮模板,用于展示一个全宽操作按钮。
219
+
220
+ 效果图:
221
+
222
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.33/assets/task-action-card.png" alt="TaskActionCard 示例" width="400" />
223
+
224
+ <p />
225
+
226
+ ```tsx
227
+ import { TaskActionCard } from '@doubao-apps/template';
228
+
229
+ <TaskActionCard
230
+ text="操作1"
231
+ onClick={() => {
232
+ console.log('action');
233
+ }}
234
+ />
235
+ ```
236
+
237
+ 说明:
238
+
239
+ - `text` 用于配置按钮文案,默认展示右箭头图标。
240
+
75
241
  ## OrderCard
76
242
 
77
243
  `OrderCard` 是提单卡模板,结构包含应用标题栏、商品摘要、提单信息、费用汇总和底部操作按钮,适合下单确认、支付确认等场景。
78
244
 
79
245
  效果图:
80
246
 
81
- <img src="https://unpkg.com/@doubao-apps/template@latest/assets/order-card.png" alt="OrderCard 示例" width="400" />
247
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.33/assets/order-card.png" alt="OrderCard 示例" width="400" />
82
248
 
83
249
  <p />
84
250
 
@@ -123,46 +289,13 @@ import { OrderCard } from '@doubao-apps/template';
123
289
  - `primaryActionText` 和 `secondaryActionText` 可以自定义底部操作按钮文案。
124
290
  - 用在 widget 中时,推荐让 `render` 直接返回 `OrderCard`。
125
291
 
126
-
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
292
  ## TransportCard
160
293
 
161
294
  `TransportCard` 是交通票务卡模板,结构包含应用标题栏、行程标题、出发/到达信息、中转信息和价格信息,适合机票、火车票、大巴等交通工具票务卡片。
162
295
 
163
296
  效果图:
164
297
 
165
- <img src="https://unpkg.com/@doubao-apps/template@latest/assets/transport-card.png" alt="TransportCard 示例" width="400" />
298
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.33/assets/transport-card.png" alt="TransportCard 示例" width="400" />
166
299
 
167
300
  <p />
168
301
 
@@ -197,7 +330,7 @@ import { TransportCard } from '@doubao-apps/template';
197
330
 
198
331
  效果图:
199
332
 
200
- <img src="https://unpkg.com/@doubao-apps/template@latest/assets/transport-list-card.png" alt="TransportListCard 示例" width="400" />
333
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.33/assets/transport-list-card.png" alt="TransportListCard 示例" width="400" />
201
334
 
202
335
  <p />
203
336
 
@@ -245,7 +378,7 @@ import { TransportListCard } from '@doubao-apps/template';
245
378
 
246
379
  效果图:
247
380
 
248
- <img src="https://unpkg.com/@doubao-apps/template@latest/assets/ticket-order-card.png" alt="TicketOrderCard 示例" width="400" />
381
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.33/assets/ticket-order-card.png" alt="TicketOrderCard 示例" width="400" />
249
382
 
250
383
  <p />
251
384
 
Binary file
Binary file
Binary file
@@ -0,0 +1,38 @@
1
+ import type { CSSProperties, TouchEvent } from '@lynx-js/types';
2
+ import type { ReactElement, ReactNode } from 'react';
3
+ import type { TemplateKey, TemplateText } from '../types.js';
4
+ import './styles.scss';
5
+ export interface AskHumanCardProps {
6
+ /** 选项列表。 */
7
+ items?: AskHumanCardItem[];
8
+ /** 是否展示底部跳过入口。 */
9
+ showSkip?: boolean;
10
+ /** 底部跳过入口文案。 */
11
+ skipText?: string;
12
+ /** 跳过入口自定义内容;优先级高于 skipText。 */
13
+ skipContent?: ReactNode;
14
+ /** 卡片根节点自定义类名。 */
15
+ className?: string;
16
+ /** 卡片根节点自定义样式。 */
17
+ style?: CSSProperties;
18
+ /** 点击卡片根节点时触发。 */
19
+ onClick?: (event: TouchEvent) => void;
20
+ /** 点击跳过入口时触发。 */
21
+ onSkipClick?: (event: TouchEvent) => void;
22
+ }
23
+ export interface AskHumanCardItem {
24
+ /** 选项唯一标识;不传时使用数组下标。 */
25
+ key?: TemplateKey;
26
+ /** 选项文案。 */
27
+ text?: TemplateText;
28
+ /** 选项自定义内容;优先级高于 text。 */
29
+ children?: ReactNode;
30
+ /** 选项根节点自定义类名。 */
31
+ className?: string;
32
+ /** 选项根节点自定义样式。 */
33
+ style?: CSSProperties;
34
+ /** 点击选项时触发。 */
35
+ onClick?: (event: TouchEvent) => void;
36
+ }
37
+ export declare function AskHumanCard(props: AskHumanCardProps): ReactElement;
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { useThemeClassName } from "@byted-doubao-apps/components";
2
+ import { clsx } from "clsx";
3
+ import "./styles.css";
4
+ const ASK_HUMAN_CARD_SKIP_ICON_CONTENT = `<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
5
+ <path d="M1.49415 9.00586C1.49171 8.59165 1.82555 8.25318 2.23976 8.25073L12.1458 8.19287L10.9746 7.021L8.53419 4.58057C8.24132 4.2877 8.24136 3.81219 8.53419 3.51929C8.82709 3.22675 9.30195 3.22656 9.59473 3.51929L12.0359 5.96045L14.4763 8.40161C14.5413 8.46664 14.5924 8.54269 14.6294 8.625V2.71875C14.6294 2.30464 14.9653 1.96893 15.3794 1.96875C15.7936 1.96875 16.1294 2.30454 16.1294 2.71875V15.2812C16.1294 15.6955 15.7936 16.0312 15.3794 16.0312C14.9653 16.0311 14.6294 15.6954 14.6294 15.2812V9.23877C14.5924 9.32101 14.5413 9.39716 14.4763 9.46216L9.59473 14.3445C9.30193 14.6372 8.82708 14.6371 8.53419 14.3445C8.24132 14.0516 8.24136 13.5768 8.53419 13.2839L12.1245 9.69287L2.24855 9.75073C1.83452 9.75316 1.49686 9.41983 1.49415 9.00586Z" fill="currentColor"/>
6
+ </svg>`;
7
+ function isAskHumanCardTextEmpty(content) {
8
+ return null == content || '' === content;
9
+ }
10
+ function isAskHumanCardNodeEmpty(content) {
11
+ return null == content || 'boolean' == typeof content || '' === content;
12
+ }
13
+ function renderAskHumanCardItem(item, index) {
14
+ const hasCustomContent = !isAskHumanCardNodeEmpty(item.children);
15
+ if (!hasCustomContent && isAskHumanCardTextEmpty(item.text)) return null;
16
+ return <view className={clsx('doubao-ask-human-card__option', item.className)} style={item.style} key={item.key ?? index} {...null != item.onClick ? {
17
+ catchtap: item.onClick
18
+ } : {}}>
19
+ {hasCustomContent ? item.children : <text className="doubao-ask-human-card__option-text" text-maxline="1">
20
+ {item.text}
21
+ </text>}
22
+ </view>;
23
+ }
24
+ function AskHumanCard(props) {
25
+ const { items = [], showSkip = true, skipText = '跳过', skipContent, className, style, onClick, onSkipClick } = props;
26
+ const optionNodes = items.map(renderAskHumanCardItem).filter((node)=>null != node);
27
+ const hasSkipContent = !isAskHumanCardNodeEmpty(skipContent);
28
+ const hasSkip = showSkip && (hasSkipContent || skipText.length > 0);
29
+ return <view className={useThemeClassName(clsx('doubao-ask-human-card', className))} style={style} bindtap={onClick}>
30
+ {optionNodes}
31
+ {hasSkip ? <view className="doubao-ask-human-card__skip" catchtap={onSkipClick}>
32
+ {hasSkipContent ? skipContent : <text className="doubao-ask-human-card__skip-text" text-maxline="1">
33
+ {skipText}
34
+ </text>}
35
+ <svg className="doubao-ask-human-card__skip-icon" content={ASK_HUMAN_CARD_SKIP_ICON_CONTENT}/>
36
+ </view> : null}
37
+ </view>;
38
+ }
39
+ export { AskHumanCard };
@@ -0,0 +1,60 @@
1
+ .doubao-ask-human-card {
2
+ --doubao-ask-human-card-bg: var(--bg-base-2-overlay);
3
+ --doubao-ask-human-card-option-bg: var(--static-white);
4
+ --doubao-ask-human-card-option-text: var(--neutral-100);
5
+ --doubao-ask-human-card-icon: var(--neutral-100);
6
+ --doubao-ask-human-card-gap: 8px;
7
+ --doubao-ask-human-card-option-height: 44px;
8
+ --doubao-ask-human-card-option-radius: 8px;
9
+ align-items: flex-start;
10
+ gap: var(--doubao-ask-human-card-gap);
11
+ box-sizing: border-box;
12
+ background-color: var(--doubao-ask-human-card-bg);
13
+ flex-direction: column;
14
+ width: 100%;
15
+ display: flex;
16
+ }
17
+
18
+ .doubao-ask-human-card__option, .doubao-ask-human-card__skip {
19
+ max-width: 100%;
20
+ height: var(--doubao-ask-human-card-option-height);
21
+ box-sizing: border-box;
22
+ background-color: var(--doubao-ask-human-card-option-bg);
23
+ border-radius: var(--doubao-ask-human-card-option-radius);
24
+ flex-direction: row;
25
+ justify-content: center;
26
+ align-items: center;
27
+ min-width: 0;
28
+ display: flex;
29
+ }
30
+
31
+ .doubao-ask-human-card__option {
32
+ padding: 11px 12px;
33
+ }
34
+
35
+ .doubao-ask-human-card__skip {
36
+ gap: 4px;
37
+ padding: 11px 10px 11px 12px;
38
+ }
39
+
40
+ .doubao-ask-human-card__option-text, .doubao-ask-human-card__skip-text {
41
+ min-width: 0;
42
+ color: var(--doubao-ask-human-card-option-text);
43
+ text-align: center;
44
+ text-overflow: ellipsis;
45
+ white-space: nowrap;
46
+ font-family: PingFang SC, sans-serif;
47
+ font-size: 16px;
48
+ font-style: normal;
49
+ font-weight: 500;
50
+ line-height: 22px;
51
+ overflow: hidden;
52
+ }
53
+
54
+ .doubao-ask-human-card__skip-icon {
55
+ width: 18px;
56
+ height: 18px;
57
+ color: var(--doubao-ask-human-card-icon);
58
+ flex-shrink: 0;
59
+ }
60
+
@@ -10,16 +10,16 @@
10
10
  width: auto;
11
11
  height: var(--doubao-template-action-bar-button-height, 44px);
12
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));
13
+ --doubao-button-border-radius: var(--doubao-template-action-bar-button-radius, 8px);
14
+ --doubao-button-default-height: var(--doubao-template-action-bar-button-height, 44px);
15
+ --doubao-button-default-padding-x: var(--doubao-template-action-bar-button-padding-x, 12px);
16
+ --doubao-button-default-padding-y: 0;
17
+ --doubao-button-default-font-size: var(--doubao-template-action-bar-button-font-size, 16px);
18
+ --doubao-button-default-line-height: var(--doubao-template-action-bar-button-line-height, 22px);
19
+ --doubao-button-primary-bg: var(--doubao-template-action-bar-primary-bg, var(--primary-50));
20
+ --doubao-button-primary-text: var(--doubao-template-action-bar-primary-text, var(--static-white));
21
+ --doubao-button-default-bg: var(--doubao-template-action-bar-secondary-bg, var(--bg-base-2-overlay));
22
+ --doubao-button-default-text: var(--doubao-template-action-bar-secondary-text, var(--neutral-100));
23
23
  flex: 1 1 0;
24
24
  min-width: 0;
25
25
  }
@@ -1,4 +1,5 @@
1
1
  import { getAppInfo } from "../../utils/app-info.js";
2
+ import { TEMPLATE_CHEVRON_RIGHT_ICON_CONTENT } from "../../utils/icons.js";
2
3
  import "./styles.css";
3
4
  function TemplateTitleBarIcon({ appIconSrc }) {
4
5
  if (null != appIconSrc && appIconSrc.length > 0) return <image className="doubao-template-title-bar__app-icon" src={appIconSrc} mode="aspectFill"/>;
@@ -19,13 +20,13 @@ function TemplateTitleBar(props) {
19
20
  <text className="doubao-template-title-bar__more-text" text-maxline="1">
20
21
  {moreText}
21
22
  </text>
22
- <view className="doubao-template-title-bar__more-chevron"/>
23
+ <svg className="doubao-template-title-bar__more-chevron" content={TEMPLATE_CHEVRON_RIGHT_ICON_CONTENT}/>
23
24
  </view> : null}
24
25
  {!hasMore && reserveMore ? <view className="doubao-template-title-bar__more-placeholder">
25
26
  <text className="doubao-template-title-bar__more-text" text-maxline="1">
26
27
  更多
27
28
  </text>
28
- <view className="doubao-template-title-bar__more-chevron"/>
29
+ <svg className="doubao-template-title-bar__more-chevron" content={TEMPLATE_CHEVRON_RIGHT_ICON_CONTENT}/>
29
30
  </view> : null}
30
31
  </view>;
31
32
  }
@@ -58,12 +58,9 @@
58
58
  }
59
59
 
60
60
  .doubao-template-title-bar__more-chevron {
61
- box-sizing: border-box;
62
- border-top: 1px solid var(--neutral-50);
63
- border-right: 1px solid var(--neutral-50);
64
- width: 7px;
65
- height: 7px;
61
+ flex-shrink: 0;
62
+ width: 12px;
63
+ height: 12px;
66
64
  margin-left: 2px;
67
- transform: rotate(45deg);
68
65
  }
69
66
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,10 @@
1
1
  export { ListCard, type ListCardItem, type ListCardProps } from './list-card/index.js';
2
+ export { AskHumanCard, type AskHumanCardItem, type AskHumanCardProps } from './ask-human-card/index.js';
2
3
  export { InvalidCard, type InvalidCardProps } from './invalid-card/index.js';
4
+ export { SingleItemCard, type SingleItemCardInfoItem, type SingleItemCardInfoRow, type SingleItemCardProps } from './single-item-card/index.js';
3
5
  export { OrderCard, type OrderCardFeeItem, type OrderCardInfoItem, type OrderCardProps } from './order-card/index.js';
4
- export { ProductActionCard, type ProductActionCardProps } from './product-action-card/index.js';
6
+ export { PriceActionListCard, type PriceActionListCardInfoRow, type PriceActionListCardItem, type PriceActionListCardProps } from './price-action-list-card/index.js';
7
+ export { TaskActionCard, type TaskActionCardProps } from './task-action-card/index.js';
5
8
  export { TransportListCard, type TransportListCardItem, type TransportListCardProps } from './transport-list-card/index.js';
6
9
  export { TransportCard, type TransportCardProps } from './transport-card/index.js';
7
10
  export type { TemplateKey, TemplateText } from './types.js';
package/dist/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  export { ListCard } from "./list-card/index.js";
2
+ export { AskHumanCard } from "./ask-human-card/index.js";
2
3
  export { InvalidCard } from "./invalid-card/index.js";
4
+ export { SingleItemCard } from "./single-item-card/index.js";
3
5
  export { OrderCard } from "./order-card/index.js";
4
- export { ProductActionCard } from "./product-action-card/index.js";
6
+ export { PriceActionListCard } from "./price-action-list-card/index.js";
7
+ export { TaskActionCard } from "./task-action-card/index.js";
5
8
  export { TransportListCard } from "./transport-list-card/index.js";
6
9
  export { TransportCard } from "./transport-card/index.js";
7
10
  export { TicketOrderCard } from "./ticket-order-card/index.js";
@@ -0,0 +1,56 @@
1
+ import type { CSSProperties, TouchEvent } from '@lynx-js/types';
2
+ import type { ReactElement, ReactNode } from 'react';
3
+ import type { TemplateKey, TemplateText } from '../types.js';
4
+ import './styles.scss';
5
+ export interface PriceActionListCardProps {
6
+ /** 标题栏右侧「更多」入口的文案。 */
7
+ moreText?: string;
8
+ /** 是否展示标题栏右侧「更多」入口。 */
9
+ showMore?: boolean;
10
+ /** 列表项数据。 */
11
+ items?: PriceActionListCardItem[];
12
+ /** 底部全宽按钮文案;不传或传空字符串时不展示。 */
13
+ footerActionText?: string;
14
+ /** 自定义卡片内容;传入后不再渲染默认列表和底部按钮。 */
15
+ children?: ReactNode;
16
+ /** 卡片根节点自定义类名。 */
17
+ className?: string;
18
+ /** 卡片根节点自定义样式。 */
19
+ style?: CSSProperties;
20
+ /** 点击卡片根节点时触发。 */
21
+ onClick?: (event: TouchEvent) => void;
22
+ /** 点击标题栏右侧「更多」入口时触发。 */
23
+ onMoreClick?: (event: TouchEvent) => void;
24
+ /** 点击底部全宽按钮时触发。 */
25
+ onFooterActionClick?: (event?: TouchEvent) => void;
26
+ }
27
+ export interface PriceActionListCardItem {
28
+ /** 列表项唯一标识;不传时使用数组下标。 */
29
+ key?: TemplateKey;
30
+ /** 左侧价格或主数值。 */
31
+ price?: TemplateText;
32
+ /** 左侧辅助标签。 */
33
+ badgeText?: TemplateText;
34
+ /** 中间信息行。最多展示前 2 行。 */
35
+ infoRows?: PriceActionListCardInfoRow[];
36
+ /** 右侧操作按钮文案;不传或传空字符串时不展示。 */
37
+ actionText?: string;
38
+ /** 列表项自定义内容;传入后不再渲染默认三列结构。 */
39
+ children?: ReactNode;
40
+ /** 列表项根节点自定义类名。 */
41
+ className?: string;
42
+ /** 列表项根节点自定义样式。 */
43
+ style?: CSSProperties;
44
+ /** 点击列表项时触发。 */
45
+ onClick?: (event: TouchEvent) => void;
46
+ /** 点击列表项右侧操作按钮时触发。 */
47
+ onActionClick?: (event?: TouchEvent) => void;
48
+ }
49
+ export interface PriceActionListCardInfoRow {
50
+ /** 信息行唯一标识;不传时使用数组下标。 */
51
+ key?: TemplateKey;
52
+ /** 信息行文案。 */
53
+ text: TemplateText;
54
+ }
55
+ export declare function PriceActionListCard(props: PriceActionListCardProps): ReactElement;
56
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,55 @@
1
+ import { Button, useThemeClassName } from "@byted-doubao-apps/components";
2
+ import { clsx } from "clsx";
3
+ import { TemplateTitleBar } from "../components/title-bar/index.js";
4
+ import "./styles.css";
5
+ const PRICE_ACTION_LIST_CARD_INFO_ROW_LIMIT = 2;
6
+ function isPriceActionListCardTextEmpty(content) {
7
+ return null == content || '' === content;
8
+ }
9
+ function isPriceActionListCardNodeEmpty(content) {
10
+ return null == content || 'boolean' == typeof content || '' === content;
11
+ }
12
+ function PriceActionListCardItemView({ item, isLast }) {
13
+ const hasPrice = !isPriceActionListCardTextEmpty(item.price);
14
+ const hasBadge = !isPriceActionListCardTextEmpty(item.badgeText);
15
+ const hasAction = null != item.actionText && item.actionText.length > 0;
16
+ const hasCustomContent = !isPriceActionListCardNodeEmpty(item.children);
17
+ const infoRows = (item.infoRows ?? []).filter((infoRow)=>!isPriceActionListCardTextEmpty(infoRow.text)).slice(0, PRICE_ACTION_LIST_CARD_INFO_ROW_LIMIT);
18
+ return <view className={clsx('doubao-price-action-list-card__item', isLast && 'doubao-price-action-list-card__item--last', item.className)} style={item.style} {...null != item.onClick ? {
19
+ catchtap: item.onClick
20
+ } : {}}>
21
+ {hasCustomContent ? item.children : <view className="doubao-price-action-list-card__item-content">
22
+ <view className="doubao-price-action-list-card__value">
23
+ {hasPrice ? <text className="doubao-price-action-list-card__price" text-maxline="1">
24
+ {item.price}
25
+ </text> : null}
26
+ {hasBadge ? <text className="doubao-price-action-list-card__badge" text-maxline="1">
27
+ {item.badgeText}
28
+ </text> : null}
29
+ </view>
30
+ <view className="doubao-price-action-list-card__info">
31
+ {infoRows.map((infoRow, index)=><text className="doubao-price-action-list-card__info-row" text-maxline="1" key={infoRow.key ?? index}>
32
+ {infoRow.text}
33
+ </text>)}
34
+ </view>
35
+ {hasAction ? <Button className="doubao-price-action-list-card__item-action" type="default" text={item.actionText} onClick={item.onActionClick}/> : null}
36
+ </view>}
37
+ </view>;
38
+ }
39
+ function PriceActionListCard(props) {
40
+ const { moreText, showMore = true, items = [], footerActionText, children, className, style, onClick, onMoreClick, onFooterActionClick } = props;
41
+ const hasCustomContent = !isPriceActionListCardNodeEmpty(children);
42
+ const hasFooterAction = null != footerActionText && footerActionText.length > 0;
43
+ return <view className={useThemeClassName(clsx('doubao-price-action-list-card', className))} style={style} bindtap={onClick} clip-radius="true">
44
+ <TemplateTitleBar moreText={moreText} showMore={showMore} onMoreClick={onMoreClick}/>
45
+ <view className="doubao-price-action-list-card__body">
46
+ {hasCustomContent ? children : <view className="doubao-price-action-list-card__default">
47
+ {items.map((item, index)=><PriceActionListCardItemView item={item} isLast={index === items.length - 1} key={item.key ?? index}/>)}
48
+ {hasFooterAction ? <view className="doubao-price-action-list-card__footer">
49
+ <Button className="doubao-price-action-list-card__footer-action" type="default" text={footerActionText} onClick={onFooterActionClick}/>
50
+ </view> : null}
51
+ </view>}
52
+ </view>
53
+ </view>;
54
+ }
55
+ export { PriceActionListCard };