victory-core 36.2.1 → 36.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/es/index.d.ts CHANGED
@@ -248,6 +248,7 @@ export interface VictoryLabelProps {
248
248
  style?: VictoryLabelStyleObject | VictoryLabelStyleObject[];
249
249
  tabIndex?: NumberOrCallback;
250
250
  text?: string[] | StringOrNumberOrCallback;
251
+ textComponent?: React.ReactElement;
251
252
  textAnchor?: TextAnchorType | { (): TextAnchorType };
252
253
  title?: string;
253
254
  transform?: string | {} | { (): string | {} };
package/es/index.js CHANGED
@@ -55,6 +55,8 @@ export { _TextSize as TextSize };
55
55
  export { default as Timer } from "./victory-util/timer";
56
56
  import * as _Transitions from "./victory-util/transitions";
57
57
  export { _Transitions as Transitions };
58
+ import * as _UserProps from "./victory-util/user-props";
59
+ export { _UserProps as UserProps };
58
60
  import * as _CommonProps from "./victory-util/common-props";
59
61
  export { _CommonProps as CommonProps };
60
62
  import * as _Wrapper from "./victory-util/wrapper";
@@ -29,6 +29,7 @@ import Portal from "../victory-portal/portal";
29
29
  import PortalContext from "../victory-portal/portal-context";
30
30
  import TimerContext from "../victory-util/timer-context";
31
31
  import * as Helpers from "../victory-util/helpers";
32
+ import * as UserProps from "../victory-util/user-props";
32
33
 
33
34
  var VictoryContainer =
34
35
  /*#__PURE__*/
@@ -200,8 +201,9 @@ function (_React$Component) {
200
201
  preserveAspectRatio = _props.preserveAspectRatio,
201
202
  role = _props.role;
202
203
  var style = responsive ? this.props.style : Helpers.omit(this.props.style, ["height", "width"]);
204
+ var userProps = UserProps.getSafeUserProps(this.props);
203
205
 
204
- var svgProps = _assign({
206
+ var svgProps = _assign(_objectSpread({
205
207
  width: width,
206
208
  height: height,
207
209
  tabIndex: tabIndex,
@@ -210,7 +212,7 @@ function (_React$Component) {
210
212
  "aria-describedby": [desc && this.getIdForElement("desc"), this.props["aria-describedby"]].filter(Boolean).join(" ") || undefined,
211
213
  viewBox: responsive ? "0 0 ".concat(width, " ").concat(height) : undefined,
212
214
  preserveAspectRatio: responsive ? preserveAspectRatio : undefined
213
- }, events);
215
+ }, userProps), events);
214
216
 
215
217
  return this.renderContainer(this.props, svgProps, style);
216
218
  }
@@ -33,6 +33,7 @@ import React from "react";
33
33
  import * as Events from "./events";
34
34
  import isEqual from "react-fast-compare";
35
35
  import VictoryTransition from "../victory-transition/victory-transition";
36
+ import * as UserProps from "../victory-util/user-props";
36
37
 
37
38
  var datumHasXandY = function (datum) {
38
39
  return !_isNil(datum._x) && !_isNil(datum._y);
@@ -379,6 +380,7 @@ export default (function (WrappedComponent, options) {
379
380
  var dataComponent = props.dataComponent,
380
381
  labelComponent = props.labelComponent,
381
382
  groupComponent = props.groupComponent;
383
+ var userProps = UserProps.getSafeUserProps(props);
382
384
  var dataComponents = this.dataKeys.reduce(function (validDataComponents, _dataKey, index) {
383
385
  var dataProps = _this9.getComponentProps(dataComponent, "data", index);
384
386
 
@@ -400,7 +402,8 @@ export default (function (WrappedComponent, options) {
400
402
 
401
403
  var children = _toConsumableArray(dataComponents).concat(_toConsumableArray(labelComponents));
402
404
 
403
- return this.renderContainer(groupComponent, children);
405
+ var group = React.cloneElement(groupComponent, userProps, children);
406
+ return this.renderContainer(group, children);
404
407
  }
405
408
  }]);
406
409
 
@@ -0,0 +1,83 @@
1
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
2
+
3
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
4
+
5
+ function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
6
+
7
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
8
+
9
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
10
+
11
+ 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; }
12
+
13
+ /*
14
+ USER_PROPS_SAFELIST is to contain any string deemed safe for user props.
15
+ The startsWidth array will contain the start of any accepted user-prop that
16
+ starts with these characters.
17
+ The exactMatch will contain a list of exact prop names that are accepted.
18
+ */
19
+ var USER_PROPS_SAFELIST = {
20
+ startsWith: ["data-", "aria-"],
21
+ exactMatch: []
22
+ };
23
+ /**
24
+ * doesPropStartWith: Function that takes a prop's key and runs it against all
25
+ * options in the USER_PROPS_SAFELIST and checks to see if it starts with any
26
+ * of those options.
27
+ * @param {string} key: prop key to be tested against whitelist
28
+ * @returns {Boolean}: returns true if the key starts with an option or false if
29
+ * otherwise
30
+ */
31
+
32
+ var doesPropStartWith = function (key) {
33
+ var startsWith = false;
34
+ USER_PROPS_SAFELIST.startsWith.forEach(function (starterString) {
35
+ var regex = new RegExp("\\b(".concat(starterString, ")(\\w|-)+"), "g");
36
+ if (regex.test(key)) startsWith = true;
37
+ });
38
+ return startsWith;
39
+ };
40
+ /**
41
+ * isExactMatch: checks to see if the given key matches any of the 'exactMatch'
42
+ * items in the whitelist
43
+ * @param {String} key: prop key to be tested against the whitelist-exact match
44
+ * array.
45
+ * @returns {Boolean}: return true if whitelist contains that key, otherwise
46
+ * returns false.
47
+ */
48
+
49
+
50
+ var isExactMatch = function (key) {
51
+ return USER_PROPS_SAFELIST.exactMatch.includes(key);
52
+ };
53
+ /**
54
+ * testIfSafeProp: tests prop's key against both startsWith and exactMatch values
55
+ * @param {String} key: prop key to be tested against the whitelist
56
+ * @returns {Boolean}: returns true if found in whitelist, otherwise returns false
57
+ */
58
+
59
+
60
+ var testIfSafeProp = function (key) {
61
+ if (doesPropStartWith(key) || isExactMatch(key)) return true;
62
+ return false;
63
+ };
64
+ /**
65
+ * getSafeUserProps - function that takes in a props object and removes any
66
+ * key-value entries that do not match filter strings in the USER_PROPS_SAFELIST
67
+ * object.
68
+ *
69
+ * @param {Object} props: props to be filtered against USER_PROPS_SAFELIST
70
+ * @returns {Object}: object containing remaining acceptable props
71
+ */
72
+
73
+
74
+ export var getSafeUserProps = function (props) {
75
+ var propsToFilter = _objectSpread({}, props);
76
+
77
+ return Object.fromEntries(Object.entries(propsToFilter).filter(function (_ref) {
78
+ var _ref2 = _slicedToArray(_ref, 1),
79
+ key = _ref2[0];
80
+
81
+ return testIfSafeProp(key);
82
+ }));
83
+ };
package/lib/index.d.ts CHANGED
@@ -248,6 +248,7 @@ export interface VictoryLabelProps {
248
248
  style?: VictoryLabelStyleObject | VictoryLabelStyleObject[];
249
249
  tabIndex?: NumberOrCallback;
250
250
  text?: string[] | StringOrNumberOrCallback;
251
+ textComponent?: React.ReactElement;
251
252
  textAnchor?: TextAnchorType | { (): TextAnchorType };
252
253
  title?: string;
253
254
  transform?: string | {} | { (): string | {} };
package/lib/index.js CHANGED
@@ -171,7 +171,7 @@ Object.defineProperty(exports, "PointPathHelpers", {
171
171
  return _pointPathHelpers.default;
172
172
  }
173
173
  });
174
- exports.LineHelpers = exports.Hooks = exports.Axis = exports.Wrapper = exports.CommonProps = exports.Transitions = exports.TextSize = exports.Style = exports.Selection = exports.Scale = exports.PropTypes = exports.Log = exports.LabelHelpers = exports.Immutable = exports.Helpers = exports.Events = exports.Domain = exports.DefaultTransitions = exports.Data = exports.Collection = void 0;
174
+ exports.LineHelpers = exports.Hooks = exports.Axis = exports.Wrapper = exports.CommonProps = exports.UserProps = exports.Transitions = exports.TextSize = exports.Style = exports.Selection = exports.Scale = exports.PropTypes = exports.Log = exports.LabelHelpers = exports.Immutable = exports.Helpers = exports.Events = exports.Domain = exports.DefaultTransitions = exports.Data = exports.Collection = void 0;
175
175
 
176
176
  var _victoryAccessibleGroup = _interopRequireDefault(require("./victory-accessible-group/victory-accessible-group"));
177
177
 
@@ -281,6 +281,10 @@ var _Transitions = _interopRequireWildcard(require("./victory-util/transitions")
281
281
 
282
282
  exports.Transitions = _Transitions;
283
283
 
284
+ var _UserProps = _interopRequireWildcard(require("./victory-util/user-props"));
285
+
286
+ exports.UserProps = _UserProps;
287
+
284
288
  var _CommonProps = _interopRequireWildcard(require("./victory-util/common-props"));
285
289
 
286
290
  exports.CommonProps = _CommonProps;
@@ -29,6 +29,8 @@ var _timerContext = _interopRequireDefault(require("../victory-util/timer-contex
29
29
 
30
30
  var Helpers = _interopRequireWildcard(require("../victory-util/helpers"));
31
31
 
32
+ var UserProps = _interopRequireWildcard(require("../victory-util/user-props"));
33
+
32
34
  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
33
35
 
34
36
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -216,7 +218,8 @@ function (_React$Component) {
216
218
  preserveAspectRatio = _props.preserveAspectRatio,
217
219
  role = _props.role;
218
220
  var style = responsive ? this.props.style : Helpers.omit(this.props.style, ["height", "width"]);
219
- var svgProps = (0, _assign2.default)({
221
+ var userProps = UserProps.getSafeUserProps(this.props);
222
+ var svgProps = (0, _assign2.default)(_objectSpread({
220
223
  width: width,
221
224
  height: height,
222
225
  tabIndex: tabIndex,
@@ -225,7 +228,7 @@ function (_React$Component) {
225
228
  "aria-describedby": [desc && this.getIdForElement("desc"), this.props["aria-describedby"]].filter(Boolean).join(" ") || undefined,
226
229
  viewBox: responsive ? "0 0 ".concat(width, " ").concat(height) : undefined,
227
230
  preserveAspectRatio: responsive ? preserveAspectRatio : undefined
228
- }, events);
231
+ }, userProps), events);
229
232
  return this.renderContainer(this.props, svgProps, style);
230
233
  }
231
234
  }]);
@@ -31,6 +31,8 @@ var _reactFastCompare = _interopRequireDefault(require("react-fast-compare"));
31
31
 
32
32
  var _victoryTransition = _interopRequireDefault(require("../victory-transition/victory-transition"));
33
33
 
34
+ var UserProps = _interopRequireWildcard(require("../victory-util/user-props"));
35
+
34
36
  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
35
37
 
36
38
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -383,6 +385,7 @@ var _default = function _default(WrappedComponent, options) {
383
385
  var dataComponent = props.dataComponent,
384
386
  labelComponent = props.labelComponent,
385
387
  groupComponent = props.groupComponent;
388
+ var userProps = UserProps.getSafeUserProps(props);
386
389
  var dataComponents = this.dataKeys.reduce(function (validDataComponents, _dataKey, index) {
387
390
  var dataProps = _this9.getComponentProps(dataComponent, "data", index);
388
391
 
@@ -404,7 +407,9 @@ var _default = function _default(WrappedComponent, options) {
404
407
 
405
408
  var children = _toConsumableArray(dataComponents).concat(_toConsumableArray(labelComponents));
406
409
 
407
- return this.renderContainer(groupComponent, children);
410
+ var group = _react.default.cloneElement(groupComponent, userProps, children);
411
+
412
+ return this.renderContainer(group, children);
408
413
  }
409
414
  }]);
410
415
 
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getSafeUserProps = void 0;
7
+
8
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
9
+
10
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
11
+
12
+ function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
13
+
14
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
15
+
16
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
17
+
18
+ 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; }
19
+
20
+ /*
21
+ USER_PROPS_SAFELIST is to contain any string deemed safe for user props.
22
+ The startsWidth array will contain the start of any accepted user-prop that
23
+ starts with these characters.
24
+ The exactMatch will contain a list of exact prop names that are accepted.
25
+ */
26
+ var USER_PROPS_SAFELIST = {
27
+ startsWith: ["data-", "aria-"],
28
+ exactMatch: []
29
+ };
30
+ /**
31
+ * doesPropStartWith: Function that takes a prop's key and runs it against all
32
+ * options in the USER_PROPS_SAFELIST and checks to see if it starts with any
33
+ * of those options.
34
+ * @param {string} key: prop key to be tested against whitelist
35
+ * @returns {Boolean}: returns true if the key starts with an option or false if
36
+ * otherwise
37
+ */
38
+
39
+ var doesPropStartWith = function (key) {
40
+ var startsWith = false;
41
+ USER_PROPS_SAFELIST.startsWith.forEach(function (starterString) {
42
+ var regex = new RegExp("\\b(".concat(starterString, ")(\\w|-)+"), "g");
43
+ if (regex.test(key)) startsWith = true;
44
+ });
45
+ return startsWith;
46
+ };
47
+ /**
48
+ * isExactMatch: checks to see if the given key matches any of the 'exactMatch'
49
+ * items in the whitelist
50
+ * @param {String} key: prop key to be tested against the whitelist-exact match
51
+ * array.
52
+ * @returns {Boolean}: return true if whitelist contains that key, otherwise
53
+ * returns false.
54
+ */
55
+
56
+
57
+ var isExactMatch = function (key) {
58
+ return USER_PROPS_SAFELIST.exactMatch.includes(key);
59
+ };
60
+ /**
61
+ * testIfSafeProp: tests prop's key against both startsWith and exactMatch values
62
+ * @param {String} key: prop key to be tested against the whitelist
63
+ * @returns {Boolean}: returns true if found in whitelist, otherwise returns false
64
+ */
65
+
66
+
67
+ var testIfSafeProp = function (key) {
68
+ if (doesPropStartWith(key) || isExactMatch(key)) return true;
69
+ return false;
70
+ };
71
+ /**
72
+ * getSafeUserProps - function that takes in a props object and removes any
73
+ * key-value entries that do not match filter strings in the USER_PROPS_SAFELIST
74
+ * object.
75
+ *
76
+ * @param {Object} props: props to be filtered against USER_PROPS_SAFELIST
77
+ * @returns {Object}: object containing remaining acceptable props
78
+ */
79
+
80
+
81
+ var getSafeUserProps = function (props) {
82
+ var propsToFilter = _objectSpread({}, props);
83
+
84
+ return Object.fromEntries(Object.entries(propsToFilter).filter(function (_ref) {
85
+ var _ref2 = _slicedToArray(_ref, 1),
86
+ key = _ref2[0];
87
+
88
+ return testIfSafeProp(key);
89
+ }));
90
+ };
91
+
92
+ exports.getSafeUserProps = getSafeUserProps;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "victory-core",
3
- "version": "36.2.1",
3
+ "version": "36.3.2",
4
4
  "description": "Victory Core",
5
5
  "keywords": [
6
6
  "data visualization",
@@ -37,5 +37,6 @@
37
37
  "scripts": {
38
38
  "version": "yarn run nps build-libs && nps build-dists"
39
39
  },
40
- "sideEffects": false
40
+ "sideEffects": false,
41
+ "gitHead": "18895d1290245732d14332bbbda10336032c9aab"
41
42
  }
package/src/index.d.ts CHANGED
@@ -248,6 +248,7 @@ export interface VictoryLabelProps {
248
248
  style?: VictoryLabelStyleObject | VictoryLabelStyleObject[];
249
249
  tabIndex?: NumberOrCallback;
250
250
  text?: string[] | StringOrNumberOrCallback;
251
+ textComponent?: React.ReactElement;
251
252
  textAnchor?: TextAnchorType | { (): TextAnchorType };
252
253
  title?: string;
253
254
  transform?: string | {} | { (): string | {} };
package/src/index.js CHANGED
@@ -39,6 +39,7 @@ export * as Style from "./victory-util/style";
39
39
  export * as TextSize from "./victory-util/textsize";
40
40
  export { default as Timer } from "./victory-util/timer";
41
41
  export * as Transitions from "./victory-util/transitions";
42
+ export * as UserProps from "./victory-util/user-props";
42
43
  export * as CommonProps from "./victory-util/common-props";
43
44
  export * as Wrapper from "./victory-util/wrapper";
44
45
  export * as Axis from "./victory-util/axis";
@@ -6,6 +6,7 @@ import Portal from "../victory-portal/portal";
6
6
  import PortalContext from "../victory-portal/portal-context";
7
7
  import TimerContext from "../victory-util/timer-context";
8
8
  import * as Helpers from "../victory-util/helpers";
9
+ import * as UserProps from "../victory-util/user-props";
9
10
 
10
11
  export default class VictoryContainer extends React.Component {
11
12
  static displayName = "VictoryContainer";
@@ -192,9 +193,13 @@ export default class VictoryContainer extends React.Component {
192
193
  preserveAspectRatio,
193
194
  role
194
195
  } = this.props;
196
+
195
197
  const style = responsive
196
198
  ? this.props.style
197
199
  : Helpers.omit(this.props.style, ["height", "width"]);
200
+
201
+ const userProps = UserProps.getSafeUserProps(this.props);
202
+
198
203
  const svgProps = assign(
199
204
  {
200
205
  width,
@@ -213,7 +218,8 @@ export default class VictoryContainer extends React.Component {
213
218
  .filter(Boolean)
214
219
  .join(" ") || undefined,
215
220
  viewBox: responsive ? `0 0 ${width} ${height}` : undefined,
216
- preserveAspectRatio: responsive ? preserveAspectRatio : undefined
221
+ preserveAspectRatio: responsive ? preserveAspectRatio : undefined,
222
+ ...userProps
217
223
  },
218
224
  events
219
225
  );
@@ -14,6 +14,7 @@ import {
14
14
  import * as Events from "./events";
15
15
  import isEqual from "react-fast-compare";
16
16
  import VictoryTransition from "../victory-transition/victory-transition";
17
+ import * as UserProps from "../victory-util/user-props";
17
18
 
18
19
  const datumHasXandY = (datum) => {
19
20
  return !isNil(datum._x) && !isNil(datum._y);
@@ -274,10 +275,12 @@ export default (WrappedComponent, options) => {
274
275
  const parentProps = isContainer
275
276
  ? this.getComponentProps(component, "parent", "parent")
276
277
  : {};
278
+
277
279
  if (parentProps.events) {
278
280
  this.globalEvents = Events.getGlobalEvents(parentProps.events);
279
281
  parentProps.events = Events.omitGlobalEvents(parentProps.events);
280
282
  }
283
+
281
284
  return React.cloneElement(component, parentProps, children);
282
285
  }
283
286
 
@@ -327,7 +330,7 @@ export default (WrappedComponent, options) => {
327
330
 
328
331
  renderData(props, shouldRenderDatum = datumHasXandY) {
329
332
  const { dataComponent, labelComponent, groupComponent } = props;
330
-
333
+ const userProps = UserProps.getSafeUserProps(props);
331
334
  const dataComponents = this.dataKeys.reduce(
332
335
  (validDataComponents, _dataKey, index) => {
333
336
  const dataProps = this.getComponentProps(
@@ -360,7 +363,8 @@ export default (WrappedComponent, options) => {
360
363
  .filter(Boolean);
361
364
 
362
365
  const children = [...dataComponents, ...labelComponents];
363
- return this.renderContainer(groupComponent, children);
366
+ const group = React.cloneElement(groupComponent, userProps, children);
367
+ return this.renderContainer(group, children);
364
368
  }
365
369
  };
366
370
  };
@@ -0,0 +1,64 @@
1
+ /*
2
+ USER_PROPS_SAFELIST is to contain any string deemed safe for user props.
3
+ The startsWidth array will contain the start of any accepted user-prop that
4
+ starts with these characters.
5
+ The exactMatch will contain a list of exact prop names that are accepted.
6
+ */
7
+ const USER_PROPS_SAFELIST = {
8
+ startsWith: ["data-", "aria-"],
9
+ exactMatch: []
10
+ };
11
+
12
+ /**
13
+ * doesPropStartWith: Function that takes a prop's key and runs it against all
14
+ * options in the USER_PROPS_SAFELIST and checks to see if it starts with any
15
+ * of those options.
16
+ * @param {string} key: prop key to be tested against whitelist
17
+ * @returns {Boolean}: returns true if the key starts with an option or false if
18
+ * otherwise
19
+ */
20
+ const doesPropStartWith = (key) => {
21
+ let startsWith = false;
22
+
23
+ USER_PROPS_SAFELIST.startsWith.forEach((starterString) => {
24
+ const regex = new RegExp(`\\b(${starterString})(\\w|-)+`, "g");
25
+ if (regex.test(key)) startsWith = true;
26
+ });
27
+
28
+ return startsWith;
29
+ };
30
+
31
+ /**
32
+ * isExactMatch: checks to see if the given key matches any of the 'exactMatch'
33
+ * items in the whitelist
34
+ * @param {String} key: prop key to be tested against the whitelist-exact match
35
+ * array.
36
+ * @returns {Boolean}: return true if whitelist contains that key, otherwise
37
+ * returns false.
38
+ */
39
+ const isExactMatch = (key) => USER_PROPS_SAFELIST.exactMatch.includes(key);
40
+
41
+ /**
42
+ * testIfSafeProp: tests prop's key against both startsWith and exactMatch values
43
+ * @param {String} key: prop key to be tested against the whitelist
44
+ * @returns {Boolean}: returns true if found in whitelist, otherwise returns false
45
+ */
46
+ const testIfSafeProp = (key) => {
47
+ if (doesPropStartWith(key) || isExactMatch(key)) return true;
48
+ return false;
49
+ };
50
+
51
+ /**
52
+ * getSafeUserProps - function that takes in a props object and removes any
53
+ * key-value entries that do not match filter strings in the USER_PROPS_SAFELIST
54
+ * object.
55
+ *
56
+ * @param {Object} props: props to be filtered against USER_PROPS_SAFELIST
57
+ * @returns {Object}: object containing remaining acceptable props
58
+ */
59
+ export const getSafeUserProps = (props) => {
60
+ const propsToFilter = { ...props };
61
+ return Object.fromEntries(
62
+ Object.entries(propsToFilter).filter(([key]) => testIfSafeProp(key))
63
+ );
64
+ };