@ crometics/ lp- 设计系统
React 18/19 组件库用于登陆页面. 船舶未捆绑的无害环境管理(每个单元一个)
和独立的样式表; 消费者仅通过 --lp-* CSS 变量和不需要
尾风自设.
安装
该套件公开发布至npm:
pnpm add @crometrics/lp-design-system
通过0.5.0的放出也去了GitHub套件;后期的放出只有npm. 另一个
@crometrics 软件包仍然被发布到 GitHub 软件包。 狦 .npmrc (项目或 ~/.npmrc) 绘制那里的范围——
@crometrics:registry=https://npm.pkg.github.com/ ——这种绘图适用于每一个
@crometrics 软件包,因此上面的命令会针对 GitHub 软件包解析,而永远不会看到
npm发布. 如果您不需要其他地图, 要么删除映射 @crometrics 软件包,或指针
以 pnpm 为单位的 npm 软件包 npmjs: 登记册前缀(pnpm 11.1+):
pnpm add "@crometrics/lp-design-system@npmjs:^0.5.0"
用于保存 "@crometrics/lp-design-system": "npmjs:^0.5.0" 改为 package.json更新
从 npm 而从其他 @crometrics gitHub 软件包中仍然有解析。 无
而Yarn没有每个包装的注册系统.
react 财务报告和审定财务报表 react-dom ^18.0.0 || ^19.0.0 属于对等依赖,必须安装于
消费者。 每一个故事测试都运行在 Resact 18.3.1(HubSpot CMS React pins)和
反应19.
使用量
在应用根导入样式表, 然后在任何地方使用组件 :
// app entry (e.g. src/main.tsx, or app/layout.tsx in Next.js)
import '@crometrics/lp-design-system/styles.css';
从自己的入口——kebab- case 组件名称导入每个组件:
import { Button } from '@crometrics/lp-design-system/button';
import { PromoBanner } from '@crometrics/lp-design-system/promo-banner';
每个组件入口只装入每个工具中的组件模块:
生产捆绑、dev服务器和测试跑道 从软件包导入
根数( e)import { Button } from '@crometrics/lp-design-system'(b) 工程和
生产过程中的树摇摆正在建立,但dev服务器和测试跑取器每加载
组件通过它.
import { Button } from '@crometrics/lp-design-system/button';
export default function Page() {
return (
<>
<Button>Primary</Button>
<Button variant="secondary" size="lg">
Secondary
</Button>
<Button variant="tertiary" icon={<CameraIcon />}>
With icon
</Button>
<Button
variant="transparent"
icon={<img alt="" src={logo} />}
iconPosition="trailing"
>
On a hero image
</Button>
<Button aria-label="Add photo" icon={<CameraIcon />} round />
</>
);
}
服务器渲染和水分
每个组件的服务器发送器( 验证为 renderToString (原始内容存档于2018-11-19). React 18 and 19.
只有两个人需要客户水合——在HubSpot CMS React中,使其成为岛屿:
| 构成部分 | 为什么它会水合物 |
|---|---|
DonationForm (这样) DonationHero 除非你通过 formSlot(中文(简体) ) | 频率/挂载状态 |
Tout | 滚动驱动的旋转木马指标mobileLayout="carousel"(中文(简体) ) |
其他一切——包括: Header, (中文(简体) ), TrustSignalsMetrics, (中文(简体) ), ThirtyNinety, (中文(简体) ),
PromoBanner, (中文(简体) ), Accordion (Base UI将自己的原始水合物)和 FooterMega —— 说
无组件 JavaScript。 与 formSlot, (中文(简体) ), DonationHero 无需水合
它的自身 超越了任何时间档的供应商 嵌入带来的.
部件也是RSC安全: Tout 财务报告和审定财务报表 DonationForm 标记
'use client',所以在 Next.js App路由器和
没有将组件 JavaScript 传送到浏览器 。 两者都可以直接从服务器中渲染
组件 - 不需要折叠文件。 无 RSC 框架( Vite SPAs, Astro, plain)
反应)忽略指令.
从服务器组件传递的道具必须是可序列的: 事件处理器, 如
Input是因为 onChange 或者说 EmailSignupForm是因为 onSubmit 只能从一个
客户端组件.
他们
--lp-* 自定义属性是整个公共造型 API。 默认声明于
:root 内 styles.css; 覆盖您 CSS 中的任意一个, 并装入
库样式表 :
:root {
--lp-color-primary: #16a34a;
}
默认镜像 Figma “ 页面设计系统” 库 .
| 变量 | 默认 | 用于 |
|---|---|---|
--lp-color-primary | #185dff | 主按钮填充, 第三级/ 透明边框 |
--lp-color-primary-hover | #0037b8 | 主按钮徘徊填充 |
--lp-color-text-on-primary | var(--lp-color-text-inverse) | 主按钮标签( 如橙色 CTA 上的暗文本) |
--lp-color-secondary | #141414 | 次要按钮填充 |
--lp-color-secondary-hover | #666666 | 次要按钮悬空 |
--lp-color-secondary-active | #212121 | 按下二级按钮填充 |
--lp-color-surface | #ffffff | 浅表面( 外部按钮填充) |
--lp-color-text | #141414 | 轻表面文字 |
--lp-color-text-inverse | #ffffff | 暗/ 品牌表面的文字 |
--lp-color-text-inverse-muted | var(--lp-color-text-inverse) | 暗面的副文本 |
--lp-color-text-inverse-brand | var(--lp-color-text-inverse) | 黑色表面的有色文字 |
--lp-color-text-inverse-accent | var(--lp-color-text-inverse) | 深色表面的正文/链接 |
--lp-color-text-muted | #666666 | 禁用文本 |
--lp-color-border-muted | #b4b4b4 | 已禁用边框 |
--lp-color-disabled | #e5e5e5 | 禁用补全 |
--lp-color-focus | #dc0173 | 重点可见大纲 |
--lp-font-sans | system-ui, -apple-system, sans-serif | 文本正文 |
--lp-font-button | "Montserrat", var(--lp-font-sans) | 按钮标签( 自己装入蒙特塞拉特) |
--lp-font-button-weight | 500 | 按键标签重量 |
--lp-font-cta-weight | 500 | 文本链接 CTA 重量(例如卡 CTAs) |
--lp-font-badge-weight | 600 | Badge variant="tag" 标签重量 |
--lp-radius | 0.375rem | 角半径 |
--lp-color-surface-secondary | #f6f6f6 | 区域背景( 如交替带色) |
--lp-color-surface-tertiary | #e5e5e5 | 子拖放区域背景 |
--lp-color-surface-inverse | #141414 | 黑暗区域背景 |
--lp-color-surface-inverse-secondary | var(--lp-color-surface-inverse) | 第二个暗面(例如暗带上一张牌) |
--lp-color-surface-tint | var(--lp-color-surface-secondary) | 有锡段带 |
--lp-color-surface-brand-secondary | var(--lp-color-surface-tertiary) | 二级品牌色带/卡片 |
--lp-color-surface-neutral | var(--lp-color-surface-secondary) | 温暖/中性段幅 |
--lp-color-surface-card | transparent | 纸牌表面(例如:. ContentCard(中文(简体) ) |
--lp-color-surface-card-hover | var(--lp-color-surface-card) | 悬浮的卡片表面 |
--lp-color-text-on-card 编号 : -hover | var(--lp-color-text) 编号 : var(--lp-color-text-on-card) | 满纸牌上的文字和悬浮的文字 |
--lp-color-surface-inverse-brand-secondary | var(--lp-color-surface-brand-secondary) | Badge variant="tag" 填满 |
--lp-color-donation-icon | currentColor | 捐款 表格的每月心脏图标 |
--lp-color-surface-brand | #185dff | 装满了徽章,有名色的表面 |
--lp-color-text-brand | #185dff | 品牌彩色文本和链接(如卡 CTAs) |
--lp-color-border | #212121 | 较强的边界(vs. -border-muted(中文(简体) ) |
--lp-color-border-inverse | var(--lp-color-border-muted) | 暗表面的边框/潜水器 |
--lp-color-accent | #dc0173 | 口音颜色 |
--lp-color-donation | #dc0173 | 捐款式按钮填充(重用口音) |
--lp-font-body | "Montserrat", var(--lp-font-sans) | 文字、徽章、卡片CTA |
--lp-font-heading | "Playfair Display", serif | 区/卡标题( 自己装入字体) |
--lp-font-heading-weight | 未设置( 标题保留浏览器/ 您的默认重量) | 重量 h1– 说吧 –h5/ CMS 标题样式 |
--lp-text-{h1-cms,h2-cms,h1,h2,h3,h4,h5}-tracking | 未设置( 继承) | 每个标题级别(例如:. -1px(中文(简体) ) |
--lp-text-h1-cms-size 编号 : -line-height | 3rem 编号 : 3rem (48px/48px), (中文(简体) ), 2.25rem编号 :2.5rem 移动 | 最大的 CMS 页面标题 |
--lp-text-h2-cms-size 编号 : -line-height | 2.25rem编号 :2.5rem (36px/40px), (中文(简体) ), 1.875rem编号 :2.25rem 移动 | 第二大内容管理系统标题 |
--lp-text-h1-size 编号 : -line-height | 2.25rem编号 :2.5rem (36px/40px), (中文(简体) ), 1.875rem编号 :2.25rem 移动 | H1级 |
--lp-text-h2-size 编号 : -line-height | 1.5rem编号 :2rem (24px/32px), (中文(简体) ), 1.25rem编号 :1.75rem 移动 | H2 数据 |
--lp-text-h3-size 编号 : -line-height | 1.25rem编号 :1.75rem (20px/28px), (中文(简体) ), 1.125rem编号 :1.75rem 移动 | H3级 |
--lp-text-h4-size 编号 : -line-height | 1.125rem编号 :1.75rem (18px/28px), (中文(简体) ), 1rem编号 :1.5rem 移动 | H4级 |
--lp-text-h5-size 编号 : -line-height | 1rem编号 :1.5rem (16px/24px), (中文(简体) ), 0.875rem编号 :1.25rem 移动 | 高级 |
--lp-text-body-lg-size 编号 : -line-height | 1.125rem编号 :1.75rem (18px/28px,无移动变体) | 大型复制件 |
--lp-text-body-size 编号 : -line-height | 1rem编号 :1.5rem (16px/24px,无移动变体) | 副本 |
--lp-text-body-sm-size 编号 : -line-height | 0.875rem编号 :1.25rem (14px/20px,无移动变体) | 体型小一点 |
--lp-text-eyebrow-size 编号 : -line-height | 0.875rem编号 :1.25rem (14px/20px,无移动变体) | 眉毛标签 |
--lp-text-cta-size 编号 : -line-height | 0.875rem编号 :1.25rem (14px/20px,无移动变体) | 文本链接 CTAs( 如卡 CTAs) |
--lp-text-button-md-size 编号 : -line-height | 0.875rem编号 :1.25rem (14px/20px) (英语) | 中键标签 |
--lp-text-button-lg-size 编号 : -line-height | 1rem编号 :1.5rem (16px/24px) (英语) | 大按钮标签 |
--lp-text-footer-size 编号 : -line-height | 天体- sm 值 | 脚印Mega版权/法律文本 |
--lp-radius-card | 0.375rem | 卡片角半径 |
--lp-radius-input | 0.375rem | 输入/文本区域角半径(与半径卡值相同,是未来重播的独立标志) |
--lp-radius-image | 0px | 图像角半径( 按设计显示) |
--lp-space-section | 6rem 台式计算机 / 4rem 移动 | 区域垂直粘贴 |
--lp-space-gutter | 1.5rem, (中文(简体) ), 7.5rem 1728px+(宽) | 区域水平粘贴 |
--lp-space-stack | 2rem | Tout 桌面网格中的卡片间隙( 通过) --lp-space-cards(中文(简体) ) |
--lp-space-cards | var(--lp-space-stack) | 牌行中的牌间间隙( Tout) |
--lp-container | 93rem (1488px) (中文(简体) ) | 最大内容宽度( 不包括沟道), 居中 |
--lp-shadow | 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px 0 rgb(0 0 0 / 0.06) | 默认高地 |
--lp-shadow-lg | 0 8px 10px -3px rgb(0 0 0 / 0.2), 0 4px 5px -2px rgb(0 0 0 / 0.15) | 上升高地(如盘旋) |
--lp-shadow-form | var(--lp-shadow-lg) | 捐款格式卡(和捐款) 英雄们 formSlot 纸牌) |
断点
布局遵循设计的三个页面框架: 移动 < 1024px, (中文(简体) ), 桌面 1024–1727px (英语), (中文(简体) ), 宽度为 1728px。反应符号默认值在这些宽度下切换,以及 主题覆盖同一媒体查询中响应的符号 :
:root {
--lp-text-h1-cms-size: 2.5rem;
} /* mobile + desktop */
@media (min-width: 1728px) {
:root {
--lp-text-h1-cms-size: 4rem;
} /* wide */
}
在0.5.0之前,宽层开始于1280px.
样式表不会重新显示您的页面 。 它确实在自己的组件内重新设置:
组件根带 a data-lp 属性,并重置零特性(Tailwind's
飞行前,范围扩大到 [data-lp] 子树)清除浏览器默认存在, 如标题
和段落边距、链接颜色和下划线以及本地按钮边框。 重置坐着
输入 lp-base 级联层和工具类 lp。任何没有层次的 CSS 在您的
页面的分数都高于两者,所以全球规则就像 h2 { margin-bottom: 1rem } 您的主题仍然
到达我们的标题。 这些规则的范围,不包括 [data-lp] 如果他们干涉。 类
除这些变量外,其他名称是执行细节,在任何发布中都可能有所改变.
构成部分
| 构成部分 | 道具 |
|---|---|
Button | variant?: 'primary' | 'secondary' | 'tertiary' | 'transparent', (中文(简体) ), size?: 'md' | 'lg', (中文(简体) ), icon?: ReactNode (单位:千美元) <img> 或内置SVG), iconPosition?: 'leading' | 'trailing', (中文(简体) ), round?: boolean, (中文(简体) ), href?: string (以 <a href> 改为 <button> 当它被设置的时候, newTab?: boolean (增加数) target="_blank" rel="noopener noreferrer"; 只有有意义的 href),加上所有 <button>编号 :<a> 道具来. 奥米 children 仅用于图标的按钮(给它一个 aria-label) (中文(简体) ). |
每个区块的全 CMS- faccing 形状(道具,切换器,中继器,变体,插槽)在
contracts/<Name>.json。在0.5.0中添加,所有可选的默认值都保留
上一个渲染 :
| 构成部分 | 新道具 |
|---|---|
Header | ctas (1-2) (中文(简体) ) { link: CtaLink; hideOnMobile? }· ; cta 仍然工作, logoSize: 'md' | 'lg' |
DonationHero | layout: 'overlay' | 'split', (中文(简体) ), story: { badge?, heading?, body? } + 键 showStory, (中文(简体) ), formSlot (替换嵌入式) DonationForm 在同一张卡中,例如,有第三方捐款表,如嵌入的筹款表; form 然后可选) |
DonationForm | amountsLabel, (中文(简体) ), appearance: 'default' | 'tint', (中文(简体) ), customAmountPlaceholder, (中文(简体) ), trustLabel + 键 showTrustLabel |
TrustSignalsMetrics | sectionHeading, (中文(简体) ), headingLevel, (中文(简体) ), sectionBody + 键 showSectionBody, (中文(简体) ), cta: CtaLink + 键 showCta, (中文(简体) ), style: 'compact' | 'cards'; 每公吨 icon + 键 showIcon, (中文(简体) ), body + 键 showBody |
Tout | headerAlign: 'left' | 'center', (中文(简体) ), mobileLayout: 'carousel' | 'stack' |
ContentCard | body + 键 showBody, (中文(简体) ), surface: 'none' | 'filled' (填充 = 符号背面有悬浮状态,全卡可点击),, mediaAspectRatio (增加数) '5:4'(中文(简体) ) |
ThirtyNinety (新设, /thirty-ninety(中文(简体) ) | 图片"CMS 30-90":旁有正方形媒体 heading, (中文(简体) ), body + 键 showBody, (中文(简体) ), cta: CtaLink + 键 showCta, (中文(简体) ), ctaFullWidthMobile, (中文(简体) ), background, (中文(简体) ), side, (中文(简体) ), headingLevel |
PromoBanner | contentStyle: 'plain' | 'card', (中文(简体) ), background (太阳: 'secondary' | 'inverse' | 'inverse-secondary', (中文(简体) ), size: 'default' | 'large', (中文(简体) ), ctaVariant, (中文(简体) ), ctaSize· ; cta 现在是一个 CtaLink |
Accordion 编号 : AccordionItem | contentStyle: 'plain' | 'card' |
FooterMega | style: 'default' | 'inverse', (中文(简体) ), signupHeading + 键 headingLevel, (中文(简体) ), signupSlot + 键 signupFormSelectors (见 页脚Mega 注册表, (中文(简体) ), legalLine, (中文(简体) ), logoSize· ; description 现在可选 |
Badge | variant: 'pill' | 'tag' |
0.6.0中的添加, 也带有保留上一个渲染的默认的可选性 :
| 构成部分 | 新道具 |
|---|---|
DonationHero, (中文(简体) ), EmailSignupHero | mediaPosition: 'top' | 'center' | 'bottom': 当照片的盒子收割时( 默认值) , 照片的哪个边缘会保留 center(中文(简体) ) |
DonationHero | mediaMinAspect: 'none' | 'square' (单位:千美元)split 仅限: square 保持相片面板至少高到宽, 因此宽的取景口和 < 1024 范围不会将其切成薄带; 在桌面上, 复制相片面板伸展以匹配 |
PromoBanner | mediaPosition (图片样式),如上 |
Input | size: 'md' | 'lg', (中文(简体) ), hideLabel |
添加到 0.7. 0 中, 并带有默认保存上一个渲染的选项 :
| 构成部分 | 新道具 |
|---|---|
DonationHero, (中文(简体) ), EmailSignupHero, (中文(简体) ), PromoBanner | mediaPosition 还要 'left', (中文(简体) ), 'right' 和角数'top-left', (中文(简体) ), 'top-right', (中文(简体) ), 'bottom-left', (中文(简体) ), 'bottom-right'(中文(简体) ) |
PromoBanner | 图片样式 : mediaDesktop 编号 : mediaMobile艺术指导作物 media 1024–1727px和低于1024px(以 <picture>· ; mediaDesktop 也覆盖移动时 mediaMobile 未设置) |
CtaLink (单位:千美元){ href, label, newTab?, id?, dataAttributes? })是用于
Header, (中文(简体) ), TrustSignalsMetrics, (中文(简体) ), ThirtyNinety 财务报告和审定财务报表 PromoBanner。 。 。 . id 财务报告和审定财务报表
dataAttributes (键必须从 data-(其他被丢弃)
CTA 元素,所以您自己的脚本可以瞄准它,例如用于分析或打开一个
第三方捐款表,如筹款:
<Header
logo={logo}
ctas={[
{
link: {
label: 'Get started',
href: '#signup',
dataAttributes: { 'data-track': 'header-primary' },
},
hideOnMobile: true,
},
{ link: { label: 'Contact us', href: '#contact', id: 'header-contact' } },
]}
/>;
页脚Mega 注册表
FooterMega 使任何你通过的形式 signupSlot: CMS 格式模块,一个
电子邮件提供者嵌入, 或者您自己的标记 。 它不可能知道这个标记,所以
signupFormSelectors 告诉它哪一个元素 得到注册设计的每个部分.
每个密钥都是可选的,并使用任何 CSS 选择器列表,在页脚的槽内匹配
只有这个 没有密钥匹配的元素继承了槽的字体,大小和颜色.
| 密钥 | 获取 |
|---|---|
form | 两栏网格;每个孩子横跨两栏 |
fieldRow | 孩子们并肩并肩 宽度相等 |
field | 文本输入样式(输入、选择、文本区域)、占位符、焦点环 |
fieldInvalid | 边框颜色出错 |
hiddenLabel | 视觉隐藏, 仍由屏幕阅读器读取( 配置占位符) |
hint | 次要文本:小而哑 |
error | 校验消息: 小, 错误颜色, 没有列表项目 |
choice | 复选框/收音机口音颜色和大小 |
submit | 主按钮 |
inlineField | A 类 form 与最后一个行共享的子 inlineSubmit (需求数) form(中文(简体) ) |
inlineSubmit | 这个 form 儿童持有呈文,除此之外 inlineField (需求数) form(中文(简体) ) |
reset | 边距和粘贴被去除( 由自己的 CSS 对抗布局的包装) |
例如,对于一个使用标记的表单模块 .hs-* 如HubSpot所言:
<FooterMega
{...footerProps}
signupFormSelectors={{
error: '.hs-error-msgs',
field: '.hs-input:not([type=checkbox], [type=radio])',
fieldInvalid: '.hs-input.error',
fieldRow: 'fieldset',
form: '.hs-form',
hiddenLabel:
'.hs-form-field:not(.hs-fieldtype-checkbox, .hs-fieldtype-booleancheckbox, .hs-fieldtype-radio) > label',
hint: '.hs-richtext',
inlineField: 'fieldset:last-of-type',
inlineSubmit: '.hs-submit',
reset: '.input, .actions',
submit: '.hs-button',
}}
signupSlot={<YourFormModule />}
/>
脚步使这些规则在 <style> 插槽内 lp 层,所以你
自己的 CSS 仍然覆盖它们; 嵌入自己样式表的少数布局声明
通常战斗(宽度、浮度、包边、隐藏标签)是 !important颜色
跟着 style 编辑 --lp-* 变量。 包含 {, (中文(简体) ), }, (中文(简体) ), ;, (中文(简体) ), < 或一个
评论掷出. 对于一个需要这些密钥中任何一个都未给出的外观的元素,请将其样式化入
您的 CSS 属于 [data-lp-part="signup-slot"] 与 --lp-* 变量.
类型合同
contracts/<Name>.json (说明 contracts/component.schema.json) 扩大每个
输入为 JSON 时的文字 . @crometrics/lp-design-system/contracts 出口情况相同
数据及其字面类型,如 <Name>Contract,加上与之相关的类型:
import {
type ContractProp,
type ContractValues,
HeaderContract,
} from '@crometrics/lp-design-system/contracts';
// Props, variants and repeater items share one union, discriminated on `type`.
const field = (prop: ContractProp) => {
switch (prop.type) {
case 'enum':
return prop.options; // readonly [string, ...string[]]
case 'link':
return prop.fields; // subset of 'label' | 'href' | 'newTab' | 'id' | 'dataAttributes'
// …
}
};
// The props a contract describes: { logo: { src; alt }; logoSize?: 'md' | 'lg'; … }
type HeaderValues = ContractValues<typeof HeaderContract>;
ContractValues 地图 text 改为 string, (中文(简体) ), boolean, (中文(简体) ), number, (中文(简体) ), enum 对它的选择,
image 改为 { src, alt } 财务报告和审定财务报表 link 改为 Pick<CtaLink, …fields>A级 richtext 道具
顺其自然 render 模式 : html 道具被注入到一个 dangerouslySetInnerHTML这样
他们拿走了CMS的HTML string· ; node 道具是作为反应儿童提供的,所以
带一个 ReactNode。将 HTML 变成这些元素(原始 HTML 字符串将显示)
逃脱). 中继器变成数组: 需要的非空的 Tuple [T, ...T[]] 何时
min ≥ 1,其他选择。 点数密钥( N)form.submitLabel)成为被嵌入物.
required 控制密钥是否是可选的,变量总是可选的.
hidden 道具和插槽被忽略(插槽是 ReactNode 道具,喜欢 formSlot 或者说
signupSlot使你变成你自己 countFrom 变体,例如
BannerGrid是因为 quantity:它们只大小其中继器,组件读取
数组长度 。 也导出 : Contract, (中文(简体) ), ContractVariant, (中文(简体) ), ContractRepeater, (中文(简体) ),
ContractSlot, (中文(简体) ), ContractPropValue<P>, (中文(简体) ), ContractRichtextRender,每个接口
道具类型( e)TextProp, (中文(简体) ), RichtextProp<Render>, (中文(简体) ), EnumProp, (中文(简体) ), LinkProp(中文(简体) ).
mapContract
@crometrics/lp-design-system/contracts/map 帮你签合同 你来一个
每叶类型输入读取器,返回 ContractValues<C>,没有断言
你那边:
import { ToutContract } from '@crometrics/lp-design-system/contracts';
import {
type ContractReaders,
mapContract,
} from '@crometrics/lp-design-system/contracts/map';
const text = (value: unknown) =>
typeof value === 'string' ? value : undefined;
const read: ContractReaders = {
boolean: (value) => (typeof value === 'boolean' ? value : undefined),
enum: text, // mapContract drops values that aren't one of the options
image: (value) => toImage(value),
link: (value) => toCtaLink(value),
number: (value) => (typeof value === 'number' ? value : undefined),
richtext: {
html: text, // must return a string
node: (value) =>
typeof value === 'string' ? htmlToReact(value) : undefined,
},
text: (value, prop) => text(value) ?? prop.default,
};
const props = mapContract(ToutContract, fieldValues, read); // ToutProps-compatible
每个读者都得到原始价值,道克的契约条目及其路径(sectionHeading, (中文(简体) ),
cards[1].body, (中文(简体) ), variants.cards) (中文(简体) ). fieldValues 反映合同:道具和
中继器坐在被点的密钥上({ form: { submitLabel } }),中继器为
项目对象,变量在下方 variants同样的方式 countFrom 给他们起名
(单位:千美元){ cards: […], variants: { cards: '3' } }) (中文(简体) ). 隐藏和插槽道具被跳过. A 类
countFrom 中继器被调整到其变量值(或默认值). 一个读者
返回时 undefined 离开道具,所以组件默认适用。 对a
required 道具,或一个 min ≥ 1 中继器,最后是空的, mapContract 掷出
相反,因为道具类型 承诺了一个价值。 倒车 prop.default 输入
读者要避免这一点.
少数合同并没有准确描述它们的组件道具,所以CMS适配器有
以映射这些字段. contracts/props.test-d.ts 每个和任何其他
合同与合同组成部分之间的差值未通过类型测试:
| 合同 | 外地 | 组件需要 |
|---|---|---|
Button | style, (中文(简体) ), label, (中文(简体) ), icon (英文缩写) | variant, (中文(简体) ), children, (中文(简体) ), icon: ReactNode |
AspectRatioImage | src (图像对象) | src: string + 键 alt· ; aspectRatio 需要时间 |
DonationForm (和 DonationHero是因为 form.*(中文(简体) ) | amounts: [{ amount }, …], (中文(简体) ), paymentIcons: { image? }[] | amounts: number[] (单位:千美元)amounts.map((item) => item.amount), (中文(简体) ), paymentIcons: { alt, src }[] (不包含 image,然后选择 image(中文(简体) ) |
AccordionItem | a 一个 Accordion items[] 条目(defaultOpen(中文(简体) ) | Accordion 用品 value |
PromoBanner | mediaDesktop.alt, (中文(简体) ), mediaMobile.alt | 无:作物再利用 media.alt |
发展
从此软件包目录中运行 :
pnpm storybook # dev at http://localhost:6006
pnpm test # runs the stories headless via addon-vitest
pnpm build # dist/*.js per component (tsdown) + dist/styles.css (@tailwindcss/cli)
故事就是测试:每个元件行为都是在 *.stories.tsx
播放函数而不是单独的 spec 文件.