-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
310 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import React, { MutableRefObject, useState } from 'react'; | ||
|
||
type RefOrDomOrId<T> = HTMLElement | string | React.Ref<T>; | ||
|
||
type F = any; | ||
|
||
const getDom = (refOrDomOrId: RefOrDomOrId<F>) => | ||
typeof refOrDomOrId === 'string' | ||
? document.querySelector(`#${refOrDomOrId}`) | ||
: (refOrDomOrId as MutableRefObject<F>)?.current || refOrDomOrId; | ||
|
||
// https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input#input_%E7%B1%BB%E5%9E%8B | ||
const disabled = ':not([disabled]):not([readonly])'; | ||
const queryInputTypes = | ||
['text', 'password', 'search', 'tel', 'url', 'number', 'email', ''] | ||
.map(item => `input[type="${item}"]${disabled}`) | ||
.join(', ') + `, input:not([type])${disabled}, textarea${disabled}`; | ||
const setAutoFocus = (refOrDomOrId: RefOrDomOrId<F>) => { | ||
const dom = getDom(refOrDomOrId); | ||
if (!dom) return; | ||
const input = dom.querySelector?.(queryInputTypes); | ||
if (!input?.focus) return; | ||
input.focus(); | ||
return true; | ||
}; | ||
|
||
/** | ||
* Passing a ref, id, or DOM element to obtain and set the focus state of the first non-disabled and non-readonly input or textarea. | ||
* @param {RefOrDomOrId} refOrDomOrId - 支持类型 HTMLElement | string | React.Ref<T> | ||
* @returns void | ||
*/ | ||
export const useAutoFocus = (refOrDomOrId?: RefOrDomOrId<F>) => { | ||
const [focused, setFocused] = useState<boolean>(false); | ||
React.useEffect(() => { | ||
if (focused || !refOrDomOrId) return; | ||
const setRes = setAutoFocus(refOrDomOrId); | ||
if (!setRes) return; | ||
setFocused(true); | ||
}, [refOrDomOrId, focused, setFocused]); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { useAutoFocus } from '@yuntijs/ui'; | ||
import React, { useEffect, useState } from 'react'; | ||
|
||
import FormContent from './components/FormContent'; | ||
import RenderContainer from './components/RenderContainer'; | ||
|
||
type IDomUseAutoFocus = Record<string, never>; | ||
|
||
const FormContentWrapper = () => { | ||
const [fomDom, setFormDom] = useState<HTMLElement | null>(null); | ||
useEffect(() => { | ||
// <Form id="form123"> in FormContent | ||
setFormDom(document.querySelector('#form123') as HTMLElement); | ||
}, []); | ||
useAutoFocus(fomDom); | ||
return <FormContent />; | ||
}; | ||
|
||
const DomUseAutoFocus: React.FC<IDomUseAutoFocus> = () => { | ||
return ( | ||
<RenderContainer> | ||
<FormContentWrapper /> | ||
</RenderContainer> | ||
); | ||
}; | ||
export default DomUseAutoFocus; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { FormHelper } from '@yuntijs/ui'; | ||
import { Button, Form, Input } from 'antd'; | ||
import React, { useState } from 'react'; | ||
|
||
const Test = () => { | ||
const [open, setOpen] = useState(false); | ||
return ( | ||
<> | ||
<Button onClick={setOpen.bind('', !open)}>Click me!</Button> | ||
{open && ( | ||
<FormHelper> | ||
<Form> | ||
<Form.Item> | ||
<Input /> | ||
</Form.Item> | ||
</Form> | ||
</FormHelper> | ||
)} | ||
</> | ||
); | ||
}; | ||
export default Test; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { withFormHelper } from '@yuntijs/ui'; | ||
import React from 'react'; | ||
|
||
import FormContent from './components/FormContent'; | ||
import RenderContainer from './components/RenderContainer'; | ||
|
||
const HocFormHelper: React.FC<Record<string, never>> = () => { | ||
const FormContentWrapper = withFormHelper()(FormContent); | ||
return ( | ||
<RenderContainer> | ||
<FormContentWrapper /> | ||
</RenderContainer> | ||
); | ||
}; | ||
export default HocFormHelper; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { useAutoFocus } from '@yuntijs/ui'; | ||
import React from 'react'; | ||
|
||
import FormContent from './components/FormContent'; | ||
import RenderContainer from './components/RenderContainer'; | ||
|
||
const FormContentWrapper = () => { | ||
// <Form id="form123"> in FormContent | ||
useAutoFocus('form123'); | ||
return <FormContent />; | ||
}; | ||
|
||
const IdUseAutoFocus: React.FC<Record<string, never>> = () => { | ||
return ( | ||
<RenderContainer> | ||
<FormContentWrapper /> | ||
</RenderContainer> | ||
); | ||
}; | ||
export default IdUseAutoFocus; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { useAutoFocus } from '@yuntijs/ui'; | ||
import React, { useRef } from 'react'; | ||
|
||
import FormContent from './components/FormContent'; | ||
import RenderContainer from './components/RenderContainer'; | ||
|
||
interface IRefUseAutoFocus {} | ||
|
||
const FormContentWrapper = () => { | ||
const divRef = useRef(null); | ||
useAutoFocus(divRef); | ||
// ⚠️注意 The form instance obtained through the ref of the Ant Design's Form component does not take effect. You need to pass the ref of native HTML tags like div or span. | ||
return ( | ||
<div ref={divRef}> | ||
<FormContent /> | ||
</div> | ||
); | ||
}; | ||
|
||
const RefUseAutoFocus: React.FC<IRefUseAutoFocus> = props => { | ||
Check warning on line 20 in src/FormHelper/demos/RefUseAutoFocus.tsx GitHub Actions / test
|
||
return ( | ||
<RenderContainer> | ||
<FormContentWrapper /> | ||
</RenderContainer> | ||
); | ||
}; | ||
export default RefUseAutoFocus; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Form, Input, InputNumber, Radio, Select, Switch } from 'antd'; | ||
import React from 'react'; | ||
|
||
interface IFormContent {} | ||
|
||
const FormContent: React.FC<IFormContent> = props => { | ||
Check warning on line 6 in src/FormHelper/demos/components/FormContent.tsx GitHub Actions / test
|
||
return ( | ||
<Form id="form123" initialValues={{ select: '' }}> | ||
<div> | ||
<input id="originRadio" type="radio" value="111" /> | ||
<label htmlFor="originRadio">HTML native radio</label> | ||
</div> | ||
<Form.Item label="select" name={'select'}> | ||
<Select disabled placeholder="hello select" showSearch> | ||
<Select.Option>123</Select.Option> | ||
</Select> | ||
</Form.Item> | ||
<Form.Item label="switch" name="inputNumber"> | ||
<InputNumber /> | ||
</Form.Item> | ||
<Form.Item label="Radio"> | ||
<Radio>123</Radio> | ||
</Form.Item> | ||
<Form.Item label="switch" name="enabled"> | ||
<Switch /> | ||
</Form.Item> | ||
<Form.Item label="password"> | ||
<Input.Password placeholder="hello" /> | ||
</Form.Item> | ||
<Form.Item label="username"> | ||
<Input placeholder="hello" /> | ||
</Form.Item> | ||
</Form> | ||
); | ||
}; | ||
export default FormContent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Button } from 'antd'; | ||
import React, { useState } from 'react'; | ||
|
||
interface IRenderContainer { | ||
children: React.ReactNode; | ||
} | ||
|
||
const RenderContainer: React.FC<IRenderContainer> = props => { | ||
const [open, setOpen] = useState(false); | ||
return ( | ||
<> | ||
<Button onClick={setOpen.bind('', !open)}>Click me!</Button> | ||
<br /> | ||
<br /> | ||
{open && props.children} | ||
</> | ||
); | ||
}; | ||
export default RenderContainer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
--- | ||
nav: Components | ||
group: Utils | ||
title: FormHelper | ||
description: Enhanced component for Form | ||
--- | ||
|
||
# FormHelper | ||
|
||
Form enhancement component, currently supporting: | ||
|
||
- autoFocus: automatically selecting the first non-disabled and non-readonly input or textarea of the form when focused. | ||
|
||
## Usage | ||
|
||
### React component FormHelper | ||
|
||
Wrap the Form component with FormHelper. Supported attributes include: | ||
|
||
| props | description | default | required | | ||
| --------- | -------------------------------------------------------------------------------------------------------------- | ------- | -------- | | ||
| autoFocus | Automatically select the focus state of the first non-disabled and non-readonly input or textarea in the form. | true | false | | ||
| id | The id of the outer wrapping div. | - | false | | ||
| className | The className of the outer wrapping div. | - | false | | ||
| style | The style of the outer wrapping div. | - | false | | ||
|
||
#### usage | ||
|
||
<code src="./demos/FormHelperDemo"></code> | ||
|
||
### withFormHelper - Higher-Order Component (HOC) | ||
|
||
As a higher-order component, withFormHelper supports the same parameters as the React component FormHelper. | ||
|
||
#### usage | ||
|
||
<code src="./demos/HocFormHelper"></code> | ||
|
||
### useAutoFocus - hooks | ||
|
||
Supports passing a ref, id, or DOM element as a parameter. | ||
|
||
#### Example of a ref parameter: | ||
|
||
<code src="./demos/RefUseAutoFocus"></code> | ||
|
||
#### Example of a id parameter: | ||
|
||
<code src="./demos/IdUseAutoFocus"></code> | ||
|
||
#### Example of a dom parameter: | ||
|
||
<code src="./demos/DomUseAutoFocus"></code> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import React, { ComponentType, FC, useRef } from 'react'; | ||
|
||
import { useAutoFocus } from './autoFocus'; | ||
|
||
export { useAutoFocus } from './autoFocus'; | ||
// Component | ||
export type FormHelperProps = { | ||
children: React.ReactNode; | ||
autoFocus?: boolean; | ||
id?: string; | ||
className?: string; | ||
style?: React.CSSProperties; | ||
}; | ||
|
||
const FormHelper: React.FC<FormHelperProps> = props => { | ||
const { autoFocus = true } = props; | ||
|
||
const ref = useRef(null); | ||
useAutoFocus(autoFocus ? ref : undefined); | ||
return ( | ||
<div | ||
className={props.className} | ||
id={props.id} | ||
ref={ref} | ||
style={props.style ?? { display: props.className ? undefined : 'contents' }} | ||
> | ||
{props.children} | ||
</div> | ||
); | ||
}; | ||
|
||
// HOC | ||
type FormHelperConfig = Omit<FormHelperProps, 'children'>; | ||
|
||
export const withFormHelper = | ||
(formHelperConfig?: FormHelperConfig) => | ||
<P extends Record<string, never>>(WrappedComponent: ComponentType<P>): FC<P> => { | ||
const HocComponent: FC<P> = props => { | ||
return ( | ||
<FormHelper {...(formHelperConfig || {})}> | ||
<WrappedComponent {...props} /> | ||
</FormHelper> | ||
); | ||
}; | ||
const displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component'; | ||
HocComponent.displayName = `withFormHelper(${displayName})`; | ||
return HocComponent; | ||
}; | ||
|
||
export { FormHelper }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters