• English
  • Component Overview

    ProComponents was developed to reduce the cost of implementing CRUD in the middle and backend, with the idea of reducing the necessary state maintenance and focusing more on the business.

    • ProLayout solves the layout problem and provides out-of-the-box menu and breadcrumb functionality
    • ProTable solves table issues, abstracts web requests and table formatting
    • ProForm solves form issues, pre-defines common layouts and behaviors
    • ProCard provides card slicing and raster layout capabilities
    • ProDescriptions provides the ability to use the same configuration as a table
    • ProSkeleton Page level skeleton screen

    Form layout toggle

    The main feature of ProForm is that it has a lot of pre-defined layouts, so if you need to switch you just need to change the Layout of the outer wrapper, here is a demo.

    Effective after stamping
    请选择
    %
    import {
      AlipayCircleOutlined,
      LockOutlined,
      PlusOutlined,
      TaobaoCircleOutlined,
      UserOutlined,
      WeiboCircleOutlined,
    } from '@ant-design/icons';
    import {
      DrawerForm,
      LightFilter,
      LoginForm,
      ModalForm,
      ProForm,
      ProFormDateRangePicker,
      ProFormDigit,
      ProFormRadio,
      ProFormSelect,
      ProFormText,
      QueryFilter,
      StepsForm,
    } from '@ant-design/pro-components';
    import { Button, Space, message } from 'antd';
    import { useState } from 'react';
    
    const iconStyles = {
      marginInlineStart: '16px',
      color: 'rgba(0, 0, 0, 0.2)',
      fontSize: '24px',
      verticalAlign: 'middle',
      cursor: 'pointer',
    };
    
    const waitTime = (time: number = 100) => {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(true);
        }, time);
      });
    };
    
    const Demo = () => {
      const Components = {
        ProForm,
        ModalForm,
        DrawerForm,
        QueryFilter,
        LightFilter,
        StepsForm,
        LoginForm,
      };
      const [type, setType] = useState<keyof typeof Components>('ProForm');
    
      if (type === 'StepsForm') {
        return (
          <>
            <ProFormRadio.Group
              style={{
                margin: 16,
              }}
              radioType="button"
              fieldProps={{
                value: type,
                onChange: (e) => setType(e.target.value),
              }}
              options={[
                'LightFilter',
                'ProForm',
                'ModalForm',
                'DrawerForm',
                'QueryFilter',
                'StepsForm',
                'LoginForm',
              ]}
            />
            <StepsForm
              onFinish={async () => {
                await waitTime(2000);
    
                message.success('Submission successful');
              }}
            >
              <StepsForm.StepForm title="Step One">
                <ProForm.Group>
                  <ProFormText
                    width="md"
                    name="name"
                    label="Contract Customer Name"
                    tooltip="Up to 24 characters"
                    placeholder="Please enter a name"
                  />
                  <ProFormText
                    width="md"
                    name="company"
                    label="Our Company Name"
                    placeholder="Please enter a name"
                  />
                </ProForm.Group>
                <ProForm.Group>
                  <ProFormText
                    name={['contract', 'name']}
                    width="md"
                    label="Contract Name"
                    placeholder="Please enter a name"
                  />
                  <ProFormDateRangePicker
                    width="md"
                    name={['contract', 'createTime']}
                    label="Contract Effective Time"
                  />
                </ProForm.Group>
              </StepsForm.StepForm>
              <StepsForm.StepForm title="Step Two">
                <ProForm.Group>
                  <ProFormSelect
                    options={[
                      {
                        value: 'chapter',
                        label: 'Effective after stamping',
                      },
                    ]}
                    readonly
                    width="xs"
                    name="useMode"
                    label="Contract Agreed Effective Method"
                  />
                  <ProFormSelect
                    width="xs"
                    options={[
                      {
                        value: 'time',
                        label: 'Terminate after performance',
                      },
                    ]}
                    name="unusedMode"
                    label="Contract Agreed Invalid Method"
                  />
                </ProForm.Group>
              </StepsForm.StepForm>
              <StepsForm.StepForm title="Step Three">
                <ProFormText width="sm" name="id" label="Main Contract Number" />
                <ProFormText
                  name="project"
                  width="md"
                  disabled
                  label="Project Name"
                  initialValue="示例项目"
                />
                <ProFormText
                  width="xs"
                  name="mangerName"
                  disabled
                  label="Business Manager"
                  initialValue="书琰"
                />
              </StepsForm.StepForm>
            </StepsForm>
          </>
        );
      }
    
      const FormComponents = Components[type as 'LoginForm'];
    
      if (type === 'LoginForm') {
        return (
          <>
            <ProFormRadio.Group
              style={{
                margin: 16,
              }}
              radioType="button"
              fieldProps={{
                value: type,
                onChange: (e) => setType(e.target.value),
              }}
              options={[
                'LightFilter',
                'ProForm',
                'ModalForm',
                'DrawerForm',
                'QueryFilter',
                'StepsForm',
                'LoginForm',
              ]}
            />
            <FormComponents
              title="Github"
              subTitle="The world's largest code hosting platform"
              actions={
                <Space>
                  Other login methods
                  <AlipayCircleOutlined style={iconStyles} />
                  <TaobaoCircleOutlined style={iconStyles} />
                  <WeiboCircleOutlined style={iconStyles} />
                </Space>
              }
            >
              <ProFormText
                name="username"
                fieldProps={{
                  size: 'large',
                  prefix: <UserOutlined className={'prefixIcon'} />,
                }}
                placeholder={'Username: admin or user'}
                rules={[
                  {
                    required: true,
                    message: 'Please enter your username!',
                  },
                ]}
              />
              <ProFormText.Password
                name="password"
                fieldProps={{
                  size: 'large',
                  prefix: <LockOutlined className={'prefixIcon'} />,
                }}
                placeholder={'Password: ant.design'}
                rules={[
                  {
                    required: true,
                    message: 'Please enter your password!',
                  },
                ]}
              />
            </FormComponents>
          </>
        );
      }
    
      return (
        <>
          <ProFormRadio.Group
            style={{
              margin: 16,
            }}
            radioType="button"
            fieldProps={{
              value: type,
              onChange: (e) => setType(e.target.value),
            }}
            options={[
              'LightFilter',
              'ProForm',
              'ModalForm',
              'DrawerForm',
              'QueryFilter',
              'StepsForm',
              'LoginForm',
            ]}
          />
          <div
            style={{
              margin: 24,
            }}
          >
            <FormComponents
              // @ts-ignore
              labelWidth="auto"
              trigger={
                <Button type="primary">
                  <PlusOutlined />
                  New Form
                </Button>
              }
              onFinish={async () => {
                await waitTime(500);
                message.success('Submission successful');
              }}
              initialValues={{
                name: 'Ant Design Co., Ltd.',
                useMode: 'chapter',
              }}
            >
              <ProForm.Group>
                <ProFormText
                  width="md"
                  name="name"
                  label="Contract Customer Name"
                  tooltip="Up to 24 characters"
                  placeholder="Please enter a name"
                />
                <ProFormText
                  width="md"
                  name="company"
                  label="Our Company Name"
                  placeholder="Please enter a name"
                />
              </ProForm.Group>
              <ProForm.Group>
                <ProFormText
                  name={['contract', 'name']}
                  width="md"
                  label="Contract Name"
                  placeholder="Please enter a name"
                />
                <ProFormDateRangePicker
                  width="md"
                  name={['contract', 'createTime']}
                  label="Contract Effective Time"
                />
              </ProForm.Group>
              <ProForm.Group>
                <ProFormSelect
                  options={[
                    {
                      value: 'chapter',
                      label: 'Effective after stamping',
                    },
                  ]}
                  readonly
                  width="xs"
                  name="useMode"
                  label="Contract Agreed Effective Method"
                />
                <ProFormSelect
                  width="xs"
                  options={[
                    {
                      value: 'time',
                      label: 'Terminate after performance',
                    },
                  ]}
                  name="unusedMode"
                  label="Contract Agreed Invalid Method"
                />
              </ProForm.Group>
              <ProFormText width="sm" name="id" label="Main Contract Number" />
              <ProFormText
                name="project"
                width="md"
                disabled
                label="Project Name"
                initialValue="示例项目"
              />
              <ProFormText
                width="xs"
                name="mangerName"
                disabled
                label="Business Manager"
                initialValue="书琰"
              />
              <ProFormDigit
                name="percent"
                label="Percent"
                width="xs"
                min={1}
                max={10}
                fieldProps={{
                  precision: 2,
                  addonAfter: '%',
                }}
              />
            </FormComponents>
          </div>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Configuring Use with the Web Request Library

    ProTable, ProList uses a new data structure which is very easy to use if you use the parameters we have agreed upon.

    const msg: {
      data: T[];
      page: number;
      success: boolean;
      total: number;
    } = {
      data: [],
      page: 1,
      success: true,
      total: 0,
    };

    If your backend data uses a familiar url, we could use a request to convert it, but it would be a pain to configure each table. If you're using umi's request, we can define a global transformer. We need to configure this in app.tsx

    import type { RequestConfig } from 'umi';
    
    export const request: RequestConfig = {
      errorConfig: {
        adaptor: (resData) => {
          return {
            ...resData,
            total: resData.sum,
            success: resData.ok,
            errorMessage: resData.message,
          };
        },
      },
    };

    When using UMI request:

    import { request } from 'umi';
    
    <ProTable request={request('/list')} />;

    If fetch is used, you can customize fetch.

    const request = (url, options) => {
      return fetch(url, options)
        .then((res) => res.json())
        .then((resData) => {
          return Promise.resolve({
            ...resData,
            total: resData.sum,
            success: resData.ok,
            errorMessage: resData.message,
          });
        });
    };
    
    // when used
    <ProTable request={request('/list')} />;

    General Configuration

    ProTable, ProDescriptions share a common set of configurations that can use the same columns and requests to generate data, the only difference being that Table requires an array, while ProDescriptions only requires an object. Here are the specific configurations.

    /**
     * Commonly supported render for each component
     */
    export type ProSchema<T = unknown, U = string, Extra = unknown> = {
      /**
       * @name Determines the unique value of this column
       */
      key?: (string | number);
      /**
       * @name The key mapped to the entity
       * @description supports a number, [a,b] will be converted to obj.a.b
       */
      dataIndex?: string | number | (string | number)[];
      /**
       * Select how to render the corresponding pattern
       */
      valueType?: ((entity: T, type: ProSchemaComponentTypes) => U) | U;
    
      /**
       * @name title
       * @description supports ReactNode and methods
       */
      title?:
        | ((
            schema: ProSchema<T, U, Extra>,
            type: ProSchemaComponentTypes,
            dom: React.ReactNode,
          ReactNode, ) => React.)
        | ReactNode;
    
      /**
       *@name shows an icon, hover shows some hints
       */
      tooltip?: LabelTooltipType | string;
    
      render?: (
        dom: React.ReactNode,
        entity: T,
        index: number,
        action: ProCoreActionType,
        schema: ProSchema<T, U, Extra>,
      ) => React.ReactNode;
    
      /**
       * @name Customize the edit schema
       * @description returns a node that will automatically wrap value and onChange
       */
      formItemRender?: (
        item: ProSchema<T, U, Extra>,
        config: {
          index?: number;
          value?: any;
          onSelect?: (value: any) => void;
          type: ProSchemaComponentTypes;
          defaultRender: (newItem: ProSchema<T, U, Extra>) => JSX.Element | null;
        },
        form: FormInstance,
      ) => React.ReactNode;
    
      /**
       * @name Custom render
       * @description must return string
       */
      renderText?: (text: any, record: T, index: number, action: ProCoreActionType) => any;
    
      fieldProps?: any;
      /**
       * @name The type of the mapped value
       */
      valueEnum?: ProSchemaValueEnumObj | ProSchemaValueEnumMap;
    
      /**
       * @name request enum from server
       */
      request?: ProFieldRequestData<ProSchema>;
    
      /**
       * @name Parameter requested from the server, changes will trigger a reload
       */
      params?: {
        [key: string]: any;
      };
      /**
       * @name hidden in descriptions
       */
      hideInDescriptions?: boolean;
    } & Extra;