Skip to content

Commit

Permalink
Refactor some components. (rsuite#1241)
Browse files Browse the repository at this point in the history
* fix(form): fix typos

* refactor(schema): refacotor schema

* docs(intl): update docs for intl

* perf: make `as` compatible with html attributes

* perf: add RsRefForwardingComponent

* perf(badge): badge uses RsRefForwardingComponent type
  • Loading branch information
simonguo authored Aug 14, 2020
1 parent 54ea165 commit 571029e
Show file tree
Hide file tree
Showing 45 changed files with 1,959 additions and 1,802 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG-V3.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@

> May 23, 2019
* **Feature**: Support `cleanErrorForFiled` method in `<Form>`. ([#470])
* **Feature**: Support `cleanErrorForField` method in `<Form>`. ([#470])
* **Feature**: Support `open` on `<Whisper>`. ([#467])
* **Bugfix**: MultiCascader: don't throw on a non-present selected value. ([#468])
* **Bugfix**: [TS] Fix type definition for DOMHelper ([#469])
Expand All @@ -100,7 +100,7 @@

---

* **Feature**: `<Form>` 组件里支持 `cleanErrorForFiled` 方法。 ([#470])
* **Feature**: `<Form>` 组件里支持 `cleanErrorForField` 方法。 ([#470])
* **Feature**: `<Whisper>` 支持 `open` 属性,默认打开 speaker 设置的组件。 ([#467])
* **Bugfix**: 修复 `<MultiCascader>` 的值在选项中不存在时候会抛出异常。 ([#468])
* **Bugfix**: [TS] 修复 `DOMHelper` 类型定义 ([#469])
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/components/form/en-US/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ Clean error message.
cleanErrors(callback: () => void) => void
```

- cleanErrorForFiled
- cleanErrorForField

Clear single field error message

```js
cleanErrorForFiled: (fieldName: keyof E, callback?: () => void) => void;
cleanErrorForField: (fieldName: keyof E, callback?: () => void) => void;
```

### `<Form.Control>`
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/components/form/zh-CN/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ checkForFieldAsync: (fieldName: keyof T) => Promise<CheckResult>;
cleanErrors(callback: () => void) => void
```

- cleanErrorForFiled 清除单个字段错误信息
- cleanErrorForField 清除单个字段错误信息

```js
cleanErrorForFiled: (fieldName: keyof E, callback?: () => void) => void;
cleanErrorForField: (fieldName: keyof E, callback?: () => void) => void;
```

### `<Form.Control>`
Expand Down
32 changes: 16 additions & 16 deletions docs/pages/guide/intl/en-US/index.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# Internationalization

The language in the React Suite component defaults to English. If you need to set another language, you can configure it with `<IntlProvider>`.
The language in the React Suite component defaults to English. If you need to set another language, you can configure it with `<CustomProvider>`.

## Usage

```jsx
import { IntlProvider } from 'rsuite';
import zhCN from 'rsuite/lib/IntlProvider/locales/zh_CN';
import CustomProvider from 'rsuite/lib/CustomProvider';
import zhCN from 'rsuite/lib/locales/zh_CN';

return (
<IntlProvider locale={zhCN}>
<CustomProvider locale={zhCN}>
<App />
</IntlProvider>
</CustomProvider>
);
```

## Format date

```jsx
import { IntlProvider } from 'rsuite';
import ruRU from 'rsuite/lib/IntlProvider/locales/ru_RU';
import CustomProvider from 'rsuite/lib/CustomProvider';
import ruRU from 'rsuite/lib/locales/ru_RU';
import format from 'date-fns/format';
import ru from 'date-fns/locale/ru';

Expand All @@ -28,9 +28,9 @@ function formatDate(data, formatStr) {
}

return (
<IntlProvider locale={ruRU} formatDate={formatDate}>
<CustomProvider locale={ruRU} formatDate={formatDate}>
<App />
</IntlProvider>
</CustomProvider>
);
```

Expand All @@ -55,20 +55,20 @@ return (

## Expand or modify language

You can refer to the configuration in the [default language](https://github.com/rsuite/rsuite/blob/master/src/IntlProvider/locales/default.ts) file to make a new language pack passed to the `<IntlProvider>` component via the locale property.
You can refer to the configuration in the [default language](https://github.com/rsuite/rsuite/blob/master/src/locales/default.ts) file to make a new language pack passed to the `<CustomProvider>` component via the locale property.

## Used with react-intl

```jsx
import { IntlProvider } from 'react-intl';
import LocaleProvider from 'rsuite/lib/IntlProvider';
import zhCN from 'rsuite/lib/IntlProvider/locales/zh_CN';
import CustomProvider from 'rsuite/lib/CustomProvider';
import zhCN from 'rsuite/lib/locales/zh_CN';

return (
<IntlProvider locale="zh">
<LocaleProvider locale={zhCN}>
<CustomProvider locale={zhCN}>
<App />
</LocaleProvider>
</CustomProvider>
</IntlProvider>
);
```
Expand All @@ -77,10 +77,10 @@ More Configuration references: [react-intl](https://github.com/yahoo/react-intl)

## Props

### `<IntlProvider>`
### `<CustomProvider>`

| Property | Type`(Default)` | Description |
| ---------- | --------------------------------------------------------------------- | ---------------------------------------------- |
| formatDate | (date: Date ,format?: string, options?: {locale?: object;}) => string | Format date |
| locale | object`(rsuite/lib/IntlProvider/locales/en_GB)` | Configure Language Pack |
| locale | object`(rsuite/lib/locales/default)` | Configure Language Pack |
| rtl | boolean | Text and other elements go from left to right. |
30 changes: 15 additions & 15 deletions docs/pages/guide/intl/zh-CN/index.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# 国际化

React Suite 组件中的语言默认为英语。 如果需要设置其他语言,可以使用 `<IntlProvider>`进行配置。
React Suite 组件中的语言默认为英语。 如果需要设置其他语言,可以使用 `<CustomProvider>`进行配置。

## 使用示例

```jsx
import { IntlProvider } from 'rsuite';
import zhCN from 'rsuite/lib/IntlProvider/locales/zh_CN';
import CustomProvider from 'rsuite/lib/CustomProvider';
import zhCN from 'rsuite/lib/locales/zh_CN';

return (
<IntlProvider locale={zhCN}>
<CustomProvider locale={zhCN}>
<App />
</IntlProvider>
</CustomProvider>
);
```

## 日期格式化

```jsx
import { IntlProvider } from 'rsuite';
import ruRU from 'rsuite/lib/IntlProvider/locales/ru_RU';
import CustomProvider from 'rsuite/lib/CustomProvider';
import ruRU from 'rsuite/lib/locales/ru_RU';
import format from 'date-fns/format';
import ru from 'date-fns/locale/ru';

Expand All @@ -28,9 +28,9 @@ function formatDate(data, formatStr) {
}

return (
<IntlProvider locale={ruRU} formatDate={formatDate}>
<CustomProvider locale={ruRU} formatDate={formatDate}>
<App />
</IntlProvider>
</CustomProvider>
);
```

Expand All @@ -55,20 +55,20 @@ return (

## 扩展或者修改语言

您可以参考 [默认语言文件](https://github.com/rsuite/rsuite/blob/master/src/IntlProvider/locales/default.ts) 中的配置,做一个新的语言包通过 `locale` 属性传递给 `<IntlProvider>` 组件。
您可以参考 [默认语言文件](https://github.com/rsuite/rsuite/blob/master/src/locales/default.ts) 中的配置,做一个新的语言包通过 `locale` 属性传递给 `<CustomProvider>` 组件。

## 与 react-intl 同时使用

```jsx
import { IntlProvider } from 'react-intl';
import LocaleProvider from 'rsuite/lib/IntlProvider';
import zhCN from 'rsuite/lib/IntlProvider/locales/zh_CN';
import CustomProvider from 'rsuite/lib/CustomProvider';
import zhCN from 'rsuite/lib/locales/zh_CN';

return (
<IntlProvider locale="zh">
<LocaleProvider locale={zhCN}>
<CustomProvider locale={zhCN}>
<App />
</LocaleProvider>
</CustomProvider>
</IntlProvider>
);
```
Expand All @@ -82,5 +82,5 @@ return (
| 属性名称 | 类型`(默认值)` | 描述 |
| ---------- | --------------------------------------------------------------------- | ---------------------------------------- |
| formatDate | (date: Date ,format?: string, options?: {locale?: object;}) => string | 格式化日期 |
| locale | object`(rsuite/lib/IntlProvider/locales/en_GB)` | 语言包配置 |
| locale | object`(rsuite/lib/locales/default)` | 语言包配置 |
| rtl | boolean | 可设置文本和其他元素的默认方向是从左到右 |
32 changes: 20 additions & 12 deletions src/@types/common.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React from 'react';
import { ReplaceProps } from './utils';

export interface StandardProps {
/** The prefix of the component CSS class */
classPrefix?: string;

/** You can use a custom element for this component */
as?: React.ElementType | string;

/** Additional classes */
className?: string;

Expand All @@ -17,6 +15,23 @@ export interface StandardProps {
style?: React.CSSProperties;
}

export interface WithAsProps<As extends React.ElementType | string = React.ElementType>
extends StandardProps {
/** You can use a custom element for this component */
as?: As;
}

export interface RsRefForwardingComponent<T extends React.ElementType, P = unknown> {
<As extends React.ElementType = T>(
props: React.PropsWithChildren<ReplaceProps<As, WithAsProps<As> & P>>,
context?: any
): React.ReactElement | null;
propTypes?: any;
contextTypes?: any;
defaultProps?: Partial<P>;
displayName?: string;
}

export interface AnimationEventProps {
/** Callback fired before the Modal transitions in */
onEnter?: (node: null | Element | Text) => void;
Expand All @@ -37,7 +52,7 @@ export interface AnimationEventProps {
onExited?: (node: null | Element | Text) => void;
}

export interface PickerBaseProps<LocaleType = any> extends StandardProps, AnimationEventProps {
export interface PickerBaseProps<LocaleType = any> extends WithAsProps, AnimationEventProps {
/** locale */
locale?: LocaleType;

Expand All @@ -57,7 +72,7 @@ export interface PickerBaseProps<LocaleType = any> extends StandardProps, Animat
disabled?: boolean;

/** You can use a custom element for this component */
toggleAs?: React.ElementType | string;
toggleAs?: React.ElementType;

/** A CSS class to apply to the Menu DOM node. */
menuClassName?: string;
Expand Down Expand Up @@ -194,10 +209,3 @@ export interface ItemDataType {
parent?: ItemDataType;
children?: ItemDataType[];
}

export interface RefForwardingComponent<P, I = HTMLDivElement>
extends React.ForwardRefExoticComponent<P> {
(
props: React.PropsWithChildren<{ children?: React.ReactNode; ref?: React.Ref<I> }>
): React.ReactElement | null;
}
8 changes: 7 additions & 1 deletion src/@types/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@ export type Pick<T, K extends keyof T> = { [P in K]: T[P] };

export type Exclude<T, U> = T extends U ? never : T;

export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
export type Omit<T, U> = Pick<T, Exclude<keyof T, keyof U>>;

export type ReplaceProps<Inner extends React.ElementType, P> = Omit<
React.ComponentPropsWithRef<Inner>,
P
> &
P;
92 changes: 46 additions & 46 deletions src/Affix/Affix.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
import PropTypes from 'prop-types';
import { getOffset } from 'dom-lib';
import { StandardProps } from '../@types/common';
import { WithAsProps, RsRefForwardingComponent } from '../@types/common';
import { useClassNames, useEventListener, useElementResize, mergeRefs } from '../utils';

export interface AffixProps
extends StandardProps,
Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
export interface AffixProps extends WithAsProps {
/** Distance from top */
top?: number;

Expand Down Expand Up @@ -94,48 +92,50 @@ function useFixed(offset: Offset, containerOffset: Offset, props: AffixProps) {
return fixed;
}

const Affix = React.forwardRef((props: AffixProps, ref: React.Ref<HTMLDivElement>) => {
const {
className,
children,
container,
classPrefix = 'affix',
as: Component = 'div',
top = 0,
onChange,
...rest
} = props;

const mountRef = useRef(null);
const offset = useOffset(mountRef);
const containerOffset = useContainerOffset(container);
const fixed = useFixed(offset, containerOffset, { top, onChange });

const { withClassPrefix, merge } = useClassNames(classPrefix);
const classes = merge(className, {
[withClassPrefix()]: fixed
});

const placeholderStyles = fixed ? { width: offset.width, height: offset.height } : undefined;
const fixedStyles: React.CSSProperties = {
position: 'fixed',
top,
left: offset?.left,
width: offset?.width,
zIndex: 10
};

const affixStyles = fixed ? fixedStyles : null;

return (
<Component {...rest} ref={mergeRefs(mountRef, ref)}>
<div className={classes} style={affixStyles}>
{children}
</div>
{fixed && <div aria-hidden="true" style={placeholderStyles}></div>}
</Component>
);
});
const Affix: RsRefForwardingComponent<'div', AffixProps> = React.forwardRef(
(props: AffixProps, ref) => {
const {
as: Component = 'div',
classPrefix = 'affix',
className,
children,
container,
top = 0,
onChange,
...rest
} = props;

const mountRef = useRef(null);
const offset = useOffset(mountRef);
const containerOffset = useContainerOffset(container);
const fixed = useFixed(offset, containerOffset, { top, onChange });

const { withClassPrefix, merge } = useClassNames(classPrefix);
const classes = merge(className, {
[withClassPrefix()]: fixed
});

const placeholderStyles = fixed ? { width: offset.width, height: offset.height } : undefined;
const fixedStyles: React.CSSProperties = {
position: 'fixed',
top,
left: offset?.left,
width: offset?.width,
zIndex: 10
};

const affixStyles = fixed ? fixedStyles : null;

return (
<Component {...rest} ref={mergeRefs(mountRef, ref)}>
<div className={classes} style={affixStyles}>
{children}
</div>
{fixed && <div aria-hidden="true" style={placeholderStyles}></div>}
</Component>
);
}
);

Affix.displayName = 'Affix';
Affix.propTypes = {
Expand Down
Loading

0 comments on commit 571029e

Please sign in to comment.