@doubao-apps/template 0.0.34 → 0.0.35

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.
@@ -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, primaryActionButtonProps, secondaryActionText, secondaryActionButtonProps, 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} primaryActionButtonProps={primaryActionButtonProps} secondaryActionText={secondaryActionText} secondaryActionButtonProps={secondaryActionButtonProps} 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
+
@@ -1,5 +1,6 @@
1
1
  import type { CSSProperties, TouchEvent } from '@lynx-js/types';
2
2
  import type { ReactElement, ReactNode } from 'react';
3
+ import { type TemplateActionButtonProps } from '../components/action-bar/index.js';
3
4
  import { type TemplateProductSummaryProps } from '../components/product-summary/index.js';
4
5
  import type { TemplateKey, TemplateText } from '../types.js';
5
6
  import './styles.scss';
@@ -22,8 +23,12 @@ export interface OrderCardProps {
22
23
  totalPrice?: TemplateText;
23
24
  /** 主按钮文案。 */
24
25
  primaryActionText?: string;
26
+ /** 主按钮配置,支持禁用、加载和点击节流。 */
27
+ primaryActionButtonProps?: TemplateActionButtonProps;
25
28
  /** 次按钮文案。 */
26
29
  secondaryActionText?: string;
30
+ /** 次按钮配置,支持禁用、加载和点击节流。 */
31
+ secondaryActionButtonProps?: TemplateActionButtonProps;
27
32
  /** 卡片根节点自定义类名。 */
28
33
  className?: string;
29
34
  /** 卡片根节点自定义样式。 */
@@ -22,7 +22,7 @@ function renderOrderCardProductItem({ item, index }) {
22
22
  </view>;
23
23
  }
24
24
  function OrderCard(props) {
25
- const { moreText, showMore = true, productItems = [], infoItems = [], feeItems = [], discountText, totalLabel, totalPrice, primaryActionText, secondaryActionText, className, style, onClick, onMoreClick, onPrimaryActionClick, onSecondaryActionClick } = props;
25
+ const { moreText, showMore = true, productItems = [], infoItems = [], feeItems = [], discountText, totalLabel, totalPrice, primaryActionText, primaryActionButtonProps, secondaryActionText, secondaryActionButtonProps, className, style, onClick, onMoreClick, onPrimaryActionClick, onSecondaryActionClick } = props;
26
26
  const productNodes = productItems.map((item, index)=>renderOrderCardProductItem({
27
27
  item,
28
28
  index
@@ -34,7 +34,7 @@ function OrderCard(props) {
34
34
 
35
35
  <TemplateInfoSection infoItems={infoItems} feeItems={feeItems} discountText={discountText} totalLabel={totalLabel} totalPrice={totalPrice} valueLayout="column"/>
36
36
 
37
- <TemplateActionBar secondaryActionText={secondaryActionText} primaryActionText={primaryActionText} onSecondaryActionClick={onSecondaryActionClick} onPrimaryActionClick={onPrimaryActionClick}/>
37
+ <TemplateActionBar secondaryActionText={secondaryActionText} secondaryActionButtonProps={secondaryActionButtonProps} primaryActionText={primaryActionText} primaryActionButtonProps={primaryActionButtonProps} onSecondaryActionClick={onSecondaryActionClick} onPrimaryActionClick={onPrimaryActionClick}/>
38
38
  </view>;
39
39
  }
40
40
  export { OrderCard };
@@ -1,5 +1,6 @@
1
1
  import type { CSSProperties, TouchEvent } from '@lynx-js/types';
2
2
  import type { ReactElement, ReactNode } from 'react';
3
+ import { type TemplateActionButtonProps } from '../components/action-bar/index.js';
3
4
  import type { TemplateKey, TemplateText } from '../types.js';
4
5
  import './styles.scss';
5
6
  export interface SingleItemCardProps {
@@ -25,8 +26,12 @@ export interface SingleItemCardProps {
25
26
  quantity?: TemplateText;
26
27
  /** 主按钮文案。 */
27
28
  primaryActionText?: string;
29
+ /** 主按钮配置,支持禁用、加载和点击节流。 */
30
+ primaryActionButtonProps?: TemplateActionButtonProps;
28
31
  /** 次按钮文案。 */
29
32
  secondaryActionText?: string;
33
+ /** 次按钮配置,支持禁用、加载和点击节流。 */
34
+ secondaryActionButtonProps?: TemplateActionButtonProps;
30
35
  /** 自定义内容区;传入后不再渲染默认图文结构。 */
31
36
  children?: ReactNode;
32
37
  /** 卡片根节点自定义类名。 */
@@ -92,7 +92,7 @@ function renderSingleItemCardTitleRow(props) {
92
92
  </view>;
93
93
  }
94
94
  function SingleItemCard(props) {
95
- const { moreText, showMore = true, imageSrc, image: image1, infoRows = [], quantity, primaryActionText, secondaryActionText, children, className, style, onClick, onMoreClick, onContentClick, onPrimaryActionClick, onSecondaryActionClick } = props;
95
+ const { moreText, showMore = true, imageSrc, image: image1, infoRows = [], quantity, primaryActionText, primaryActionButtonProps, secondaryActionText, secondaryActionButtonProps, children, className, style, onClick, onMoreClick, onContentClick, onPrimaryActionClick, onSecondaryActionClick } = props;
96
96
  const hasCustomContent = !isSingleItemCardNodeEmpty(children);
97
97
  const titleRowNode = renderSingleItemCardTitleRow(props);
98
98
  const infoRowNodes = getSingleItemCardInfoRows(infoRows, quantity).map((row, rowIndex)=>renderSingleItemCardInfoRow(row, rowIndex, quantity)).filter((node)=>null != node).slice(0, SINGLE_ITEM_CARD_INFO_ROW_LIMIT);
@@ -109,7 +109,7 @@ function SingleItemCard(props) {
109
109
  </view>
110
110
  </view>}
111
111
  </view>
112
- <TemplateActionBar className="doubao-single-item-card__action-bar" secondaryActionText={secondaryActionText} primaryActionText={primaryActionText} onSecondaryActionClick={onSecondaryActionClick} onPrimaryActionClick={onPrimaryActionClick}/>
112
+ <TemplateActionBar className="doubao-single-item-card__action-bar" secondaryActionText={secondaryActionText} secondaryActionButtonProps={secondaryActionButtonProps} primaryActionText={primaryActionText} primaryActionButtonProps={primaryActionButtonProps} onSecondaryActionClick={onSecondaryActionClick} onPrimaryActionClick={onPrimaryActionClick}/>
113
113
  </view>;
114
114
  }
115
115
  export { SingleItemCard };
@@ -37,11 +37,11 @@
37
37
  }
38
38
 
39
39
  .doubao-single-item-card__image {
40
- width: var(--doubao-single-item-card-image-size, 80px);
41
- height: var(--doubao-single-item-card-image-size, 80px);
42
40
  background-color: var(--doubao-single-item-card-image-bg);
43
41
  border-radius: 5px;
44
42
  flex-shrink: 0;
43
+ width: 80px;
44
+ height: 80px;
45
45
  overflow: hidden;
46
46
  }
47
47
 
@@ -1,5 +1,6 @@
1
1
  import type { CSSProperties, TouchEvent } from '@lynx-js/types';
2
2
  import type { ReactElement, ReactNode } from 'react';
3
+ import { type TemplateActionButtonProps } from '../components/action-bar/index.js';
3
4
  import type { TemplateKey, TemplateText } from '../types.js';
4
5
  import './styles.scss';
5
6
  export interface TicketOrderCardProps {
@@ -21,8 +22,12 @@ export interface TicketOrderCardProps {
21
22
  totalContent?: ReactNode;
22
23
  /** 主按钮文案。 */
23
24
  primaryActionText?: string;
25
+ /** 主按钮配置,支持禁用、加载和点击节流。 */
26
+ primaryActionButtonProps?: TemplateActionButtonProps;
24
27
  /** 次按钮文案。 */
25
28
  secondaryActionText?: string;
29
+ /** 次按钮配置,支持禁用、加载和点击节流。 */
30
+ secondaryActionButtonProps?: TemplateActionButtonProps;
26
31
  /** 卡片根节点自定义类名。 */
27
32
  className?: string;
28
33
  /** 卡片根节点自定义样式。 */
@@ -9,7 +9,7 @@ function isTicketOrderTextEmpty(content) {
9
9
  return null == content || '' === content;
10
10
  }
11
11
  function TicketOrderCard(props) {
12
- const { moreText, showMore = true, routeItems = [], infoItems = [], feeItems = [], totalLabel, totalPrice, totalContent, primaryActionText, secondaryActionText, className, style, onClick, onMoreClick, onPrimaryActionClick, onSecondaryActionClick } = props;
12
+ const { moreText, showMore = true, routeItems = [], infoItems = [], feeItems = [], totalLabel, totalPrice, totalContent, primaryActionText, primaryActionButtonProps, secondaryActionText, secondaryActionButtonProps, className, style, onClick, onMoreClick, onPrimaryActionClick, onSecondaryActionClick } = props;
13
13
  const hasRouteItems = hasTemplateRouteSectionItems(routeItems);
14
14
  const hasInfoSection = infoItems.length > 0 || feeItems.length > 0 || void 0 !== totalContent || !isTicketOrderTextEmpty(totalLabel) || !isTicketOrderTextEmpty(totalPrice);
15
15
  const hasDefaultBody = hasRouteItems || hasInfoSection;
@@ -21,7 +21,7 @@ function TicketOrderCard(props) {
21
21
  {hasInfoSection ? <TemplateInfoSection infoItems={infoItems} feeItems={feeItems} totalLabel={totalLabel} totalPrice={totalPrice} totalContent={totalContent}/> : null}
22
22
  </view> : null}
23
23
 
24
- <TemplateActionBar secondaryActionText={secondaryActionText} primaryActionText={primaryActionText} onSecondaryActionClick={onSecondaryActionClick} onPrimaryActionClick={onPrimaryActionClick}/>
24
+ <TemplateActionBar secondaryActionText={secondaryActionText} secondaryActionButtonProps={secondaryActionButtonProps} primaryActionText={primaryActionText} primaryActionButtonProps={primaryActionButtonProps} onSecondaryActionClick={onSecondaryActionClick} onPrimaryActionClick={onPrimaryActionClick}/>
25
25
  </view>;
26
26
  }
27
27
  export { TicketOrderCard };
@@ -5,14 +5,14 @@
5
5
  --doubao-transport-list-card-main-text: var(--neutral-100);
6
6
  --doubao-transport-list-card-secondary-text: var(--neutral-50);
7
7
  --doubao-transport-list-card-placeholder-bg: var(--bg-base-1-overlay);
8
- --doubao-btn-border-radius: var(--doubao-transport-list-card-view-more-radius, 8px);
9
- --doubao-btn-default-height: var(--doubao-transport-list-card-view-more-height, 44px);
8
+ --doubao-btn-border-radius: 8px;
9
+ --doubao-btn-default-height: 44px;
10
10
  --doubao-btn-default-padding-x: 12px;
11
11
  --doubao-btn-default-padding-y: 0;
12
- --doubao-btn-default-font-size: var(--doubao-transport-list-card-view-more-font-size, 16px);
13
- --doubao-btn-default-line-height: var(--doubao-transport-list-card-view-more-line-height, 22px);
14
- --doubao-btn-default-bg: var(--doubao-transport-list-card-view-more-bg, var(--bg-base-2-overlay));
15
- --doubao-btn-default-text: var(--doubao-transport-list-card-view-more-text, var(--neutral-100));
12
+ --doubao-btn-default-font-size: 16px;
13
+ --doubao-btn-default-line-height: 22px;
14
+ --doubao-btn-default-bg: var(--bg-base-2-overlay);
15
+ --doubao-btn-default-text: var(--neutral-100);
16
16
  box-sizing: border-box;
17
17
  background-color: var(--doubao-transport-list-card-bg);
18
18
  border: 1px solid var(--doubao-transport-list-card-border);