chore: merge master

This commit is contained in:
二货机器人 2022-08-01 17:12:27 +08:00
commit fa4f7f089d
14 changed files with 4009 additions and 3241 deletions

View File

@ -15,6 +15,14 @@ timeline: true
---
## 4.22.3
`2022-08-01`
- 🐞 Fixed flickering when `fileList` updating in Uploader with React 18. [#36801](https://github.com/ant-design/ant-design/pull/36801) [@zhengjitf](https://github.com/zhengjitf)
- 🐞 Fix Form.Item with small size `labelCol` and `wrapperCol` not break line in vertical layout. [#36800](https://github.com/ant-design/ant-design/pull/36800)
- 🐞 Fix Row in flex layout takes too wide space by default. [#36770](https://github.com/ant-design/ant-design/pull/36770)
## 4.22.2
`2022-07-28`

View File

@ -15,6 +15,14 @@ timeline: true
---
## 4.22.3
`2022-08-01`
- 🐞 修复在 React 18 版本中 Uploader 的 `fileList` 发生更新后出现闪烁的情况。[#36801](https://github.com/ant-design/ant-design/pull/36801) [@zhengjitf](https://github.com/zhengjitf)
- 🐞 修复 Form.Item 在垂直布局下使用小尺寸的 `labelCol``wrapperCol` 时不换行的问题。[#36800](https://github.com/ant-design/ant-design/pull/36800)
- 🐞 修复 Row 在 flex 布局中占据过多空间的问题。[#36770](https://github.com/ant-design/ant-design/pull/36770)
## 4.22.2
`2022-07-28`

View File

@ -12,59 +12,32 @@ import { tuple } from '../_util/type';
// CSSINJS
import useStyle from './style';
type EventType =
| React.KeyboardEvent<HTMLDivElement>
| React.MouseEvent<HTMLDivElement | HTMLButtonElement>;
type getContainerFunc = () => HTMLElement;
type ILevelMove = number | [number, number];
const PlacementTypes = tuple('top', 'right', 'bottom', 'left');
type placementType = typeof PlacementTypes[number];
const SizeTypes = tuple('default', 'large');
type sizeType = typeof SizeTypes[number];
export interface PushState {
distance: string | number;
}
export interface DrawerProps {
autoFocus?: boolean;
// Drawer diff props: 'open' | 'motion' | 'maskMotion' | 'wrapperClassName'
export interface DrawerProps extends RcDrawerProps {
size?: sizeType;
closable?: boolean;
closeIcon?: React.ReactNode;
destroyOnClose?: boolean;
forceRender?: boolean;
getContainer?: string | HTMLElement | getContainerFunc | false;
maskClosable?: boolean;
mask?: boolean;
maskStyle?: React.CSSProperties;
style?: React.CSSProperties;
size?: sizeType;
/** Wrapper dom node style of header and body */
drawerStyle?: React.CSSProperties;
headerStyle?: React.CSSProperties;
bodyStyle?: React.CSSProperties;
contentWrapperStyle?: React.CSSProperties;
footerStyle?: React.CSSProperties;
title?: React.ReactNode;
visible?: boolean;
width?: number | string;
height?: number | string;
zIndex?: number;
prefixCls?: string;
push?: boolean | PushState;
placement?: placementType;
onClose?: (e: EventType) => void;
afterVisibleChange?: (visible: boolean) => void;
className?: string;
handler?: React.ReactNode;
keyboard?: boolean;
extra?: React.ReactNode;
footer?: React.ReactNode;
footerStyle?: React.CSSProperties;
level?: string | string[] | null | undefined;
levelMove?: ILevelMove | ((e: { target: HTMLElement; open: boolean }) => ILevelMove);
children?: React.ReactNode;
extra?: React.ReactNode;
afterVisibleChange?: (visible: boolean) => void;
}
const defaultPushState: PushState = { distance: 180 };

File diff suppressed because it is too large Load Diff

View File

@ -115,7 +115,13 @@ const App: React.FC = () => {
<Divider />
<Form layout="vertical">{sharedItem}</Form>
<Form layout="vertical">
{sharedItem}
<Form.Item label="col12" name="col12" labelCol={{ span: 12 }} wrapperCol={{ span: 12 }}>
<Input />
</Form.Item>
</Form>
</>
);
};

View File

@ -3,6 +3,7 @@ order: 3.1
title:
zh-CN: 表单禁用
en-US: Form disabled
version: 4.21.0
---
## zh-CN
@ -41,81 +42,85 @@ const FormDisabledDemo = () => {
};
return (
<Form
labelCol={{ span: 4 }}
wrapperCol={{ span: 14 }}
layout="horizontal"
initialValues={{ disabled: componentDisabled }}
onValuesChange={onFormLayoutChange}
disabled={componentDisabled}
>
<Form.Item label="Form disabled" name="disabled" valuePropName="checked">
<Checkbox>disabled</Checkbox>
</Form.Item>
<Form.Item label="Radio">
<Radio.Group>
<Radio value="apple"> Apple </Radio>
<Radio value="pear"> Pear </Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="Input">
<Input />
</Form.Item>
<Form.Item label="Select">
<Select>
<Select.Option value="demo">Demo</Select.Option>
</Select>
</Form.Item>
<Form.Item label="TreeSelect">
<TreeSelect
treeData={[
{ title: 'Light', value: 'light', children: [{ title: 'Bamboo', value: 'bamboo' }] },
]}
/>
</Form.Item>
<Form.Item label="Cascader">
<Cascader
options={[
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
},
],
},
]}
/>
</Form.Item>
<Form.Item label="DatePicker">
<DatePicker />
</Form.Item>
<Form.Item label="RangePicker">
<RangePicker />
</Form.Item>
<Form.Item label="InputNumber">
<InputNumber />
</Form.Item>
<Form.Item label="TextArea">
<TextArea rows={4} />
</Form.Item>
<Form.Item label="Switch" valuePropName="checked">
<Switch />
</Form.Item>
<Form.Item label="Upload" valuePropName="fileList">
<Upload action="/upload.do" listType="picture-card">
<div>
<PlusOutlined />
<div style={{ marginTop: 8 }}>Upload</div>
</div>
</Upload>
</Form.Item>
<Form.Item label="Button">
<Button>Button</Button>
</Form.Item>
</Form>
<>
<Checkbox checked={componentDisabled} onChange={e => setComponentDisabled(e.target.checked)}>
Form disabled
</Checkbox>
<Form
labelCol={{ span: 4 }}
wrapperCol={{ span: 14 }}
layout="horizontal"
onValuesChange={onFormLayoutChange}
disabled={componentDisabled}
>
<Form.Item label="Chekbox" name="disabled" valuePropName="checked">
<Checkbox>Checkbox</Checkbox>
</Form.Item>
<Form.Item label="Radio">
<Radio.Group>
<Radio value="apple"> Apple </Radio>
<Radio value="pear"> Pear </Radio>
</Radio.Group>
</Form.Item>
<Form.Item label="Input">
<Input />
</Form.Item>
<Form.Item label="Select">
<Select>
<Select.Option value="demo">Demo</Select.Option>
</Select>
</Form.Item>
<Form.Item label="TreeSelect">
<TreeSelect
treeData={[
{ title: 'Light', value: 'light', children: [{ title: 'Bamboo', value: 'bamboo' }] },
]}
/>
</Form.Item>
<Form.Item label="Cascader">
<Cascader
options={[
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
},
],
},
]}
/>
</Form.Item>
<Form.Item label="DatePicker">
<DatePicker />
</Form.Item>
<Form.Item label="RangePicker">
<RangePicker />
</Form.Item>
<Form.Item label="InputNumber">
<InputNumber />
</Form.Item>
<Form.Item label="TextArea">
<TextArea rows={4} />
</Form.Item>
<Form.Item label="Switch" valuePropName="checked">
<Switch />
</Form.Item>
<Form.Item label="Upload" valuePropName="fileList">
<Upload action="/upload.do" listType="picture-card">
<div>
<PlusOutlined />
<div style={{ marginTop: 8 }}>Upload</div>
</div>
</Upload>
</Form.Item>
<Form.Item label="Button">
<Button>Button</Button>
</Form.Item>
</Form>
</>
);
};

View File

@ -20,7 +20,7 @@ High performance Form component with data scope management. Including data colle
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| colon | Configure the default value of `colon` for Form.Item. Indicates whether the colon after the label is displayed (only effective when prop layout is horizontal) | boolean | true | |
| disabled | Set form component disable, only available for antd components | boolean | false |
| disabled | Set form component disable, only available for antd components | boolean | false | 4.21.0 |
| component | Set the Form rendering element. Do not create a DOM node for `false` | ComponentType \| false | form | |
| fields | Control of form fields through state management (such as redux). Not recommended for non-strong demand. View [example](#components-form-demo-global-state) | [FieldData](#FieldData)\[] | - | |
| form | Form control instance created by `Form.useForm()`. Automatically created when not provided | [FormInstance](#FormInstance) | - | |

View File

@ -21,7 +21,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/ORmcdeaoO/Form.svg
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| colon | 配置 Form.Item 的 `colon` 的默认值。表示是否显示 label 后面的冒号 (只有在属性 layout 为 horizontal 时有效) | boolean | true | |
| disabled | 设置表单组件禁用,仅对 antd 组件有效 | boolean | false |
| disabled | 设置表单组件禁用,仅对 antd 组件有效 | boolean | false | 4.21.0 |
| component | 设置 Form 渲染元素,为 `false` 则不创建 DOM 节点 | ComponentType \| false | form | |
| fields | 通过状态管理(如 redux控制表单字段如非强需求不推荐使用。查看[示例](#components-form-demo-global-state) | [FieldData](#FieldData)\[] | - | |
| form | 经 `Form.useForm()` 创建的 form 控制实例,不提供时会自动创建 | [FormInstance](#FormInstance) | - | |

View File

@ -0,0 +1,93 @@
@import (reference) '../../style/themes/index';
@form-prefix-cls: ~'@{ant-prefix}-form';
@form-item-prefix-cls: ~'@{form-prefix-cls}-item';
// ================== Label ==================
.make-vertical-layout-label() {
& when (@form-vertical-label-margin > 0) {
margin: @form-vertical-label-margin;
}
padding: @form-vertical-label-padding;
line-height: @line-height-base;
white-space: initial;
text-align: left;
> label {
margin: 0;
&::after {
display: none;
}
}
}
.make-vertical-layout() {
.@{form-prefix-cls}-item .@{form-prefix-cls}-item-label {
.make-vertical-layout-label();
}
.@{form-prefix-cls} {
.@{form-prefix-cls}-item {
flex-wrap: wrap;
.@{form-prefix-cls}-item-label,
.@{form-prefix-cls}-item-control {
flex: 0 0 100%;
max-width: 100%;
}
}
}
}
.@{form-prefix-cls}-vertical {
.@{form-item-prefix-cls} {
&-row {
flex-direction: column;
}
&-label > label {
height: auto;
}
.@{form-prefix-cls}-item-control {
width: 100%;
}
}
}
.@{form-prefix-cls}-vertical .@{form-item-prefix-cls}-label,
/* when labelCol is 24, it is a vertical form */
.@{ant-prefix}-col-24.@{form-item-prefix-cls}-label,
.@{ant-prefix}-col-xl-24.@{form-item-prefix-cls}-label {
.make-vertical-layout-label();
}
@media (max-width: @screen-xs-max) {
.make-vertical-layout();
.@{ant-prefix}-col-xs-24.@{form-item-prefix-cls}-label {
.make-vertical-layout-label();
}
}
@media (max-width: @screen-sm-max) {
.@{ant-prefix}-col-sm-24.@{form-item-prefix-cls}-label {
.make-vertical-layout-label();
}
}
@media (max-width: @screen-md-max) {
.@{ant-prefix}-col-md-24.@{form-item-prefix-cls}-label {
.make-vertical-layout-label();
}
}
@media (max-width: @screen-lg-max) {
.@{ant-prefix}-col-lg-24.@{form-item-prefix-cls}-label {
.make-vertical-layout-label();
}
}
@media (max-width: @screen-xl-max) {
.@{ant-prefix}-col-xl-24.@{form-item-prefix-cls}-label {
.make-vertical-layout-label();
}
}

View File

@ -0,0 +1,565 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@upload-prefix-cls: ~'@{ant-prefix}-upload';
@upload-item: ~'@{ant-prefix}-upload-list-item';
@upload-picture-card-size: 104px;
@upload-picture-card-border-style: @border-style-base;
.@{upload-prefix-cls} {
.reset-component();
outline: 0;
p {
margin: 0;
}
&-btn {
display: block;
width: 100%;
outline: none;
}
input[type='file'] {
cursor: pointer;
}
&&-select {
display: inline-block;
}
&&-disabled {
color: @disabled-color;
cursor: not-allowed;
}
&&-select-picture-card {
width: @upload-picture-card-size;
height: @upload-picture-card-size;
margin-right: 8px;
margin-bottom: 8px;
text-align: center;
vertical-align: top;
background-color: @background-color-light;
border: @border-width-base dashed @border-color-base;
border-radius: @border-radius-base;
cursor: pointer;
transition: border-color 0.3s;
> .@{upload-prefix-cls} {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
text-align: center;
}
&:hover {
border-color: @primary-color;
.@{upload-prefix-cls}-disabled& {
border-color: @border-color-base;
}
}
}
&&-drag {
position: relative;
width: 100%;
height: 100%;
text-align: center;
background: @background-color-light;
border: @border-width-base dashed @border-color-base;
border-radius: @border-radius-base;
cursor: pointer;
transition: border-color 0.3s;
.@{upload-prefix-cls} {
padding: @padding-md 0;
}
&.@{upload-prefix-cls}-drag-hover:not(.@{upload-prefix-cls}-disabled) {
border-color: @primary-7;
}
&.@{upload-prefix-cls}-disabled {
cursor: not-allowed;
}
.@{upload-prefix-cls}-btn {
display: table;
height: 100%;
}
.@{upload-prefix-cls}-drag-container {
display: table-cell;
vertical-align: middle;
}
&:not(.@{upload-prefix-cls}-disabled):hover {
border-color: @primary-5;
}
p.@{upload-prefix-cls}-drag-icon {
.@{iconfont-css-prefix} {
color: @primary-5;
font-size: 48px;
}
margin-bottom: 20px;
}
p.@{upload-prefix-cls}-text {
margin: 0 0 4px;
color: @heading-color;
font-size: @font-size-lg;
}
p.@{upload-prefix-cls}-hint {
color: @text-color-secondary;
font-size: @font-size-base;
}
.@{iconfont-css-prefix}-plus {
color: @disabled-color;
font-size: 30px;
transition: all 0.3s;
&:hover {
color: @text-color-secondary;
}
}
&:hover .@{iconfont-css-prefix}-plus {
color: @text-color-secondary;
}
}
&-picture-card-wrapper {
.clearfix();
display: inline-block;
width: 100%;
}
}
.@{upload-prefix-cls}-list {
.reset-component();
.clearfix();
line-height: @line-height-base;
// ============================ Item ============================
&-item {
position: relative;
height: @line-height-base * @font-size-base;
margin-top: @margin-xs;
font-size: @font-size-base;
&-name {
display: inline-block;
width: 100%;
padding-left: @font-size-base + 8px;
overflow: hidden;
line-height: @line-height-base;
white-space: nowrap;
text-overflow: ellipsis;
}
&-card-actions {
position: absolute;
right: 0;
&-btn {
opacity: 0;
}
&-btn.@{ant-prefix}-btn-sm {
height: @line-height-base * @font-size-base;
line-height: 1;
vertical-align: top;
}
&.picture {
top: 22px;
line-height: 0;
}
&-btn:focus,
&.picture &-btn {
opacity: 1;
}
.@{iconfont-css-prefix} {
color: @upload-actions-color;
transition: all 0.3s;
}
&:hover .@{iconfont-css-prefix} {
color: @text-color;
}
}
&-info {
height: 100%;
transition: background-color 0.3s;
> span {
display: block;
width: 100%;
height: 100%;
}
.@{iconfont-css-prefix}-loading,
.@{upload-prefix-cls}-text-icon {
.@{iconfont-css-prefix} {
position: absolute;
top: (@font-size-base / 2) - 2px;
color: @text-color-secondary;
font-size: @font-size-base;
}
}
}
&:hover &-info {
background-color: @item-hover-bg;
}
&:hover &-card-actions-btn {
opacity: 1;
}
&-error,
&-error .@{upload-prefix-cls}-text-icon > .@{iconfont-css-prefix},
&-error &-name {
color: @error-color;
}
&-error &-card-actions {
.@{iconfont-css-prefix} {
color: @error-color;
}
&-btn {
opacity: 1;
}
}
&-progress {
position: absolute;
bottom: -12px;
width: 100%;
padding-left: @font-size-base + 12px;
font-size: @font-size-base;
line-height: 0;
}
}
// =================== Picture & Picture Card ===================
&-picture,
&-picture-card {
.@{upload-item} {
position: relative;
height: 66px;
padding: @padding-xs;
border: @border-width-base @upload-picture-card-border-style @border-color-base;
border-radius: @border-radius-base;
&:hover {
background: transparent;
}
&-error {
border-color: @error-color;
}
}
.@{upload-item}-info {
padding: 0;
}
.@{upload-item}:hover .@{upload-item}-info {
background: transparent;
}
.@{upload-item}-uploading {
border-style: dashed;
}
.@{upload-item}-thumbnail {
width: 48px;
height: 48px;
line-height: 60px;
text-align: center;
opacity: 0.8;
.@{iconfont-css-prefix} {
font-size: 26px;
}
}
// Adjust the color of the error icon : https://github.com/ant-design/ant-design/pull/24160
.@{upload-item}-error .@{upload-item}-thumbnail {
.@{iconfont-css-prefix} {
svg path {
&[fill='#e6f7ff'] {
fill: @error-color-deprecated-bg;
}
&[fill='#1890ff'] {
fill: @error-color;
}
}
}
}
.@{upload-item}-icon {
position: absolute;
top: 50%;
left: 50%;
font-size: 26px;
transform: translate(-50%, -50%);
.@{iconfont-css-prefix} {
font-size: 26px;
}
}
.@{upload-item}-image {
max-width: 100%;
}
.@{upload-item}-thumbnail img {
display: block;
width: 48px;
height: 48px;
overflow: hidden;
}
.@{upload-item}-name {
display: inline-block;
box-sizing: border-box;
max-width: 100%;
margin: 0 0 0 8px;
padding-right: 8px;
padding-left: 48px;
overflow: hidden;
line-height: 44px;
white-space: nowrap;
text-overflow: ellipsis;
transition: all 0.3s;
}
.@{upload-item}-uploading .@{upload-item}-name {
margin-bottom: 12px;
}
.@{upload-item}-progress {
bottom: 14px;
width: ~'calc(100% - 24px)';
margin-top: 0;
padding-left: 56px;
}
}
// ======================== Picture Card ========================
&-picture-card {
&-container {
display: inline-block;
width: @upload-picture-card-size;
height: @upload-picture-card-size;
margin: 0 @margin-xs @margin-xs 0;
vertical-align: top;
}
.@{upload-item} {
height: 100%;
margin: 0;
}
.@{upload-item}-info {
position: relative;
height: 100%;
overflow: hidden;
&::before {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
background-color: fade(@black, 50%);
opacity: 0;
transition: all 0.3s;
content: ' ';
}
}
.@{upload-item}:hover .@{upload-item}-info::before {
opacity: 1;
}
.@{upload-item}-actions {
position: absolute;
top: 50%;
left: 50%;
z-index: 10;
white-space: nowrap;
transform: translate(-50%, -50%);
opacity: 0;
transition: all 0.3s;
.@{iconfont-css-prefix}-eye,
.@{iconfont-css-prefix}-download,
.@{iconfont-css-prefix}-delete {
z-index: 10;
width: 16px;
margin: 0 4px;
color: @text-color-dark;
font-size: 16px;
cursor: pointer;
transition: all 0.3s;
&:hover {
color: @text-color-inverse;
}
}
}
.@{upload-item}-info:hover + .@{upload-item}-actions,
.@{upload-item}-actions:hover {
opacity: 1;
}
.@{upload-item}-thumbnail,
.@{upload-item}-thumbnail img {
position: static;
display: block;
width: 100%;
height: 100%;
object-fit: contain;
}
.@{upload-item}-name {
display: none;
margin: 8px 0 0;
padding: 0;
line-height: @line-height-base;
text-align: center;
}
.@{upload-item}-file + .@{upload-item}-name {
position: absolute;
bottom: 10px;
display: block;
}
.@{upload-item}-uploading {
&.@{upload-item} {
background-color: @background-color-light;
}
.@{upload-item}-info {
height: auto;
&::before,
.@{iconfont-css-prefix}-eye,
.@{iconfont-css-prefix}-delete {
display: none;
}
}
}
.@{upload-item}-progress {
bottom: 32px;
width: calc(100% - 14px);
padding-left: 0;
}
}
// ======================= Picture & Text =======================
&-text,
&-picture {
&-container {
transition: opacity @animation-duration-slow, height @animation-duration-slow;
&::before {
display: table;
width: 0;
height: 0;
content: '';
}
// Don't know why span here, just stretch it
.@{upload-prefix-cls}-span {
display: block;
flex: auto;
}
}
// text & picture no need this additional element.
// But it used for picture-card, let's keep it.
.@{upload-prefix-cls}-span {
display: flex;
align-items: center;
> * {
flex: none;
}
}
.@{upload-item}-name {
flex: auto;
margin: 0;
padding: 0 @padding-xs;
}
.@{upload-item}-card-actions {
position: static;
}
}
// ============================ Text ============================
&-text {
.@{upload-prefix-cls}-text-icon {
.@{iconfont-css-prefix} {
position: static;
}
}
}
// =========================== Motion ===========================
.@{upload-prefix-cls}-animate-inline-appear,
.@{upload-prefix-cls}-animate-inline-enter,
.@{upload-prefix-cls}-animate-inline-leave {
animation-duration: @animation-duration-slow;
animation-timing-function: @ease-in-out-circ;
animation-fill-mode: forwards;
}
.@{upload-prefix-cls}-animate-inline-appear,
.@{upload-prefix-cls}-animate-inline-enter {
animation-name: uploadAnimateInlineIn;
}
.@{upload-prefix-cls}-animate-inline-leave {
animation-name: uploadAnimateInlineOut;
}
}
@keyframes uploadAnimateInlineIn {
from {
width: 0;
height: 0;
margin: 0;
padding: 0;
opacity: 0;
}
}
@keyframes uploadAnimateInlineOut {
to {
width: 0;
height: 0;
margin: 0;
padding: 0;
opacity: 0;
}
}
@import './rtl';

View File

@ -23,7 +23,6 @@ For example:
import type { Moment } from 'moment';
import momentGenerateConfig from 'rc-picker/lib/generate/moment';
import generatePicker from 'antd/es/date-picker/generatePicker';
import 'antd/es/date-picker/style/index';
const DatePicker = generatePicker<Moment>(momentGenerateConfig);
@ -63,7 +62,6 @@ For example:
import type { Moment } from 'moment';
import momentGenerateConfig from 'rc-picker/lib/generate/moment';
import generateCalendar from 'antd/es/calendar/generateCalendar';
import 'antd/es/calendar/style';
const Calendar = generateCalendar<Moment>(momentGenerateConfig);

View File

@ -21,7 +21,6 @@ Ant Design 默认使用 [Day.js](https://day.js.org) 来处理时间日期问题
import { Moment } from 'moment';
import momentGenerateConfig from 'rc-picker/es/generate/moment';
import generatePicker from 'antd/es/date-picker/generatePicker';
import 'antd/es/date-picker/style/index';
const DatePicker = generatePicker<Moment>(momentGenerateConfig);
@ -61,7 +60,6 @@ export default TimePicker;
import { Moment } from 'moment';
import momentGenerateConfig from 'rc-picker/es/generate/moment';
import generateCalendar from 'antd/es/calendar/generateCalendar';
import 'antd/es/calendar/style';
const Calendar = generateCalendar<Moment>(momentGenerateConfig);

View File

@ -162,7 +162,7 @@
"@ant-design/tools": "^15.0.4",
"@docsearch/css": "^3.0.0",
"@qixian.cs/github-contributors-list": "^1.0.3",
"@size-limit/file": "^7.0.8",
"@size-limit/file": "^8.0.0",
"@stackblitz/sdk": "^1.3.0",
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.0.0",
@ -284,7 +284,7 @@
"scrollama": "^3.0.0",
"semver": "^7.3.5",
"simple-git": "^3.0.0",
"size-limit": "^7.0.8",
"size-limit": "^8.0.0",
"stylelint": "^14.9.0",
"stylelint-config-prettier": "^9.0.2",
"stylelint-config-rational-order": "^0.1.2",