grommet
Version:
focus on the essential experience
314 lines (298 loc) • 13.7 kB
JavaScript
;
exports.__esModule = true;
exports.formViewNameKey = exports.formStepKey = exports.formSortKey = exports.formSearchKey = exports.formRangeKey = exports.formPageKey = exports.formGroupByKey = exports.formColumnsKey = exports.DataForm = void 0;
var _react = _interopRequireWildcard(require("react"));
var _styledComponents = _interopRequireDefault(require("styled-components"));
var _Box = require("../Box");
var _Button = require("../Button");
var _Footer = require("../Footer");
var _Form = require("../Form");
var _DataContext = require("../../contexts/DataContext");
var _DataFormContext = require("../../contexts/DataFormContext");
var _MessageContext = require("../../contexts/MessageContext");
var _useDebounce = require("../../utils/use-debounce");
var _useThemeValue2 = require("../../utils/useThemeValue");
var _excluded = ["children", "footer", "onDone", "pad", "updateOn"];
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
var MaxForm = (0, _styledComponents["default"])(_Form.Form).withConfig({
displayName: "DataForm__MaxForm",
componentId: "sc-v64e1r-0"
})(["max-width:100%;", ""], function (props) {
return props.fill && 'max-height: 100%;';
});
// We convert the view structure to something more flat to work better
// with the Form inputs. These keys are how we flatten the Form value object
// from the view object.
var formSearchKey = exports.formSearchKey = '_search';
var formSortKey = exports.formSortKey = '_sort';
var formRangeKey = exports.formRangeKey = '_range';
var formStepKey = exports.formStepKey = '_step';
var formPageKey = exports.formPageKey = '_page';
var formColumnsKey = exports.formColumnsKey = '_columns';
var formGroupByKey = exports.formGroupByKey = '_groupBy';
var formViewNameKey = exports.formViewNameKey = '_view';
var viewFormKeyMap = {
search: formSearchKey,
sort: formSortKey,
step: formStepKey,
page: formPageKey,
columns: formColumnsKey,
groupBy: formGroupByKey,
view: formViewNameKey
};
// flatten nested objects.
// For example: { a: { b: v, c: z } } -> { 'a.b': v, 'a.c': z }
var _flatten = function flatten(formValue, options) {
var result = JSON.parse(JSON.stringify(formValue));
Object.keys(result).forEach(function (i) {
// We check the type of the i using
// typeof() function and recursively
// call the function again
// ignore _range situations
if (typeof result[i] === 'object' && !Array.isArray(result[i]) && (options != null && options.full || !result[i][formRangeKey])) {
var temp = _flatten(result[i], options);
Object.keys(temp).forEach(function (j) {
// Store temp in result
// ignore empty arrays
if (!Array.isArray(temp[j]) || Array.isArray(temp[j]) && temp[j].length) result[i + "." + j] = temp[j];
});
delete result[i];
}
});
return result;
};
// unflatten nested objects. For example: { 'a.b': v } -> { a: { b: v } }
var unflatten = function unflatten(formValue) {
var result = JSON.parse(JSON.stringify(formValue));
var specialKeys = Object.values(viewFormKeyMap);
Object.keys(result).filter(function (k) {
return !specialKeys.includes(k);
}).forEach(function (k) {
var parts = k.split('.');
var val = result[k];
delete result[k];
var parent = result;
while (parts.length > 1) {
var sub = parts.shift();
if (!parent[sub]) parent[sub] = {};
parent = parent[sub];
}
parent[parts.shift()] = val;
});
return result;
};
// converts from the external view format to the internal Form value format
var viewToFormValue = function viewToFormValue(view) {
var result = _extends({}, (view == null ? void 0 : view.properties) || {});
// convert { min: , max: } range to [min, max] for RangeSelector
Object.keys(result).forEach(function (key) {
var _result$key, _result$key2;
if (typeof ((_result$key = result[key]) == null ? void 0 : _result$key.min) === 'number' || typeof ((_result$key2 = result[key]) == null ? void 0 : _result$key2.max) === 'number') {
var _result$key3;
result[key] = (_result$key3 = {}, _result$key3[formRangeKey] = [result[key].min, result[key].max], _result$key3);
}
});
// convert formal view keys to their form '_' prefixed counterparts
Object.keys(viewFormKeyMap).forEach(function (key) {
if (view != null && view[key]) result[viewFormKeyMap[key]] = view[key];
});
// always have some blank search text
if (!result[formSearchKey]) result[formSearchKey] = '';
if (view != null && view.sort) result[formSortKey] = view.sort;
if (view != null && view.name) result[formViewNameKey] = view.name;
if (view != null && view.columns) result[formColumnsKey] = view.columns;
if (view != null && view.groupBy) result[formGroupByKey] = view.groupBy;
return unflatten(result);
};
// converts from the internal Form value format to the external view format
var formValueToView = function formValueToView(value, views) {
var result = {};
// if the user chose a view, use that
if (value[formViewNameKey]) result = JSON.parse(JSON.stringify(views.find(function (v) {
return v.name === value[formViewNameKey];
})));
var valueCopy = _extends({}, value);
Object.keys(viewFormKeyMap).forEach(function (key) {
if (valueCopy[viewFormKeyMap[key]]) {
result[key] = valueCopy[viewFormKeyMap[key]];
}
delete valueCopy[viewFormKeyMap[key]];
});
// flatten any nested objects
var flatValue = _flatten(valueCopy);
result.properties = _extends({}, result.properties || {}, flatValue);
// convert any ranges
Object.keys(result.properties).forEach(function (key) {
if (result.properties[key][formRangeKey]) {
result.properties[key] = {
min: result.properties[key][formRangeKey][0],
max: result.properties[key][formRangeKey][1]
};
}
});
return result;
};
// remove any empty arrays of property values by deleting the key for
// that property in the view properties
var clearEmpty = function clearEmpty(formValue, pendingReset) {
var value = formValue;
Object.keys(value).forEach(function (k) {
if (Array.isArray(value[k]) && value[k].length === 0) delete value[k];
// special case for when range selector returns to its min/max
// flat format with full: true needed to match filter name structure
// { a: b: { _range: [0, 100] } } ==> a.b._range: [0, 100]
if (typeof value[k] === 'object' && !Array.isArray(value[k])) {
var _pendingReset$current;
var filterName = k + "." + Object.keys(_flatten(value[k], {
full: true
}))[0];
if (pendingReset != null && (_pendingReset$current = pendingReset.current) != null && _pendingReset$current.has(filterName)) {
delete value[k];
pendingReset.current["delete"](filterName);
}
}
});
return value;
};
// if paging, when anything other than the page changes, reset the page to 1
var resetPage = function resetPage(nextFormValue, prevFormValue) {
if (prevFormValue[formPageKey] && prevFormValue[formPageKey] > 1)
// eslint-disable-next-line no-param-reassign
nextFormValue[formPageKey] = 1;
};
// function shared by onSubmit and onChange to coordinate view
// name changes
var normalizeValue = function normalizeValue(nextValue, prevValue, views, pendingReset) {
if (nextValue[formViewNameKey] && nextValue[formViewNameKey] !== prevValue[formViewNameKey]) {
// view name changed, reset view contents from named view
return viewToFormValue(views.find(function (v) {
return v.name === nextValue[formViewNameKey];
}));
}
// something else changed
// clear empty properties
var result = clearEmpty(nextValue, pendingReset);
// if we have a view and something changed, clear the view
if (result[formViewNameKey]) {
var view = views.find(function (v) {
return v.name === result[formViewNameKey];
});
var viewValue = viewToFormValue(view);
clearEmpty(viewValue, pendingReset);
if (Object.keys(viewValue).length !== Object.keys(result).length) {
delete result[formViewNameKey];
} else if (Object.keys(viewValue).some(function (k) {
return (
// allow mismatch between empty and set strings
viewValue[k] && result[k] && JSON.stringify(result[k]) !== JSON.stringify(viewValue[k])
);
})) {
delete result[formViewNameKey];
}
}
return result;
};
// 300ms was chosen empirically as a reasonable default
var DEBOUNCE_TIMEOUT = 300;
var DataForm = exports.DataForm = function DataForm(_ref) {
var children = _ref.children,
footer = _ref.footer,
onDone = _ref.onDone,
pad = _ref.pad,
_ref$updateOn = _ref.updateOn,
updateOn = _ref$updateOn === void 0 ? 'submit' : _ref$updateOn,
rest = _objectWithoutPropertiesLoose(_ref, _excluded);
var _useContext = (0, _react.useContext)(_DataContext.DataContext),
messages = _useContext.messages,
onView = _useContext.onView,
view = _useContext.view,
views = _useContext.views;
var _useContext2 = (0, _react.useContext)(_MessageContext.MessageContext),
format = _useContext2.format;
var _useState = (0, _react.useState)(viewToFormValue(view)),
formValue = _useState[0],
setFormValue = _useState[1];
// special case for range selectors which always have a value.
// when value returns to its min/max, remove it from view
// like other properties
var pendingReset = (0, _react.useRef)(new Set());
var contextValue = (0, _react.useMemo)(function () {
return {
inDataForm: true,
pendingReset: pendingReset
};
}, []);
var debounce = (0, _useDebounce.useDebounce)(DEBOUNCE_TIMEOUT);
var _useThemeValue = (0, _useThemeValue2.useThemeValue)(),
theme = _useThemeValue.theme;
var onSubmit = (0, _react.useCallback)(function (_ref2) {
var value = _ref2.value;
var nextValue = normalizeValue(value, formValue, views, pendingReset);
resetPage(nextValue, formValue);
setFormValue(nextValue);
onView(formValueToView(nextValue, views));
if (onDone) onDone();
}, [formValue, onDone, onView, views]);
var onChange = (0, _react.useCallback)(function (value, _ref3) {
var touched = _ref3.touched;
var nextValue = normalizeValue(value, formValue, views, pendingReset);
resetPage(nextValue, formValue);
setFormValue(nextValue);
if (updateOn === 'change') {
// debounce search
if (touched[formSearchKey]) {
debounce(function () {
return function () {
return onView(formValueToView(nextValue, views));
};
});
} else {
onView(formValueToView(nextValue, views));
}
}
}, [debounce, formValue, onView, updateOn, views]);
(0, _react.useEffect)(function () {
return setFormValue(viewToFormValue(view));
}, [view]);
var content = children;
if (footer !== false && updateOn === 'submit' || pad) {
var _theme$dataFilters, _theme$dataFilters2;
content = /*#__PURE__*/_react["default"].createElement(_Box.Box, {
fill: "vertical"
}, /*#__PURE__*/_react["default"].createElement(_Box.Box, {
flex: true,
overflow: "auto",
pad: {
horizontal: pad,
top: pad
}
}, /*#__PURE__*/_react["default"].createElement(_Box.Box, {
flex: false
}, content)), footer !== false && updateOn === 'submit' && /*#__PURE__*/_react["default"].createElement(_Footer.Footer, {
flex: false,
pad: {
horizontal: pad,
bottom: pad
},
margin: (_theme$dataFilters = theme.dataFilters) == null || (_theme$dataFilters = _theme$dataFilters.footer) == null || (_theme$dataFilters = _theme$dataFilters.actions) == null ? void 0 : _theme$dataFilters.margin,
gap: (_theme$dataFilters2 = theme.dataFilters) == null || (_theme$dataFilters2 = _theme$dataFilters2.footer) == null || (_theme$dataFilters2 = _theme$dataFilters2.actions) == null ? void 0 : _theme$dataFilters2.gap
}, /*#__PURE__*/_react["default"].createElement(_Button.Button, {
label: format({
id: 'dataForm.submit',
messages: messages == null ? void 0 : messages.dataForm
}),
type: "submit",
primary: true
})));
}
return /*#__PURE__*/_react["default"].createElement(MaxForm, _extends({}, rest, {
value: formValue,
onSubmit: updateOn === 'submit' ? onSubmit : undefined,
onChange: onChange
}), /*#__PURE__*/_react["default"].createElement(_DataFormContext.DataFormContext.Provider, {
value: contextValue
}, content));
};