@ canonical/ react-ds- global-form (英语)
Pragma设计系统的形式组件. 这个软件包提供了一个基于反应-hook-form的字段系统,它有两种核心模式:一个用于渲染不同输入类型并用于扩展字段行为的字段切换.
先决条件
- 反应19或以上
安装
bun add @canonical/react-ds-global-form @canonical/styles
导入设计系统的样式 第一个 在应用程序条目中,在进口部件之前:
import "@canonical/styles";
或者,从样式表: @import url("@canonical/styles");。 。 。 .
每个组件在导入时都会带出自己的样式表。 软件包样式表(字段布局、输入铬、窗体符号)不是由任何组件导入的,所以在样式之后直接导入:
import "@canonical/react-ds-global-form/dist/esm/index.css";
CSS 组件如何到达页面
这个软件包将CSS放在了两条路的页面上. dist/esm/index.css —— 导入上方的文件片段—— 是软件包级别样式表: --form-* 符号块、字段网格、共享输入铬和 density.css,使每个控件大小达到根上下文和密度单元格。 每个组件模块然后自导自出样式表(import "./styles.css"),所以导入一个组件就是将该组件的CSS放入页面;一个捆绑器将这些进口物收集到应用程序的CSS中. 这里没有在运行时间注入, 和组件 你从来没有进口船只 没有CSS.
后果是,捆绑者碰巧发出这些被单的指令并不是你能够依赖的,这就是下面的级联层的目的.
每个样式表都在 ds.components.global
每个样式表下 src/ - 包项, density.css,29个组件表和密度示例,共32个——用一个级联层包裹:
@layer ds.components.global {
.ds.field-label {
/* … */
}
}
@canonical/styles 在一个语句中宣布每层的顺序 ds.components.global 坐于其上相近相. 二事随顺.
ds.components.app上面一层是应用层 @canonical/react-ds-app-lxd 他们的兄弟姐妹。 还没有一个被包起来( 在撰写时, 没有样式表 ) packages/react/ds-app-* 内装一层; 正在将它们与这个包件一起包装。 今天,一个应用级仍然比这个软件包好,原因恰恰相反——它是无层的,无层的节拍分层. 一旦这些软件包落地,层层保证的是,一个字段的应用级规则或一个输入,这个软件包也用级联层来取胜,而不是用装载器最后释放的哪个捆绑来取胜.
父层 ds.components 位于两层之上,而不是两层之间: 直接写入其中的一条规则 落在这层隐含的底层中, 它的分数超过了它下面的每一个被命名的底层。 因此,没有普拉克马船 直接写入 ds.components ——布局预设于 src/index.css 以前是,在孤独 @layer ds.components 块,它们现在像其他东西一样 被装在这个包里.
申请本身 无层 CSS现在击败了这个软件包中的每一个规则,无论哪一边的选取者,因为没有层次的作者规则排在每层的分数后. 这是CSS按照设计工作,这是故意逃出舱门:一个需要覆盖窗体控件的应用程序会写出一个简单的规则,它会获胜。 实际的应用程序 没有 无意中取胜,让CSS进入 @layer app。 。 。 .
捐助者规则: 每个样式表下 src/ 用包装打开. @keyframes 和软件包本身 :root 默认值会进入其中; @property 财务报告和审定财务报表 @font-face 登记在区块上方。 最后一个是惯例,而不是级联力:用Chromium 151测量,两个共享一个名字的注册完全按照风格规则排序——一个在更高层的胜者无论来源顺序如何,一个无层次的胜者胜出一个分层的 @property, (中文(简体) ), @font-face 财务报告和审定财务报表 @keyframes 一样。 将登记保留在区块上方是他们读成的全文件权威,并把它们放在某个人查查登记的名字会找到的地方。 一个 @import 也保留在块上方——进口只有在其他规则之前有效——而且需要 layer(ds.components.global) 关键词 仅限 当工作表没有被包起来时; src/index.css 进口 density.css 裸体,因为 density.css 声明层本身,关键词将嵌入声明 ds.components.global.ds.components.global,一个会输给 index.css自己的规矩 永远无法到达 !important 以赢得争斗——一项重要宣言颠倒了地层秩序,完全不能被地层仲裁. 这个 @canonical/styles README"卡斯卡德地层"部分是全序和被故意留下的未分层的参考. 一个例外是 .storybook/styles.css,这是故意的外面 src/:这是《故事书》的用具,而不是包的一部分——从未出版(files: ["dist"],然后在预览页中添加一个 .rtl 工具 —— 保持未分层是它能够覆盖预览的内容 .
拥有他们制作的原生人的盒子
这个软件包使本地元素比其他任何元素都多: <input> 有十几类, <select>, (中文(简体) ), <textarea>, (中文(简体) ), <label>, (中文(简体) ), <legend>, (中文(简体) ), <fieldset>, (中文(简体) ), <button>构成原生元素的组件负责该元素的框-其边距、宽度、宽度、宽度、宽度 min-width页:1 box-sizing 用于 ::placeholder 用于提供文本输入。 任何未申报的组件,都由主机页面加载的其他内容填入,并在同样运行另一个框架的页面上填入,这个框架是可见的bug而不是默认. 宣布这个盒子是做它自己的改变;在它着陆之前,把"控制在我们自己的页面上看对了"视为比听起来更弱的保证.
本软件包门户中没有任何内容: 否 createPortal,没有 appendChild,没有 <dialog>. 逃避集装箱的两个表面——组合框清单(ComboboxInput/common/List/List.tsx:42)和取色器的监视面板(ColorInput/ColorInput.tsx:198)——使用"波波弗"API,将一个元素推广到上层进行绘画,但将其留在了DOM中的位置. 所以他们留在里面 .ds 树的呼号 和元素层 @canonical/styles 潜入树下的地方仍然有.
过渡读取运动符号
本一揽子方案中的每一个过渡都从 --motion-duration-fast三个期限标志的快步 @canonical/styles 永远不要从字面上说出来。 这不是一个平庸的规则。 下 prefers-reduced-motion: reduce 样式软件包将所有三个期限符号设置为 0s,零化是pragma的减动机制:一个组件本身 transition 宣言保持其在级联中的位置,只是一意孤行。 硬码持续时间对于它来说是隐形的,并且为要求其系统不要的读者保持动画. 这是代码标准 cs:css.properties.values ("设计活值的标志") 有牙齿在上面.
捐助者规则: a 没有字面持续时间 transition 或一个 animation新的一个读出一个符号 一个赤裸的 0s 只有一个例外,因为它已经说"没有运动"。 象征他们自己生活 @canonical/styles (单位:千美元)motion.css;如果一个控制需要一个步骤,则三个步骤不提供,则该步骤将添加在那里,而不是写入一个组件。 减肥是例外,是故意的: ease 这里,而不是 var(--motion-easing-standard),因为那个标志是 ease-out 换掉是第二个改变 控制的感觉, 它骑着PRA-153 和缺失的子fast 持续时间.
依赖关系
表格系统以两个主要库为基础:
- 反应- hook-form - 实行国家管理、验证和实地登记。 这个
Field组件用途useFormContext内部,所以形式必须用FormProvider。 。 。 . - 下调 - 给组合框域提供可访问的自动完成行为.
使用量
将表格包装为 Form 组件和使用 Field 用于输入:
import { Form, Field } from "@canonical/react-ds-global-form";
function ContactForm() {
const onSubmit = (data) => console.log(data);
return (
<Form onSubmit={onSubmit}>
<Field
name="email"
inputType="email"
label="Email address"
description="We'll never share your email."
/>
<Field
name="message"
inputType="textarea"
label="Message"
/>
<button type="submit">Send</button>
</Form>
);
}
窗体模式
Form 将孩子包裹在反应上 FormProvider 并使用两种模式:
-
内部模式 (以上)——通过
onSubmit,可选择defaultValues(单位:千美元) 验证mode· ;Form创建useForm以你为例 最好的一个 自成形而来. -
外部模式 - 创建
useForm以你为榜样,通过它作为methods因为你拥有它,你可以读formState(例如:.isSubmitting和 调用其方法reset, (中文(简体) ),setValue, (中文(简体) ),watch(中文(简体) ). 用于 Aync 提交 , 共享状态,或多步骤形式.import { useForm } from "react-hook-form"; const methods = useForm({ mode: "onBlur", defaultValues: { email: "" } }); const { reset, formState: { isSubmitting } } = methods; <Form methods={methods} onSubmit={async (data) => { await save(data); reset(); }}> <Field name="email" inputType="email" label="Email" /> <button type="submit" disabled={isSubmitting}>Send</button> </Form>;当你通过
methods, (中文(简体) ),Form属于自己的defaultValues编号 :mode道具被忽略了—— 配置您所显示的useForm电话.
这个图书馆是一层薄薄的 反应- hook-form
(单位:千美元)^7.71: 审定规则(registerProps, (中文(简体) ), formState字段
数组,和计数解析器都是RHF的API. 见 开始 指南
在童话书中, 完整地走过 与可运行的例子
反应- hook-form 文件 整个地表.
字段切换模式
这个 Field 组件用途 inputType 选择适当的输入组件:
| 输入类型 | 构成部分 | 说明 |
|---|---|---|
text, (中文(简体) ), email, (中文(简体) ), password, (中文(简体) ), number, (中文(简体) ), tel, (中文(简体) ), url | 文本 | 标准文本输入 |
textarea | 文本区域 | 多行文本 |
checkbox | 复选框 | 布尔切换 |
range | 范围 | 滑动器输入 |
select | 选择 | 下拉选择 |
simple-choices | 简单选择 | 无线电按钮或复选框 |
combobox | 组合框 | 可搜索的下拉 |
hidden | 隐藏 | 隐藏输入 |
custom | 您的组件 | 通过 CustomComponent 道具 |
所有字段都被包裹着 withWrapper,它提供格式注册,标签,描述,出错显示,以及中间软件支持.
自定义字段
对于内置未覆盖的字段类型,使用 inputType="custom"数字 :
import { Field } from "@canonical/react-ds-global-form";
import { MyColorPicker } from "./MyColorPicker";
<Field
name="brandColor"
inputType="custom"
CustomComponent={MyColorPicker}
label="Brand Color"
/>
自定义组件必须用 withWrapper自定义组件必须满足 InputProps 键入并整合到反应-hook-form 通过 useFormContext。 。 。 .
独立输入
字段图案构成的每个输入也单独输出: TextInput, (中文(简体) ), SelectInput, (中文(简体) ), CheckboxInput, (中文(简体) ), SwitchInput, (中文(简体) ), RadioInput, (中文(简体) ), NumberInput, (中文(简体) ), PasswordInput, (中文(简体) ), RangeInput, (中文(简体) ), RatingInput, (中文(简体) ), DateInput, (中文(简体) ), TimeInput, (中文(简体) ), DateTimeInput, (中文(简体) ), ColorInput, (中文(简体) ), ComboboxInput, (中文(简体) ), PhoneInput, (中文(简体) ), FileUploadInput, (中文(简体) ), TextareaInput 财务报告和审定财务报表 HiddenInput,每个都有它的道具类型。 介绍性:否 <Form>,没有反应-hook-form上下文和标签,所以表单以外的一个控制保持相同的输入铬. 说吧 aria-label 或一个 <label> 自己来的.
import { SelectInput } from "@canonical/react-ds-global-form";
<SelectInput
aria-label="Language"
value={locale}
onChange={(event) => setLocale(event.target.value)}
options={[
{ value: "en", label: "English", lang: "en" },
{ value: "fr", label: "français", lang: "fr" },
]}
/>
一个选项是可选的 lang 标记用另一种语言书写的标签,所以辅助技术可以正确宣告它.
中间软件模式
Middleware是包接字段来添加功能的更高级的组件. 他们通过 middleware 道具 :
<Field
name="country"
inputType="select"
label="Country"
middleware={[addRESTOptions("/api/countries")]}
/>
中间软件签名是 (Component) => Component。多个中间软件按阵列顺序组成,第一个中间软件是最外层的包装器.
内置中件
添加REST 选项 - 从 API 端点获取选项 :
import { addRESTOptions } from "@canonical/react-ds-global-form";
<Field
name="category"
inputType="select"
middleware={[
addRESTOptions("/api/categories", {
transformData: (data) => data.categories,
}),
]}
/>
添加RESTV升级 - 用 API 验证字段值:
import { addRESTValidation } from "@canonical/react-ds-global-form";
<Field
name="username"
inputType="text"
middleware={[
addRESTValidation("/api/validate-username", {
debounceWait: 300,
minLength: 3,
}),
]}
/>
自定义中件遵循相同的工厂模式:一个外函数接受配置并返回一个HOC.
有条件显示
字段可以根据其它字段值有条件地渲染:
<Field
name="company"
inputType="text"
label="Company"
condition={[
["accountType"],
([type]) => type === "business",
]}
/>
字段只使条件函数返回真实时生效 .
故事书
cd packages/react/ds-global-form
bun run storybook
Storybook配置包括MSW集成来模拟后端响应.
构成部分规格
表格组件规格定义载于 设计系统本体学。 。 。 .