@servicenow/library-enhanced-element
Version:
Base element for Now Design System components
106 lines (88 loc) • 2.91 kB
JavaScript
import makeScopedActionName from './scoped-action-name';
import reduce from 'lodash/reduce';
import forEach from 'lodash/forEach';
import omit from 'lodash/omit';
import mapValues from 'lodash/mapValues';
import get from 'lodash/get';
import constantCase from './constant-case';
const toManagedPropName = (propName) =>
'manage' + propName[0].toUpperCase() + propName.slice(1);
const omitManagedKey = (descriptor) => omit(descriptor, 'manageable');
/* Extracted from https://code.devsnc.com/dev/sn-seismic/blob/5aff3fb9bc51ada3bc487f78a5d3b02c04bf410b/packages/core/src/utils/combinePropertyDefs.js */
const getComponentProperties = (config) => {
const {properties = {}, behaviors = []} = config;
return reduce(
behaviors,
(acc, behavior) => {
const properties = get(
behavior,
'behavior.properties',
get(behavior, 'properties', {})
);
forEach(properties, (value, key) => {
acc[key] = value;
});
return acc;
},
{...properties}
);
};
export const extendWithManageableProperties = (tagName, baseConfig) => {
const properties = getComponentProperties(baseConfig);
const propNamesToManage = Object.keys(properties).reduce((acc, propName) => {
if (properties[propName].manageable) {
acc.push(propName);
}
return acc;
}, []);
if (!propNamesToManage.length) {
return baseConfig;
}
const managedActions = propNamesToManage.reduce((acc, propName) => {
const actionName = makeScopedActionName(
tagName,
constantCase(propName) + '_SET'
);
const managedPropName = toManagedPropName(propName);
const actionHandler = ({host, state, action, updateProperties}) => {
let value = action.payload.value;
const isPropertySelector =
typeof value === 'string' && value[0] === '@' && value.indexOf('/') > 0;
const isManaged = state.properties[managedPropName];
// if a component is a descendant of itself, need to make sure that SET
// actions from the child don't change the property of the parent
const isActionForCurrentHost = host.nowId === action.meta.id;
if (isManaged || !isActionForCurrentHost) {
return;
}
/*
* Here we're escaping the value to prevent selectable properties from
* intercepting and overriding the original value. Managed properties
* need to be escaped by the customer.
*
* This only happens when the value matches the pattern: '@abc/def'
*/
if (isPropertySelector) {
value = `\\${value}`;
}
updateProperties({[propName]: value});
};
acc[actionName] = actionHandler;
return acc;
}, {});
const managedProperties = propNamesToManage.reduce((acc, propName) => {
acc[toManagedPropName(propName)] = {};
return acc;
}, {});
return {
...baseConfig,
actionHandlers: {
...managedActions,
...baseConfig.actionHandlers
},
properties: {
...managedProperties,
...mapValues(baseConfig.properties, omitManagedKey)
}
};
};