@doubao-apps/template 0.0.34 → 0.0.35-rc.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
@@ -38,7 +38,7 @@ import { ListCard } from '@doubao-apps/template';
38
38
 
39
39
  效果图:
40
40
 
41
- <img src="https://unpkg.com/@doubao-apps/template@0.0.34/assets/ask_human.png" alt="AskHumanCard 示例" width="400" />
41
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.35-rc.0/assets/ask_human.png" alt="AskHumanCard 示例" width="400" />
42
42
 
43
43
  <p />
44
44
 
@@ -127,7 +127,7 @@ import { ListCard } from '@doubao-apps/template';
127
127
 
128
128
  效果图:
129
129
 
130
- <img src="https://unpkg.com/@doubao-apps/template@0.0.34/assets/single-item-card.png" alt="SingleItemCard 示例" width="400" />
130
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.35-rc.0/assets/single-item-card.png" alt="SingleItemCard 示例" width="400" />
131
131
 
132
132
  <p />
133
133
 
@@ -168,13 +168,53 @@ import { SingleItemCard } from '@doubao-apps/template';
168
168
  - `primaryActionText` 和 `secondaryActionText` 可以配置底部操作按钮,不传时不展示操作区。
169
169
  - 如果需要完全自定义内容区域,可以传入 `children`,模板会保留标题栏和卡片外壳。
170
170
 
171
+ ## MediaLayoutCard
172
+
173
+ `MediaLayoutCard` 是媒体布局卡模板,结构包含应用标题栏、左侧媒体、中间标题与信息行、右侧扩展内容和底部操作按钮,适合需要自定义布局内容的入口卡片。
174
+
175
+ 效果图:
176
+
177
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.35-rc.0/assets/media-layout-card.png" alt="SingleItemCard 示例" width="400" />
178
+
179
+ <p />
180
+
181
+ ```tsx
182
+ import { MediaLayoutCard } from '@doubao-apps/template';
183
+
184
+ <MediaLayoutCard
185
+ moreText="更多"
186
+ title="小程序名称"
187
+ media={<image src="https://example.com/app-icon.png" mode="aspectFill" />}
188
+ infoRows={[
189
+ {
190
+ content: <text>提供小程序开发、构建、调试和发布能力。</text>
191
+ },
192
+ {
193
+ text: '辅助信息'
194
+ }
195
+ ]}
196
+ extra={<text>右侧内容</text>}
197
+ primaryActionText="确认"
198
+ onPrimaryActionClick={() => {
199
+ console.log('confirm');
200
+ }}
201
+ />
202
+ ```
203
+
204
+ 说明:
205
+
206
+ - `infoRows` 最多展示前 2 行;纯文字可使用 `text`,需要自定义节点时使用 `content`。
207
+ - `extra` 用于配置右侧扩展内容,例如价格、标签、状态或自定义操作区。
208
+ - `primaryActionText` 和 `secondaryActionText` 用于配置底部操作按钮;只传主按钮时展示蓝色全宽按钮,只传次按钮时展示灰色全宽按钮,同时传入时展示左右双按钮。
209
+ - 如果需要完全自定义内容区域,可以传入 `children`,模板会保留标题栏和底部操作区。
210
+
171
211
  ## PriceActionListCard
172
212
 
173
213
  `PriceActionListCard` 是价格操作列表卡模板,结构包含应用标题栏、多条价格信息和底部操作按钮,适合展示多个可操作的报价、权益或结果项。
174
214
 
175
215
  效果图:
176
216
 
177
- <img src="https://unpkg.com/@doubao-apps/template@0.0.34/assets/price-action-list-card.png" alt="PriceActionListCard 示例" width="400" />
217
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.35-rc.0/assets/price-action-list-card.png" alt="PriceActionListCard 示例" width="400" />
178
218
 
179
219
  <p />
180
220
 
@@ -222,7 +262,7 @@ import { PriceActionListCard } from '@doubao-apps/template';
222
262
 
223
263
  效果图:
224
264
 
225
- <img src="https://unpkg.com/@doubao-apps/template@0.0.34/assets/task-action-card.png" alt="TaskActionCard 示例" width="400" />
265
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.35-rc.0/assets/task-action-card.png" alt="TaskActionCard 示例" width="400" />
226
266
 
227
267
  <p />
228
268
 
@@ -247,7 +287,7 @@ import { TaskActionCard } from '@doubao-apps/template';
247
287
 
248
288
  效果图:
249
289
 
250
- <img src="https://unpkg.com/@doubao-apps/template@0.0.34/assets/order-card.png" alt="OrderCard 示例" width="400" />
290
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.35-rc.0/assets/order-card.png" alt="OrderCard 示例" width="400" />
251
291
 
252
292
  <p />
253
293
 
@@ -308,7 +348,7 @@ import { OrderCard } from '@doubao-apps/template';
308
348
 
309
349
  效果图:
310
350
 
311
- <img src="https://unpkg.com/@doubao-apps/template@0.0.34/assets/transport-card.png" alt="TransportCard 示例" width="400" />
351
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.35-rc.0/assets/transport-card.png" alt="TransportCard 示例" width="400" />
312
352
 
313
353
  <p />
314
354
 
@@ -343,7 +383,7 @@ import { TransportCard } from '@doubao-apps/template';
343
383
 
344
384
  效果图:
345
385
 
346
- <img src="https://unpkg.com/@doubao-apps/template@0.0.34/assets/transport-list-card.png" alt="TransportListCard 示例" width="400" />
386
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.35-rc.0/assets/transport-list-card.png" alt="TransportListCard 示例" width="400" />
347
387
 
348
388
  <p />
349
389
 
@@ -390,7 +430,7 @@ import { TransportListCard } from '@doubao-apps/template';
390
430
 
391
431
  效果图:
392
432
 
393
- <img src="https://unpkg.com/@doubao-apps/template@0.0.34/assets/ticket-order-card.png" alt="TicketOrderCard 示例" width="400" />
433
+ <img src="https://unpkg.com/@doubao-apps/template@0.0.35-rc.0/assets/ticket-order-card.png" alt="TicketOrderCard 示例" width="400" />
394
434
 
395
435
  <p />
396
436
 
Binary file
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export { ListCard, type ListCardItem, type ListCardProps } from './list-card/ind
2
2
  export { AskHumanCard, type AskHumanCardItem, type AskHumanCardProps } from './ask-human-card/index.js';
3
3
  export { InvalidCard, type InvalidCardProps } from './invalid-card/index.js';
4
4
  export { SingleItemCard, type SingleItemCardInfoItem, type SingleItemCardInfoRow, type SingleItemCardProps } from './single-item-card/index.js';
5
+ export { MediaLayoutCard, type MediaLayoutCardInfoRow, type MediaLayoutCardProps } from './media-layout-card/index.js';
6
+ export { PriceText, Tag, type PriceTextProps, type TagProps } from './ui/index.js';
5
7
  export { OrderCard, type OrderCardFeeItem, type OrderCardInfoItem, type OrderCardProductItem, type OrderCardProps } from './order-card/index.js';
6
8
  export { PriceActionListCard, type PriceActionListCardInfoRow, type PriceActionListCardItem, type PriceActionListCardProps } from './price-action-list-card/index.js';
7
9
  export { TaskActionCard, type TaskActionCardProps } from './task-action-card/index.js';
package/dist/index.js CHANGED
@@ -2,6 +2,8 @@ export { ListCard } from "./list-card/index.js";
2
2
  export { AskHumanCard } from "./ask-human-card/index.js";
3
3
  export { InvalidCard } from "./invalid-card/index.js";
4
4
  export { SingleItemCard } from "./single-item-card/index.js";
5
+ export { MediaLayoutCard } from "./media-layout-card/index.js";
6
+ export { PriceText, Tag } from "./ui/index.js";
5
7
  export { OrderCard } from "./order-card/index.js";
6
8
  export { PriceActionListCard } from "./price-action-list-card/index.js";
7
9
  export { TaskActionCard } from "./task-action-card/index.js";
@@ -0,0 +1,54 @@
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 MediaLayoutCardProps {
6
+ /** 标题栏右侧「更多」入口的文案。 */
7
+ moreText?: string;
8
+ /** 是否展示标题栏右侧「更多」入口。 */
9
+ showMore?: boolean;
10
+ /** 主标题。字符串和数字会按默认单行标题样式渲染,传入节点时直接渲染自定义内容。 */
11
+ title?: ReactNode;
12
+ /** 是否展示主标题右侧箭头。 */
13
+ showChevron?: boolean;
14
+ /** 左侧媒体节点。 */
15
+ media?: ReactNode;
16
+ /** 中间信息行。最多展示前 2 行。 */
17
+ infoRows?: MediaLayoutCardInfoRow[];
18
+ /** 右侧扩展内容。 */
19
+ extra?: ReactNode;
20
+ /** 右侧次按钮文案;extra 为空时生效。 */
21
+ extraActionText?: string;
22
+ /** 主按钮文案。 */
23
+ primaryActionText?: string;
24
+ /** 次按钮文案。 */
25
+ secondaryActionText?: string;
26
+ /** 自定义内容区;传入后不再渲染默认布局。 */
27
+ children?: ReactNode;
28
+ /** 卡片根节点自定义类名。 */
29
+ className?: string;
30
+ /** 卡片根节点自定义样式。 */
31
+ style?: CSSProperties;
32
+ /** 点击卡片根节点时触发。 */
33
+ onClick?: (event: TouchEvent) => void;
34
+ /** 点击标题栏右侧「更多」入口时触发。 */
35
+ onMoreClick?: (event: TouchEvent) => void;
36
+ /** 点击内容区时触发。 */
37
+ onContentClick?: (event: TouchEvent) => void;
38
+ /** 点击右侧次按钮时触发。 */
39
+ onExtraActionClick?: (event?: TouchEvent) => void;
40
+ /** 点击主按钮时触发。 */
41
+ onPrimaryActionClick?: (event?: TouchEvent) => void;
42
+ /** 点击次按钮时触发。 */
43
+ onSecondaryActionClick?: (event?: TouchEvent) => void;
44
+ }
45
+ export interface MediaLayoutCardInfoRow {
46
+ /** 信息行唯一标识;不传时使用数组下标。 */
47
+ key?: TemplateKey;
48
+ /** 信息行内容;优先级高于 text。字符串和数字会按默认信息样式渲染,传入节点时直接渲染自定义内容。 */
49
+ content?: ReactNode;
50
+ /** 信息行单字段文案;只需要传入文字时使用。 */
51
+ text?: TemplateText;
52
+ }
53
+ export declare function MediaLayoutCard(props: MediaLayoutCardProps): ReactElement;
54
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,83 @@
1
+ import { Button, useThemeClassName } from "@byted-doubao-apps/components";
2
+ import { clsx } from "clsx";
3
+ import { TemplateActionBar } from "../components/action-bar/index.js";
4
+ import { TemplateTitleBar } from "../components/title-bar/index.js";
5
+ import { TEMPLATE_CHEVRON_RIGHT_ICON_CONTENT } from "../utils/icons.js";
6
+ import "./styles.css";
7
+ const MEDIA_LAYOUT_CARD_INFO_ROW_LIMIT = 2;
8
+ function isMediaLayoutCardNodeEmpty(content) {
9
+ return null == content || 'boolean' == typeof content || '' === content;
10
+ }
11
+ function renderMediaLayoutCardText(content, className) {
12
+ if (isMediaLayoutCardNodeEmpty(content)) return null;
13
+ if ('string' == typeof content || 'number' == typeof content) return <text className={className} text-maxline="1">
14
+ {content}
15
+ </text>;
16
+ return <view className={`${className}-custom`}>{content}</view>;
17
+ }
18
+ function renderMediaLayoutCardTitle(content, showChevron) {
19
+ const titleNode = renderMediaLayoutCardText(content, 'doubao-media-layout-card__title');
20
+ if (null == titleNode) return null;
21
+ return <view className="doubao-media-layout-card__title-row">
22
+ <view className="doubao-media-layout-card__title-main">{titleNode}</view>
23
+ {showChevron ? <svg className="doubao-media-layout-card__chevron" content={TEMPLATE_CHEVRON_RIGHT_ICON_CONTENT}/> : null}
24
+ </view>;
25
+ }
26
+ function MediaLayoutCardMedia(props) {
27
+ const { media } = props;
28
+ if (!isMediaLayoutCardNodeEmpty(media)) return <view className="doubao-media-layout-card__media">{media}</view>;
29
+ return <view className="doubao-media-layout-card__media"/>;
30
+ }
31
+ function getMediaLayoutCardInfoContent(row) {
32
+ return isMediaLayoutCardNodeEmpty(row.content) ? row.text : row.content;
33
+ }
34
+ function renderMediaLayoutCardInfoRow(row, index) {
35
+ const content = getMediaLayoutCardInfoContent(row);
36
+ if (isMediaLayoutCardNodeEmpty(content)) return null;
37
+ return <view className="doubao-media-layout-card__info-row" key={row.key ?? index}>
38
+ {renderMediaLayoutCardText(content, 'doubao-media-layout-card__info-text')}
39
+ </view>;
40
+ }
41
+ function renderMediaLayoutCardExtra(props) {
42
+ const { extra, extraActionText, onExtraActionClick } = props;
43
+ if (!isMediaLayoutCardNodeEmpty(extra)) {
44
+ if ('string' == typeof extra || 'number' == typeof extra) return <view className="doubao-media-layout-card__extra">
45
+ <text className="doubao-media-layout-card__extra-text" text-maxline="1">
46
+ {extra}
47
+ </text>
48
+ </view>;
49
+ return <view className="doubao-media-layout-card__extra">{extra}</view>;
50
+ }
51
+ if (null != extraActionText && extraActionText.length > 0) return <view className="doubao-media-layout-card__extra">
52
+ <Button className="doubao-media-layout-card__extra-action" type="default" text={extraActionText} onClick={onExtraActionClick}/>
53
+ </view>;
54
+ return null;
55
+ }
56
+ function MediaLayoutCard(props) {
57
+ const { moreText, showMore = true, title, showChevron = true, media, infoRows = [], extra, extraActionText, primaryActionText, secondaryActionText, children, className, style, onClick, onMoreClick, onContentClick, onExtraActionClick, onPrimaryActionClick, onSecondaryActionClick } = props;
58
+ const hasCustomContent = !isMediaLayoutCardNodeEmpty(children);
59
+ const titleNode = renderMediaLayoutCardTitle(title, showChevron);
60
+ const infoRowNodes = infoRows.map((row, index)=>renderMediaLayoutCardInfoRow(row, index)).filter((node)=>null != node).slice(0, MEDIA_LAYOUT_CARD_INFO_ROW_LIMIT);
61
+ const extraNode = renderMediaLayoutCardExtra({
62
+ extra,
63
+ extraActionText,
64
+ onExtraActionClick
65
+ });
66
+ return <view className={useThemeClassName(clsx('doubao-media-layout-card', className))} style={style} bindtap={onClick} clip-radius="true">
67
+ <TemplateTitleBar moreText={moreText} showMore={showMore} onMoreClick={onMoreClick}/>
68
+ <view className="doubao-media-layout-card__body" {...null != onContentClick ? {
69
+ catchtap: onContentClick
70
+ } : {}}>
71
+ {hasCustomContent ? children : <view className="doubao-media-layout-card__layout">
72
+ <MediaLayoutCardMedia media={media}/>
73
+ <view className="doubao-media-layout-card__main">
74
+ {titleNode}
75
+ {infoRowNodes}
76
+ </view>
77
+ {extraNode}
78
+ </view>}
79
+ </view>
80
+ <TemplateActionBar className="doubao-media-layout-card__action-bar" primaryActionText={primaryActionText} secondaryActionText={secondaryActionText} onPrimaryActionClick={onPrimaryActionClick} onSecondaryActionClick={onSecondaryActionClick}/>
81
+ </view>;
82
+ }
83
+ export { MediaLayoutCard };
@@ -0,0 +1,131 @@
1
+ .doubao-media-layout-card {
2
+ box-sizing: border-box;
3
+ background-color: var(--bg-base-1);
4
+ border: 1px solid var(--bg-base-2-overlay);
5
+ border-radius: 8px;
6
+ flex-direction: column;
7
+ align-items: stretch;
8
+ width: 100%;
9
+ display: flex;
10
+ overflow: hidden;
11
+ }
12
+
13
+ .doubao-media-layout-card__body {
14
+ box-sizing: border-box;
15
+ background-color: var(--bg-base-1);
16
+ width: 100%;
17
+ padding: 12px;
18
+ }
19
+
20
+ .doubao-media-layout-card__layout {
21
+ flex-direction: row;
22
+ align-items: center;
23
+ width: 100%;
24
+ display: flex;
25
+ }
26
+
27
+ .doubao-media-layout-card__media {
28
+ background-color: var(--bg-base-1-overlay);
29
+ border-radius: 8px;
30
+ flex-shrink: 0;
31
+ width: 96px;
32
+ height: 96px;
33
+ overflow: hidden;
34
+ }
35
+
36
+ .doubao-media-layout-card__main {
37
+ flex-direction: column;
38
+ flex: 1 1 0;
39
+ align-items: flex-start;
40
+ min-width: 0;
41
+ margin-left: 12px;
42
+ display: flex;
43
+ }
44
+
45
+ .doubao-media-layout-card__title, .doubao-media-layout-card__title-custom, .doubao-media-layout-card__info-text, .doubao-media-layout-card__info-text-custom, .doubao-media-layout-card__extra-text {
46
+ max-width: 100%;
47
+ overflow: hidden;
48
+ }
49
+
50
+ .doubao-media-layout-card__title-row {
51
+ flex-direction: row;
52
+ align-items: center;
53
+ width: 100%;
54
+ display: flex;
55
+ }
56
+
57
+ .doubao-media-layout-card__title-main {
58
+ flex-direction: row;
59
+ align-items: center;
60
+ max-width: 100%;
61
+ display: flex;
62
+ }
63
+
64
+ .doubao-media-layout-card__title {
65
+ color: var(--neutral-100);
66
+ text-overflow: ellipsis;
67
+ white-space: nowrap;
68
+ font-family: PingFang SC, sans-serif;
69
+ font-size: 16px;
70
+ font-style: normal;
71
+ font-weight: 500;
72
+ line-height: 24px;
73
+ }
74
+
75
+ .doubao-media-layout-card__chevron {
76
+ flex-shrink: 0;
77
+ width: 12px;
78
+ height: 12px;
79
+ margin-left: 4px;
80
+ }
81
+
82
+ .doubao-media-layout-card__title-custom, .doubao-media-layout-card__info-text-custom {
83
+ flex-direction: row;
84
+ align-items: center;
85
+ width: 100%;
86
+ display: flex;
87
+ }
88
+
89
+ .doubao-media-layout-card__info-row {
90
+ flex-direction: row;
91
+ align-items: center;
92
+ width: 100%;
93
+ margin-top: 2px;
94
+ padding: 3px 0;
95
+ display: flex;
96
+ overflow: hidden;
97
+ }
98
+
99
+ .doubao-media-layout-card__info-text, .doubao-media-layout-card__extra-text {
100
+ color: var(--neutral-50);
101
+ text-overflow: ellipsis;
102
+ white-space: nowrap;
103
+ font-family: PingFang SC, sans-serif;
104
+ font-size: 13px;
105
+ font-style: normal;
106
+ font-weight: 400;
107
+ line-height: 20px;
108
+ }
109
+
110
+ .doubao-media-layout-card__extra {
111
+ flex-direction: row;
112
+ flex-shrink: 0;
113
+ align-items: center;
114
+ margin-left: auto;
115
+ display: flex;
116
+ }
117
+
118
+ .doubao-media-layout-card__extra-action {
119
+ --doubao-button-border-radius: 8px;
120
+ --doubao-button-default-height: 44px;
121
+ --doubao-button-default-padding-x: 12px;
122
+ --doubao-button-default-padding-y: 0;
123
+ --doubao-button-default-font-size: 16px;
124
+ --doubao-button-default-line-height: 22px;
125
+ --doubao-button-default-bg: var(--bg-base-2-overlay);
126
+ --doubao-button-default-text: var(--neutral-100);
127
+ flex-shrink: 0;
128
+ width: 80px;
129
+ height: 44px;
130
+ }
131
+