From 9c3e9310b60ede069336f30337787cf252036f28 Mon Sep 17 00:00:00 2001
From: Jandiasnow <88074479@qq.com>
Date: Thu, 23 May 2024 15:42:51 +0800
Subject: [PATCH] feat: add basic
---
.dumirc.ts | 3 +-
.github/workflows/deploy-ghpages.yml | 2 +-
README.md | 5 +
docs/index.md | 12 +-
package.json | 1 +
packages/annotate-text/README.md | 4 +-
packages/annotate-text/index.md | 8 +-
packages/antv-ava/README.md | 4 +-
packages/antv-ava/index.md | 12 +-
packages/basic/.fatherrc.ts | 23 ++
packages/basic/.gitignore | 3 +
packages/basic/README.md | 20 ++
packages/basic/docs/react/Profiler.tsx | 25 ++
packages/basic/docs/react/StrictMode.tsx | 35 ++
packages/basic/docs/react/Suspense.tsx | 13 +
packages/basic/docs/react/createPortal.tsx | 31 ++
packages/basic/docs/react/flushSync.tsx | 21 ++
packages/basic/docs/react/lazy.tsx | 28 ++
packages/basic/docs/react/lazyComponent.tsx | 3 +
packages/basic/docs/react/memo.tsx | 23 ++
packages/basic/docs/react/use.tsx | 26 ++
packages/basic/docs/react/useContext.tsx | 19 +
.../basic/docs/react/useContextReducer.tsx | 71 ++++
.../basic/docs/react/useDeferredValue.tsx | 20 ++
packages/basic/docs/react/useEffectEvent.tsx | 58 +++
.../basic/docs/react/useEffectEventHook.tsx | 21 ++
packages/basic/docs/react/useId.tsx | 7 +
packages/basic/docs/react/useLayoutEffect.tsx | 19 +
packages/basic/docs/react/useOptimistic.tsx | 54 +++
packages/basic/docs/react/useReducer.tsx | 39 +++
packages/basic/docs/react/useReducerImmer.tsx | 35 ++
packages/basic/docs/react/useRef.tsx | 17 +
packages/basic/docs/react/useRefChild.tsx | 36 ++
packages/basic/docs/react/useRefList.tsx | 43 +++
.../docs/react/useStateDebounceUpdate.tsx | 41 +++
.../docs/react/useStateMultipleUpdate.tsx | 21 ++
.../docs/react/useStateNestedObjectUpdate.tsx | 25 ++
.../basic/docs/react/useSyncExternalStore.tsx | 25 ++
packages/basic/docs/react/useTransition.tsx | 25 ++
packages/basic/index.md | 252 ++++++++++++++
packages/basic/index.tsx | 1 +
packages/basic/package.json | 29 ++
packages/basic/src/index.ts | 1 +
packages/basic/src/index.tsx | 1 +
pnpm-lock.yaml | 329 +++++++++++++++---
45 files changed, 1425 insertions(+), 66 deletions(-)
create mode 100644 packages/basic/.fatherrc.ts
create mode 100644 packages/basic/.gitignore
create mode 100644 packages/basic/README.md
create mode 100644 packages/basic/docs/react/Profiler.tsx
create mode 100644 packages/basic/docs/react/StrictMode.tsx
create mode 100644 packages/basic/docs/react/Suspense.tsx
create mode 100644 packages/basic/docs/react/createPortal.tsx
create mode 100644 packages/basic/docs/react/flushSync.tsx
create mode 100644 packages/basic/docs/react/lazy.tsx
create mode 100644 packages/basic/docs/react/lazyComponent.tsx
create mode 100644 packages/basic/docs/react/memo.tsx
create mode 100644 packages/basic/docs/react/use.tsx
create mode 100644 packages/basic/docs/react/useContext.tsx
create mode 100644 packages/basic/docs/react/useContextReducer.tsx
create mode 100644 packages/basic/docs/react/useDeferredValue.tsx
create mode 100644 packages/basic/docs/react/useEffectEvent.tsx
create mode 100644 packages/basic/docs/react/useEffectEventHook.tsx
create mode 100644 packages/basic/docs/react/useId.tsx
create mode 100644 packages/basic/docs/react/useLayoutEffect.tsx
create mode 100644 packages/basic/docs/react/useOptimistic.tsx
create mode 100644 packages/basic/docs/react/useReducer.tsx
create mode 100644 packages/basic/docs/react/useReducerImmer.tsx
create mode 100644 packages/basic/docs/react/useRef.tsx
create mode 100644 packages/basic/docs/react/useRefChild.tsx
create mode 100644 packages/basic/docs/react/useRefList.tsx
create mode 100644 packages/basic/docs/react/useStateDebounceUpdate.tsx
create mode 100644 packages/basic/docs/react/useStateMultipleUpdate.tsx
create mode 100644 packages/basic/docs/react/useStateNestedObjectUpdate.tsx
create mode 100644 packages/basic/docs/react/useSyncExternalStore.tsx
create mode 100644 packages/basic/docs/react/useTransition.tsx
create mode 100644 packages/basic/index.md
create mode 100644 packages/basic/index.tsx
create mode 100644 packages/basic/package.json
create mode 100644 packages/basic/src/index.ts
create mode 100644 packages/basic/src/index.tsx
diff --git a/.dumirc.ts b/.dumirc.ts
index bbb077f..555a258 100644
--- a/.dumirc.ts
+++ b/.dumirc.ts
@@ -2,7 +2,7 @@ import { defineConfig } from 'dumi';
import { readdirSync } from 'fs';
import { join } from 'path';
-const PUBLIC_PATH = '/';
+const PUBLIC_PATH = '/frontend/';
const isProduction = process.env.NODE_ENV === 'production';
const headPkgList: string[] = [];
@@ -12,6 +12,7 @@ const pkgDirList = readdirSync(join(__dirname, 'packages')).filter(
const pkgs = {
'antv-ava': 'antv-ava',
'annotate-text': 'annotate-text',
+ 'basic': 'basic',
};
export const alias = pkgDirList.reduce((pre, name) => {
pre[`@jandia/${pkgs[name]}`] = join(__dirname, 'packages', name, 'src');
diff --git a/.github/workflows/deploy-ghpages.yml b/.github/workflows/deploy-ghpages.yml
index 6057752..9dff678 100644
--- a/.github/workflows/deploy-ghpages.yml
+++ b/.github/workflows/deploy-ghpages.yml
@@ -43,4 +43,4 @@ jobs:
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GH_TOKEN }}
- publish_dir: ./dist/FrontEnd
+ publish_dir: ./dist/frontend
diff --git a/README.md b/README.md
index 0aacdda..9cb5c5e 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,7 @@ $ pnpm run build
| ---------------------------------------------- | ---------------------------------------------- | ---------------------------------------------- | --------------------------- |
| [@jandiasnow/antv-ava][antv-ava-url] | [packages/antv-ava][antv-ava-github] | [![][antv-ava-shield]][antv-ava-url] | ![][antv-ava-download] |
| [@jandiasnow/annotate-text][annotate-text-url] | [packages/annotate-text][annotate-text-github] | [![][annotate-text-shield]][annotate-text-url] | ![][annotate-text-download] |
+| [@jandiasnow/basic][basic-url] | [packages/basic][basic-github] | [![][basic-shield]][basic-url] | ![][basic-download] |
## LICENSE
@@ -34,3 +35,7 @@ MIT
[antv-ava-github]: https://github.com/jandiasnow/frontend/tree/master/packages/antv-ava/README.md
[antv-ava-shield]: https://img.shields.io/npm/v/@jandiasnow/antv-ava?color=369eff&labelColor=black&logo=npm&logoColor=white&style=flat-square
[antv-ava-url]: https://www.npmjs.com/package/@jandiasnow/antv-ava
+[basic-download]: https://img.shields.io/npm/dt/@jandiasnow/basic?labelColor=black&style=flat-square
+[basic-github]: https://github.com/jandiasnow/frontend/tree/master/packages/basic/README.md
+[basic-shield]: https://img.shields.io/npm/v/@jandiasnow/basic?color=369eff&labelColor=black&logo=npm&logoColor=white&style=flat-square
+[basic-url]: https://www.npmjs.com/package/@jandiasnow/basic
diff --git a/docs/index.md b/docs/index.md
index c464875..e8bb5a8 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -9,12 +9,16 @@ hero:
- text: Github
link: https://github.com/Jandiasnow/FrontEnd
features:
+ - title: basic
+ emoji: 🧩
+ link: /packages/basic
+ description: Basic warehouse of frontend
- title: AVA
- emoji: 💎
+ emoji: 🚀
link: /packages/antv-ava
- description: Intelligent visualization
+ description: antv-ava demos
- title: annotate-text
- emoji: 💎
+ emoji: 📜
link: /packages/annotate-text
- description: Intelligent visualization
+ description: annotate-text warehouse comparison and use examples
---
diff --git a/package.json b/package.json
index cec2ff8..48647e0 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
"dev": "dumi dev",
"dev:annotate-text": "concurrently \"pnpm --filter 'annotate-text' dev\" \"npm run dev\"",
"dev:antv-ava": "concurrently \"pnpm --filter 'antv-ava' dev\" \"npm run dev\"",
+ "dev:basic": "concurrently \"pnpm --filter 'basic' dev\" \"npm run dev\"",
"docs:build": "dumi build",
"lint": "npm run lint:es && npm run lint:style && npm run lint:md",
"lint-fix": "npm run lint-fix:es && npm run lint-fix:style",
diff --git a/packages/annotate-text/README.md b/packages/annotate-text/README.md
index 4978106..3b298df 100644
--- a/packages/annotate-text/README.md
+++ b/packages/annotate-text/README.md
@@ -1,6 +1,6 @@
-# @jadiasnow/annotate-text
+# @jandiasnow/annotate-text
-🌐 [@jadiasnow/annotate-text](https://www.npmjs.com/package/@jandiasnow/annotate-text) is an demo examples for
+📜 [@jandiasnow/annotate-text](https://www.npmjs.com/package/@jandiasnow/annotate-text) is an demo examples for
[react-text-annotate-blend](https://github.com/smhaley/react-text-annotate-blend),
[react-nlp-annotate](https://github.com/UniversalDataTool/react-nlp-annotate),
[@recogito/react-text-annotator](https://github.com/recogito/text-annotator-js/blob/main/packages/text-annotator-react/package.json),
diff --git a/packages/annotate-text/index.md b/packages/annotate-text/index.md
index 65e8e57..d9d5e01 100644
--- a/packages/annotate-text/index.md
+++ b/packages/annotate-text/index.md
@@ -9,7 +9,7 @@ order: 0
Annotate Text
-🌐 [@jadiasnow/annotate-text](https://www.npmjs.com/package/@jandiasnow/annotate-text) is an demo examples for
+📜 [@jandiasnow/annotate-text](https://www.npmjs.com/package/@jandiasnow/annotate-text) is an demo examples for
[react-text-annotate-blend](https://github.com/smhaley/react-text-annotate-blend),
[react-nlp-annotate](https://github.com/UniversalDataTool/react-nlp-annotate),
[@recogito/react-text-annotator](https://github.com/recogito/text-annotator-js/blob/main/packages/text-annotator-react/package.json),
@@ -18,13 +18,13 @@ order: 0
-### website
+## 🔗 website
-## Warehouse comparison
+## 🆚 Warehouse comparison
| name | website repo | advantage | defect | used |
| ------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
@@ -34,7 +34,7 @@ order: 0
| [@recogito/recogito-js](https://github.com/recogito/recogito-js) | - | 1. 最近一年有更新
2. 支持 html 类型标记
3. 支持标签关系标记 | 1. 没有 react 版本
2. 样式不好调整,点击事件不好添加 | 页面功能复杂可考虑 |
| [annotato](https://github.com/YusufCelik/annotato) | - | 1. react 版本,代码简单,二次开发比较容易
2. 支持点击事件、样式自定义
3. 支持 html
4. 使用简单 | 1. 最近更新 3 年前
2. 不支持 html 类型
3. 不支持标签关系标记 | 页面功能简单可使用 |
-## 🌐 Usage
+## 📝 Usage
### react-text-annotate-blend
diff --git a/packages/antv-ava/README.md b/packages/antv-ava/README.md
index dff47d9..f0dd706 100644
--- a/packages/antv-ava/README.md
+++ b/packages/antv-ava/README.md
@@ -1,6 +1,6 @@
-# @jadiasnow/antv-ava
+# @jandiasnow/antv-ava
-🌐 [@jadiasnow/antv-ava](https://www.npmjs.com/package/@jandiasnow/ava) is an demo examples for [@antv/ava](https://ava.antv.antgroup.com/guide/intro).
+🚀 [@jandiasnow/antv-ava](https://www.npmjs.com/package/@jandiasnow/ava) is an demo examples for [@antv/ava](https://ava.antv.antgroup.com/guide/intro).
## Development
diff --git a/packages/antv-ava/index.md b/packages/antv-ava/index.md
index 92b7a00..49fcc34 100644
--- a/packages/antv-ava/index.md
+++ b/packages/antv-ava/index.md
@@ -9,19 +9,11 @@ order: 0
Antv Ava
-🌐 [@jadiasnow/antv-ava](https://www.npmjs.com/package/@jandiasnow/ava) is an demo examples for [@antv/ava](https://ava.antv.antgroup.com/guide/intro).
+🚀 [@jandiasnow/antv-ava](https://www.npmjs.com/package/@jandiasnow/ava) is an demo examples for [@antv/ava](https://ava.antv.antgroup.com/guide/intro).
-## 📦 Installation
-
-To install @, run the following command:
-
-```bash
-
-```
-
-## 🌐 Usage
+## 📝 Usage
### 图表知识库(ckb)
diff --git a/packages/basic/.fatherrc.ts b/packages/basic/.fatherrc.ts
new file mode 100644
index 0000000..ea98c7d
--- /dev/null
+++ b/packages/basic/.fatherrc.ts
@@ -0,0 +1,23 @@
+import { defineConfig } from 'father';
+
+const library = 'JandiasnowBasic';
+
+const externals = {};
+
+export default defineConfig({
+ extends: '../../.fatherrc.base.ts',
+ cjs: {
+ input: 'src', // 默认编译目录
+ platform: 'node', // 默认构建为 Node.js 环境的产物
+ transformer: 'esbuild', // 默认使用 esbuild 以获得更快的构建速度
+ },
+ umd: {
+ entry: {
+ 'src/index.ts': {
+ name: library,
+ sourcemap: true,
+ externals,
+ },
+ },
+ },
+});
diff --git a/packages/basic/.gitignore b/packages/basic/.gitignore
new file mode 100644
index 0000000..a5a9814
--- /dev/null
+++ b/packages/basic/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+dist
+.dumi
\ No newline at end of file
diff --git a/packages/basic/README.md b/packages/basic/README.md
new file mode 100644
index 0000000..1a39ae2
--- /dev/null
+++ b/packages/basic/README.md
@@ -0,0 +1,20 @@
+# @jandiasnow/basic
+
+🧩 [@jandiasnow/basic](https://www.npmjs.com/package/@jandiasnow/basic) is an warehouse of frontend basic
+
+## Development
+
+```bash
+# install dependencies
+$ pnpm install
+
+# start dev server
+$ pnpm start
+
+# build docs
+$ pnpm run build
+```
+
+## LICENSE
+
+MIT
diff --git a/packages/basic/docs/react/Profiler.tsx b/packages/basic/docs/react/Profiler.tsx
new file mode 100644
index 0000000..f8a4331
--- /dev/null
+++ b/packages/basic/docs/react/Profiler.tsx
@@ -0,0 +1,25 @@
+import { Tabs } from 'antd';
+import React, { Profiler, useState } from 'react';
+
+export default () => {
+ const [tab, setTab] = useState('key1');
+ return (
+ {
+ console.warn(':', params);
+ }}
+ >
+ {
+ setTab(v);
+ }}
+ />
+
+ );
+};
diff --git a/packages/basic/docs/react/StrictMode.tsx b/packages/basic/docs/react/StrictMode.tsx
new file mode 100644
index 0000000..57cecdf
--- /dev/null
+++ b/packages/basic/docs/react/StrictMode.tsx
@@ -0,0 +1,35 @@
+import { Space } from 'antd';
+import React, { StrictMode, useState } from 'react';
+
+let initialStories = [
+ { id: 0, label: "Ankit's Story" },
+ { id: 1, label: "Taylor's Story" },
+];
+
+export default function App() {
+ let [stories] = useState(initialStories);
+ const [isHover, setIsHover] = useState(false);
+ const items = stories as any;
+ items.push({ id: 'create', label: 'Create Story' });
+
+ return (
+
+ setIsHover(true)}
+ onPointerLeave={() => setIsHover(false)}
+ style={{
+ backgroundColor: isHover ? '#ddd' : '#fff',
+ }}
+ >
+ {items.map(story => (
+
+ {story.label}
+
+ ))}
+
+
+ );
+}
diff --git a/packages/basic/docs/react/Suspense.tsx b/packages/basic/docs/react/Suspense.tsx
new file mode 100644
index 0000000..39e3d19
--- /dev/null
+++ b/packages/basic/docs/react/Suspense.tsx
@@ -0,0 +1,13 @@
+import { Space, Spin } from 'antd';
+import React, { Suspense } from 'react';
+
+export default () => {
+ return (
+ loading}>
+
+ wrapper
+ loading1}>info
+
+
+ );
+};
diff --git a/packages/basic/docs/react/createPortal.tsx b/packages/basic/docs/react/createPortal.tsx
new file mode 100644
index 0000000..c2d7325
--- /dev/null
+++ b/packages/basic/docs/react/createPortal.tsx
@@ -0,0 +1,31 @@
+import { Button, Space, Typography } from 'antd';
+import React, { useId, useState } from 'react';
+import { createPortal } from 'react-dom';
+
+const ModalContent = ({ onClose }) => {
+ return (
+
+ modal content
+
+
+ );
+};
+
+export default () => {
+ const [showModal, setShowModal] = useState(false);
+ const domId = useId();
+
+ return (
+
+
+
+
+
+ {showModal &&
+ createPortal(
+ setShowModal(false)} />,
+ document.querySelector("[id=':r3:']") as any
+ )}
+
+ );
+};
diff --git a/packages/basic/docs/react/flushSync.tsx b/packages/basic/docs/react/flushSync.tsx
new file mode 100644
index 0000000..1bd007a
--- /dev/null
+++ b/packages/basic/docs/react/flushSync.tsx
@@ -0,0 +1,21 @@
+import { Button, Input, Space } from 'antd';
+import React, { useState } from 'react';
+import { flushSync } from 'react-dom';
+
+export default () => {
+ const [text, setText] = useState('init');
+
+ const handleChange = () => {
+ flushSync(() => {
+ setText('change');
+ });
+ };
+
+ return (
+
+ {text}
+
+ setText(e.target.value)} value={text} />
+
+ );
+};
diff --git a/packages/basic/docs/react/lazy.tsx b/packages/basic/docs/react/lazy.tsx
new file mode 100644
index 0000000..5a3b1d7
--- /dev/null
+++ b/packages/basic/docs/react/lazy.tsx
@@ -0,0 +1,28 @@
+import { Checkbox, Space, Spin } from 'antd';
+import { Suspense, lazy, useState } from 'react';
+
+const delayForDemo = promise => {
+ return new Promise(resolve => {
+ setTimeout(resolve, 2000);
+ }).then(() => promise);
+};
+
+const LazyComponent = lazy(() => delayForDemo(import('./lazyComponent.tsx')));
+
+export default () => {
+ const [showPreview, setShowPreview] = useState(false);
+
+ return (
+
+ setShowPreview(e.target.checked)} value={showPreview}>
+ Show preview
+
+ {showPreview && (
+ }>
+ Preview:
+
+
+ )}
+
+ );
+};
diff --git a/packages/basic/docs/react/lazyComponent.tsx b/packages/basic/docs/react/lazyComponent.tsx
new file mode 100644
index 0000000..6cd4e84
--- /dev/null
+++ b/packages/basic/docs/react/lazyComponent.tsx
@@ -0,0 +1,3 @@
+export default () => {
+ return 'lazyComponent';
+};
diff --git a/packages/basic/docs/react/memo.tsx b/packages/basic/docs/react/memo.tsx
new file mode 100644
index 0000000..83297a8
--- /dev/null
+++ b/packages/basic/docs/react/memo.tsx
@@ -0,0 +1,23 @@
+import { Input, Space } from 'antd';
+import { memo, useState } from 'react';
+
+const MemoComponent = memo(({ name }) => {
+ console.warn('Greeting was rendered at', new Date().toLocaleTimeString());
+ return (
+
+ {new Date().toLocaleTimeString()}: {name || '-'}
+
+ );
+});
+
+export default function MyApp() {
+ const [name, setName] = useState('');
+ const [address, setAddress] = useState('');
+ return (
+
+ setName(e.target.value)} placeholder="Name" value={name} />
+ setAddress(e.target.value)} placeholder="Address" value={address} />
+
+
+ );
+}
diff --git a/packages/basic/docs/react/use.tsx b/packages/basic/docs/react/use.tsx
new file mode 100644
index 0000000..ccb9952
--- /dev/null
+++ b/packages/basic/docs/react/use.tsx
@@ -0,0 +1,26 @@
+import { Button, Space } from 'antd';
+import { createContext, use, useState } from 'react';
+
+const ThemeContext = createContext('theme');
+
+const Content = () => {
+ const [show, setShow] = useState();
+ let theme = 'default';
+ if (show) {
+ theme = use(ThemeContext);
+ }
+ return (
+
+ {theme}
+
+
+ );
+};
+
+export default () => {
+ return (
+
+
+
+ );
+};
diff --git a/packages/basic/docs/react/useContext.tsx b/packages/basic/docs/react/useContext.tsx
new file mode 100644
index 0000000..8e266f3
--- /dev/null
+++ b/packages/basic/docs/react/useContext.tsx
@@ -0,0 +1,19 @@
+import React, { createContext, useContext } from 'react';
+
+// create
+export const LevelContext = createContext('');
+
+const Child = () => {
+ // use
+ const level = useContext(LevelContext);
+ return <>{level}>;
+};
+
+export default () => {
+ // use
+ return (
+
+
+
+ );
+};
diff --git a/packages/basic/docs/react/useContextReducer.tsx b/packages/basic/docs/react/useContextReducer.tsx
new file mode 100644
index 0000000..35f74a4
--- /dev/null
+++ b/packages/basic/docs/react/useContextReducer.tsx
@@ -0,0 +1,71 @@
+import { Button, Space } from 'antd';
+import React, { createContext, useContext, useReducer } from 'react';
+
+// use reducer create context
+const initialTasks = [{ id: 0, text: 'Philosopher’s Path', done: true }];
+
+type Dispatch = React.Dispatch<{ type: 'changed'; task: (typeof initialTasks)[0] }>;
+
+const TasksContext = createContext(initialTasks);
+const TasksDispatchContext = createContext(null!);
+
+const tasksReducer = (tasks, action: { type: 'changed'; task: any }) => {
+ switch (action.type) {
+ case 'changed': {
+ return tasks.map(t => {
+ return t.id === action.task.id
+ ? { ...action.task, change: (action.task.change || 0) + 1 }
+ : t;
+ });
+ }
+ default: {
+ throw new Error('Unknown action: ' + action.type);
+ }
+ }
+};
+
+export const TasksProvider = ({ children }) => {
+ const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
+
+ return (
+
+ {children}
+
+ );
+};
+
+// use func
+export const useTasks = () => {
+ return useContext(TasksContext);
+};
+export const useTasksDispatch = () => {
+ return useContext(TasksDispatchContext);
+};
+
+// use
+const Child = () => {
+ const dispatch = useTasksDispatch();
+ const tasks = useTasks();
+ return (
+
+
+ {JSON.stringify(tasks)}
+
+ );
+};
+export default () => {
+ return (
+
+
+
+ );
+};
diff --git a/packages/basic/docs/react/useDeferredValue.tsx b/packages/basic/docs/react/useDeferredValue.tsx
new file mode 100644
index 0000000..cba9f5e
--- /dev/null
+++ b/packages/basic/docs/react/useDeferredValue.tsx
@@ -0,0 +1,20 @@
+import { Input, Space, Typography } from 'antd';
+import React, { useDeferredValue, useState } from 'react';
+
+export default () => {
+ const [query, setQuery] = useState('');
+ const deferredQuery = useDeferredValue(query);
+ const isStale = query !== deferredQuery;
+ return (
+
+ setQuery(e.target.value)} value={query} />
+
+ {deferredQuery}
+
+
+ );
+};
diff --git a/packages/basic/docs/react/useEffectEvent.tsx b/packages/basic/docs/react/useEffectEvent.tsx
new file mode 100644
index 0000000..e6fab1a
--- /dev/null
+++ b/packages/basic/docs/react/useEffectEvent.tsx
@@ -0,0 +1,58 @@
+// import React, { useState, useEffect } from 'react';
+// import { Button, Typography, Space } from 'antd'
+
+// // import { experimental_useEffectEvent as useEffectEvent } from 'react';
+// // import { createConnection } from './chat.js';
+
+// const serverUrl = 'https://localhost:1234';
+
+// function ChatRoom({ roomId, theme }) {
+// // const onConnected = useEffectEvent(() => {
+// // showNotification('Connected!', theme);
+// // });
+
+// // useEffect(() => {
+// // const connection = createConnection(serverUrl, roomId);
+// // connection.on('connected', () => {
+// // onConnected();
+// // });
+// // connection.connect();
+// // return () => connection.disconnect();
+// // }, [roomId]);
+
+// return Welcome to the {roomId} room!
+// }
+
+// export default () => {
+// const [roomId, setRoomId] = useState('general');
+// const [isDark, setIsDark] = useState(false);
+// return (
+// <>
+//
+//
+//
+//
+// >
+// );
+// }
+export default () => 1;
diff --git a/packages/basic/docs/react/useEffectEventHook.tsx b/packages/basic/docs/react/useEffectEventHook.tsx
new file mode 100644
index 0000000..413abfa
--- /dev/null
+++ b/packages/basic/docs/react/useEffectEventHook.tsx
@@ -0,0 +1,21 @@
+// //7. useEffectEvent hook
+// import { useEffect, useEffectEvent } from 'react';
+// // ...
+
+// export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) {
+// const onMessage = useEffectEvent(onReceiveMessage);
+
+// useEffect(() => {
+// const options = {
+// serverUrl: serverUrl,
+// roomId: roomId
+// };
+// const connection = createConnection(options);
+// connection.connect();
+// connection.on('message', (msg) => {
+// onMessage(msg);
+// });
+// return () => connection.disconnect();
+// }, [roomId, serverUrl]); // ✅ All dependencies declared
+// }
+export default () => 1;
diff --git a/packages/basic/docs/react/useId.tsx b/packages/basic/docs/react/useId.tsx
new file mode 100644
index 0000000..6e84752
--- /dev/null
+++ b/packages/basic/docs/react/useId.tsx
@@ -0,0 +1,7 @@
+import { Typography } from 'antd';
+import React, { useId } from 'react';
+
+export default () => {
+ const id = useId();
+ return {id};
+};
diff --git a/packages/basic/docs/react/useLayoutEffect.tsx b/packages/basic/docs/react/useLayoutEffect.tsx
new file mode 100644
index 0000000..be906b5
--- /dev/null
+++ b/packages/basic/docs/react/useLayoutEffect.tsx
@@ -0,0 +1,19 @@
+import { Space, Typography } from 'antd';
+import React, { useLayoutEffect, useRef, useState } from 'react';
+
+export default () => {
+ const ref = useRef(null!);
+ const [rect, setRect] = useState();
+
+ useLayoutEffect(() => {
+ const r = ref.current.getBoundingClientRect();
+ setRect(r);
+ }, []);
+
+ return (
+
+ height: {rect?.height}
+ width: {rect?.width}
+
+ );
+};
diff --git a/packages/basic/docs/react/useOptimistic.tsx b/packages/basic/docs/react/useOptimistic.tsx
new file mode 100644
index 0000000..5b614fe
--- /dev/null
+++ b/packages/basic/docs/react/useOptimistic.tsx
@@ -0,0 +1,54 @@
+import { useOptimistic, useRef, useState } from 'react';
+
+const deliverMessage = async message => {
+ await new Promise(resolve => {
+ setTimeout(() => {
+ resolve(true);
+ }, 1000);
+ });
+ return message;
+};
+
+export default () => {
+ const formRef = useRef(null!);
+
+ const [messages, setMessages] = useState<
+ {
+ text: string;
+ sending?: boolean;
+ key?: number;
+ }[]
+ >([{ text: 'Hello there!', sending: false, key: 1 }]) as any;
+
+ const [optimisticMessages, addOptimisticMessage] = useOptimistic(
+ messages,
+ (state, newMessage) => [
+ ...state,
+ {
+ text: newMessage,
+ sending: true,
+ },
+ ]
+ );
+ async function formAction(formData) {
+ addOptimisticMessage(formData.get('message'));
+ formRef.current.reset();
+ const sentMessage = await deliverMessage(formData.get('message'));
+ setMessages(messages => [...messages, { text: sentMessage }]);
+ }
+
+ return (
+ <>
+ {optimisticMessages.map((message, index) => (
+
+ {message.text}
+ {!!message.sending && (Sending...)}
+
+ ))}
+
+ >
+ );
+};
diff --git a/packages/basic/docs/react/useReducer.tsx b/packages/basic/docs/react/useReducer.tsx
new file mode 100644
index 0000000..8fc8873
--- /dev/null
+++ b/packages/basic/docs/react/useReducer.tsx
@@ -0,0 +1,39 @@
+import { Button, Space } from 'antd';
+import React, { useReducer } from 'react';
+
+// use
+const tasksReducer = (tasks, action: { type: 'changed'; task: any }) => {
+ switch (action.type) {
+ case 'changed': {
+ return tasks.map(t => {
+ return t.id === action.task.id
+ ? { ...action.task, change: (action.task.change || 0) + 1 }
+ : t;
+ });
+ }
+ default: {
+ throw new Error('Unknown action: ' + action.type);
+ }
+ }
+};
+const initData = [{ id: 0, text: 'Visit Kafka Museum', done: true }];
+
+export default () => {
+ const [tasks, dispatch] = useReducer(tasksReducer, initData);
+ return (
+
+
+ {JSON.stringify(tasks)}
+
+ );
+};
diff --git a/packages/basic/docs/react/useReducerImmer.tsx b/packages/basic/docs/react/useReducerImmer.tsx
new file mode 100644
index 0000000..374eb71
--- /dev/null
+++ b/packages/basic/docs/react/useReducerImmer.tsx
@@ -0,0 +1,35 @@
+import { Button, Space } from 'antd';
+import React from 'react';
+import { useImmerReducer } from 'use-immer';
+
+const tasksReducer = (draft, action: { type: 'changed' }) => {
+ switch (action.type) {
+ case 'changed': {
+ // use
+ draft[0].id = draft[0].id + 1;
+ break;
+ }
+ default: {
+ throw new Error('Unknown action: ' + action.type);
+ }
+ }
+};
+const initData = [{ id: 0, text: 'Visit Kafka Museum', done: true }];
+
+export default () => {
+ const [tasks, dispatch] = useImmerReducer(tasksReducer, initData);
+ return (
+
+
+ {JSON.stringify(tasks)}
+
+ );
+};
diff --git a/packages/basic/docs/react/useRef.tsx b/packages/basic/docs/react/useRef.tsx
new file mode 100644
index 0000000..1662c62
--- /dev/null
+++ b/packages/basic/docs/react/useRef.tsx
@@ -0,0 +1,17 @@
+import { Button, Input, InputRef, Space } from 'antd';
+import React, { useRef } from 'react';
+
+export default () => {
+ const inputRef = useRef(null!);
+
+ const handleClick = () => {
+ inputRef?.current?.focus();
+ };
+
+ return (
+
+
+
+
+ );
+};
diff --git a/packages/basic/docs/react/useRefChild.tsx b/packages/basic/docs/react/useRefChild.tsx
new file mode 100644
index 0000000..d672f41
--- /dev/null
+++ b/packages/basic/docs/react/useRefChild.tsx
@@ -0,0 +1,36 @@
+import { Button, Input, InputRef, Space } from 'antd';
+import React, { forwardRef, useImperativeHandle, useRef } from 'react';
+
+// create
+interface MyInputRef {
+ focus: () => void;
+}
+interface MyInputProps {
+ test?: string;
+}
+const MyInput = forwardRef((props, ref) => {
+ const realInputRef = useRef(null!);
+ useImperativeHandle(ref, () => ({
+ // Only expose focus and nothing else
+ focus() {
+ realInputRef.current.focus();
+ },
+ }));
+ return ;
+});
+
+// use
+export default () => {
+ const inputRef = useRef(null!);
+
+ function handleClick() {
+ inputRef.current.focus();
+ }
+
+ return (
+
+
+
+
+ );
+};
diff --git a/packages/basic/docs/react/useRefList.tsx b/packages/basic/docs/react/useRefList.tsx
new file mode 100644
index 0000000..118ffd7
--- /dev/null
+++ b/packages/basic/docs/react/useRefList.tsx
@@ -0,0 +1,43 @@
+import { Button, Input, Space } from 'antd';
+import React, { useRef, useState } from 'react';
+
+export default () => {
+ const itemsRef = useRef