carbon-react 111.18.0 → 111.19.0

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.
@@ -1,6 +1,6 @@
1
1
  function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
2
 
3
- import React, { useContext, useEffect, useMemo } from "react";
3
+ import React, { useContext, useEffect, useLayoutEffect, useMemo, useRef } from "react";
4
4
  import PropTypes from "prop-types";
5
5
  import invariant from "invariant";
6
6
  import { filterStyledSystemMarginProps } from "../../style/utils";
@@ -62,10 +62,24 @@ const FormField = ({
62
62
  setWarning,
63
63
  setInfo
64
64
  } = useContext(TabContext);
65
+ const isMounted = useRef(false);
66
+ useLayoutEffect(() => {
67
+ isMounted.current = true;
68
+ return () => {
69
+ isMounted.current = false;
70
+ };
71
+ }, []);
65
72
  useEffect(() => {
66
- if (setError) setError(id, !!error);
67
- if (setWarning) setWarning(id, !!warning);
68
- if (setInfo) setInfo(id, !!info);
73
+ if (setError) setError(id, error);
74
+ if (setWarning) setWarning(id, warning);
75
+ if (setInfo) setInfo(id, info);
76
+ return () => {
77
+ if (!isMounted.current) {
78
+ if (setError && error) setError(id, false);
79
+ if (setWarning && warning) setWarning(id, false);
80
+ if (setInfo && info) setInfo(id, false);
81
+ }
82
+ };
69
83
  }, [id, setError, setWarning, setInfo, error, warning, info]);
70
84
  const marginProps = filterStyledSystemMarginProps(rest);
71
85
  const fieldHelp = fieldHelpContent ? /*#__PURE__*/React.createElement(FieldHelp, {
@@ -27,24 +27,24 @@ const Tab = ({
27
27
  const [tabErrors, setTabErrors] = useState({});
28
28
  const [tabWarnings, setTabWarnings] = useState({});
29
29
  const [tabInfos, setTabInfos] = useState({});
30
- const setError = useCallback((childId, hasError) => {
31
- if (tabErrors[childId] !== hasError) {
30
+ const setError = useCallback((childId, error) => {
31
+ if (tabErrors[childId] !== error) {
32
32
  setTabErrors({ ...tabErrors,
33
- [childId]: hasError
33
+ [childId]: error
34
34
  });
35
35
  }
36
36
  }, [tabErrors]);
37
- const setWarning = useCallback((childId, hasWarning) => {
38
- if (tabWarnings[childId] !== hasWarning) {
37
+ const setWarning = useCallback((childId, warning) => {
38
+ if (tabWarnings[childId] !== warning) {
39
39
  setTabWarnings({ ...tabWarnings,
40
- [childId]: hasWarning
40
+ [childId]: warning
41
41
  });
42
42
  }
43
43
  }, [tabWarnings]);
44
- const setInfo = useCallback((childId, hasInfo) => {
45
- if (tabInfos[childId] !== hasInfo) {
44
+ const setInfo = useCallback((childId, info) => {
45
+ if (tabInfos[childId] !== info) {
46
46
  setTabInfos({ ...tabInfos,
47
- [childId]: hasInfo
47
+ [childId]: info
48
48
  });
49
49
  }
50
50
  }, [tabInfos]);
@@ -2,9 +2,9 @@ import * as React from "react";
2
2
  import { PaddingProps } from "styled-system";
3
3
 
4
4
  export interface TabContextProps {
5
- setError?: (childId: string, hasError: boolean) => void;
6
- setWarning?: (childId: string, hasWarning: boolean) => void;
7
- setInfo?: (childId: string, hasInfo: boolean) => void;
5
+ setError?: (childId: string, error?: boolean | string) => void;
6
+ setWarning?: (childId: string, warning?: boolean | string) => void;
7
+ setInfo?: (childId: string, info?: boolean | string) => void;
8
8
  }
9
9
 
10
10
  export interface TabProps extends PaddingProps {
@@ -27,6 +27,7 @@ const Tabs = ({
27
27
  variant = "default",
28
28
  validationStatusOverride,
29
29
  headerWidth,
30
+ showValidationsSummary,
30
31
  ...rest
31
32
  }) => {
32
33
  /** The children nodes converted into an Array */
@@ -48,24 +49,24 @@ const Tabs = ({
48
49
  const [tabsErrors, setTabsErrors] = useState({});
49
50
  const [tabsWarnings, setTabsWarnings] = useState({});
50
51
  const [tabsInfos, setTabsInfos] = useState({});
51
- const updateErrors = useCallback((id, hasError) => {
52
- if (tabsErrors[id] !== hasError) {
52
+ const updateErrors = useCallback((id, error) => {
53
+ if (tabsErrors[id] !== error) {
53
54
  setTabsErrors({ ...tabsErrors,
54
- [id]: hasError
55
+ [id]: error
55
56
  });
56
57
  }
57
58
  }, [tabsErrors]);
58
- const updateWarnings = useCallback((id, hasWarning) => {
59
- if (tabsWarnings[id] !== hasWarning) {
59
+ const updateWarnings = useCallback((id, warning) => {
60
+ if (tabsWarnings[id] !== warning) {
60
61
  setTabsWarnings({ ...tabsWarnings,
61
- [id]: hasWarning
62
+ [id]: warning
62
63
  });
63
64
  }
64
65
  }, [tabsWarnings]);
65
- const updateInfos = useCallback((id, hasInfo) => {
66
- if (tabsInfos[id] !== hasInfo) {
66
+ const updateInfos = useCallback((id, info) => {
67
+ if (tabsInfos[id] !== info) {
67
68
  setTabsInfos({ ...tabsInfos,
68
- [id]: hasInfo
69
+ [id]: info
69
70
  });
70
71
  }
71
72
  }, [tabsInfos]);
@@ -182,16 +183,34 @@ const Tabs = ({
182
183
  customLayout
183
184
  } = child.props;
184
185
  const refId = `${tabId}-tab`;
185
- const errors = tabsErrors[tabId] ? Object.entries(tabsErrors[tabId]).filter(tab => tab[1] === true).length : 0;
186
- const warnings = tabsWarnings[tabId] ? Object.entries(tabsWarnings[tabId]).filter(tab => tab[1] === true).length : 0;
187
- const infos = tabsInfos[tabId] ? Object.entries(tabsInfos[tabId]).filter(tab => tab[1] === true).length : 0;
186
+ const errors = tabsErrors[tabId];
187
+ const warnings = tabsWarnings[tabId];
188
+ const infos = tabsInfos[tabId];
189
+ const errorsCount = errors && Object.entries(errors).filter(tab => tab[1]).length;
190
+ const warningsCount = warnings && Object.entries(warnings).filter(tab => tab[1]).length;
191
+ const infosCount = infos && Object.entries(infos).filter(tab => tab[1]).length;
188
192
  const hasOverride = validationStatusOverride && validationStatusOverride[tabId];
189
193
  const errorOverride = hasOverride && validationStatusOverride[tabId].error;
190
194
  const warningOverride = hasOverride && validationStatusOverride[tabId].warning;
191
195
  const infoOverride = hasOverride && validationStatusOverride[tabId].info;
192
- const tabHasError = errorOverride !== undefined ? errorOverride : errors > 0;
193
- const tabHasWarning = warningOverride !== undefined ? warningOverride : warnings > 0 && !tabHasError;
194
- const tabHasInfo = infoOverride !== undefined ? infoOverride : infos > 0 && !tabHasError && !tabHasWarning;
196
+ const tabHasError = errorOverride !== undefined ? errorOverride : !!errorsCount;
197
+ const tabHasWarning = warningOverride !== undefined ? warningOverride : !!warningsCount && !tabHasError;
198
+ const tabHasInfo = infoOverride !== undefined ? infoOverride : !!infosCount && !tabHasError && !tabHasWarning;
199
+
200
+ const getValidationMessage = (message, validations = {}) => {
201
+ const summaryOfMessages = Object.values(validations).filter(value => value && typeof value === "string");
202
+
203
+ if (!showValidationsSummary || !summaryOfMessages.length) {
204
+ return message;
205
+ }
206
+
207
+ if (summaryOfMessages.length === 1) {
208
+ return summaryOfMessages[0];
209
+ }
210
+
211
+ return summaryOfMessages.map(value => `• ${value}`).join("\n");
212
+ };
213
+
195
214
  const tabTitle = /*#__PURE__*/React.createElement(TabTitle, {
196
215
  position: isInSidebar ? "left" : position,
197
216
  className: child.props.className || "",
@@ -212,9 +231,9 @@ const Tabs = ({
212
231
  borders: borders !== "off",
213
232
  siblings: siblings,
214
233
  titlePosition: titlePosition,
215
- errorMessage: errorMessage,
216
- warningMessage: warningMessage,
217
- infoMessage: infoMessage,
234
+ errorMessage: getValidationMessage(errorMessage, errors),
235
+ warningMessage: getValidationMessage(warningMessage, warnings),
236
+ infoMessage: getValidationMessage(infoMessage, infos),
218
237
  alternateStyling: variant === "alternate",
219
238
  noLeftBorder: ["no left side", "no sides"].includes(borders),
220
239
  noRightBorder: ["no right side", "no sides"].includes(borders),
@@ -341,6 +360,11 @@ Tabs.propTypes = { ...marginPropTypes,
341
360
  warning: PropTypes.bool,
342
361
  info: PropTypes.bool
343
362
  })
344
- })
363
+ }),
364
+
365
+ /** When this prop is set any string validation failures in the children of each Tab
366
+ * will be summaraised in the Tooltip next to the Tab title
367
+ */
368
+ showValidationsSummary: PropTypes.bool
345
369
  };
346
370
  export { Tabs, Tab };
@@ -40,6 +40,10 @@ export interface TabsProps extends MarginProps {
40
40
  info?: boolean;
41
41
  };
42
42
  };
43
+ /** When this prop is set any string validation failures in the children of each Tab
44
+ * will be summaraised in the Tooltip next to the Tab title
45
+ */
46
+ showValidationsSummary?: boolean;
43
47
  }
44
48
 
45
49
  declare function Tabs(props: TabsProps): JSX.Element;
@@ -84,10 +84,24 @@ const FormField = ({
84
84
  setWarning,
85
85
  setInfo
86
86
  } = (0, _react.useContext)(_tab.TabContext);
87
+ const isMounted = (0, _react.useRef)(false);
88
+ (0, _react.useLayoutEffect)(() => {
89
+ isMounted.current = true;
90
+ return () => {
91
+ isMounted.current = false;
92
+ };
93
+ }, []);
87
94
  (0, _react.useEffect)(() => {
88
- if (setError) setError(id, !!error);
89
- if (setWarning) setWarning(id, !!warning);
90
- if (setInfo) setInfo(id, !!info);
95
+ if (setError) setError(id, error);
96
+ if (setWarning) setWarning(id, warning);
97
+ if (setInfo) setInfo(id, info);
98
+ return () => {
99
+ if (!isMounted.current) {
100
+ if (setError && error) setError(id, false);
101
+ if (setWarning && warning) setWarning(id, false);
102
+ if (setInfo && info) setInfo(id, false);
103
+ }
104
+ };
91
105
  }, [id, setError, setWarning, setInfo, error, warning, info]);
92
106
  const marginProps = (0, _utils.filterStyledSystemMarginProps)(rest);
93
107
  const fieldHelp = fieldHelpContent ? /*#__PURE__*/_react.default.createElement(_fieldHelp.default, {
@@ -48,24 +48,24 @@ const Tab = ({
48
48
  const [tabErrors, setTabErrors] = (0, _react.useState)({});
49
49
  const [tabWarnings, setTabWarnings] = (0, _react.useState)({});
50
50
  const [tabInfos, setTabInfos] = (0, _react.useState)({});
51
- const setError = (0, _react.useCallback)((childId, hasError) => {
52
- if (tabErrors[childId] !== hasError) {
51
+ const setError = (0, _react.useCallback)((childId, error) => {
52
+ if (tabErrors[childId] !== error) {
53
53
  setTabErrors({ ...tabErrors,
54
- [childId]: hasError
54
+ [childId]: error
55
55
  });
56
56
  }
57
57
  }, [tabErrors]);
58
- const setWarning = (0, _react.useCallback)((childId, hasWarning) => {
59
- if (tabWarnings[childId] !== hasWarning) {
58
+ const setWarning = (0, _react.useCallback)((childId, warning) => {
59
+ if (tabWarnings[childId] !== warning) {
60
60
  setTabWarnings({ ...tabWarnings,
61
- [childId]: hasWarning
61
+ [childId]: warning
62
62
  });
63
63
  }
64
64
  }, [tabWarnings]);
65
- const setInfo = (0, _react.useCallback)((childId, hasInfo) => {
66
- if (tabInfos[childId] !== hasInfo) {
65
+ const setInfo = (0, _react.useCallback)((childId, info) => {
66
+ if (tabInfos[childId] !== info) {
67
67
  setTabInfos({ ...tabInfos,
68
- [childId]: hasInfo
68
+ [childId]: info
69
69
  });
70
70
  }
71
71
  }, [tabInfos]);
@@ -2,9 +2,9 @@ import * as React from "react";
2
2
  import { PaddingProps } from "styled-system";
3
3
 
4
4
  export interface TabContextProps {
5
- setError?: (childId: string, hasError: boolean) => void;
6
- setWarning?: (childId: string, hasWarning: boolean) => void;
7
- setInfo?: (childId: string, hasInfo: boolean) => void;
5
+ setError?: (childId: string, error?: boolean | string) => void;
6
+ setWarning?: (childId: string, warning?: boolean | string) => void;
7
+ setInfo?: (childId: string, info?: boolean | string) => void;
8
8
  }
9
9
 
10
10
  export interface TabProps extends PaddingProps {
@@ -57,6 +57,7 @@ const Tabs = ({
57
57
  variant = "default",
58
58
  validationStatusOverride,
59
59
  headerWidth,
60
+ showValidationsSummary,
60
61
  ...rest
61
62
  }) => {
62
63
  /** The children nodes converted into an Array */
@@ -78,24 +79,24 @@ const Tabs = ({
78
79
  const [tabsErrors, setTabsErrors] = (0, _react.useState)({});
79
80
  const [tabsWarnings, setTabsWarnings] = (0, _react.useState)({});
80
81
  const [tabsInfos, setTabsInfos] = (0, _react.useState)({});
81
- const updateErrors = (0, _react.useCallback)((id, hasError) => {
82
- if (tabsErrors[id] !== hasError) {
82
+ const updateErrors = (0, _react.useCallback)((id, error) => {
83
+ if (tabsErrors[id] !== error) {
83
84
  setTabsErrors({ ...tabsErrors,
84
- [id]: hasError
85
+ [id]: error
85
86
  });
86
87
  }
87
88
  }, [tabsErrors]);
88
- const updateWarnings = (0, _react.useCallback)((id, hasWarning) => {
89
- if (tabsWarnings[id] !== hasWarning) {
89
+ const updateWarnings = (0, _react.useCallback)((id, warning) => {
90
+ if (tabsWarnings[id] !== warning) {
90
91
  setTabsWarnings({ ...tabsWarnings,
91
- [id]: hasWarning
92
+ [id]: warning
92
93
  });
93
94
  }
94
95
  }, [tabsWarnings]);
95
- const updateInfos = (0, _react.useCallback)((id, hasInfo) => {
96
- if (tabsInfos[id] !== hasInfo) {
96
+ const updateInfos = (0, _react.useCallback)((id, info) => {
97
+ if (tabsInfos[id] !== info) {
97
98
  setTabsInfos({ ...tabsInfos,
98
- [id]: hasInfo
99
+ [id]: info
99
100
  });
100
101
  }
101
102
  }, [tabsInfos]);
@@ -216,16 +217,33 @@ const Tabs = ({
216
217
  customLayout
217
218
  } = child.props;
218
219
  const refId = `${tabId}-tab`;
219
- const errors = tabsErrors[tabId] ? Object.entries(tabsErrors[tabId]).filter(tab => tab[1] === true).length : 0;
220
- const warnings = tabsWarnings[tabId] ? Object.entries(tabsWarnings[tabId]).filter(tab => tab[1] === true).length : 0;
221
- const infos = tabsInfos[tabId] ? Object.entries(tabsInfos[tabId]).filter(tab => tab[1] === true).length : 0;
220
+ const errors = tabsErrors[tabId];
221
+ const warnings = tabsWarnings[tabId];
222
+ const infos = tabsInfos[tabId];
223
+ const errorsCount = errors && Object.entries(errors).filter(tab => tab[1]).length;
224
+ const warningsCount = warnings && Object.entries(warnings).filter(tab => tab[1]).length;
225
+ const infosCount = infos && Object.entries(infos).filter(tab => tab[1]).length;
222
226
  const hasOverride = validationStatusOverride && validationStatusOverride[tabId];
223
227
  const errorOverride = hasOverride && validationStatusOverride[tabId].error;
224
228
  const warningOverride = hasOverride && validationStatusOverride[tabId].warning;
225
229
  const infoOverride = hasOverride && validationStatusOverride[tabId].info;
226
- const tabHasError = errorOverride !== undefined ? errorOverride : errors > 0;
227
- const tabHasWarning = warningOverride !== undefined ? warningOverride : warnings > 0 && !tabHasError;
228
- const tabHasInfo = infoOverride !== undefined ? infoOverride : infos > 0 && !tabHasError && !tabHasWarning;
230
+ const tabHasError = errorOverride !== undefined ? errorOverride : !!errorsCount;
231
+ const tabHasWarning = warningOverride !== undefined ? warningOverride : !!warningsCount && !tabHasError;
232
+ const tabHasInfo = infoOverride !== undefined ? infoOverride : !!infosCount && !tabHasError && !tabHasWarning;
233
+
234
+ const getValidationMessage = (message, validations = {}) => {
235
+ const summaryOfMessages = Object.values(validations).filter(value => value && typeof value === "string");
236
+
237
+ if (!showValidationsSummary || !summaryOfMessages.length) {
238
+ return message;
239
+ }
240
+
241
+ if (summaryOfMessages.length === 1) {
242
+ return summaryOfMessages[0];
243
+ }
244
+
245
+ return summaryOfMessages.map(value => `• ${value}`).join("\n");
246
+ };
229
247
 
230
248
  const tabTitle = /*#__PURE__*/_react.default.createElement(_tabTitle.default, {
231
249
  position: isInSidebar ? "left" : position,
@@ -247,9 +265,9 @@ const Tabs = ({
247
265
  borders: borders !== "off",
248
266
  siblings: siblings,
249
267
  titlePosition: titlePosition,
250
- errorMessage: errorMessage,
251
- warningMessage: warningMessage,
252
- infoMessage: infoMessage,
268
+ errorMessage: getValidationMessage(errorMessage, errors),
269
+ warningMessage: getValidationMessage(warningMessage, warnings),
270
+ infoMessage: getValidationMessage(infoMessage, infos),
253
271
  alternateStyling: variant === "alternate",
254
272
  noLeftBorder: ["no left side", "no sides"].includes(borders),
255
273
  noRightBorder: ["no right side", "no sides"].includes(borders),
@@ -378,5 +396,10 @@ Tabs.propTypes = { ...marginPropTypes,
378
396
  warning: _propTypes.default.bool,
379
397
  info: _propTypes.default.bool
380
398
  })
381
- })
399
+ }),
400
+
401
+ /** When this prop is set any string validation failures in the children of each Tab
402
+ * will be summaraised in the Tooltip next to the Tab title
403
+ */
404
+ showValidationsSummary: _propTypes.default.bool
382
405
  };
@@ -40,6 +40,10 @@ export interface TabsProps extends MarginProps {
40
40
  info?: boolean;
41
41
  };
42
42
  };
43
+ /** When this prop is set any string validation failures in the children of each Tab
44
+ * will be summaraised in the Tooltip next to the Tab title
45
+ */
46
+ showValidationsSummary?: boolean;
43
47
  }
44
48
 
45
49
  declare function Tabs(props: TabsProps): JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carbon-react",
3
- "version": "111.18.0",
3
+ "version": "111.19.0",
4
4
  "description": "A library of reusable React components for easily building user interfaces.",
5
5
  "files": [
6
6
  "lib",