@doubao-dev/template 0.0.38-canary-22dd4cbf-20260720020201
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.
Potentially problematic release.
This version of @doubao-dev/template might be problematic. Click here for more details.
- package/README.md +282 -0
- package/assets/ask-human-card.png +0 -0
- package/assets/checkout-card.png +0 -0
- package/assets/content-card.png +0 -0
- package/assets/price-action-card.png +0 -0
- package/assets/ticket-order-card.png +0 -0
- package/assets/transit-card.png +0 -0
- package/dist/ask-human-card/index.d.ts +44 -0
- package/dist/ask-human-card/index.js +79 -0
- package/dist/ask-human-card/styles.css +66 -0
- package/dist/checkout-card/index.d.ts +55 -0
- package/dist/checkout-card/index.js +40 -0
- package/dist/checkout-card/styles.css +34 -0
- package/dist/components/chevron-right-icon/index.d.ts +6 -0
- package/dist/components/chevron-right-icon/index.js +13 -0
- package/dist/components/extra-action/index.d.ts +50 -0
- package/dist/components/extra-action/index.js +31 -0
- package/dist/components/extra-action/styles.css +10 -0
- package/dist/components/footer/index.d.ts +27 -0
- package/dist/components/footer/index.js +15 -0
- package/dist/components/footer/styles.css +27 -0
- package/dist/components/header/index.d.ts +13 -0
- package/dist/components/header/index.js +27 -0
- package/dist/components/header/styles.css +62 -0
- package/dist/components/info-section/index.d.ts +47 -0
- package/dist/components/info-section/index.js +93 -0
- package/dist/components/info-section/styles.css +151 -0
- package/dist/components/product-summary/index.d.ts +26 -0
- package/dist/components/product-summary/index.js +55 -0
- package/dist/components/product-summary/styles.css +121 -0
- package/dist/components/route-section/index.d.ts +23 -0
- package/dist/components/route-section/index.js +39 -0
- package/dist/components/route-section/styles.css +54 -0
- package/dist/components/transport-summary/index.d.ts +31 -0
- package/dist/components/transport-summary/index.js +109 -0
- package/dist/components/transport-summary/styles.css +214 -0
- package/dist/content-card/index.d.ts +45 -0
- package/dist/content-card/index.js +72 -0
- package/dist/content-card/styles.css +160 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +6 -0
- package/dist/price-action-card/index.d.ts +52 -0
- package/dist/price-action-card/index.js +64 -0
- package/dist/price-action-card/styles.css +161 -0
- package/dist/ticket-order-card/index.d.ts +70 -0
- package/dist/ticket-order-card/index.js +27 -0
- package/dist/ticket-order-card/styles.css +18 -0
- package/dist/transit-card/index.d.ts +52 -0
- package/dist/transit-card/index.js +29 -0
- package/dist/transit-card/styles.css +53 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.js +0 -0
- package/dist/utils/app-info.d.ts +6 -0
- package/dist/utils/app-info.js +20 -0
- package/dist/utils/icons.d.ts +2 -0
- package/dist/utils/icons.js +28 -0
- package/package.json +40 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useThemeClassName } from "@byted-doubao-apps/components";
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { renderTemplateExtraAction, stopTemplateExtraActionTap } from "../components/extra-action/index.js";
|
|
4
|
+
import { TemplateCardFooter } from "../components/footer/index.js";
|
|
5
|
+
import { TemplateCardHeader } from "../components/header/index.js";
|
|
6
|
+
import "./styles.css";
|
|
7
|
+
function isContentCardNodeEmpty(content) {
|
|
8
|
+
return null == content || 'boolean' == typeof content || '' === content;
|
|
9
|
+
}
|
|
10
|
+
function ContentCardThumbnail({ thumbnail }) {
|
|
11
|
+
if (isContentCardNodeEmpty(thumbnail)) return null;
|
|
12
|
+
return <view className="doubao-content-card__thumbnail">{thumbnail}</view>;
|
|
13
|
+
}
|
|
14
|
+
function renderContentCardText(content, className) {
|
|
15
|
+
if (isContentCardNodeEmpty(content)) return null;
|
|
16
|
+
if ('string' == typeof content || 'number' == typeof content) return <text className={className} text-maxline="1">
|
|
17
|
+
{content}
|
|
18
|
+
</text>;
|
|
19
|
+
return <view className={`${className}-custom`}>{content}</view>;
|
|
20
|
+
}
|
|
21
|
+
function isTemplateExtraAction(action) {
|
|
22
|
+
return null != action && 'object' == typeof action && 'type' in action && ('button' === action.type || 'switch' === action.type || 'playback' === action.type);
|
|
23
|
+
}
|
|
24
|
+
function isContentCardActionEmpty(action) {
|
|
25
|
+
return null == action || 'boolean' == typeof action || '' === action;
|
|
26
|
+
}
|
|
27
|
+
function renderContentCardAction(action) {
|
|
28
|
+
if (isContentCardActionEmpty(action)) return null;
|
|
29
|
+
if (isTemplateExtraAction(action)) return renderTemplateExtraAction(action, {
|
|
30
|
+
button: 'doubao-content-card__item-action-button',
|
|
31
|
+
switch: 'doubao-content-card__item-action-switch',
|
|
32
|
+
playback: 'doubao-content-card__item-action-playback',
|
|
33
|
+
playbackPlaying: 'doubao-content-card__item-action-playback--playing',
|
|
34
|
+
playbackDisabled: 'doubao-content-card__item-action-playback--disabled',
|
|
35
|
+
playbackIcon: 'doubao-content-card__item-action-playback-icon'
|
|
36
|
+
});
|
|
37
|
+
return action;
|
|
38
|
+
}
|
|
39
|
+
function ContentCardItemView({ item, isLast }) {
|
|
40
|
+
const { title, subtitle } = item;
|
|
41
|
+
const hasThumbnail = !isContentCardNodeEmpty(item.thumbnail);
|
|
42
|
+
const subtitleNode = renderContentCardText(subtitle, 'doubao-content-card__subtitle');
|
|
43
|
+
const actionNode = renderContentCardAction(item.action);
|
|
44
|
+
return <view className={clsx('doubao-content-card__item', isLast && 'doubao-content-card__item--last', !hasThumbnail && 'doubao-content-card__item--without-thumbnail', item.className)} style={item.style} {...null != item.onClick ? {
|
|
45
|
+
catchtap: item.onClick
|
|
46
|
+
} : {}}>
|
|
47
|
+
{item.children ?? <view className="doubao-content-card__content">
|
|
48
|
+
<view className="doubao-content-card__main">
|
|
49
|
+
{hasThumbnail && <ContentCardThumbnail thumbnail={item.thumbnail}/>}
|
|
50
|
+
<view className="doubao-content-card__text">
|
|
51
|
+
{renderContentCardText(title, 'doubao-content-card__title')}
|
|
52
|
+
{subtitleNode && <view className="doubao-content-card__secondary">{subtitleNode}</view>}
|
|
53
|
+
</view>
|
|
54
|
+
</view>
|
|
55
|
+
{actionNode && <view className="doubao-content-card__item-action" catchtap={stopTemplateExtraActionTap}>
|
|
56
|
+
{actionNode}
|
|
57
|
+
</view>}
|
|
58
|
+
</view>}
|
|
59
|
+
</view>;
|
|
60
|
+
}
|
|
61
|
+
function ContentCard(props) {
|
|
62
|
+
const { header, items, footer, children, className, style, onClick } = props;
|
|
63
|
+
const contentItems = items ?? [];
|
|
64
|
+
return <view className={useThemeClassName(clsx('doubao-content-card', className))} style={style} bindtap={onClick} clip-radius="true">
|
|
65
|
+
<TemplateCardHeader actionText={header?.actionText} showAction={header?.showAction} onActionClick={header?.onActionClick}/>
|
|
66
|
+
<view className="doubao-content-card__body">
|
|
67
|
+
{children ?? contentItems.map((item, index)=><ContentCardItemView key={item.key ?? index} item={item} isLast={index === contentItems.length - 1}/>)}
|
|
68
|
+
</view>
|
|
69
|
+
<TemplateCardFooter primaryActionButton={footer?.primaryActionButton} secondaryActionButton={footer?.secondaryActionButton}/>
|
|
70
|
+
</view>;
|
|
71
|
+
}
|
|
72
|
+
export { ContentCard };
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
.doubao-content-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-content-card__body {
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
background-color: var(--bg-base-1);
|
|
16
|
+
width: 100%;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.doubao-content-card__item {
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
background-color: var(--bg-base-1);
|
|
22
|
+
width: 100%;
|
|
23
|
+
padding: 12px;
|
|
24
|
+
position: relative;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.doubao-content-card__item--without-thumbnail {
|
|
28
|
+
padding-top: 16px;
|
|
29
|
+
padding-bottom: 16px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.doubao-content-card__item:after {
|
|
33
|
+
content: "";
|
|
34
|
+
background-color: var(--neutral-transparent-1);
|
|
35
|
+
height: .5px;
|
|
36
|
+
position: absolute;
|
|
37
|
+
bottom: 0;
|
|
38
|
+
left: 104px;
|
|
39
|
+
right: 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.doubao-content-card__item--last:after {
|
|
43
|
+
display: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.doubao-content-card__content {
|
|
47
|
+
flex-direction: row;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: 12px;
|
|
50
|
+
width: 100%;
|
|
51
|
+
min-width: 0;
|
|
52
|
+
display: flex;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.doubao-content-card__main {
|
|
56
|
+
flex-direction: row;
|
|
57
|
+
flex: 1 1 0;
|
|
58
|
+
align-items: center;
|
|
59
|
+
gap: 12px;
|
|
60
|
+
min-width: 0;
|
|
61
|
+
display: flex;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.doubao-content-card__thumbnail {
|
|
65
|
+
background-color: var(--bg-base-1-overlay);
|
|
66
|
+
border-radius: 5px;
|
|
67
|
+
flex-shrink: 0;
|
|
68
|
+
width: 80px;
|
|
69
|
+
height: 80px;
|
|
70
|
+
overflow: hidden;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.doubao-content-card__text {
|
|
74
|
+
flex-direction: column;
|
|
75
|
+
flex: 1 1 0;
|
|
76
|
+
align-items: flex-start;
|
|
77
|
+
min-width: 0;
|
|
78
|
+
display: flex;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.doubao-content-card__title {
|
|
82
|
+
width: 100%;
|
|
83
|
+
height: 24px;
|
|
84
|
+
color: var(--neutral-100);
|
|
85
|
+
text-overflow: ellipsis;
|
|
86
|
+
white-space: nowrap;
|
|
87
|
+
font-family: PingFang SC, sans-serif;
|
|
88
|
+
font-size: 16px;
|
|
89
|
+
font-style: normal;
|
|
90
|
+
font-weight: 500;
|
|
91
|
+
line-height: 24px;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.doubao-content-card__title-custom, .doubao-content-card__subtitle-custom {
|
|
96
|
+
flex-direction: row;
|
|
97
|
+
align-items: center;
|
|
98
|
+
width: 100%;
|
|
99
|
+
max-width: 100%;
|
|
100
|
+
display: flex;
|
|
101
|
+
overflow: hidden;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.doubao-content-card__secondary {
|
|
105
|
+
flex-direction: row;
|
|
106
|
+
align-items: center;
|
|
107
|
+
width: 100%;
|
|
108
|
+
min-width: 0;
|
|
109
|
+
height: 24px;
|
|
110
|
+
display: flex;
|
|
111
|
+
overflow: hidden;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.doubao-content-card__subtitle {
|
|
115
|
+
width: 100%;
|
|
116
|
+
color: var(--neutral-70);
|
|
117
|
+
text-overflow: ellipsis;
|
|
118
|
+
white-space: nowrap;
|
|
119
|
+
font-family: PingFang SC, sans-serif;
|
|
120
|
+
font-size: 13px;
|
|
121
|
+
font-style: normal;
|
|
122
|
+
font-weight: 400;
|
|
123
|
+
line-height: 20px;
|
|
124
|
+
overflow: hidden;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.doubao-content-card__item-action {
|
|
128
|
+
flex-direction: row;
|
|
129
|
+
flex-shrink: 0;
|
|
130
|
+
justify-content: center;
|
|
131
|
+
align-items: center;
|
|
132
|
+
display: flex;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.doubao-content-card__item-action-button {
|
|
136
|
+
width: 80px;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.doubao-content-card__item-action-switch {
|
|
140
|
+
flex-shrink: 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.doubao-content-card__item-action-playback {
|
|
144
|
+
flex-shrink: 0;
|
|
145
|
+
justify-content: center;
|
|
146
|
+
align-items: center;
|
|
147
|
+
width: 32px;
|
|
148
|
+
height: 32px;
|
|
149
|
+
display: flex;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.doubao-content-card__item-action-playback--disabled {
|
|
153
|
+
opacity: .4;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.doubao-content-card__item-action-playback-icon {
|
|
157
|
+
width: 32px;
|
|
158
|
+
height: 32px;
|
|
159
|
+
}
|
|
160
|
+
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { ContentCard, type ContentCardItem, type ContentCardProps } from './content-card/index.js';
|
|
2
|
+
export type { TemplateCardHeaderProps } from './components/header/index.js';
|
|
3
|
+
export type { TemplateCardFooterActionButton, TemplateCardFooterProps } from './components/footer/index.js';
|
|
4
|
+
export type { TemplateExtraAction, TemplateExtraActionButton, TemplateExtraActionPlayback, TemplateExtraActionSwitch } from './components/extra-action/index.js';
|
|
5
|
+
export { AskHumanCard, type AskHumanCardArrowPosition, type AskHumanCardItem, type AskHumanCardProps } from './ask-human-card/index.js';
|
|
6
|
+
export { CheckoutCard, type CheckoutCardFeeItem, type CheckoutCardInfoItem, type CheckoutCardProductItem, type CheckoutCardProps } from './checkout-card/index.js';
|
|
7
|
+
export { PriceActionCard, type PriceActionCardInfoRow, type PriceActionCardItem, type PriceActionCardProps } from './price-action-card/index.js';
|
|
8
|
+
export { TransitCard, type TransitCardItem, type TransitCardProps } from './transit-card/index.js';
|
|
9
|
+
export type { TemplateKey, TemplateText } from './types.js';
|
|
10
|
+
export { TicketOrderCard, type TicketOrderCardFeeItem, type TicketOrderCardInfoItem, type TicketOrderCardProps, type TicketOrderCardRouteItem } from './ticket-order-card/index.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { ContentCard } from "./content-card/index.js";
|
|
2
|
+
export { AskHumanCard } from "./ask-human-card/index.js";
|
|
3
|
+
export { CheckoutCard } from "./checkout-card/index.js";
|
|
4
|
+
export { PriceActionCard } from "./price-action-card/index.js";
|
|
5
|
+
export { TransitCard } from "./transit-card/index.js";
|
|
6
|
+
export { TicketOrderCard } from "./ticket-order-card/index.js";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { CSSProperties, TouchEvent } from '@lynx-js/types';
|
|
2
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
3
|
+
import { type TemplateCardFooterProps } from '../components/footer/index.js';
|
|
4
|
+
import { type TemplateCardHeaderProps } from '../components/header/index.js';
|
|
5
|
+
import type { TemplateKey, TemplateText } from '../types.js';
|
|
6
|
+
import './styles.scss';
|
|
7
|
+
export interface PriceActionCardProps {
|
|
8
|
+
/** 标题栏配置。 */
|
|
9
|
+
header?: TemplateCardHeaderProps;
|
|
10
|
+
/** 列表项数据。 */
|
|
11
|
+
items?: PriceActionCardItem[];
|
|
12
|
+
/** 底部操作区配置。 */
|
|
13
|
+
footer?: TemplateCardFooterProps;
|
|
14
|
+
/** 自定义卡片内容;传入后不再渲染默认列表,标题栏和底部操作区仍由模板渲染。 */
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
/** 卡片根节点自定义类名。 */
|
|
17
|
+
className?: string;
|
|
18
|
+
/** 卡片根节点自定义样式。 */
|
|
19
|
+
style?: CSSProperties;
|
|
20
|
+
/** 点击卡片根节点时触发。 */
|
|
21
|
+
onClick?: (event: TouchEvent) => void;
|
|
22
|
+
}
|
|
23
|
+
export interface PriceActionCardItem {
|
|
24
|
+
/** 列表项唯一标识;不传时使用数组下标。 */
|
|
25
|
+
key?: TemplateKey;
|
|
26
|
+
/** 左侧价格或主数值。 */
|
|
27
|
+
price?: TemplateText;
|
|
28
|
+
/** 左侧辅助标签。 */
|
|
29
|
+
badgeText?: TemplateText;
|
|
30
|
+
/** 中间信息行。最多展示前 2 行。 */
|
|
31
|
+
infoRows?: PriceActionCardInfoRow[];
|
|
32
|
+
/** 右侧操作按钮文案;不传或传空字符串时不展示。 */
|
|
33
|
+
actionText?: string;
|
|
34
|
+
/** 列表项自定义内容;传入后不再渲染默认三列结构。 */
|
|
35
|
+
children?: ReactNode;
|
|
36
|
+
/** 列表项根节点自定义类名。 */
|
|
37
|
+
className?: string;
|
|
38
|
+
/** 列表项根节点自定义样式。 */
|
|
39
|
+
style?: CSSProperties;
|
|
40
|
+
/** 点击列表项时触发。 */
|
|
41
|
+
onClick?: (event: TouchEvent) => void;
|
|
42
|
+
/** 点击列表项右侧操作按钮时触发。 */
|
|
43
|
+
onActionClick?: (event?: TouchEvent) => void;
|
|
44
|
+
}
|
|
45
|
+
export interface PriceActionCardInfoRow {
|
|
46
|
+
/** 信息行唯一标识;不传时使用数组下标。 */
|
|
47
|
+
key?: TemplateKey;
|
|
48
|
+
/** 信息行文案。 */
|
|
49
|
+
text: TemplateText;
|
|
50
|
+
}
|
|
51
|
+
export declare function PriceActionCard(props: PriceActionCardProps): ReactElement;
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Button, useThemeClassName } from "@byted-doubao-apps/components";
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { TemplateCardFooter } from "../components/footer/index.js";
|
|
4
|
+
import { TemplateCardHeader } from "../components/header/index.js";
|
|
5
|
+
import "./styles.css";
|
|
6
|
+
const PRICE_ACTION_CARD_INFO_ROW_LIMIT = 2;
|
|
7
|
+
const PRICE_ACTION_CARD_CURRENCY_PATTERN = /^([¥¥$€£])(.+)$/;
|
|
8
|
+
function isPriceActionCardTextEmpty(content) {
|
|
9
|
+
return null == content || '' === content;
|
|
10
|
+
}
|
|
11
|
+
function isPriceActionCardNodeEmpty(content) {
|
|
12
|
+
return null == content || 'boolean' == typeof content || '' === content;
|
|
13
|
+
}
|
|
14
|
+
function PriceActionCardPrice({ price }) {
|
|
15
|
+
const priceText = String(price);
|
|
16
|
+
const [, currency, value] = priceText.match(PRICE_ACTION_CARD_CURRENCY_PATTERN) ?? [];
|
|
17
|
+
return <view className="doubao-price-action-card__price">
|
|
18
|
+
{null != currency && <text className="doubao-price-action-card__price-currency" text-maxline="1">
|
|
19
|
+
{currency}
|
|
20
|
+
</text>}
|
|
21
|
+
<text className="doubao-price-action-card__price-value" text-maxline="1">
|
|
22
|
+
{value ?? priceText}
|
|
23
|
+
</text>
|
|
24
|
+
</view>;
|
|
25
|
+
}
|
|
26
|
+
function PriceActionCardItemView({ item, isLast }) {
|
|
27
|
+
const hasPrice = !isPriceActionCardTextEmpty(item.price);
|
|
28
|
+
const hasBadge = !isPriceActionCardTextEmpty(item.badgeText);
|
|
29
|
+
const hasAction = null != item.actionText && item.actionText.length > 0;
|
|
30
|
+
const hasCustomContent = !isPriceActionCardNodeEmpty(item.children);
|
|
31
|
+
const infoRows = (item.infoRows ?? []).filter((infoRow)=>!isPriceActionCardTextEmpty(infoRow.text)).slice(0, PRICE_ACTION_CARD_INFO_ROW_LIMIT);
|
|
32
|
+
return <view className={clsx('doubao-price-action-card__item', isLast && 'doubao-price-action-card__item--last', item.className)} style={item.style} {...null != item.onClick ? {
|
|
33
|
+
catchtap: item.onClick
|
|
34
|
+
} : {}}>
|
|
35
|
+
{hasCustomContent ? item.children : <view className="doubao-price-action-card__item-content">
|
|
36
|
+
<view className="doubao-price-action-card__value">
|
|
37
|
+
{hasPrice && <PriceActionCardPrice price={item.price ?? ''}/>}
|
|
38
|
+
{hasBadge && <text className="doubao-price-action-card__badge" text-maxline="1">
|
|
39
|
+
{item.badgeText}
|
|
40
|
+
</text>}
|
|
41
|
+
</view>
|
|
42
|
+
<view className="doubao-price-action-card__info">
|
|
43
|
+
{infoRows.map((infoRow, index)=><text className="doubao-price-action-card__info-row" text-maxline="1" key={infoRow.key ?? index}>
|
|
44
|
+
{infoRow.text}
|
|
45
|
+
</text>)}
|
|
46
|
+
</view>
|
|
47
|
+
{hasAction && <Button className="doubao-price-action-card__item-action" type="default" text={item.actionText} onClick={item.onActionClick}/>}
|
|
48
|
+
</view>}
|
|
49
|
+
</view>;
|
|
50
|
+
}
|
|
51
|
+
function PriceActionCard(props) {
|
|
52
|
+
const { header, items = [], footer, children, className, style, onClick } = props;
|
|
53
|
+
const hasCustomContent = !isPriceActionCardNodeEmpty(children);
|
|
54
|
+
return <view className={useThemeClassName(clsx('doubao-price-action-card', className))} style={style} bindtap={onClick} clip-radius="true">
|
|
55
|
+
<TemplateCardHeader actionText={header?.actionText} showAction={header?.showAction} onActionClick={header?.onActionClick}/>
|
|
56
|
+
<view className="doubao-price-action-card__body">
|
|
57
|
+
{hasCustomContent ? children : <view className="doubao-price-action-card__default">
|
|
58
|
+
{items.map((item, index)=><PriceActionCardItemView item={item} isLast={index === items.length - 1} key={item.key ?? index}/>)}
|
|
59
|
+
</view>}
|
|
60
|
+
</view>
|
|
61
|
+
<TemplateCardFooter primaryActionButton={footer?.primaryActionButton} secondaryActionButton={footer?.secondaryActionButton}/>
|
|
62
|
+
</view>;
|
|
63
|
+
}
|
|
64
|
+
export { PriceActionCard };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
.doubao-price-action-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-price-action-card__body {
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
background-color: var(--bg-base-1);
|
|
16
|
+
width: 100%;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.doubao-price-action-card__default {
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
width: 100%;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.doubao-price-action-card__item {
|
|
25
|
+
box-sizing: border-box;
|
|
26
|
+
background-color: var(--bg-base-1);
|
|
27
|
+
flex-direction: row;
|
|
28
|
+
align-items: center;
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 82px;
|
|
31
|
+
padding: 14px 12px;
|
|
32
|
+
display: flex;
|
|
33
|
+
position: relative;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.doubao-price-action-card__item:after {
|
|
37
|
+
content: "";
|
|
38
|
+
background-color: var(--neutral-transparent-1);
|
|
39
|
+
height: .5px;
|
|
40
|
+
position: absolute;
|
|
41
|
+
bottom: 0;
|
|
42
|
+
left: 95px;
|
|
43
|
+
right: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.doubao-price-action-card__item--last:after {
|
|
47
|
+
display: none;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.doubao-price-action-card__item-content {
|
|
51
|
+
flex-direction: row;
|
|
52
|
+
align-items: center;
|
|
53
|
+
width: 100%;
|
|
54
|
+
padding-left: 4px;
|
|
55
|
+
display: flex;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.doubao-price-action-card__value {
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
flex-shrink: 0;
|
|
61
|
+
align-items: flex-start;
|
|
62
|
+
width: 67px;
|
|
63
|
+
min-width: 0;
|
|
64
|
+
display: flex;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.doubao-price-action-card__price {
|
|
68
|
+
max-width: 100%;
|
|
69
|
+
height: 20px;
|
|
70
|
+
color: var(--pink-500);
|
|
71
|
+
white-space: nowrap;
|
|
72
|
+
flex-direction: row;
|
|
73
|
+
align-items: flex-end;
|
|
74
|
+
font-family: SF Pro, sans-serif;
|
|
75
|
+
font-style: normal;
|
|
76
|
+
display: flex;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.doubao-price-action-card__price-currency, .doubao-price-action-card__price-value {
|
|
81
|
+
min-width: 0;
|
|
82
|
+
color: var(--pink-500);
|
|
83
|
+
text-overflow: ellipsis;
|
|
84
|
+
white-space: nowrap;
|
|
85
|
+
font-family: SF Pro, sans-serif;
|
|
86
|
+
font-style: normal;
|
|
87
|
+
font-weight: 600;
|
|
88
|
+
overflow: hidden;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.doubao-price-action-card__price-currency {
|
|
92
|
+
flex-shrink: 0;
|
|
93
|
+
font-size: 13px;
|
|
94
|
+
line-height: 15px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.doubao-price-action-card__price-value {
|
|
98
|
+
font-size: 17px;
|
|
99
|
+
line-height: 20px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.doubao-price-action-card__badge {
|
|
103
|
+
box-sizing: border-box;
|
|
104
|
+
max-width: 100%;
|
|
105
|
+
height: 20px;
|
|
106
|
+
color: var(--pink-500);
|
|
107
|
+
text-overflow: ellipsis;
|
|
108
|
+
white-space: nowrap;
|
|
109
|
+
background-color: var(--pink-trans-6);
|
|
110
|
+
border-radius: 4px;
|
|
111
|
+
padding: 2px 3px;
|
|
112
|
+
font-family: PingFang SC, sans-serif;
|
|
113
|
+
font-size: 11px;
|
|
114
|
+
font-style: normal;
|
|
115
|
+
font-weight: 400;
|
|
116
|
+
line-height: 14px;
|
|
117
|
+
overflow: hidden;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.doubao-price-action-card__info {
|
|
121
|
+
flex-direction: column;
|
|
122
|
+
flex: 1 1 0;
|
|
123
|
+
justify-content: center;
|
|
124
|
+
min-width: 0;
|
|
125
|
+
margin-left: 16px;
|
|
126
|
+
display: flex;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.doubao-price-action-card__info-row {
|
|
130
|
+
width: 100%;
|
|
131
|
+
color: var(--neutral-70);
|
|
132
|
+
text-overflow: ellipsis;
|
|
133
|
+
white-space: nowrap;
|
|
134
|
+
font-family: PingFang SC, sans-serif;
|
|
135
|
+
font-size: 13px;
|
|
136
|
+
font-style: normal;
|
|
137
|
+
font-weight: 400;
|
|
138
|
+
line-height: 20px;
|
|
139
|
+
overflow: hidden;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.doubao-price-action-card__info-row + .doubao-price-action-card__info-row {
|
|
143
|
+
margin-top: 2px;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.doubao-price-action-card__item-action {
|
|
147
|
+
--doubao-button-border-radius: 8px;
|
|
148
|
+
--doubao-button-default-border-radius: 8px;
|
|
149
|
+
--doubao-button-default-height: 38px;
|
|
150
|
+
--doubao-button-default-padding-x: 12px;
|
|
151
|
+
--doubao-button-default-padding-y: 0;
|
|
152
|
+
--doubao-button-default-font-size: 14px;
|
|
153
|
+
--doubao-button-default-line-height: 20px;
|
|
154
|
+
--doubao-button-default-bg: var(--bg-base-1-overlay);
|
|
155
|
+
--doubao-button-default-text: var(--neutral-100);
|
|
156
|
+
flex-shrink: 0;
|
|
157
|
+
width: 80px;
|
|
158
|
+
height: 38px;
|
|
159
|
+
margin-left: 12px;
|
|
160
|
+
}
|
|
161
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { CSSProperties, TouchEvent } from '@lynx-js/types';
|
|
2
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
3
|
+
import { type TemplateCardFooterProps } from '../components/footer/index.js';
|
|
4
|
+
import { type TemplateCardHeaderProps } from '../components/header/index.js';
|
|
5
|
+
import type { TemplateKey, TemplateText } from '../types.js';
|
|
6
|
+
import './styles.scss';
|
|
7
|
+
export interface TicketOrderCardProps {
|
|
8
|
+
/** 标题栏配置。 */
|
|
9
|
+
header?: TemplateCardHeaderProps;
|
|
10
|
+
/** 航程信息列表。 */
|
|
11
|
+
routeItems?: TicketOrderCardRouteItem[];
|
|
12
|
+
/** 订单信息列表。 */
|
|
13
|
+
infoItems?: TicketOrderCardInfoItem[];
|
|
14
|
+
/** 费用明细列表。 */
|
|
15
|
+
feeItems?: TicketOrderCardFeeItem[];
|
|
16
|
+
/** 合计价格前的标签文案。 */
|
|
17
|
+
totalLabel?: TemplateText;
|
|
18
|
+
/** 合计价格。 */
|
|
19
|
+
totalPrice?: TemplateText;
|
|
20
|
+
/** 合计区域自定义内容;优先级高于 totalLabel 和 totalPrice。 */
|
|
21
|
+
totalContent?: ReactNode;
|
|
22
|
+
/** 底部操作区配置。 */
|
|
23
|
+
footer?: TemplateCardFooterProps;
|
|
24
|
+
/** 卡片根节点自定义类名。 */
|
|
25
|
+
className?: string;
|
|
26
|
+
/** 卡片根节点自定义样式。 */
|
|
27
|
+
style?: CSSProperties;
|
|
28
|
+
/** 点击卡片根节点时触发。 */
|
|
29
|
+
onClick?: (event: TouchEvent) => void;
|
|
30
|
+
}
|
|
31
|
+
export interface TicketOrderCardRouteItem {
|
|
32
|
+
/** 航程项唯一标识;不传时使用数组下标。 */
|
|
33
|
+
key?: TemplateKey;
|
|
34
|
+
/** 航程标题,例如「出发地 - 到达地」。 */
|
|
35
|
+
title?: TemplateText;
|
|
36
|
+
/** 航程描述,例如「6月1日 周六 20:50-23:50 CZ0000 经济舱」。 */
|
|
37
|
+
description?: TemplateText;
|
|
38
|
+
/** 是否展示标题右侧箭头。 */
|
|
39
|
+
showChevron?: boolean;
|
|
40
|
+
/** 点击航程项时触发。 */
|
|
41
|
+
onClick?: (event: TouchEvent) => void;
|
|
42
|
+
}
|
|
43
|
+
export interface TicketOrderCardInfoItem {
|
|
44
|
+
/** 信息项唯一标识;不传时使用数组下标。 */
|
|
45
|
+
key?: TemplateKey;
|
|
46
|
+
/** 信息项标签。 */
|
|
47
|
+
label?: TemplateText;
|
|
48
|
+
/** 信息项标签块内容;优先级高于 label。 */
|
|
49
|
+
labelContent?: ReactNode;
|
|
50
|
+
/** 信息项主内容。 */
|
|
51
|
+
value?: TemplateText;
|
|
52
|
+
/** 信息项主内容块内容;优先级高于 value。 */
|
|
53
|
+
valueContent?: ReactNode;
|
|
54
|
+
/** 信息项补充内容。 */
|
|
55
|
+
valueExtra?: TemplateText;
|
|
56
|
+
/** 信息项补充内容块内容;优先级高于 valueExtra。 */
|
|
57
|
+
valueExtraContent?: ReactNode;
|
|
58
|
+
}
|
|
59
|
+
export interface TicketOrderCardFeeItem {
|
|
60
|
+
/** 费用项唯一标识;不传时使用数组下标。 */
|
|
61
|
+
key?: TemplateKey;
|
|
62
|
+
/** 费用项标签。 */
|
|
63
|
+
label?: TemplateText;
|
|
64
|
+
/** 费用项金额或数值。 */
|
|
65
|
+
value?: TemplateText;
|
|
66
|
+
/** 费用项自定义内容;优先级高于 label 和 value。 */
|
|
67
|
+
content?: ReactNode;
|
|
68
|
+
}
|
|
69
|
+
export declare function TicketOrderCard(props: TicketOrderCardProps): ReactElement;
|
|
70
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useThemeClassName } from "@byted-doubao-apps/components";
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { TemplateCardFooter } from "../components/footer/index.js";
|
|
4
|
+
import { TemplateCardHeader } from "../components/header/index.js";
|
|
5
|
+
import { TemplateInfoSection } from "../components/info-section/index.js";
|
|
6
|
+
import { TemplateRouteSection, hasTemplateRouteSectionItems } from "../components/route-section/index.js";
|
|
7
|
+
import "./styles.css";
|
|
8
|
+
function isTicketOrderTextEmpty(content) {
|
|
9
|
+
return null == content || '' === content;
|
|
10
|
+
}
|
|
11
|
+
function TicketOrderCard(props) {
|
|
12
|
+
const { header, routeItems = [], infoItems = [], feeItems = [], totalLabel, totalPrice, totalContent, footer, className, style, onClick } = props;
|
|
13
|
+
const hasRouteItems = hasTemplateRouteSectionItems(routeItems);
|
|
14
|
+
const hasInfoSection = infoItems.length > 0 || feeItems.length > 0 || void 0 !== totalContent || !isTicketOrderTextEmpty(totalLabel) || !isTicketOrderTextEmpty(totalPrice);
|
|
15
|
+
const hasDefaultBody = hasRouteItems || hasInfoSection;
|
|
16
|
+
return <view className={useThemeClassName(clsx('doubao-ticket-order-card', className))} style={style} bindtap={onClick}>
|
|
17
|
+
<TemplateCardHeader actionText={header?.actionText} showAction={header?.showAction} onActionClick={header?.onActionClick}/>
|
|
18
|
+
|
|
19
|
+
{hasDefaultBody && <view className="doubao-ticket-order-card__body">
|
|
20
|
+
{hasRouteItems && <TemplateRouteSection items={routeItems}/>}
|
|
21
|
+
{hasInfoSection && <TemplateInfoSection infoItems={infoItems} feeItems={feeItems} totalLabel={totalLabel} totalPrice={totalPrice} totalContent={totalContent}/>}
|
|
22
|
+
</view>}
|
|
23
|
+
|
|
24
|
+
<TemplateCardFooter secondaryActionButton={footer?.secondaryActionButton} primaryActionButton={footer?.primaryActionButton}/>
|
|
25
|
+
</view>;
|
|
26
|
+
}
|
|
27
|
+
export { TicketOrderCard };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.doubao-ticket-order-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-ticket-order-card__body {
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
background-color: var(--bg-base-1);
|
|
16
|
+
width: 100%;
|
|
17
|
+
}
|
|
18
|
+
|