cofi

cofi

  • Docs
  • Form Demos
  • Components Demos
  • Layout Demos
  • Editor
  • GitHub

›React Form

Getting started

  • Introduction

Form Class

  • Installation
  • Overview
  • Arguments
  • Id
  • Data
  • Fields
  • Path
  • Component
  • Formatter & Parser
  • Dependencies
  • Required
  • Validators
  • Exclude Term
  • Disable Term
  • Require Term
  • Dependencies Change
  • Context
  • Dirty
  • Invalid
  • Errors
  • Processing
  • Pending Actions
  • Hooks
  • Term
  • Log
  • Error Codes
  • Actions
  • Definition Shorthand

Advanced Usages

  • Grid Usage
  • Form Persistency
  • Undo & Redo
  • Replay Actions
  • Track Actions
  • Server Validation
  • Entity Templates
  • Folder Structure

React Form

  • Installation
  • Overview
  • Form
  • Field
  • Components
  • Layout
  • Demos

Tools

  • Editor
  • DevTools

More Info

  • Test Cofi
  • Packages
  • Why Cofi?
  • Technologies
  • Videos
  • Channels

Contribute

  • Code of Conduct
  • Contributing Guide
  • Contributors

Components

Unified api components - a set of stateless / stateful components that use the same set of props, and render real components inside (for instance - TextInput ). Components are rendered in a generic way using FieldView component render function. These components can serve as a mapping layer between Cofi form and other internal components (such as Material UI components). Props include a number of callbacks that notify a change, such as onValueChange.

Stateless Vs Stateful Components

Using stateless components in a Field is recommended. It enables storing the entire form state in a specific point as part of a single json object. Afterwards, the object can be used to init cofi from the same status and resume the action without interruption. (Useful for state persistence between page refreshes, form templates, debugging and etc.)

However, you can use stateful components as well, without using state and onStateChange props, and without defining field.component.state and field.component.stateChange in a Field definition. In that case field.component.state will not be updated in the form store, but instead will need state maintenance inside the component itself. You can still use field.component.state in that case as the initial state of the component.

For more info please view stateful component and stateless component

Props

NameTypeDescription
valueanyData represented by the component. The Field will inject the value to the component from the model.data using the field.path, and will update the model.data with the new value that the onValueChange callback prop supplies
stateobjectCurrent ui state of the component. The Field will inject the current ui state to the component from the field.component.state, and will update the field.component.state with the new state that the onStateChange callback prop supplies
disabledbooleanIf true, component indicates disabled (should disable all functionality and apply corresponding styling)
dirtybooleanIf true, component indicates dirty
emptybooleanIf true, component indicates empty
requiredbooleanIf true, component indicates required
invalidbooleanIf true, component indicates invalid. (For example, apply red border styling for component)
onValueChangefunctionA function that propagates a new value to be changed in the form. Function's arg is a value or an updater function as described in changeValue action
onStateChangefunctionA function that propagates a new ui state to be changed in the form. Function's arg is a state object or an updater function as described in changeState action

Example

Simple Example

import React from 'react';
import Input from '@mui/material/Input';

export default ({ value = '', state = {}, onValueChange }) => <Input
  value={value}
  onChange={(e) => onValueChange(e.target.value)}
  type={state.type}
  placeholder={state.placeholder}
/>

Advanced example

import React from 'react';
import InternalCheckboxCollection from 'some-components-library/CheckboxCollection';

export default ({ value = [] state, disabled, invalid, onValueChange, onStateChange }) => {

  const onItemCheckChange = (e, checked) => {
    // pass a new value object to the hook
    const itemValue = e.target.value;
    const newValue = [...value];
    
    if (checked) {
      newValue.push(itemValue);
    } else {
      newValue.splice(value.indexOf(itemValue), 1);
    }

    onValueChange(newValue);
  };

  const onSearchFilterChange = (filter) => {
    // pass a new state object to the hook
    const newState = { ...state, search: { ...state.search, value: filter } };
    onStateChange(newState);
  }

  return <InternalCheckboxCollection
    search={state.search}
    items={state.items}
    inline={state.inline}
    value={value}
    disabled={disabled}
    onCheckChange={onItemCheckChange}
    onSearchChange={onSearchFilterChange}
  />;
}

Utils

toCofi

To use existing components library in a form (such as Material UI) - a map from the Cofi component generic props to the existing component props is needed.

Example - using react functional component

/* Input.js */
import React from 'react';
import Input from '@mui/material/Input';

export default ({ value = '', state = {}, disabled = false, onValueChange }) => <Input
  type={state.type}
  placeholder={state.placeholder}
  value={value}
  disabled={disabled}
  onChange={(e) => onValueChange(e.target.value)}
/>

Example - using toCofi HOC

/* Input.js */
import { toCofi } from '@cofi/react-components/utils';
import Input from '@mui/material/Input';

export const mapper = ({ value = '', disabled = false, state = {}, onValueChange }) => ({
  type: state.type
  placeholder: state.placeholder,
  value,
  disabled,
  onChange: (e) => onValueChange(e.target.value),
});

export default toCofi(Input, mapper);

Using the above HOC saves the react import as well as simplify tests (More info).

Our Common Components

We have a collection of common components with unified api that can be used, documented here: common components

For instance:

// import input text component
import Text from '@cofi/react-components/edit/Text'

// import text label component
import Text from '@cofi/react-components/view/Text'

We plan to keep @cofi/react-component as generic as possible. We also define all the params under state to be stringify (for example, we don't pass components or functions in the state object) - in order to keep our common components stateless to support persistency. In your project, if a custom cofi component needs a non-strigify data, you can:

  • Define a resourceId in the component state (i.e someField.component.state.resourceId = 'myExtraData').
  • Define the resource under the resources object (i.e resources.myExtraData = () => {})
  • Consume Cofi's context in the component, and get the resource from context.resources[props.state.resourceId]

In our common components we used Material UI as our base components. If your app uses Material UI along with styled components like we did in our form and layout demos, you will need to wrap your app's Root component with StylesProvider of Material UI in order to fix their class names collision that causing ui to break.

Example form our demos:

import { createGenerateClassName, StylesProvider } from '@mui/styles';

const generateClassName = createGenerateClassName({
  productionPrefix: 'cofi-react-form-demos',
});

<StylesProvider generateClassName={generateClassName}>
  <Root />
</StylesProvider>
← FieldLayout →
  • Stateless Vs Stateful Components
  • Props
  • Example
  • Utils
    • toCofi
  • Our Common Components
cofi
Copyright © 2021 Verizon Media
DOCS
IntroductionForm ClassReact FormReact ComponentsReact Layout
DEMOS
React FormReact ComponentsReact Layout
CONTRIBUTING
Code Of ConductContributing GuideContributorsUsers
CHANNELS
StarGitHubStack OverflowMediumVideos