UNPKG

informed

Version:

A lightweight framework and utility for building powerful forms in React applications

255 lines (226 loc) 9.09 kB
import { objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, extends as _extends } from '../_virtual/_rollupPluginBabelHelpers.js'; import React, { useState, useMemo, useEffect } from 'react'; import { getSchemaPathFromJsonPath, computeFieldFromProperty, sanitize, checkCondition } from '../utils.js'; import { ObjectMap } from '../ObjectMap.js'; import { useFormController } from '../hooks/useFormController.js'; import { useScope } from '../hooks/useScope.js'; import { useConditional } from '../hooks/useConditional.js'; import { Debug } from '../debug.js'; import { FormFields } from './FormFields.js'; import { Relevant } from './Relevant.js'; import { Scope } from './Scope.js'; import { useFieldApi } from '../hooks/useFieldApi.js'; import { useUpdateEffect } from '../hooks/useUpdateEffect.js'; import { ArrayField } from './ArrayField.js'; var _excluded = ["name", "schema"]; // import { useForceUpdate } from '../hooks/useForceUpdate'; var logger = Debug('informed:FormField' + '\t'); var FormField = function FormField(_ref) { var _fieldMap$componentTy; var name = _ref.name, schema = _ref.schema, rest = _objectWithoutProperties(_ref, _excluded); // Get the field map off the forms context var _useFormController = useFormController(), fieldMap = _useFormController.fieldMap, getOptions = _useFormController.getOptions, emitter = _useFormController.emitter; // Name might be scoped var fullName = useScope(name); // Grab the schema var options = getOptions(); // Grap api var fieldApi = useFieldApi(name); // For conditional props var _useState = useState({}), _useState2 = _slicedToArray(_useState, 2), condProp = _useState2[0], setCondProp = _useState2[1]; // IF schema was passed its a sub schema and we lookup via name otherwise we look at whole schema var lookupName = schema ? name : fullName; var lookupSchema = schema !== null && schema !== void 0 ? schema : options.schema; // First find property from the schema via the path to that field // Examples // field = "name" ---> properties.name // field = "brother.name" ---> properties.brother.properties.name // field = "brother.siblings[1].friend.name" ---> properties.brother.properties.siblings.items.properties.friend.properties.name var path = getSchemaPathFromJsonPath(lookupName); var property = ObjectMap.get(lookupSchema, path); // console.log( // 'Lookup Name:', // lookupName, // '\nSchema Path:', // path, // '\nProperty:', // lookupSchema // ); // If property was not found try to find it in conditions var condition; if (!property) { if (lookupSchema.allOf) { lookupSchema.allOf.forEach(function (item) { if (item["if"]) { property = ObjectMap.get(item.then, path); condition = item["if"]; } }); } // If property was still not found return null if (!property) { return null; } } // Next compute the field from property var schemaField = useMemo(function () { return computeFieldFromProperty(name, property); }, [name]); var schemaProps = schemaField.props, type = schemaField.type, properties = schemaField.properties, items = schemaField.items, componentType = schemaField.componentType, uiBefore = schemaField.uiBefore, uiAfter = schemaField.uiAfter; // Register for events on our field useEffect(function () { var updater = function updater(target, property) { // Example // target="foo" // property = // { // oneOf: [ // { const: '', title: '- Select -' }, // { const: 'modelS', title: 'Model S' }, // { const: 'modelX', title: 'Model X' }, // { const: 'model3', title: 'Model 3' } // ] // } if (target === name) { logger("Updating field props for ".concat(target), computeFieldFromProperty(name, property)); setCondProp(computeFieldFromProperty(name, property)); } }; var remover = function remover(target) { if (target === name) { setCondProp({}); } }; emitter.on('update-combine', updater); emitter.on('update-remove', remover); return function () { emitter.removeListener('update-combine', updater); emitter.removeListener('update-remove', remover); }; }, [name]); var hookProps = useConditional({ name: schemaProps.name, evaluate: schemaProps.evaluate, evaluateWhen: schemaProps.evaluateWhen, dependsOn: schemaProps.dependsOn }); // Combine any conditional props with the schema props var props = useMemo(function () { // Pull new props off of cond property var condProps = condProp.props; // Lay those on top of existing ones var newSchemaProps = sanitize(schemaProps); var newCondProps = sanitize(condProps); var newHookProps = sanitize(hookProps); // Temp fix if (schemaProps !== null && schemaProps !== void 0 && schemaProps.required || newCondProps !== null && newCondProps !== void 0 && newCondProps.required || newHookProps !== null && newHookProps !== void 0 && newHookProps.required) { rest.required = (schemaProps === null || schemaProps === void 0 ? void 0 : schemaProps.required) || (newCondProps === null || newCondProps === void 0 ? void 0 : newCondProps.required) || (newHookProps === null || newHookProps === void 0 ? void 0 : newHookProps.required); } var newProps = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, newSchemaProps), newCondProps), newHookProps), rest); logger("Schema Props for ".concat(name), newSchemaProps); logger("Cond Props for ".concat(name), newCondProps); logger("Hook Props for ".concat(name), newHookProps); logger("New Props for ".concat(name), newProps); return newProps; }, [condProp, hookProps]); useUpdateEffect(function () { if (props.options) { logger('options changed', props.options); fieldApi.reset(); } }, [props.options]); // Component is either on field map or components list passed in var Component = (_fieldMap$componentTy = fieldMap[componentType]) !== null && _fieldMap$componentTy !== void 0 ? _fieldMap$componentTy : options.components ? options.components[componentType] : null; // Maybe its with options // Example adapter: // withOptions: { // array: CheckboxGroup, // }, if (schemaProps.options && fieldMap.withOptions && !items) { Component = fieldMap.withOptions[componentType] || Component; // console.log('HERE!!!!!', componentType, fieldMap.withOptions); } // console.log('WTF', schemaField); logger('Rendering Field', name, schemaField); // Scope for nested if (!Component && type === 'object' && properties) { return /*#__PURE__*/React.createElement(Scope, { scope: name }, /*#__PURE__*/React.createElement(FormFields, { schema: schemaField })); } // Just component if (Component && type === 'object' && properties) { return /*#__PURE__*/React.createElement(Scope, { scope: name }, /*#__PURE__*/React.createElement(Component, props, /*#__PURE__*/React.createElement(FormFields, { schema: schemaField }))); } // Array field for array ( if none was provided use our default ) if (!Component && type === 'array' && items) { return /*#__PURE__*/React.createElement(ArrayField, _extends({ name: name, items: items, uiBefore: uiBefore, uiAfter: uiAfter }, props)); } // User created custom array field if (Component && componentType === 'array' && items && type === 'array') { return /*#__PURE__*/React.createElement(Component, _extends({ name: name, items: items, uiBefore: uiBefore, uiAfter: uiAfter }, props)); } // If no component return null ( dont render ) if (!Component) { return null; } if (condition) { var _condition = condition, conditions = _condition.properties; var when = function when(_ref2) { var formApi = _ref2.formApi, scope = _ref2.scope; // Example key "married, Example condition: "{ const: 'yes' }" return Object.entries(conditions).every(function (_ref3) { var _ref4 = _slicedToArray(_ref3, 2), propertyName = _ref4[0], condition = _ref4[1]; return checkCondition(condition, formApi.getValue(scope ? "".concat(scope, ".").concat(propertyName) : propertyName)); }); }; var Comp = function Comp() { return /*#__PURE__*/React.createElement(Relevant, { when: when }, /*#__PURE__*/React.createElement(Component, _extends({ name: name }, props))); }; // console.log('WTF', Component); return /*#__PURE__*/React.createElement(Comp, null); } // Note we DONT pass in scoped name here because useField is already scoped return /*#__PURE__*/React.createElement(Component, _extends({ name: name }, props)); }; export { FormField };