# sula ruler

# 介绍

Sula-Ruler 是基于 rc-field-form 的 List 组件实现的,同时对于组件间通信和关联方面做了增强。Sula-Ruler主要解决了前端中台规则组件(例如左值、比较符、右值的复杂表单组件)开发成本高的问题。

# 特性

统一的表单组件管理能力 组件间通信与关联能力增强 内置视觉与交互规范 高效、高体验开发规则类复杂表单组件

# ruler 核心

# 使用方法

import Ruler from '@sula/ruler';
const {
  List,
  Row,
  Field,
} = Ruler;

示例

import React from "react";
import Ruler from "@sula/ruler";
import { Row, Col, Button, Select, Input } from "antd";

export default props => {
  const onChange = value => {}

  const onFieldValueChange = ctx => {
    if (ctx.value === '95') {
      ctx.setSiblingSource('level', [{ text: '终极', value: 'Super' }])
      ctx.setSiblingValue('level', 'Super')
    } else {
      if (ctx.getSiblingValue('level') === 'High') {
        ctx.setSiblingValue('level', 'High')
      }
    }
  }

  const onFieldDidMount = ctx => {
    if (ctx.name === 'level') {
      ctx.setSource([{ text: '高级', value: 'High' }])
    }
  }
  
  return (
    <div>
      <Ruler
        onChange={onChange}
        onFieldValueChange={onFieldValueChange}
        onFieldDidMount={onFieldDidMount}
      >
        {(lists, { add, remove }) => {
          const listElems = lists.map(list => {
            return (
              <Ruler.List name={list.name} key={list.key}>
                {(conditions, op) => {
                  const conditionElems = conditions.map(condition => {
                    return (
                      <Ruler.Row name={condition.name} key={condition.key}>
                        <Row type="flex">
                          <Col>
                            <Ruler.Field
                              name="singer"
                              key="singer"
                              rules={[{ required: true }]}
                            >
                              <Input
                                placeholder={`${list.name}-${condition.name}-singer`}
                              />
                            </Ruler.Field>
                          </Col>
                          <Col>
                            <Ruler.Field name="level" key="level">
                              {({
                                prevValue,
                                value,
                                getSiblingValue,
                                source,
                              }) => {
                                const singerValue = getSiblingValue('singer')
                                return (
                                  <Input
                                    placeholder={`${list.name}-${condition.name}-level`}
                                  />
                                )
                              }}
                            </Ruler.Field>
                          </Col>
                        </Row>
                      </Ruler.Row>
                    )
                  })
                  return (
                    <div
                      style={{
                        marginBottom: 16,
                        border: '1px solid green',
                        padding: 8,
                      }}
                    >
                      <Select style={{ width: 120 }} />
                      {conditionElems}
                      <div>
                        <Button
                          icon="plus"
                          onClick={() => {
                            op.add()
                          }}
                        >{`listName: ${list.name} - add field`}</Button>
                        <Button
                          type="danger"
                          icon="minus"
                          onClick={() => {
                            op.remove(1)
                          }}
                        >{`listName: ${list.name} - remove field 1`}</Button>
                      </div>
                    </div>
                  )
                }}
              </Ruler.List>
            )
          })

          return (
            <div>
              {listElems}
              <div>
                <Button
                  type="primary"
                  onClick={() => {
                    add()
                  }}
                >
                  add list
                </Button>{' '}
                <Button
                  onClick={() => {
                    remove(0)
                  }}
                >
                  remove list 0
                </Button>
              </div>
            </div>
          )
        }}
      </Ruler>
      <br />
    </div>
  )
};

# API

Ruler

参数 说明 类型 默认值
onChange 变化回调 Function(value: any[]) -
value 规则组件值 any[] -
onFieldValueChange 输入值变化时,用于一行中的组件存在关联的场景 Function(ctx: Ctx),见下 -
onFieldDidMount 当添加一个field时,产生的回调,通常你可以在这里设置field的初始数据源 Function(ctx: Ctx),见下 -
disabled 是否禁用 boolean false
children 渲染子元素 Function(lists: {name: number, key: number}[], operation: {add: Function, remove: Function(name: number)}): React.ReactElement -
hasValidate 是否支持校验条件,false时会使用更紧凑的展现方式 boolean true
interface Ctx {
  name: string;
  meta: Meta;
  prevValue: any;
  value: any;
  getSiblingValue: (name: string) => any;
  setSiblingValue: (name: string, value: any) => void;
  setSiblingValues: (values: { name: string; value: any }[]) => void;
  setSiblingSource: (name: string, source: any) => void;
  setSource(source: { text: string; value: any }[]); // 只有在onFieldDidMount才会有
}

Ruler.List

参数 说明 类型 默认值
name 永远为0~N(N为当前list个数)间的一个数字 number -
key 用于React数组节点的唯一key number -
children 渲染子元素 Function(rows: {name: number, key: number}[], operation: {add: Function, remove: Function(name: number)}): React.ReactElement -

Ruler.Row

参数 说明 类型 默认值
name 永远为0~N(N为当前Row个数)间的一个数字 number -
key 用于React数组节点的唯一key number -

Ruler.Field

参数 说明 类型 默认值
name 对应该表单组件在value中的key,例如name为level,value为[[{level: 'High'}]] string -
key 唯一key string -
rules 检验条件 string -
children 渲染子元素,render模式用于根据行其他表单元素不同值采用不同的呈现 ReactElement Function(ctx: Ctx): ReactElement,ctx见下
interface Ctx {
  name: string;
  meta: Meta;
  prevValue: any;
  value: any;
  getSiblingValue: (name: string) => any;
}

# RulerRow 行条件

# 使用方法

import RulerRow from '@sula-ruler/row';

# API

RulerRow

参数 说明 类型 默认值
add 增加一行的调用方法 Function -
remove 删除当前行的调用方法 Function(name: number) -
fields 一行中的表单元素定义 Field[],见下 -
key 用于React数组节点的唯一key number -
name 永远为0~N(N为当前Row个数)间的一个数字 number -
style 样式 React.CSSProperties -
className 样式类 string -
interface Field {
  name: string;
| defaultValue: any; // 该field的初始值
  getValueFromEvent?: (...args: EventArgs) => any;
  valuePropName?: string;
  trigger?: string;
  children: React.ReactElement | ((ctx: Ctx) => React.ReactNode);
  rules?: Rule[];
  render: React.ReactElement | ((ctx: Ctx) => React.ReactNode);
  span?: number;
}
interface Ctx {
  name: string;
  meta: Meta;
  prevValue: any;
  value: any;
  getSiblingValue: (name: string) => any;
}

# RuleList 多行条件

# 使用方法

import RulerList from '@sula-ruler/list';

# API

RulerList

参数 说明 类型 默认值
range list中展示的行数范围 [number, number] -
fields 一行中的表单元素定义 Field[],见下 -
key 用于React数组节点的唯一key number -
name 永远为0~N(N为当前Row个数)间的一个数字 number -
children 渲染子元素 Function(lists: {name: number, key: number}[], operation: {add: Function, remove: Function(name: number)}): React.ReactElement -
interface Field {
  name: string;
  getValueFromEvent?: (...args: EventArgs) => any;
  valuePropName?: string;
  trigger?: string;
  children: React.ReactElement | ((ctx: Ctx) => React.ReactNode);
  rules?: Rule[];
  render: React.ReactElement | ((ctx: Ctx) => React.ReactNode);
  span?: number;
}
interface Ctx {
  name: string;
  meta: Meta;
  prevValue: any;
  value: any;
  getSiblingValue: (name: string) => any;
}

# Condition 多条件

# 使用方法

import Condition from "@sula-ruler/condition";

示例:

import React from 'react';
import Condition from '@sula-ruler/condition';
import { Input } from 'antd';

const fields = [{
  name: "source",
  span: 8,
  render: (ctx) => {
    const { source = [] } = ctx;
    return (
    <Select placeholder="远程数据源" style={{ width: "100%" }}>
      {source.map((item) => {
        return <Option key={item.id}>{item.title}</Option>;
      })}
    </Select>
  )}
}, {
  name: 'fruit',
  span: 8,
  defaultValue: '苹果',
  render: <Input placeholder="水果" />
}, {
  name: 'price',
  span: 8,
  defaultValue: 10,
  render: <Input placeholder="价格" />
}]
const ConditionRule = (props) => {
  const [value, setValue] = React.useState([{fruit: '苹果', price: 10}]);
  const handleChange = (val) => {
    console.log('value: ', val);
    setValue(val);
  };

  const onFieldDidMount = (ctx) => {
    fetch({
      url: 'https://jsonplaceholder.typicode.com/posts'
    }).then(source => {
      if(ctx.name === 'source') {
        ctx.setSource(source);
      }
    });
  }

  const onFieldValueChange = ctx => {
    const { value, setSiblingValue } = ctx;
    if (value === "apple") {
      setSiblingValue("price", 10);
    } else {
      setSiblingValue("price", 15);
    }
  };

  return <Condition  
    range={[1]} 
    onChange={handleChange} 
    value={value} 
    fields={fields} 
    onFieldDidMount={onFieldDidMount}
    onFieldValueChange={onFieldValueChange}
    />
}

export default () => <ConditionRule />;

# API

参数 说明 类型 默认值
range list中展示的行数范围 [number] -
fields 一行中的表单元素定义 Field[],见下 -
onChange 变化回调 Function(value: any[]) -
onFieldValueChange 输入值变化时,用于一行中的组件存在关联的场景 Function(ctx: Ctx),见下 -
onFieldDidMount 当添加一个field时,产生的回调,通常你可以在这里设置field的初始数据源 Function(ctx: Ctx),见下 -
value 规则组件值 any[] -
disabled 是否禁用 boolean false
hasValidate 是否支持校验条件,false时会使用更紧凑的展现方式 boolean true

# ConditionGroup 分组多行条件

ConditionGroup对Ruler和RulerList进行了封装,你可以直接使用ConditionGroup是实现分组多条件呈现。

# 使用方法

import ConditionGroup from '@sula-ruler/condition-group';

示例:

import React from "react";
import ConditionGroup from "@sula-ruler/condition-group";
import { Input } from "antd";

const fields = [
  {
    name: "fruit",
    span: 12,
    render: <Input placeholder="水果" />
  },
  {
    name: "price",
    span: 12,
    render: <Input placeholder="价格" />
  }
];
const ConditionGroupRule = props => {
  const [value, setValue] = React.useState([[{fruit: '苹果', price: 10}]]);
  const handleChange = val => {
    console.log("value: ", val);
    setValue(val);
  };

  return (
    <ConditionGroup
      titleRender={name => `Group ${name}`}
      onChange={handleChange}
      value={value}
      fields={fields}
      range={[1]}
      groupRange={[1]}
    ></ConditionGroup>
  );
};

export default () => <ConditionGroupRule />;

# API

参数 说明 类型 默认值
range list中展示的行数范围 [number] -
fields 一行中的表单元素定义 Field[],见下 -
onChange 变化回调 Function(value: any[]) -
onFieldValueChange 输入值变化时,用于一行中的组件存在关联的场景 Function(ctx: Ctx),见下 -
onFieldDidMount 当添加一个field时,产生的回调,通常你可以在这里设置field的初始数据源 Function(ctx: Ctx),见下 -
value 规则组件值 any[] -
disabled 是否禁用 boolean false
hasValidate 是否支持校验条件,false时会使用更紧凑的展现方式 boolean true
titleRender 组标题 Function() -
groupRange 最少组数 [number] -
Last Updated: 2020/4/1 下午3:58:41