Skip to content

Commit e4b8643

Browse files
committed
doc: update create-login-page document.
1 parent f97ad43 commit e4b8643

File tree

4 files changed

+282
-1
lines changed

4 files changed

+282
-1
lines changed

core/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ import Login, { Render } from 'react-login-page';
233233

234234
const Demo = () => {
235235
const [name, setName] = React.useState(1);
236-
console.log('name:', name);
237236
return (
238237
<Login>
239238
<Render>{({ blocks, fields, $$index, extra }, data) => <label>{blocks.title}</label>}</Render>

core/docs/create-login-page.md

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
# Create Login Page
2+
3+
Welcome to the tutorial! We will build a compact yet feature-rich login page component, teaching you how to quickly create a login page component.
4+
5+
## Step 1: Create the Login Page Container
6+
7+
```tsx
8+
import { FC, PropsWithChildren } from 'react';
9+
import { Render, Provider, Container } from 'react-login-page';
10+
11+
const RenderLogin = () => {
12+
return (
13+
<Render>
14+
<div className="login-page-example-wrapper"> </div>
15+
</Render>
16+
);
17+
};
18+
19+
const LoginPage: FC<PropsWithChildren<React.HTMLAttributes<HTMLDivElement>>> = ({
20+
children,
21+
className,
22+
...divProps
23+
}) => {
24+
return (
25+
<Provider>
26+
<Container {...divProps} className={`login-page-example ${className || ''}`}>
27+
<RenderLogin />
28+
{children}
29+
</Container>
30+
</Provider>
31+
);
32+
};
33+
34+
type LoginComponent = FC<PropsWithChildren<React.HTMLAttributes<HTMLDivElement>>> & {};
35+
const Login = LoginPage as LoginComponent;
36+
Login.displayName = 'LoginExamplePage';
37+
38+
export default Login;
39+
```
40+
41+
In the example above, we defined an empty `Login` component. The `<Provider>` component is used for data collection, and the layout is placed inside the `<Container>` component, which wraps a `div` around the content to be rendered. The `<Render>` component provides a flexible API to help render the component layout.
42+
43+
## Step 2: Define a `Title` Component
44+
45+
```tsx
46+
import { PropsWithChildren } from 'react';
47+
import { Block, BlockProps, BlockTagType } from 'react-login-page';
48+
49+
export const Title = <T extends BlockTagType>(props: PropsWithChildren<Partial<BlockProps<T>>>) => {
50+
const { keyname = 'title', ...elmProps } = props;
51+
if (!elmProps.children) {
52+
elmProps.children = 'Login';
53+
}
54+
return <Block {...elmProps} keyname={keyname} />;
55+
};
56+
57+
Title.displayName = 'ExampleLogin.Title';
58+
```
59+
60+
When using the `<Title>` component, we need to write the display logic. The `keyname` defined in the `<Title>` component is very important, as we need it when displaying the component. Its purpose is to give your component a name, and determine its position based on the name when displaying it.
61+
62+
```tsx
63+
import { Render, useStore } from 'react-login-page';
64+
65+
const RenderLogin = () => {
66+
const { blocks = {} } = useStore();
67+
return (
68+
<Render>
69+
<div className="login-page-example-wrapper">
70+
<h2>{blocks.title}</h2>
71+
</div>
72+
</Render>
73+
);
74+
};
75+
```
76+
77+
If you need to display the `<Title>` component by default, you should add it to the `<Provider>` component by default.
78+
79+
```tsx
80+
<Provider>
81+
<Title>Example Title</Title>
82+
</Provider>
83+
```
84+
85+
## Step 3: Define an `Input Box` Component
86+
87+
```tsx
88+
import { FC } from 'react';
89+
import { Input, InputProps } from 'react-login-page';
90+
91+
export const Username: FC<InputProps> = (props) => {
92+
const { keyname = 'username', name, ...elmProps } = props;
93+
return (
94+
<Input placeholder="Username" spellCheck={false} {...elmProps} name={name || keyname} keyname={keyname || name} />
95+
);
96+
};
97+
98+
Username.displayName = 'LoginExamplePage.Username';
99+
```
100+
101+
By default, you need to display the `<Username />` component, so add it to the `<Provider>` component.
102+
103+
```tsx
104+
<Provider>
105+
<Username />
106+
</Provider>
107+
```
108+
109+
## Step 4: Define a `Submit Button` Component
110+
111+
```tsx
112+
import { FC } from 'react';
113+
import { Button, ButtonProps } from 'react-login-page';
114+
115+
export const Submit: FC<ButtonProps> = (props) => {
116+
const { keyname = 'submit', ...elmProps } = props;
117+
if (!elmProps.children) {
118+
elmProps.children = 'Submit';
119+
}
120+
return <Button type="submit" keyname={keyname} {...elmProps} />;
121+
};
122+
123+
Submit.displayName = 'LoginExamplePage.Submit';
124+
```
125+
126+
By default, you need to display the `<Submit />` component, so add it to the `<Provider>` component.
127+
128+
```tsx
129+
<Provider>
130+
<Submit />
131+
</Provider>
132+
```
133+
134+
If you also need to display a `Reset Button` by default, you can add another one based on `<Submit />` in the `<Provider>` component:
135+
136+
```tsx
137+
<Provider>
138+
<Submit />
139+
<Submit keyname="resetBtn" type="reset">
140+
Reset
141+
</Submit>
142+
</Provider>
143+
```
144+
145+
## Step 5: Provide a Point Component
146+
147+
Defines [dot notation](https://legacy.reactjs.org/docs/jsx-in-depth.html#using-dot-notation-for-jsx-type) components.
148+
149+
```tsx
150+
type LoginComponent = FC<PropsWithChildren<React.HTMLAttributes<HTMLDivElement>>> & {
151+
Title: typeof Title;
152+
Username: typeof Username;
153+
Submit: typeof Submit;
154+
};
155+
const Login = LoginPage as LoginComponent;
156+
157+
Login.displayName = 'LoginExamplePage';
158+
Login.Title = Title;
159+
Login.Username = Username;
160+
Login.Submit = Submit;
161+
162+
export default Login;
163+
```
164+
165+
## Using the Defined Component
166+
167+
```tsx
168+
import LoginExample from '../login';
169+
170+
function Demo() {
171+
return <LoginExample />;
172+
}
173+
```
174+
175+
## Complete Example
176+
177+
```tsx mdx:preview
178+
import React, { FC, PropsWithChildren, isValidElement, cloneElement } from 'react';
179+
import { Render, Provider, Container, useStore } from 'react-login-page';
180+
import { Block, BlockProps, BlockTagType } from 'react-login-page';
181+
import { Button, ButtonProps } from 'react-login-page';
182+
import { Input, InputProps } from 'react-login-page';
183+
184+
// <Title /> Component
185+
const Title = <T extends BlockTagType>(props: PropsWithChildren<Partial<BlockProps<T>>>) => {
186+
const { keyname = 'title', ...elmProps } = props;
187+
if (!elmProps.children) {
188+
elmProps.children = 'Login';
189+
}
190+
return <Block {...elmProps} keyname={keyname} />;
191+
};
192+
Title.displayName = 'ExampleLogin.Title';
193+
194+
// <Username /> Component
195+
const Username: FC<InputProps> = (props) => {
196+
const { keyname = 'username', name, ...elmProps } = props;
197+
return (
198+
<Input placeholder="Username" spellCheck={false} {...elmProps} name={name || keyname} keyname={keyname || name} />
199+
);
200+
};
201+
Username.displayName = 'LoginExamplePage.Username';
202+
203+
// <Submit /> Component
204+
const Submit: FC<ButtonProps> = (props) => {
205+
const { keyname = 'submit', ...elmProps } = props;
206+
if (!elmProps.children) {
207+
elmProps.children = 'Submit';
208+
}
209+
return <Button type="submit" keyname={keyname} {...elmProps} />;
210+
};
211+
Submit.displayName = 'LoginExamplePage.Submit';
212+
213+
const RenderLogin = () => {
214+
const { blocks = {}, data = {} } = useStore();
215+
const { fields, buttons } = data;
216+
return (
217+
<Render>
218+
<div className="login-page-example-wrapper">
219+
<b>{blocks.title}</b>
220+
{fields
221+
.sort((a, b) => a.index - b.index)
222+
.map((item, idx) => {
223+
return <label key={item.name + idx}>{item.children}</label>;
224+
})}
225+
<section>
226+
{buttons
227+
.sort((a, b) => a.index - b.index)
228+
.map((item, idx) => {
229+
const child = item.children;
230+
if (!isValidElement(child)) return null;
231+
return cloneElement(child, {
232+
...child.props,
233+
key: item.name + idx,
234+
});
235+
})}
236+
</section>
237+
</div>
238+
</Render>
239+
);
240+
};
241+
242+
const LoginPage: FC<PropsWithChildren<React.HTMLAttributes<HTMLDivElement>>> = ({
243+
children,
244+
className,
245+
...divProps
246+
}) => {
247+
return (
248+
<Provider>
249+
<Title>Example Title</Title>
250+
<Username />
251+
<Submit />
252+
<Submit keyname="resetBtn" type="reset">
253+
Reset
254+
</Submit>
255+
<Container {...divProps} className={`login-page-example ${className || ''}`}>
256+
<RenderLogin />
257+
{children}
258+
</Container>
259+
</Provider>
260+
);
261+
};
262+
263+
type LoginComponent = FC<PropsWithChildren<React.HTMLAttributes<HTMLDivElement>>> & {
264+
Title: typeof Title;
265+
};
266+
const Login = LoginPage as LoginComponent;
267+
Login.displayName = 'LoginExamplePage';
268+
Login.Title = Title;
269+
270+
// Here, we use the encapsulated <Login /> component
271+
const Example = () => {
272+
return <Login></Login>;
273+
};
274+
275+
export default Example;
276+
```

core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
},
2424
"./README.md": "./README.md",
2525
"./form-data.md": "./docs/form-data.md",
26+
"./create-login-page.md": "./docs/create-login-page.md",
2627
"./package.json": "./package.json"
2728
},
2829
"scripts": {

website/src/router.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ export const routes: MenuRouteObject = {
4646
label: 'Working With FormData',
4747
element: <Preview path={() => import('react-login-page/form-data.md')} />,
4848
},
49+
{
50+
path: 'create-login-page',
51+
label: 'Create Login Page',
52+
element: <Preview path={() => import('react-login-page/create-login-page.md')} />,
53+
},
4954
],
5055
},
5156
{

0 commit comments

Comments
 (0)