From 247c0d6eaa8480fab72c57ad3464e75b385bb906 Mon Sep 17 00:00:00 2001
From: lorne <1991wangliang@gmail.com>
Date: Wed, 14 May 2025 17:27:09 +0800
Subject: [PATCH 1/8] fix playground
---
playground/README.md | 9 ---------
playground/package.json | 2 +-
playground/webpack.common.js | 1 +
3 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/playground/README.md b/playground/README.md
index 7ad832b..388baf7 100644
--- a/playground/README.md
+++ b/playground/README.md
@@ -1,14 +1,5 @@
# playground
-
-## 运行步骤
-### 编译form-mobile
-```
-yarn build
-```
-在form-mobile目录下执行编译命令,编译完成后会在dist目录下生成form-mobile的代码包。
-
-
### 运行实例
```
diff --git a/playground/package.json b/playground/package.json
index 284a7fd..cd43a09 100644
--- a/playground/package.json
+++ b/playground/package.json
@@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
- "@codingapi/form-mobile": "file:../dist",
+ "@codingapi/form-mobile": "file:../src",
"@types/node": "^16.18.108",
"@types/react": "^18.3.5",
"@types/react-dom": "^18.3.0",
diff --git a/playground/webpack.common.js b/playground/webpack.common.js
index 29a8f66..a8652ef 100644
--- a/playground/webpack.common.js
+++ b/playground/webpack.common.js
@@ -20,6 +20,7 @@ module.exports = {
extensions: ['.ts', '.tsx', '.js'],
alias: {
'@': path.resolve(__dirname, 'src'),
+ '@codingapi/form-mobile': path.resolve(__dirname, '../src'),
},
},
module: {
From cfe262c14d6b14c609dac6f47b8d9de691942295 Mon Sep 17 00:00:00 2001
From: lorne <1991wangliang@gmail.com>
Date: Wed, 14 May 2025 21:32:36 +0800
Subject: [PATCH 2/8] fix fom
---
package.json | 4 +-
src/Form/factory.tsx | 161 -------------------------
src/Form/index.tsx | 6 +-
src/Form/register.tsx | 32 +++++
src/Popup/index.scss | 16 +++
src/Popup/index.tsx | 55 +++++++++
src/PullToRefreshList/index.scss | 9 ++
src/PullToRefreshList/index.tsx | 195 +++++++++++++++++++++++++++++++
src/index.ts | 3 +-
9 files changed, 314 insertions(+), 167 deletions(-)
delete mode 100644 src/Form/factory.tsx
create mode 100644 src/Form/register.tsx
create mode 100644 src/Popup/index.scss
create mode 100644 src/Popup/index.tsx
create mode 100644 src/PullToRefreshList/index.scss
create mode 100644 src/PullToRefreshList/index.tsx
diff --git a/package.json b/package.json
index 822d728..07a821f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@codingapi/form-mobile",
- "version": "0.0.24",
+ "version": "0.0.25",
"description": "A UI Framework built with React and TypeScript",
"keywords": [
"ui",
@@ -35,7 +35,7 @@
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"dependencies": {
- "@codingapi/ui-framework": "^0.0.24",
+ "@codingapi/ui-framework": "^0.0.28",
"antd-mobile": "^5.39.0"
},
"scripts": {
diff --git a/src/Form/factory.tsx b/src/Form/factory.tsx
deleted file mode 100644
index 9103fc9..0000000
--- a/src/Form/factory.tsx
+++ /dev/null
@@ -1,161 +0,0 @@
-import React from "react";
-import {FormField} from "@codingapi/ui-framework";
-import {FormInput} from "./input";
-import {FormPassword} from "./password";
-import {FormCaptcha} from "./captcha";
-import {FormCheckbox} from "./checkbox";
-import {FormRadio} from "./radio";
-import {FormRate} from "./rate";
-import {FormSlider} from "./slider";
-import {FormStepper} from "./stepper";
-import {FormTextArea} from "./textarea";
-import {FormSwitch} from "./switch";
-import {FormDate} from "./date";
-import {FormCascader} from "./cascader";
-import {FormSelect} from "./select";
-import {FormSelector} from "./selector";
-import {FormUploader} from "./uploder";
-
-export class FormFactory {
-
- static create = (field: FormField) => {
- const type = field.type;
- const props = field.props;
-
- if (type === 'input') {
- return (
-
- )
- }
-
- if (type === 'password') {
- return (
-
- )
- }
-
- if (type === 'captcha') {
- return (
-
- )
- }
-
- if (type === 'checkbox') {
- return (
-
- )
- }
-
- if (type === 'radio') {
- return (
-
- )
- }
-
- if (type === 'rate') {
- return (
-
- )
- }
-
- if (type === 'slider') {
- return (
-
- )
- }
- if (type === 'stepper') {
- return (
-
- )
- }
-
- if (type === 'textarea') {
- return (
-
- )
- }
-
- if (type === 'switch') {
- return (
-
- )
- }
-
- if (type === 'date') {
- return (
-
- )
- }
-
- if (type === 'cascader') {
- return (
-
- )
- }
-
- if (type === 'selector') {
- return (
-
- )
- }
-
- if (type === 'select') {
- return (
-
- )
- }
-
- if (type === 'uploader') {
- return (
-
- )
- }
- }
-
-}
-
diff --git a/src/Form/index.tsx b/src/Form/index.tsx
index 848bc13..744e858 100644
--- a/src/Form/index.tsx
+++ b/src/Form/index.tsx
@@ -1,9 +1,9 @@
import React, {useEffect} from "react";
import {Form as MobileForm} from "antd-mobile";
-import {FormFactory} from "./factory";
-import {AntdForm, AntdFormInstance, FormField, FormInstance} from "@codingapi/ui-framework";
+import {AntdForm, AntdFormInstance, FormField, FormInstance,FormFactory} from "@codingapi/ui-framework";
import {FormContext} from "./context";
import "./index.scss";
+import "./register";
export interface FormProps {
// 表单字段
@@ -59,7 +59,7 @@ const FormComponent: React.FC = (props) => {
footer={props.footer}
>
{fields.length > 0 && fields.map((field) => {
- return FormFactory.create(field) as React.ReactNode;
+ return FormFactory.getInstance().create(field) as React.ReactNode;
})}
{props.children}
diff --git a/src/Form/register.tsx b/src/Form/register.tsx
new file mode 100644
index 0000000..b359f38
--- /dev/null
+++ b/src/Form/register.tsx
@@ -0,0 +1,32 @@
+import {FormFactory} from "@codingapi/ui-framework";
+import {FormInput} from "./input";
+import {FormPassword} from "./password";
+import {FormCaptcha} from "./captcha";
+import {FormCheckbox} from "./checkbox";
+import {FormRadio} from "./radio";
+import {FormRate} from "./rate";
+import {FormSlider} from "./slider";
+import {FormStepper} from "./stepper";
+import {FormTextArea} from "./textarea";
+import {FormSwitch} from "./switch";
+import {FormDate} from "./date";
+import {FormCascader} from "./cascader";
+import {FormSelect} from "./select";
+import {FormSelector} from "./selector";
+import {FormUploader} from "./uploder";
+
+FormFactory.getInstance().addItem('input',FormInput);
+FormFactory.getInstance().addItem('password',FormPassword);
+FormFactory.getInstance().addItem('captcha',FormCaptcha);
+FormFactory.getInstance().addItem('checkbox',FormCheckbox);
+FormFactory.getInstance().addItem('radio',FormRadio);
+FormFactory.getInstance().addItem('rate',FormRate);
+FormFactory.getInstance().addItem('slider',FormSlider);
+FormFactory.getInstance().addItem('stepper',FormStepper);
+FormFactory.getInstance().addItem('textarea',FormTextArea);
+FormFactory.getInstance().addItem('switch',FormSwitch);
+FormFactory.getInstance().addItem('date',FormDate);
+FormFactory.getInstance().addItem('cascader',FormCascader);
+FormFactory.getInstance().addItem('select',FormSelect);
+FormFactory.getInstance().addItem('selector',FormSelector);
+FormFactory.getInstance().addItem('uploader',FormUploader);
diff --git a/src/Popup/index.scss b/src/Popup/index.scss
new file mode 100644
index 0000000..4f717e5
--- /dev/null
+++ b/src/Popup/index.scss
@@ -0,0 +1,16 @@
+$body-background-color: #e6e7ea;
+
+.mobile-popup {
+}
+
+.mobile-popup-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px;
+ border-bottom: 1px solid $body-background-color;
+}
+
+.mobile-popup-content {
+ padding: 10px;
+}
diff --git a/src/Popup/index.tsx b/src/Popup/index.tsx
new file mode 100644
index 0000000..31ffc0b
--- /dev/null
+++ b/src/Popup/index.tsx
@@ -0,0 +1,55 @@
+import React from "react";
+import {Popup as AntPopup} from "antd-mobile";
+import "./index.scss";
+
+interface PopupProps {
+ title?: string;
+ visible: boolean;
+ setVisible: (visible: boolean) => void;
+ children?: React.ReactNode;
+ position?: 'top' | 'right' | 'bottom' | 'left';
+ bodyStyle?: React.CSSProperties;
+ onOk?: () => void;
+ onCancel?: () => void;
+}
+
+const Popup: React.FC = (props) => {
+
+ return (
+ {
+ props.setVisible(false)
+ }}
+ onClose={() => {
+ props.setVisible(false)
+ }}
+ position={props.position}
+ bodyStyle={props.bodyStyle}
+ >
+
+
+
+ {props.children}
+
+
+
+
+ )
+}
+
+export default Popup;
diff --git a/src/PullToRefreshList/index.scss b/src/PullToRefreshList/index.scss
new file mode 100644
index 0000000..4957367
--- /dev/null
+++ b/src/PullToRefreshList/index.scss
@@ -0,0 +1,9 @@
+$body-background-color: #e6e7ea;
+
+.mobile-list{
+ background-color: $body-background-color;
+
+ .adm-infinite-scroll{
+ padding: 8px !important;
+ }
+}
diff --git a/src/PullToRefreshList/index.tsx b/src/PullToRefreshList/index.tsx
new file mode 100644
index 0000000..1e3f42f
--- /dev/null
+++ b/src/PullToRefreshList/index.tsx
@@ -0,0 +1,195 @@
+import React, {useEffect} from "react";
+import {ErrorBlock, InfiniteScroll, PullToRefresh as AntPullToRefresh} from "antd-mobile";
+import {PullStatus} from "antd-mobile/es/components/pull-to-refresh";
+import "./index.scss";
+
+export interface ListResponse {
+ data: {
+ total: number;
+ list: any[]
+ },
+ success: boolean
+}
+
+export interface ListAction {
+ reload: () => void;
+}
+
+export interface PullToRefreshListProps {
+ // 样式
+ style?: React.CSSProperties;
+ // className
+ className?: string;
+
+ listAction?: React.Ref;
+ // 每页数量,默认为10
+ pageSize?: number;
+ // 刷新数据
+ onRefresh?: (pageSize: number) => Promise;
+ // 加载更多
+ onLoadMore?: (pageSize: number, last: any) => Promise;
+ // 渲染列表项
+ item: (item: any, index: number) => React.ReactNode;
+ // 拉去数据提示
+ pullStates?: {
+ // 默认值,用力拉
+ pulling: string;
+ // 默认值,松开吧
+ canRelease: string;
+ // 默认值,玩命加载中...
+ refreshing: string;
+ // 默认值,好啦
+ complete: string
+ };
+ // 空数据提示
+ blockStates?: {
+ // 默认值,暂无信息
+ title: string;
+ // 默认值,没有任何信息
+ description: string;
+ }
+ // 无数据提示,默认值为无更多数据
+ noDataStates?: React.ReactNode;
+}
+
+const PullToRefreshList: React.FC = (props) => {
+
+ const pageSize = props.pageSize || 10;
+ const [orderList, setOrderList] = React.useState([]);
+ const [last, setLast] = React.useState("");
+ // 没有数据了
+ const [noData, setNoData] = React.useState(false);
+ // 是否还有更多数据
+ const [hasMore, setHasMore] = React.useState(true);
+
+ const [loading, setLoading] = React.useState(false);
+
+ const noDataStates = props.noDataStates || "暂无更多数据...";
+
+ const statusRecord: Record = {
+ pulling: props.pullStates?.pulling || '用力拉',
+ canRelease: props.pullStates?.canRelease || '松开吧',
+ refreshing: props.pullStates?.refreshing || '玩命加载中...',
+ complete: props.pullStates?.complete || '好啦',
+ }
+
+ React.useImperativeHandle(props.listAction, () => ({
+ reload: () => {
+ setOrderList([]);
+ refresh();
+ }
+ }), [props.listAction, props])
+
+ const loadMore = async () => {
+ if (loading) {
+ return;
+ }
+ if (props.onLoadMore) {
+ setLoading(true);
+ props.onLoadMore(last, pageSize)
+ .then(res => {
+ if (res.success) {
+ const {data} = res;
+ if (data.total > 0) {
+ const list = data.list;
+ const last = list[list.length - 1].id;
+ setLast(last);
+ const currentList = orderList;
+
+ for (let i = 0; i < list.length; i++) {
+ const item = list[i];
+ if (currentList.find((value: any) => value.id === item.id)) {
+ continue;
+ }
+ currentList.push(item);
+ }
+
+ setOrderList(currentList);
+ setHasMore(data.total > list.length);
+ } else {
+ setHasMore(false);
+ if (!last) {
+ setNoData(true);
+ }
+ }
+ }
+ })
+ .finally(() => {
+ setLoading(false);
+ });
+ }
+ }
+
+ const refresh = () => {
+ if (loading) {
+ return;
+ }
+ if (props.onRefresh) {
+ setLoading(true);
+ props.onRefresh(pageSize)
+ .then(res => {
+ if (res.success) {
+ const {data} = res;
+ if (data.total > 0) {
+ const list = data.list;
+ const last = list[list.length - 1].id;
+ setLast(last);
+ setOrderList(list);
+ setHasMore(data.total > list.length);
+ } else {
+ setHasMore(false);
+ setNoData(true)
+ }
+ }
+ })
+ .finally(() => {
+ setLoading(false);
+ });
+ }
+ }
+
+ useEffect(() => {
+ refresh();
+ }, []);
+
+ return (
+
+
{
+ refresh();
+ }}
+ renderText={status => {
+ return {statusRecord[status]}
+ }}
+ >
+ {orderList && orderList.map((item: any, index: number) => {
+ return props.item(item, index);
+ })}
+
+ {orderList && orderList.length > 0 && (
+
+ {noDataStates}
+
+ )}
+ {noData && (
+
+ )}
+
+
+
+ )
+}
+
+export default PullToRefreshList;
diff --git a/src/index.ts b/src/index.ts
index 61b4734..5a78616 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -15,6 +15,7 @@ export * from './Form/stepper';
export * from './Form/switch';
export * from './Form/textarea';
export * from './Form/uploder';
-export * from './Form/factory';
export * from './Form/index';
export * from './Descriptions';
+export * from './Popup';
+export * from './PullToRefreshList';
From e337270a43a11f11949136eb04eaa8ab90fd9f3d Mon Sep 17 00:00:00 2001
From: lorne <1991wangliang@gmail.com>
Date: Wed, 14 May 2025 21:37:34 +0800
Subject: [PATCH 3/8] fix form
---
package.json | 2 +-
src/Popup/index.tsx | 4 +---
src/PullToRefreshList/index.tsx | 3 +--
3 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/package.json b/package.json
index 07a821f..9512f12 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@codingapi/form-mobile",
- "version": "0.0.25",
+ "version": "0.0.26",
"description": "A UI Framework built with React and TypeScript",
"keywords": [
"ui",
diff --git a/src/Popup/index.tsx b/src/Popup/index.tsx
index 31ffc0b..d91827d 100644
--- a/src/Popup/index.tsx
+++ b/src/Popup/index.tsx
@@ -13,7 +13,7 @@ interface PopupProps {
onCancel?: () => void;
}
-const Popup: React.FC = (props) => {
+export const Popup: React.FC = (props) => {
return (
= (props) => {
)
}
-
-export default Popup;
diff --git a/src/PullToRefreshList/index.tsx b/src/PullToRefreshList/index.tsx
index 1e3f42f..af8dfec 100644
--- a/src/PullToRefreshList/index.tsx
+++ b/src/PullToRefreshList/index.tsx
@@ -52,7 +52,7 @@ export interface PullToRefreshListProps {
noDataStates?: React.ReactNode;
}
-const PullToRefreshList: React.FC = (props) => {
+export const PullToRefreshList: React.FC = (props) => {
const pageSize = props.pageSize || 10;
const [orderList, setOrderList] = React.useState([]);
@@ -192,4 +192,3 @@ const PullToRefreshList: React.FC = (props) => {
)
}
-export default PullToRefreshList;
From 2ee53a892b4132189097f2786c0522461b3f176f Mon Sep 17 00:00:00 2001
From: lorne <1991wangliang@gmail.com>
Date: Wed, 14 May 2025 22:38:06 +0800
Subject: [PATCH 4/8] fix form
---
package.json | 2 +-
playground/src/App.tsx | 22 +++++++++++-----------
src/PullToRefreshList/index.tsx | 12 +++---------
3 files changed, 15 insertions(+), 21 deletions(-)
diff --git a/package.json b/package.json
index 9512f12..0d24ce0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@codingapi/form-mobile",
- "version": "0.0.26",
+ "version": "0.0.28",
"description": "A UI Framework built with React and TypeScript",
"keywords": [
"ui",
diff --git a/playground/src/App.tsx b/playground/src/App.tsx
index 8be3b8b..c5d765f 100644
--- a/playground/src/App.tsx
+++ b/playground/src/App.tsx
@@ -156,9 +156,9 @@ const FooterButtons: React.FC<{ formInstance: FormInstance }> = ({formInstance})
)
}
-const FormPage = ()=>{
+const App = ()=>{
- const [activeKey, setActiveKey] = React.useState("property");
+ const [activeKey, setActiveKey] = React.useState("left");
const leftFormInstance = Form.useForm();
const rightFormInstance = Form.useForm();
@@ -368,20 +368,20 @@ const FormPage = ()=>{
setActiveKey(value);
}}
>
-
-
+
+
- {activeKey ==='field' && (
+ {activeKey ==='left' && (
<>