Skip to content

Commit 7e4cb5d

Browse files
committed
feat(react-login-page): add Textarea/Select components.
1 parent fabc9e3 commit 7e4cb5d

File tree

7 files changed

+143
-15
lines changed

7 files changed

+143
-15
lines changed

core/README.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ const Demo = () => {
8282
<div>
8383
<header>{blocks.logo} {blocks.title}</header>
8484
{fields.sort((a, b) => a.index - b.index).map((item, idx) => {
85-
return <label key={item.name + idx}>{item.children}</label>
85+
return (
86+
<div key={item.name + idx}>
87+
<label>{item.children}{item.children?.props?.extra}</label>
88+
</div>
89+
);
8690
})}
8791
<div>
8892
{buttons.sort((a, b) => a.index - b.index).map((item, idx) => {
@@ -98,6 +102,15 @@ const Demo = () => {
98102
</Render>
99103
<Login.Block name="logo" tagName="span">⚛️</Login.Block>
100104
<Login.Block name="title" tagName="span">Login</Login.Block>
105+
<Login.Textarea name="note"></Login.Textarea>
106+
<Login.Select name="select">
107+
<option value="w" selected="">Choose an item...</option>
108+
<option value="1">One</option>
109+
<option value="2">Two</option>
110+
<option value="3">Three</option>
111+
<option value="4">Four</option>
112+
</Login.Select>
113+
<Login.Input name="checkbox" type="checkbox" index={3} extra={<span> Remember me </span>} />
101114
<Login.Input name="username" index={1} placeholder="Please input Username" />
102115
<Login.Input name="password" index={0} placeholder="please enter password" />
103116
<Login.Button name="submit" index={1} type="submit">Submit</Login.Button>
@@ -158,6 +171,59 @@ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement>
158171
export declare const Input: FC<PropsWithChildren<InputProps>>;
159172
```
160173
174+
### `Login.Textarea`
175+
176+
```jsx
177+
import Login, { Textarea } from 'react-login-page';
178+
179+
<Login.Textarea name="note" />
180+
<Textarea name="note" />
181+
```
182+
183+
```ts
184+
import React, { FC, PropsWithChildren } from 'react';
185+
export interface TextareaProps extends React.InputHTMLAttributes<HTMLTextAreaElement> {
186+
name?: string;
187+
/** Used to define the name of form controls */
188+
rename?: string;
189+
/** Can be shown or hidden with controls */
190+
visible?: boolean;
191+
/** "index" refers to the use of indexes to control the order of controls, which can provide more flexible API encapsulation. */
192+
index?: number;
193+
}
194+
export declare const Textarea: FC<PropsWithChildren<TextareaProps>>;
195+
```
196+
197+
### `Login.Select`
198+
199+
```jsx
200+
import Login, { Select } from 'react-login-page';
201+
202+
<Login.Select name="selectname">
203+
<option value="1">One</option>
204+
<option value="2">Two</option>
205+
</Login.Select>
206+
207+
<Select name="selectname">
208+
<option value="1">One</option>
209+
<option value="2">Two</option>
210+
</Select>
211+
```
212+
213+
```ts
214+
import React, { FC, PropsWithChildren } from 'react';
215+
export interface SelectProps extends React.InputHTMLAttributes<HTMLSelectElement> {
216+
name?: string;
217+
/** Used to define the name of form controls */
218+
rename?: string;
219+
/** Can be shown or hidden with controls */
220+
visible?: boolean;
221+
/** "index" refers to the use of indexes to control the order of controls, which can provide more flexible API encapsulation. */
222+
index?: number;
223+
}
224+
export declare const Select: FC<PropsWithChildren<SelectProps>>;
225+
```
226+
161227
### `Login.Button`
162228
163229
```jsx

core/src/Block.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { PropsWithChildren, useRef, useEffect, createElement } from 'react';
2-
import { useStore, BlockTagType } from './store';
2+
import { useStore, BlockTagType, Blocks } from './store';
3+
import { FunctionComponent } from 'react';
34

45
// export type BlockTagType = React.ComponentType | keyof JSX.IntrinsicElements;
56

@@ -20,12 +21,9 @@ export const Block = <Tag extends BlockTagType = 'div'>(props: PropsWithChildren
2021
const { name, visible = true, tagName = 'div', ...elmProps } = props;
2122
if (ref.current !== elmProps && name) {
2223
ref.current = { ...elmProps };
23-
24-
const div = (visible ? createElement(tagName, { ...elmProps }, elmProps.children) : null);
24+
const div = (visible ? createElement(tagName, { ...elmProps }, elmProps.children) : null)
2525
dispatch({
26-
// blocks: { ...blocks, [name]: div as unknown as React.ReactElement<Tag> },
27-
// @ts-ignore
28-
blocks: { ...blocks, [name]: div },
26+
blocks: { ...blocks, [name]: div as unknown as Blocks<'div'> },
2927
});
3028
}
3129
}, [props, ref]);

core/src/Input.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ export const Input: FC<PropsWithChildren<InputProps>> = (props) => {
1818
useEffect(() => {
1919
if (ref.current !== props && name) {
2020
ref.current = { ...props };
21-
const oldProps = fields[name]?.props;
22-
if (rename) {
23-
console.log('oldProps:', oldProps, name, rename, fields[name])
24-
}
2521
dispatch({
2622
fields: { ...fields, [name]: visible ? <input {...elmProps} name={rename || name} /> : null },
2723
});

core/src/Select.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React, { FC, PropsWithChildren, useRef, useEffect } from 'react';
2+
import { useStore } from './store';
3+
4+
export interface SelectProps extends React.InputHTMLAttributes<HTMLSelectElement> {
5+
name?: string;
6+
/** Used to define the name of form controls */
7+
rename?: string;
8+
/** Can be shown or hidden with controls */
9+
visible?: boolean;
10+
/** "index" refers to the use of indexes to control the order of controls, which can provide more flexible API encapsulation. */
11+
index?: number;
12+
}
13+
14+
export const Select: FC<PropsWithChildren<SelectProps>> = (props) => {
15+
const ref = useRef<SelectProps>();
16+
const { fields = {}, dispatch } = useStore();
17+
const { name, rename, visible = true, ...elmProps } = props;
18+
useEffect(() => {
19+
if (ref.current !== props && name) {
20+
ref.current = { ...props };
21+
dispatch({
22+
fields: { ...fields, [name]: visible ? <select {...elmProps} name={rename || name} /> : null },
23+
});
24+
}
25+
}, [props, name, ref]);
26+
27+
return null;
28+
};
29+
30+
Select.displayName = 'Login.Select';

core/src/Textarea.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React, { FC, PropsWithChildren, useRef, useEffect } from 'react';
2+
import { useStore } from './store';
3+
4+
export interface TextareaProps extends React.InputHTMLAttributes<HTMLTextAreaElement> {
5+
name?: string;
6+
/** Used to define the name of form controls */
7+
rename?: string;
8+
/** Can be shown or hidden with controls */
9+
visible?: boolean;
10+
/** "index" refers to the use of indexes to control the order of controls, which can provide more flexible API encapsulation. */
11+
index?: number;
12+
}
13+
14+
export const Textarea: FC<PropsWithChildren<TextareaProps>> = (props) => {
15+
const ref = useRef<TextareaProps>();
16+
const { fields = {}, dispatch } = useStore();
17+
const { name, rename, visible = true, ...elmProps } = props;
18+
useEffect(() => {
19+
if (ref.current !== props && name) {
20+
ref.current = { ...props };
21+
dispatch({
22+
fields: { ...fields, [name]: visible ? <textarea {...elmProps} name={rename || name} /> : null },
23+
});
24+
}
25+
}, [props, name, ref]);
26+
27+
return null;
28+
};
29+
30+
Textarea.displayName = 'Login.Textarea';

core/src/index.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ import React from 'react';
22
import { Provider } from './store';
33
import { Container, ContainerRef } from './Container';
44
import { Block } from './Block';
5+
import { Textarea } from './Textarea';
6+
import { Select } from './Select';
57
import { Input } from './Input';
68
import { Button } from './Button';
79

8-
export * from './Block';
910
export * from './Input';
11+
export * from './Textarea';
12+
export * from './Select';
13+
export * from './Block';
1014
export * from './Button';
1115
export * from './Container';
1216
export * from './Render';
@@ -26,13 +30,17 @@ type LoginComponent = React.FC<React.PropsWithRef<LoginProps>> & {
2630
Block: typeof Block;
2731
Button: typeof Button;
2832
Input: typeof Input;
33+
Textarea: typeof Textarea;
34+
Select: typeof Select;
2935
};
3036

3137
const Login: LoginComponent = React.forwardRef<ContainerRef>(InternalLogin) as unknown as LoginComponent;
3238

3339
Login.Block = Block;
3440
Login.Button = Button;
3541
Login.Input = Input;
42+
Login.Textarea = Textarea;
43+
Login.Select = Select;
3644
Login.displayName = 'Login';
3745

3846
export default Login;

core/src/store.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ export interface StoreContextValue<Tag extends BlockTagType> extends InitialStat
66

77
export type BlockTagType = keyof JSX.IntrinsicElements;
88

9-
type Fields = React.ReactElement<HTMLInputElement & { index?: number; }>;
10-
type Buttons = React.ReactElement<HTMLButtonElement & { index?: number; }>;
11-
type Blocks<Tag extends BlockTagType = 'div'> = React.ReactElement<Tag & { index?: number; }>;
9+
export type Fields = React.ReactElement<HTMLInputElement & { index?: number; }>;
10+
export type Buttons = React.ReactElement<HTMLButtonElement & { index?: number; }>;
11+
export type Blocks<Tag extends BlockTagType = 'div'> = React.ReactElement<Tag & { index?: number; }>;
1212

1313
export interface RenderStateProps<Tag extends BlockTagType = 'div'> {
1414
fields?: Record<string, Fields | null>;

0 commit comments

Comments
 (0)