@doubao-apps/template 0.0.29 → 0.0.30

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
@@ -1,6 +1,48 @@
1
1
  # @doubao-apps/template
2
2
 
3
- Doubao Apps 模板库,用于提供常见卡片和页面结构。模板会把已有组件组合成完整、符合设计稿的区块,开发者可以直接传入业务数据来快速搭建卡片。
3
+ Doubao Apps Widget 模板库,用于快速开发卡片类 widget。模板会把已有组件组合成完整、符合设计稿的卡片结构,开发者只需要在 `defineWidget` 里选择合适的模板并传入业务数据。
4
+
5
+ 模板适合用在 widget 的 `render` 中。通常一个 widget 对应一张卡片,建议直接返回模板组件,不额外包裹无意义的 `view` / `scroll-view`:
6
+
7
+ ```tsx
8
+ import { defineWidget } from '@doubao-apps/framework';
9
+ import { ListCard } from '@doubao-apps/template';
10
+
11
+ export default defineWidget({
12
+ aiMeta: {
13
+ id: 'product-list',
14
+ name: '商品列表',
15
+ description: '展示商品列表卡片',
16
+ border: true
17
+ },
18
+ render() {
19
+ return (
20
+ <ListCard
21
+ items={[
22
+ {
23
+ title: '主标题',
24
+ price: '4199',
25
+ priceUnit: '元',
26
+ description: '商品描述商品描述',
27
+ imageSrc: 'https://example.com/product.png'
28
+ },
29
+ {
30
+ title: '第二个商品',
31
+ price: '299',
32
+ priceUnit: '元',
33
+ description: '商品描述商品描述'
34
+ }
35
+ ]}
36
+ onViewMoreClick={() => {
37
+ console.log('view more');
38
+ }}
39
+ />
40
+ );
41
+ }
42
+ });
43
+ ```
44
+
45
+ 如果只是验证 UI 效果,也可以在普通页面里直接渲染模板组件;但真实卡片接入建议优先按 widget 方式组织。
4
46
 
5
47
  ## ListCard
6
48
 
@@ -18,7 +60,8 @@ export default function Page() {
18
60
  price: '4199',
19
61
  priceUnit: '元',
20
62
  description: '商品描述商品描述',
21
- imageSrc: 'https://example.com/product.png'
63
+ imageSrc: 'https://example.com/product.png',
64
+ actionText: '下单'
22
65
  },
23
66
  {
24
67
  title: '第二个商品',
@@ -42,8 +85,9 @@ export default function Page() {
42
85
 
43
86
  - 当 `items` 超过 4 条时,默认只展示前 4 条,并在底部展示「查看更多」按钮。
44
87
  - 可以通过 `viewMoreText` 和 `onViewMoreClick` 自定义「查看更多」按钮文案和点击行为。
45
- - 如果只需要展示单条内容,也可以直接使用 `title` / `price` / `description` / `imageSrc` 等快捷属性。
88
+ - 每个列表项都可以通过 `actionText` `onActionClick` 自行决定是否展示右侧操作按钮。
46
89
  - 如果需要完全自定义内容区域,可以传入 `children`,模板会保留标题栏和卡片外壳。
90
+ - 用在 widget 中时,推荐让 `render` 直接返回 `ListCard`。
47
91
 
48
92
  ## OrderCard
49
93
 
@@ -92,6 +136,7 @@ export default function Page() {
92
136
  - `infoItems` 用于配置提单信息列表。
93
137
  - `feeItems`、`discountText`、`totalLabel`、`totalPrice` 用于配置费用汇总。
94
138
  - `primaryActionText` 和 `secondaryActionText` 可以自定义底部操作按钮文案。
139
+ - 用在 widget 中时,推荐让 `render` 直接返回 `OrderCard`。
95
140
 
96
141
  ## InvalidCard
97
142
 
@@ -111,3 +156,8 @@ export default function Page() {
111
156
  );
112
157
  }
113
158
  ```
159
+
160
+ 说明:
161
+
162
+ - `title` 用于配置失效状态文案。
163
+ - 用在 widget 中时,推荐让 `render` 直接返回 `InvalidCard`。
@@ -1,9 +1,7 @@
1
1
  import { useThemeClassName } from "@byted-doubao-apps/components";
2
+ import { clsx } from "clsx";
2
3
  import { getAppInfo } from "../utils/app-info.js";
3
4
  import "./styles.css";
4
- function joinClassNames(...classNames) {
5
- return classNames.filter(Boolean).join(' ');
6
- }
7
5
  function InvalidCardIcon({ appIconSrc }) {
8
6
  if (null != appIconSrc && appIconSrc.length > 0) return <image className="doubao-invalid-card__app-icon" src={appIconSrc} mode="aspectFill"/>;
9
7
  return <view className="doubao-invalid-card__app-icon"/>;
@@ -11,7 +9,7 @@ function InvalidCardIcon({ appIconSrc }) {
11
9
  function InvalidCard(props) {
12
10
  const { title = '任务状态已更新', className, style, onClick } = props;
13
11
  const appInfo = getAppInfo();
14
- return <view className={useThemeClassName(joinClassNames('doubao-invalid-card', className))} style={style} bindtap={onClick} clip-radius="true">
12
+ return <view className={useThemeClassName(clsx('doubao-invalid-card', className))} style={style} bindtap={onClick} clip-radius="true">
15
13
  <view className="doubao-invalid-card__title-bar">
16
14
  <view className="doubao-invalid-card__app">
17
15
  <InvalidCardIcon appIconSrc={appInfo.appIconSrc}/>
@@ -10,18 +10,6 @@ export interface ListCardProps {
10
10
  items?: ListCardItem[];
11
11
  /** 列表超过 4 条时,底部「查看更多」按钮的文案。 */
12
12
  viewMoreText?: string;
13
- /** 单条默认内容的标题;未传入 items 和 children 时生效。 */
14
- title?: string;
15
- /** 单条默认内容的价格;未传入 items 和 children 时生效。 */
16
- price?: string | number;
17
- /** 单条默认内容的价格单位;未传入 items 和 children 时生效。 */
18
- priceUnit?: string;
19
- /** 单条默认内容的描述;未传入 items 和 children 时生效。 */
20
- description?: string;
21
- /** 单条默认内容的图片地址;未传入 items 和 children 时生效。 */
22
- imageSrc?: string;
23
- /** 单条默认内容的自定义图片节点;优先级高于 imageSrc。 */
24
- image?: ReactNode;
25
13
  /** 自定义卡片内容;传入后不再渲染默认列表内容和「查看更多」按钮。 */
26
14
  children?: ReactNode;
27
15
  /** 卡片根节点自定义类名。 */
@@ -52,12 +40,16 @@ export interface ListCardItem {
52
40
  image?: ReactNode;
53
41
  /** 列表项自定义内容;传入后不再渲染默认图文结构。 */
54
42
  children?: ReactNode;
43
+ /** 列表项右侧操作按钮文案;不传或传空字符串时不展示按钮。 */
44
+ actionText?: string;
55
45
  /** 列表项根节点自定义类名。 */
56
46
  className?: string;
57
47
  /** 列表项根节点自定义样式。 */
58
48
  style?: CSSProperties;
59
49
  /** 点击列表项时触发。 */
60
50
  onClick?: (event: TouchEvent) => void;
51
+ /** 点击列表项右侧操作按钮时触发。 */
52
+ onActionClick?: (event?: TouchEvent) => void;
61
53
  }
62
54
  export declare function ListCard(props: ListCardProps): ReactElement;
63
55
  //# sourceMappingURL=index.d.ts.map
@@ -1,9 +1,7 @@
1
1
  import { Button, useThemeClassName } from "@byted-doubao-apps/components";
2
+ import { clsx } from "clsx";
2
3
  import { getAppInfo } from "../utils/app-info.js";
3
4
  import "./styles.css";
4
- function joinClassNames(...classNames) {
5
- return classNames.filter(Boolean).join(' ');
6
- }
7
5
  function ListCardIcon({ appIconSrc }) {
8
6
  if (null != appIconSrc && appIconSrc.length > 0) return <image className="doubao-list-card__app-icon" src={appIconSrc} mode="aspectFill"/>;
9
7
  return <view className="doubao-list-card__app-icon"/>;
@@ -15,47 +13,45 @@ function ListCardImage(props) {
15
13
  return <view className="doubao-list-card__image"/>;
16
14
  }
17
15
  function ListCardProductItem({ item, isLast }) {
18
- const { title = '主标题', price = '4199', priceUnit = '元', description = '商品描述商品描述' } = item;
19
- const hasSecondaryLine = void 0 !== price || null != description;
20
- return <view className={joinClassNames('doubao-list-card__item', isLast && 'doubao-list-card__item--last', item.className)} style={item.style} {...null != item.onClick ? {
16
+ const { title, price, priceUnit, description } = item;
17
+ const hasImage = null != item.image || null != item.imageSrc && item.imageSrc.length > 0;
18
+ const hasPrice = null != price && '' !== price;
19
+ const hasDescription = null != description && description.length > 0;
20
+ const hasSecondaryLine = hasPrice || hasDescription;
21
+ const hasAction = null != item.actionText && item.actionText.length > 0;
22
+ return <view className={clsx('doubao-list-card__item', isLast && 'doubao-list-card__item--last', item.className)} style={item.style} {...null != item.onClick ? {
21
23
  catchtap: item.onClick
22
24
  } : {}}>
23
25
  {item.children ?? <view className="doubao-list-card__content">
24
- <ListCardImage image={item.image} imageSrc={item.imageSrc}/>
25
- <view className="doubao-list-card__text">
26
- <text className="doubao-list-card__title" text-maxline="1">
27
- {title}
28
- </text>
29
- {hasSecondaryLine ? <view className="doubao-list-card__secondary">
30
- {void 0 !== price ? <text className="doubao-list-card__price" text-maxline="1">
31
- {price}
32
- {priceUnit}
33
- </text> : null}
34
- {void 0 !== price && null != description ? <view className="doubao-list-card__dot"/> : null}
35
- {null != description ? <text className="doubao-list-card__description" text-maxline="1">
36
- {description}
37
- </text> : null}
38
- </view> : null}
26
+ <view className="doubao-list-card__main">
27
+ {hasImage ? <ListCardImage image={item.image} imageSrc={item.imageSrc}/> : null}
28
+ <view className={clsx('doubao-list-card__text', hasImage && 'doubao-list-card__text--with-image')}>
29
+ {null != title && title.length > 0 ? <text className="doubao-list-card__title" text-maxline="1">
30
+ {title}
31
+ </text> : null}
32
+ {hasSecondaryLine ? <view className="doubao-list-card__secondary">
33
+ {hasPrice ? <text className="doubao-list-card__price" text-maxline="1">
34
+ {price}
35
+ {null != priceUnit && priceUnit.length > 0 ? priceUnit : null}
36
+ </text> : null}
37
+ {hasPrice && hasDescription ? <view className="doubao-list-card__dot"/> : null}
38
+ {hasDescription ? <text className="doubao-list-card__description" text-maxline="1">
39
+ {description}
40
+ </text> : null}
41
+ </view> : null}
42
+ </view>
39
43
  </view>
44
+ {hasAction ? <Button className="doubao-list-card__item-action" type="default" text={item.actionText} onClick={item.onActionClick}/> : null}
40
45
  </view>}
41
46
  </view>;
42
47
  }
43
48
  function ListCard(props) {
44
- const { moreText = '更多', showMore = true, title = '主标题', price = '4199', priceUnit = '元', description = '商品描述商品描述', items, viewMoreText = '查看更多', children, className, style, onClick, onMoreClick, onViewMoreClick } = props;
49
+ const { moreText, showMore = true, items, viewMoreText = '查看更多', children, className, style, onClick, onMoreClick, onViewMoreClick } = props;
45
50
  const appInfo = getAppInfo();
46
- const contentItems = items ?? (null != children ? [] : [
47
- {
48
- title,
49
- price,
50
- priceUnit,
51
- description,
52
- image: props.image,
53
- imageSrc: props.imageSrc
54
- }
55
- ]);
51
+ const contentItems = items ?? [];
56
52
  const shouldShowViewMore = null == children && null != items && contentItems.length > 4;
57
53
  const visibleItems = shouldShowViewMore ? contentItems.slice(0, 4) : contentItems;
58
- return <view className={useThemeClassName(joinClassNames('doubao-list-card', className))} style={style} bindtap={onClick} clip-radius="true">
54
+ return <view className={useThemeClassName(clsx('doubao-list-card', className))} style={style} bindtap={onClick} clip-radius="true">
59
55
  <view className="doubao-list-card__title-bar">
60
56
  <view className="doubao-list-card__app">
61
57
  <ListCardIcon appIconSrc={appInfo.appIconSrc}/>
@@ -63,7 +59,7 @@ function ListCard(props) {
63
59
  {appInfo.appName}
64
60
  </text>
65
61
  </view>
66
- {showMore ? <view className="doubao-list-card__more" catchtap={onMoreClick}>
62
+ {showMore && null != moreText && moreText.length > 0 ? <view className="doubao-list-card__more" catchtap={onMoreClick}>
67
63
  <text className="doubao-list-card__more-text" text-maxline="1">
68
64
  {moreText}
69
65
  </text>
@@ -113,11 +113,20 @@
113
113
  .doubao-list-card__content {
114
114
  flex-direction: row;
115
115
  align-items: center;
116
+ gap: 20px;
116
117
  width: 100%;
117
118
  min-width: 0;
118
119
  display: flex;
119
120
  }
120
121
 
122
+ .doubao-list-card__main {
123
+ flex-direction: row;
124
+ flex: 1 1 0;
125
+ align-items: center;
126
+ min-width: 0;
127
+ display: flex;
128
+ }
129
+
121
130
  .doubao-list-card__image {
122
131
  background-color: var(--bg-base-1-overlay);
123
132
  border-radius: 5px;
@@ -132,10 +141,13 @@
132
141
  flex: 1 1 0;
133
142
  align-items: flex-start;
134
143
  min-width: 0;
135
- margin-left: 12px;
136
144
  display: flex;
137
145
  }
138
146
 
147
+ .doubao-list-card__text--with-image {
148
+ margin-left: 12px;
149
+ }
150
+
139
151
  .doubao-list-card__title {
140
152
  width: 100%;
141
153
  height: 24px;
@@ -189,6 +201,20 @@
189
201
  margin: 0 6px;
190
202
  }
191
203
 
204
+ .doubao-list-card__item-action {
205
+ --doubao-btn-border-radius: 8px;
206
+ --doubao-btn-default-height: 38px;
207
+ --doubao-btn-default-padding-x: 12px;
208
+ --doubao-btn-default-padding-y: 0;
209
+ --doubao-btn-default-font-size: 14px;
210
+ --doubao-btn-default-line-height: 20px;
211
+ --doubao-btn-default-bg: var(--bg-base-1-overlay);
212
+ --doubao-btn-default-text: var(--neutral-100);
213
+ flex-shrink: 0;
214
+ width: 80px;
215
+ height: 38px;
216
+ }
217
+
192
218
  .doubao-list-card__view-more-wrap {
193
219
  box-sizing: border-box;
194
220
  background-color: var(--bg-base-1);
@@ -1,9 +1,7 @@
1
1
  import { Button, useThemeClassName } from "@byted-doubao-apps/components";
2
+ import { clsx } from "clsx";
2
3
  import { getAppInfo } from "../utils/app-info.js";
3
4
  import "./styles.css";
4
- function joinClassNames(...classNames) {
5
- return classNames.filter(Boolean).join(' ');
6
- }
7
5
  function OrderCardIcon({ appIconSrc }) {
8
6
  if (null != appIconSrc && appIconSrc.length > 0) return <image className="doubao-order-card__app-icon" src={appIconSrc} mode="aspectFill"/>;
9
7
  return <view className="doubao-order-card__app-icon"/>;
@@ -15,28 +13,21 @@ function OrderCardProductImage(props) {
15
13
  return <view className="doubao-order-card__product-image"/>;
16
14
  }
17
15
  function OrderCard(props) {
18
- const { moreText = '更多', showMore = true, productTitle = '主标题', productSpec = '商品规格商品规格', productPricePrefix = '券后', productPrice = '¥5.8', productQuantity = '1', infoItems = [
19
- {
20
- label: '提单信息',
21
- value: '信息字段最多支持 2 行',
22
- valueExtra: '信息字段最多支持 2 行'
23
- },
24
- {
25
- label: '提单信息',
26
- value: '信息字段最多支持 2 行'
27
- }
28
- ], feeItems = [
29
- {
30
- label: '运费',
31
- value: '¥3.0'
32
- },
33
- {
34
- label: '打包费',
35
- value: '¥1.0'
36
- }
37
- ], discountText = '共优惠 ¥6', totalLabel = '合计', totalPrice = '¥9.8', primaryActionText = '立即支付', secondaryActionText = '修改', className, style, onClick, onMoreClick, onProductClick, onPrimaryActionClick, onSecondaryActionClick } = props;
16
+ const { moreText, showMore = true, productTitle, productSpec, productPricePrefix, productPrice, productQuantity, infoItems = [], feeItems = [], discountText, totalLabel, totalPrice, primaryActionText, secondaryActionText, className, style, onClick, onMoreClick, onProductClick, onPrimaryActionClick, onSecondaryActionClick } = props;
38
17
  const appInfo = getAppInfo();
39
- return <view className={useThemeClassName(joinClassNames('doubao-order-card', className))} style={style} bindtap={onClick} clip-radius="true">
18
+ const hasProductImage = null != props.productImage || null != props.productImageSrc && props.productImageSrc.length > 0;
19
+ const hasProductMainLine = null != productTitle && productTitle.length > 0 || null != productPricePrefix && productPricePrefix.length > 0 || null != productPrice && '' !== productPrice;
20
+ const hasProductSecondaryLine = null != productSpec && productSpec.length > 0 || null != productQuantity && '' !== productQuantity;
21
+ const hasProduct = hasProductImage || hasProductMainLine || hasProductSecondaryLine;
22
+ const hasInfoItems = infoItems.length > 0;
23
+ const hasDiscount = null != discountText && discountText.length > 0;
24
+ const hasFeeItems = feeItems.length > 0;
25
+ const hasTotal = null != totalLabel && totalLabel.length > 0 || null != totalPrice && '' !== totalPrice;
26
+ const hasSummary = hasDiscount || hasFeeItems || hasTotal;
27
+ const hasPrimaryAction = null != primaryActionText && primaryActionText.length > 0;
28
+ const hasSecondaryAction = null != secondaryActionText && secondaryActionText.length > 0;
29
+ const hasActions = hasPrimaryAction || hasSecondaryAction;
30
+ return <view className={useThemeClassName(clsx('doubao-order-card', className))} style={style} bindtap={onClick} clip-radius="true">
40
31
  <view className="doubao-order-card__title-bar">
41
32
  <view className="doubao-order-card__app">
42
33
  <OrderCardIcon appIconSrc={appInfo.appIconSrc}/>
@@ -44,7 +35,7 @@ function OrderCard(props) {
44
35
  {appInfo.appName}
45
36
  </text>
46
37
  </view>
47
- {showMore ? <view className="doubao-order-card__more" catchtap={onMoreClick}>
38
+ {showMore && null != moreText && moreText.length > 0 ? <view className="doubao-order-card__more" catchtap={onMoreClick}>
48
39
  <text className="doubao-order-card__more-text" text-maxline="1">
49
40
  {moreText}
50
41
  </text>
@@ -52,75 +43,75 @@ function OrderCard(props) {
52
43
  </view> : null}
53
44
  </view>
54
45
 
55
- <view className="doubao-order-card__product" catchtap={onProductClick}>
56
- <OrderCardProductImage productImage={props.productImage} productImageSrc={props.productImageSrc}/>
57
- <view className="doubao-order-card__product-content">
58
- <view className="doubao-order-card__product-line-main">
59
- <view className="doubao-order-card__product-title-wrap">
60
- <text className="doubao-order-card__product-title" text-maxline="1">
61
- {productTitle}
62
- </text>
63
- <view className="doubao-order-card__product-chevron"/>
64
- </view>
65
- <view className="doubao-order-card__product-price">
66
- <text className="doubao-order-card__product-price-prefix" text-maxline="1">
67
- {productPricePrefix}
68
- </text>
69
- <text className="doubao-order-card__product-price-value" text-maxline="1">
70
- {productPrice}
71
- </text>
72
- </view>
46
+ {hasProduct ? <view className="doubao-order-card__product" catchtap={onProductClick}>
47
+ {hasProductImage ? <OrderCardProductImage productImage={props.productImage} productImageSrc={props.productImageSrc}/> : null}
48
+ <view className={clsx('doubao-order-card__product-content', hasProductImage && 'doubao-order-card__product-content--with-image')}>
49
+ {hasProductMainLine ? <view className="doubao-order-card__product-line-main">
50
+ {null != productTitle && productTitle.length > 0 ? <view className="doubao-order-card__product-title-wrap">
51
+ <text className="doubao-order-card__product-title" text-maxline="1">
52
+ {productTitle}
53
+ </text>
54
+ <view className="doubao-order-card__product-chevron"/>
55
+ </view> : null}
56
+ {null != productPricePrefix && productPricePrefix.length > 0 || null != productPrice && '' !== productPrice ? <view className="doubao-order-card__product-price">
57
+ {null != productPricePrefix && productPricePrefix.length > 0 ? <text className="doubao-order-card__product-price-prefix" text-maxline="1">
58
+ {productPricePrefix}
59
+ </text> : null}
60
+ {null != productPrice && '' !== productPrice ? <text className="doubao-order-card__product-price-value" text-maxline="1">
61
+ {productPrice}
62
+ </text> : null}
63
+ </view> : null}
64
+ </view> : null}
65
+ {hasProductSecondaryLine ? <view className="doubao-order-card__product-line-secondary">
66
+ {null != productSpec && productSpec.length > 0 ? <text className="doubao-order-card__product-spec" text-maxline="1">
67
+ {productSpec}
68
+ </text> : null}
69
+ {null != productQuantity && '' !== productQuantity ? <text className="doubao-order-card__product-quantity" text-maxline="1">
70
+ ×{productQuantity}
71
+ </text> : null}
72
+ </view> : null}
73
73
  </view>
74
- <view className="doubao-order-card__product-line-secondary">
75
- <text className="doubao-order-card__product-spec" text-maxline="1">
76
- {productSpec}
77
- </text>
78
- <text className="doubao-order-card__product-quantity" text-maxline="1">
79
- ×{productQuantity}
80
- </text>
81
- </view>
82
- </view>
83
- </view>
74
+ </view> : null}
84
75
 
85
- <view className="doubao-order-card__info">
86
- {infoItems.map((item, index)=><view className="doubao-order-card__info-row" key={item.key ?? index}>
87
- <text className="doubao-order-card__info-label" text-maxline="1">
88
- {item.label}
89
- </text>
90
- <view className="doubao-order-card__info-value-wrap">
91
- <text className="doubao-order-card__info-value" text-maxline="1">
92
- {item.value}
93
- </text>
94
- {null != item.valueExtra ? <text className="doubao-order-card__info-value" text-maxline="1">
95
- {item.valueExtra}
96
- </text> : null}
97
- </view>
98
- </view>)}
99
- <view className="doubao-order-card__summary">
100
- <view className="doubao-order-card__summary-content">
101
- {discountText.length > 0 ? <text className="doubao-order-card__fee-text" text-maxline="1">
102
- {discountText}
103
- </text> : null}
104
- {feeItems.map((item, index)=><text className="doubao-order-card__fee-text" text-maxline="1" key={item.key ?? index}>
76
+ {hasInfoItems || hasSummary ? <view className="doubao-order-card__info">
77
+ {infoItems.map((item, index)=><view className="doubao-order-card__info-row" key={item.key ?? index}>
78
+ <text className="doubao-order-card__info-label" text-maxline="1">
105
79
  {item.label}
106
- {item.value}
107
- </text>)}
108
- <view className="doubao-order-card__total">
109
- <text className="doubao-order-card__total-label" text-maxline="1">
110
- {totalLabel}
111
- </text>
112
- <text className="doubao-order-card__total-price" text-maxline="1">
113
- {totalPrice}
114
80
  </text>
115
- </view>
116
- </view>
117
- </view>
118
- </view>
81
+ <view className="doubao-order-card__info-value-wrap">
82
+ <text className="doubao-order-card__info-value" text-maxline="1">
83
+ {item.value}
84
+ </text>
85
+ {null != item.valueExtra ? <text className="doubao-order-card__info-value" text-maxline="1">
86
+ {item.valueExtra}
87
+ </text> : null}
88
+ </view>
89
+ </view>)}
90
+ {hasSummary ? <view className="doubao-order-card__summary">
91
+ <view className="doubao-order-card__summary-content">
92
+ {hasDiscount ? <text className="doubao-order-card__fee-text" text-maxline="1">
93
+ {discountText}
94
+ </text> : null}
95
+ {feeItems.map((item, index)=><text className="doubao-order-card__fee-text" text-maxline="1" key={item.key ?? index}>
96
+ {item.label}
97
+ {item.value}
98
+ </text>)}
99
+ {hasTotal ? <view className="doubao-order-card__total">
100
+ {null != totalLabel && totalLabel.length > 0 ? <text className="doubao-order-card__total-label" text-maxline="1">
101
+ {totalLabel}
102
+ </text> : null}
103
+ {null != totalPrice && '' !== totalPrice ? <text className="doubao-order-card__total-price" text-maxline="1">
104
+ {totalPrice}
105
+ </text> : null}
106
+ </view> : null}
107
+ </view>
108
+ </view> : null}
109
+ </view> : null}
119
110
 
120
- <view className="doubao-order-card__actions">
121
- <Button className="doubao-order-card__action doubao-order-card__action--secondary" type="default" text={secondaryActionText} onClick={onSecondaryActionClick}/>
122
- <Button className="doubao-order-card__action doubao-order-card__action--primary" type="primary" text={primaryActionText} onClick={onPrimaryActionClick}/>
123
- </view>
111
+ {hasActions ? <view className="doubao-order-card__actions">
112
+ {hasSecondaryAction ? <Button className="doubao-order-card__action doubao-order-card__action--secondary" type="default" text={secondaryActionText} onClick={onSecondaryActionClick}/> : null}
113
+ {hasPrimaryAction ? <Button className="doubao-order-card__action doubao-order-card__action--primary" type="primary" text={primaryActionText} onClick={onPrimaryActionClick}/> : null}
114
+ </view> : null}
124
115
  </view>;
125
116
  }
126
117
  export { OrderCard };
@@ -105,10 +105,13 @@
105
105
  flex-direction: column;
106
106
  flex: 1 1 0;
107
107
  min-width: 0;
108
- margin-left: 12px;
109
108
  display: flex;
110
109
  }
111
110
 
111
+ .doubao-order-card__product-content--with-image {
112
+ margin-left: 12px;
113
+ }
114
+
112
115
  .doubao-order-card__product-line-main, .doubao-order-card__product-line-secondary {
113
116
  flex-direction: row;
114
117
  align-items: center;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doubao-apps/template",
3
- "version": "0.0.29",
3
+ "version": "0.0.30",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -16,6 +16,9 @@
16
16
  "README.md",
17
17
  "!dist/**/*.map"
18
18
  ],
19
+ "dependencies": {
20
+ "clsx": "2.1.1"
21
+ },
19
22
  "peerDependencies": {
20
23
  "@lynx-js/react": "^0.115.1",
21
24
  "@lynx-js/types": "^3.6.0",