listpage-next 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
File without changes
@@ -0,0 +1,17 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+ import { FormItemProps } from 'antd';
3
+ import { ComponentType } from '../../typings';
4
+ export interface FilterFormOption {
5
+ name: string;
6
+ label?: ReactNode;
7
+ component?: ComponentType | ReactElement;
8
+ colSpan?: number;
9
+ formItemProps?: Omit<FormItemProps, 'children'>;
10
+ }
11
+ export interface FilterFormProps<FormValue = any> {
12
+ options: FilterFormOption[];
13
+ initialValues?: FormValue;
14
+ onSubmit?: (values?: FormValue) => void;
15
+ onReset?: () => void;
16
+ }
17
+ export declare const FilterForm: <T = any>({ options, initialValues, onSubmit, onReset, }: FilterFormProps<T>) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,56 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useRef } from "react";
3
+ import { Button, Form, Space } from "antd";
4
+ import { FilterGridLayout } from "../FilterGridLayout/index.js";
5
+ import { getComponent } from "../../utils/getComponent.js";
6
+ import { FilterItem } from "../FilterItem/index.js";
7
+ const FilterForm = ({ options, initialValues, onSubmit, onReset })=>{
8
+ const formRef = useRef(null);
9
+ const items = useMemo(()=>(options ?? []).map(({ colSpan, component, label, ...props })=>{
10
+ const renderComponent = getComponent(component);
11
+ return {
12
+ key: props.name,
13
+ node: /*#__PURE__*/ jsx(FilterItem, {
14
+ label: label,
15
+ formItemProps: props,
16
+ children: renderComponent
17
+ }),
18
+ colSpan: colSpan || 2
19
+ };
20
+ }), [
21
+ options
22
+ ]);
23
+ const handleSubmit = ()=>{
24
+ const values = formRef.current?.getFieldsValue();
25
+ onSubmit?.(values);
26
+ };
27
+ const handleReset = ()=>{
28
+ formRef.current?.resetFields();
29
+ onReset?.();
30
+ };
31
+ return /*#__PURE__*/ jsxs(Form, {
32
+ ref: formRef,
33
+ initialValues: initialValues ?? {},
34
+ children: [
35
+ /*#__PURE__*/ jsx(FilterGridLayout, {
36
+ items: items
37
+ }),
38
+ /*#__PURE__*/ jsxs(Space, {
39
+ children: [
40
+ /*#__PURE__*/ jsx(Button, {
41
+ onClick: handleSubmit,
42
+ type: "primary",
43
+ htmlType: "submit",
44
+ children: "提交"
45
+ }),
46
+ /*#__PURE__*/ jsx(Button, {
47
+ onClick: handleReset,
48
+ htmlType: "reset",
49
+ children: "重置"
50
+ })
51
+ ]
52
+ })
53
+ ]
54
+ });
55
+ };
56
+ export { FilterForm };
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ export interface FilterGridLayoutProps {
3
+ items: {
4
+ node: React.ReactNode;
5
+ key: string;
6
+ colSpan?: number;
7
+ }[];
8
+ }
9
+ export declare const FilterGridLayout: (props: FilterGridLayoutProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import "react";
3
+ import styled_components from "styled-components";
4
+ const GridContainer = styled_components.div`
5
+ display: grid;
6
+ grid-template-columns: repeat(12, 1fr);
7
+ gap: 1rem;
8
+ `;
9
+ const GridItem = styled_components.div`
10
+ grid-column: span ${(props)=>props.$colSpan};
11
+ `;
12
+ const FilterGridLayout = (props)=>{
13
+ const { items } = props;
14
+ return /*#__PURE__*/ jsx(GridContainer, {
15
+ children: items.map((item, i)=>/*#__PURE__*/ jsx(GridItem, {
16
+ $colSpan: item.colSpan || 12,
17
+ children: item.node
18
+ }, item.key))
19
+ });
20
+ };
21
+ export { FilterGridLayout };
@@ -0,0 +1,8 @@
1
+ import { FormItemProps } from 'antd';
2
+ import { ReactElement, ReactNode } from 'react';
3
+ export interface FilterItemProps {
4
+ label?: ReactNode;
5
+ children: ReactElement;
6
+ formItemProps: FormItemProps;
7
+ }
8
+ export declare const FilterItem: (props: FilterItemProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,46 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Form } from "antd";
3
+ import { LabelWrapper } from "../LabelWrapper/index.js";
4
+ import { cloneElement, useState } from "react";
5
+ import { omit } from "lodash";
6
+ const FilterItem = (props)=>{
7
+ const { label, children, formItemProps } = props;
8
+ const [focus, setFocus] = useState(false);
9
+ return /*#__PURE__*/ jsx(Form.Item, {
10
+ ...omit(formItemProps, [
11
+ 'name'
12
+ ]),
13
+ shouldUpdate: true,
14
+ noStyle: true,
15
+ children: (form)=>{
16
+ const errors = form.getFieldError(formItemProps.name);
17
+ const value = form.getFieldValue(formItemProps.name);
18
+ const valuePropName = formItemProps.valuePropName || 'value';
19
+ const triggerPropsName = formItemProps.trigger || 'onChange';
20
+ const onChange = (v)=>{
21
+ form.setFieldValue(formItemProps.name, v);
22
+ };
23
+ const onFocus = ()=>{
24
+ setFocus(true);
25
+ };
26
+ const onBlur = ()=>{
27
+ setFocus(false);
28
+ };
29
+ const realChildren = /*#__PURE__*/ cloneElement(children, {
30
+ [valuePropName]: value,
31
+ [triggerPropsName]: onChange,
32
+ onFocus,
33
+ onBlur
34
+ });
35
+ const disabled = children.props.disabled;
36
+ const status = disabled ? 'disabled' : focus ? 'focused' : errors?.length ? 'error' : void 0;
37
+ return /*#__PURE__*/ jsx(LabelWrapper, {
38
+ status: status,
39
+ errors: errors,
40
+ label: label,
41
+ children: realChildren
42
+ });
43
+ }
44
+ });
45
+ };
46
+ export { FilterItem };
@@ -0,0 +1,8 @@
1
+ import { ReactElement, ReactNode } from 'react';
2
+ export interface LabelWrapperProps<V = any> {
3
+ label?: ReactNode;
4
+ status?: 'disabled' | 'error' | 'focused';
5
+ children: ReactElement;
6
+ errors?: string[];
7
+ }
8
+ export declare const LabelWrapper: <T = any>({ label, status, children, errors, }: LabelWrapperProps<T>) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,65 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import styled_components from "styled-components";
3
+ const WrapperContainer = styled_components.div`
4
+ position: relative;
5
+ margin-bottom: 1.5rem;
6
+ `;
7
+ const ChildrenContainer = styled_components.div`
8
+ & > div {
9
+ width: 100%;
10
+ }
11
+ `;
12
+ const Label = styled_components.label`
13
+ position: absolute;
14
+ left: 1rem;
15
+ top: -10px;
16
+ background: transparent;
17
+ padding: 0 0.5rem;
18
+ font-size: 0.75rem;
19
+ font-weight: 400;
20
+ z-index: 10;
21
+ transition: all 0.2s ease-in-out;
22
+
23
+ /* 使用 text-shadow 为文字添加白色背景效果 */
24
+ text-shadow:
25
+ -3px -3px 0 white,
26
+ 2px -2px 0 white,
27
+ -2px 2px 0 white,
28
+ 2px 2px 0 white,
29
+ 0 -3px 2px white,
30
+ 0 3px 2px white,
31
+ -3px 0 2px white,
32
+ 3px 0 2px white,
33
+ -1px -1px 1px white,
34
+ 1px -1px 1px white,
35
+ -1px 1px 1px white,
36
+ 1px 1px 1px white;
37
+
38
+ color: ${(props)=>{
39
+ if ('disabled' === props.$status) return '#9ca3af';
40
+ if ('error' === props.$status) return '#ef4444';
41
+ if ('focused' === props.$status) return '#3b82f6';
42
+ return '#374151';
43
+ }};
44
+ `;
45
+ const ErrorMessage = styled_components.div`
46
+ color: #ef4444;
47
+ font-size: 0.75rem;
48
+ margin-top: 0.25rem;
49
+ `;
50
+ const LabelWrapper = ({ label, status, children, errors = [] })=>/*#__PURE__*/ jsxs(WrapperContainer, {
51
+ children: [
52
+ /*#__PURE__*/ jsx(Label, {
53
+ htmlFor: "label",
54
+ $status: status,
55
+ children: label
56
+ }),
57
+ /*#__PURE__*/ jsx(ChildrenContainer, {
58
+ children: children
59
+ }),
60
+ errors?.length > 0 && /*#__PURE__*/ jsx(ErrorMessage, {
61
+ children: errors.join(', ')
62
+ })
63
+ ]
64
+ });
65
+ export { LabelWrapper };
@@ -0,0 +1,2 @@
1
+ export { FilterForm } from './components/FilterForm';
2
+ export type { FilterFormOption } from './components/FilterForm';
@@ -0,0 +1,2 @@
1
+ import { FilterForm } from "./components/FilterForm/index.js";
2
+ export { FilterForm };
@@ -0,0 +1 @@
1
+ export type ComponentType = 'input' | 'select';
@@ -0,0 +1 @@
1
+ export * from './component';
@@ -0,0 +1 @@
1
+ export * from "./component.js";
@@ -0,0 +1,3 @@
1
+ import { ReactElement } from 'react';
2
+ import { ComponentType } from '../typings/component';
3
+ export declare const getComponent: (component?: ReactElement | ComponentType) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Input, Select } from "antd";
3
+ const EnhancedInput = (props)=>/*#__PURE__*/ jsx(Input, {
4
+ ...props,
5
+ onChange: (e)=>props.onChange?.(e.target.value)
6
+ });
7
+ const getComponent = (component)=>{
8
+ if ('string' == typeof component) {
9
+ const type = component;
10
+ if ('input' === type) return /*#__PURE__*/ jsx(EnhancedInput, {});
11
+ if ('select' === type) return /*#__PURE__*/ jsx(Select, {});
12
+ }
13
+ if (component) return component;
14
+ return /*#__PURE__*/ jsx(EnhancedInput, {});
15
+ };
16
+ export { getComponent };
@@ -0,0 +1 @@
1
+ export declare const Demo1: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,36 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { DatePicker, Select } from "antd";
3
+ import { FilterForm } from "../index.js";
4
+ const Demo1 = ()=>{
5
+ const options = [
6
+ {
7
+ name: 'title',
8
+ label: '标题',
9
+ component: 'input'
10
+ },
11
+ {
12
+ name: 'type',
13
+ label: '类型',
14
+ component: /*#__PURE__*/ jsx(Select, {})
15
+ },
16
+ {
17
+ name: 'region',
18
+ label: '区域',
19
+ component: /*#__PURE__*/ jsx(Select, {})
20
+ },
21
+ {
22
+ name: 'dateRange',
23
+ label: '发布日期',
24
+ component: /*#__PURE__*/ jsx(DatePicker.RangePicker, {}),
25
+ colSpan: 4
26
+ }
27
+ ];
28
+ const onSubmit = (values)=>{
29
+ console.log(values);
30
+ };
31
+ return /*#__PURE__*/ jsx(FilterForm, {
32
+ options: options,
33
+ onSubmit: onSubmit
34
+ });
35
+ };
36
+ export { Demo1 };
@@ -0,0 +1,2 @@
1
+ import '@ant-design/v5-patch-for-react-19';
2
+ export { FilterForm } from './components/FilterGroup';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import "@ant-design/v5-patch-for-react-19";
2
+ import { FilterForm } from "./components/FilterGroup/index.js";
3
+ export { FilterForm };
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "listpage-next",
3
+ "version": "0.0.1",
4
+ "description": "A React component library for creating filter forms with Ant Design",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "types": "./dist/index.d.ts",
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "keywords": [
19
+ "react",
20
+ "antd",
21
+ "filter",
22
+ "form",
23
+ "component",
24
+ "typescript"
25
+ ],
26
+ "license": "MIT",
27
+ "scripts": {
28
+ "build": "rslib build",
29
+ "dev": "npx storybook dev",
30
+ "format": "prettier --write .",
31
+ "prepublishOnly": "npm run build"
32
+ },
33
+ "devDependencies": {
34
+ "@rsbuild/core": "^1.5.7",
35
+ "@rsbuild/plugin-react": "^1.4.0",
36
+ "@rslib/core": "^0.13.3",
37
+ "@storybook/addon-essentials": "^8.6.14",
38
+ "@types/lodash": "^4.17.20",
39
+ "@types/react": "^19.1.13",
40
+ "@types/styled-components": "^5.1.34",
41
+ "prettier": "^3.6.2",
42
+ "react": "^19.1.1",
43
+ "storybook": "^8.6.14",
44
+ "storybook-addon-rslib": "^1.0.3",
45
+ "storybook-react-rsbuild": "^1.0.3",
46
+ "@storybook/test": "^8.6.14",
47
+ "@ant-design/v5-patch-for-react-19": "^1.0.3",
48
+ "typescript": "^5.9.2"
49
+ },
50
+ "peerDependencies": {
51
+ "react": ">=16.9.0",
52
+ "react-dom": ">=16.9.0"
53
+ },
54
+ "dependencies": {
55
+ "ahooks": "^3.9.5",
56
+ "antd": "^5.27.3",
57
+ "dayjs": "^1.11.18",
58
+ "lodash": "^4.17.21",
59
+ "styled-components": "^6.1.19"
60
+ }
61
+ }