UNPKG

@itsjonq/controls

Version:

A control panel to develop React UI

232 lines (189 loc) 6.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _exportNames = { store: true, addField: true, updateField: true, updateFields: true, unsafeOverrideFields: true, resetFields: true }; exports.addField = addField; exports.updateField = updateField; exports.updateFields = updateFields; exports.unsafeOverrideFields = unsafeOverrideFields; exports.resetFields = resetFields; exports.store = void 0; var _unistore = _interopRequireDefault(require("unistore")); var _is = require("@itsjonq/is"); var _selectors = require("./selectors"); Object.keys(_selectors).forEach(function (key) { if (key === "default" || key === "__esModule") return; if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; Object.defineProperty(exports, key, { enumerable: true, get: function get() { return _selectors[key]; } }); }); var _transformValue = require("../knobs/transformValue"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /** * The store for the Controls fields. Using a dedicated store allows for updates * and re-renders to happen outside of the React render cycle. Effectively, * creating an alternate stream. This is the key to enabling the knobs like * text(), color(), and date() to work without them being React hooks. * * This alternative state stream is a technique used by libraries like * React Redux or Emotion. * * We're using unistore to create to store due to it's simplicity and * (light) weight. */ var store = (0, _unistore.default)({ fields: [] }); /** * Creates a specific "field" object (shape) to be added to the store. * @param {string} prop The unique key for the field. * @param {any} value The value for the field. * @param {Object} props Additional props for the field. e.g. Options for a select() * @returns {Object} A field to be added to the store. */ exports.store = store; function createField(prop, value, props) { var transformValue = props.transformValue || _transformValue.toValue; return _objectSpread({ prop: prop, transformValue: transformValue }, props, { value: transformValue(value) }); } /** * Adds a field to the store. If the field already exists, it would be * updated instead. Fields within the store have to have a unique key (prop). * @param {Object} props Data to be parsed and added to the store as a field. * @returns {any} The value of the field. */ function addField(props) { var prop = props.prop, value = props.value; var prevField = (0, _selectors.getField)(prop); if (prevField) { return; } var prevFields = (0, _selectors.getFields)(); var nextField = createField(prop, value, props); var nextFields = [].concat(prevFields, [nextField]); store.setState({ fields: nextFields }); return value; } /** * Updates a field to the store. * @param {string} prop The id (prop) of the field to update. * @param {any} value The next value for the field. * @returns {any} The next value of the field. */ function updateField(prop, value) { var _updateFields; var prevField = (0, _selectors.getField)(prop); if (!prevField) { return value; } var prevValue = prevField.value, transformValueProp = prevField.transformValue; var nextValue = transformValueProp(value); if (prevValue === nextValue) { return nextValue; } updateFields((_updateFields = {}, _updateFields[prop] = value, _updateFields)); return value; } /** * Updates several fields in the store. * @param {Object} fields Fields to be updated. Key is the id, value is the next value. * @returns {Array} The updated fields. */ function updateFields(fields) { if (fields === void 0) { fields = {}; } if (!_is.is.plainObject(fields)) { return []; } var props = Object.keys(fields); var prevFields = (0, _selectors.getFields)(); var diffs = 0; var nextFields = prevFields.map(function (field) { var prop = field.prop, value = field.value; if (props.includes(prop)) { var nextValue = fields[prop]; if (value !== nextValue) { diffs++; } return _objectSpread({}, field, { value: nextValue }); } return field; }); // Prevents unnecessary re-renders if there are no changes. if (diffs) { store.setState({ fields: nextFields }); } return nextFields; } /** * A forceful way to override the fields. Hope you know what you're doing! * @param {Array|Object} fields The next fields to forcefully update to. * @returns {any} The next fields, if successful. */ function unsafeOverrideFields(fields) { if (fields === void 0) { fields = {}; } var nextFields; if (_is.is.plainObject(fields)) { nextFields = Object.keys(fields).reduce(function (next, prop) { var value = fields[prop]; return [].concat(next, [{ prop: prop, value: value }]); }, []); } if (_is.is.array) { nextFields = fields; } if (nextFields) { store.setState({ fields: nextFields }); } return nextFields; } /** * Resets (empties) the all of the fields within the store. This enables * the default behaviour of removing fields when the component that * triggers the control via useControl is unmounted. */ function resetFields() { var prevFields = (0, _selectors.getFields)(); var nextFields = prevFields.filter(function () { return false; }); store.setState({ fields: nextFields }); }