carbon-react 120.6.1 → 121.0.1

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.
Files changed (54) hide show
  1. package/esm/__internal__/character-count/character-count.component.d.ts +4 -2
  2. package/esm/__internal__/character-count/character-count.component.js +16 -6
  3. package/esm/__internal__/character-count/character-count.style.d.ts +4 -1
  4. package/esm/__internal__/character-count/character-count.style.js +26 -2
  5. package/esm/components/breadcrumbs/crumb/crumb.component.js +1 -0
  6. package/esm/components/date/date.component.d.ts +1 -1
  7. package/esm/components/grouped-character/grouped-character.component.js +0 -1
  8. package/esm/components/link/link.component.js +9 -4
  9. package/esm/components/link/link.style.d.ts +1 -0
  10. package/esm/components/link/link.style.js +15 -16
  11. package/esm/components/menu/menu-item/menu-item.style.js +1 -15
  12. package/esm/components/number/number.component.js +0 -1
  13. package/esm/components/textarea/textarea.component.d.ts +0 -2
  14. package/esm/components/textarea/textarea.component.js +6 -11
  15. package/esm/components/textbox/textbox.component.d.ts +0 -2
  16. package/esm/components/textbox/textbox.component.js +7 -12
  17. package/esm/components/textbox/textbox.style.js +4 -0
  18. package/esm/hooks/__internal__/useCharacterCount/useCharacterCount.d.ts +1 -6
  19. package/esm/hooks/__internal__/useCharacterCount/useCharacterCount.js +24 -8
  20. package/esm/hooks/__internal__/useDebounce/index.d.ts +1 -0
  21. package/esm/hooks/__internal__/useDebounce/index.js +1 -0
  22. package/esm/hooks/__internal__/useDebounce/useDebounce.d.ts +4 -0
  23. package/esm/hooks/__internal__/useDebounce/useDebounce.js +19 -0
  24. package/esm/locales/en-gb.js +3 -3
  25. package/esm/locales/locale.d.ts +1 -1
  26. package/esm/locales/pl-pl.js +2 -2
  27. package/lib/__internal__/character-count/character-count.component.d.ts +4 -2
  28. package/lib/__internal__/character-count/character-count.component.js +16 -6
  29. package/lib/__internal__/character-count/character-count.style.d.ts +4 -1
  30. package/lib/__internal__/character-count/character-count.style.js +31 -5
  31. package/lib/components/breadcrumbs/crumb/crumb.component.js +1 -0
  32. package/lib/components/date/date.component.d.ts +1 -1
  33. package/lib/components/grouped-character/grouped-character.component.js +0 -1
  34. package/lib/components/link/link.component.js +8 -3
  35. package/lib/components/link/link.style.d.ts +1 -0
  36. package/lib/components/link/link.style.js +15 -16
  37. package/lib/components/menu/menu-item/menu-item.style.js +1 -15
  38. package/lib/components/number/number.component.js +0 -1
  39. package/lib/components/textarea/textarea.component.d.ts +0 -2
  40. package/lib/components/textarea/textarea.component.js +6 -11
  41. package/lib/components/textbox/textbox.component.d.ts +0 -2
  42. package/lib/components/textbox/textbox.component.js +7 -12
  43. package/lib/components/textbox/textbox.style.js +4 -0
  44. package/lib/hooks/__internal__/useCharacterCount/useCharacterCount.d.ts +1 -6
  45. package/lib/hooks/__internal__/useCharacterCount/useCharacterCount.js +23 -7
  46. package/lib/hooks/__internal__/useDebounce/index.d.ts +1 -0
  47. package/lib/hooks/__internal__/useDebounce/index.js +13 -0
  48. package/lib/hooks/__internal__/useDebounce/package.json +6 -0
  49. package/lib/hooks/__internal__/useDebounce/useDebounce.d.ts +4 -0
  50. package/lib/hooks/__internal__/useDebounce/useDebounce.js +26 -0
  51. package/lib/locales/en-gb.js +3 -3
  52. package/lib/locales/locale.d.ts +1 -1
  53. package/lib/locales/pl-pl.js +2 -2
  54. package/package.json +1 -1
@@ -6,24 +6,34 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _react = _interopRequireDefault(require("react"));
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
- var _characterCount = _interopRequireDefault(require("./character-count.style"));
9
+ var _characterCount = require("./character-count.style");
10
10
  var _useLocale = _interopRequireDefault(require("../../hooks/__internal__/useLocale"));
11
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
12
  const CharacterCount = ({
13
13
  value,
14
+ debouncedValue = value,
14
15
  limit,
16
+ isDebouncedOverLimit,
15
17
  isOverLimit,
16
- "data-element": dataElement
18
+ visuallyHiddenHintId
17
19
  }) => {
18
20
  const limitMinusValue = +limit - +value;
19
21
  const valueMinusLimit = +value - +limit;
22
+ const debouncedLimitMinusValue = +limit - +debouncedValue;
23
+ const debouncedValueMinusLimit = debouncedValue - +limit;
20
24
  const l = (0, _useLocale.default)();
21
25
  const getFormatNumber = (rawValue, locale) => new Intl.NumberFormat(locale).format(rawValue);
22
- return /*#__PURE__*/_react.default.createElement(_characterCount.default, {
23
- "aria-live": "polite",
26
+ return /*#__PURE__*/_react.default.createElement(_characterCount.StyledCharacterCountWrapper, null, /*#__PURE__*/_react.default.createElement(_characterCount.VisuallyHiddenHint, {
27
+ "data-element": "visually-hidden-hint",
28
+ id: visuallyHiddenHintId
29
+ }, l.characterCount.visuallyHiddenHint(getFormatNumber(limit, l.locale()))), /*#__PURE__*/_react.default.createElement(_characterCount.StyledCharacterCount, {
30
+ "aria-hidden": "true",
24
31
  isOverLimit: isOverLimit,
25
- "data-element": dataElement
26
- }, !isOverLimit ? l.characterCount.charactersLeft(limitMinusValue, getFormatNumber(limitMinusValue, l.locale())) : l.characterCount.tooManyCharacters(valueMinusLimit, getFormatNumber(valueMinusLimit, l.locale())));
32
+ "data-element": "character-count"
33
+ }, !isOverLimit ? l.characterCount.charactersLeft(limitMinusValue, getFormatNumber(limitMinusValue, l.locale())) : l.characterCount.tooManyCharacters(valueMinusLimit, getFormatNumber(valueMinusLimit, l.locale()))), /*#__PURE__*/_react.default.createElement(_characterCount.VisuallyHiddenCharacterCount, {
34
+ "data-element": "visually-hidden-character-count",
35
+ "aria-live": "polite"
36
+ }, !isDebouncedOverLimit ? l.characterCount.charactersLeft(debouncedLimitMinusValue, getFormatNumber(debouncedLimitMinusValue, l.locale())) : l.characterCount.tooManyCharacters(debouncedValueMinusLimit, getFormatNumber(debouncedValueMinusLimit, l.locale()))));
27
37
  };
28
38
  var _default = CharacterCount;
29
39
  exports.default = _default;
@@ -1,4 +1,7 @@
1
+ declare const StyledCharacterCountWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
1
2
  declare const StyledCharacterCount: import("styled-components").StyledComponent<"div", any, {
2
3
  isOverLimit: boolean;
3
4
  }, never>;
4
- export default StyledCharacterCount;
5
+ declare const VisuallyHiddenCharacterCount: import("styled-components").StyledComponent<"div", any, {}, never>;
6
+ declare const VisuallyHiddenHint: import("styled-components").StyledComponent<"div", any, {}, never>;
7
+ export { StyledCharacterCountWrapper, StyledCharacterCount, VisuallyHiddenCharacterCount, VisuallyHiddenHint, };
@@ -3,14 +3,21 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
6
+ exports.VisuallyHiddenHint = exports.VisuallyHiddenCharacterCount = exports.StyledCharacterCountWrapper = exports.StyledCharacterCount = void 0;
7
7
  var _styledComponents = _interopRequireWildcard(require("styled-components"));
8
8
  var _base = _interopRequireDefault(require("../../style/themes/base"));
9
+ var _visuallyHidden = _interopRequireDefault(require("../../style/utils/visually-hidden"));
9
10
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
11
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
11
12
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
13
+ const StyledCharacterCountWrapper = _styledComponents.default.div``;
14
+ exports.StyledCharacterCountWrapper = StyledCharacterCountWrapper;
12
15
  const StyledCharacterCount = _styledComponents.default.div`
13
- text-align: right;
16
+ ::after {
17
+ content: " ";
18
+ }
19
+
20
+ text-align: left;
14
21
  font-size: 12px;
15
22
  margin-top: 4px;
16
23
  margin-bottom: 4px;
@@ -24,8 +31,27 @@ const StyledCharacterCount = _styledComponents.default.div`
24
31
  font-weight: 700;
25
32
  `}
26
33
  `;
34
+ exports.StyledCharacterCount = StyledCharacterCount;
35
+ const VisuallyHiddenCharacterCount = _styledComponents.default.div`
36
+ ::after {
37
+ content: " ";
38
+ }
39
+
40
+ ${_visuallyHidden.default}
41
+ `;
42
+ exports.VisuallyHiddenCharacterCount = VisuallyHiddenCharacterCount;
43
+ const VisuallyHiddenHint = _styledComponents.default.div`
44
+ ::before {
45
+ content: " ";
46
+ }
47
+
48
+ ::after {
49
+ content: " ";
50
+ }
51
+
52
+ ${_visuallyHidden.default}
53
+ `;
54
+ exports.VisuallyHiddenHint = VisuallyHiddenHint;
27
55
  StyledCharacterCount.defaultProps = {
28
56
  theme: _base.default
29
- };
30
- var _default = StyledCharacterCount;
31
- exports.default = _default;
57
+ };
@@ -77,6 +77,7 @@ Crumb.propTypes = {
77
77
  "data-component": _propTypes.default.string,
78
78
  "data-element": _propTypes.default.string,
79
79
  "data-role": _propTypes.default.string,
80
+ "hasFocus": _propTypes.default.bool,
80
81
  "href": _propTypes.default.string,
81
82
  "isCurrent": _propTypes.default.bool,
82
83
  "onClick": _propTypes.default.func,
@@ -12,7 +12,7 @@ export interface DateChangeEvent {
12
12
  };
13
13
  };
14
14
  }
15
- export interface DateInputProps extends Omit<TextboxProps, "value" | "formattedValue" | "rawValue" | "onChange" | "onBlur" | "onMouseDown" | "onChangeDeferred" | "deferTimeout" | "children" | "leftChildren" | "placeholder" | "iconOnClick" | "iconOnMouseDown" | "enforceCharacterLimit" | "characterLimit" | "warnOverLimit" | "iconTabIndex" | "inputIcon"> {
15
+ export interface DateInputProps extends Omit<TextboxProps, "value" | "formattedValue" | "rawValue" | "onChange" | "onBlur" | "onMouseDown" | "onChangeDeferred" | "deferTimeout" | "children" | "leftChildren" | "placeholder" | "iconOnClick" | "iconOnMouseDown" | "characterLimit" | "warnOverLimit" | "iconTabIndex" | "inputIcon"> {
16
16
  /** Boolean to allow the input to have an empty value */
17
17
  allowEmptyValue?: boolean;
18
18
  /** Boolean to toggle where DatePicker is rendered in relation to the Date Input */
@@ -213,7 +213,6 @@ GroupedCharacter.propTypes = {
213
213
  "dir": _propTypes.default.string,
214
214
  "disabled": _propTypes.default.bool,
215
215
  "draggable": _propTypes.default.oneOfType([_propTypes.default.oneOf(["false", "true"]), _propTypes.default.bool]),
216
- "enforceCharacterLimit": _propTypes.default.bool,
217
216
  "enterKeyHint": _propTypes.default.oneOf(["done", "enter", "go", "next", "previous", "search", "send"]),
218
217
  "error": _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
219
218
  "fieldHelp": _propTypes.default.node,
@@ -38,6 +38,7 @@ const Link = /*#__PURE__*/_react.default.forwardRef(({
38
38
  removeAriaLabelOnIcon,
39
39
  ...rest
40
40
  }, ref) => {
41
+ const [hasFocus, setHasFocus] = (0, _react.useState)(false);
41
42
  const l = (0, _useLocale.default)();
42
43
  const {
43
44
  inMenu
@@ -84,7 +85,9 @@ const Link = /*#__PURE__*/_react.default.forwardRef(({
84
85
  href,
85
86
  rel,
86
87
  "aria-label": ariaLabel,
87
- ...ariaProps
88
+ ...ariaProps,
89
+ onFocus: () => setHasFocus(true),
90
+ onBlur: () => setHasFocus(false)
88
91
  };
89
92
  const buttonProps = {
90
93
  type: "button"
@@ -96,8 +99,7 @@ const Link = /*#__PURE__*/_react.default.forwardRef(({
96
99
  }
97
100
  return /*#__PURE__*/_react.default.createElement(type, type === "button" ? {
98
101
  ...componentProps,
99
- ...buttonProps,
100
- placeholderTabIndex
102
+ ...buttonProps
101
103
  } : {
102
104
  ...componentProps,
103
105
  ...(placeholderTabIndex && href === undefined && !onClick && {
@@ -116,6 +118,8 @@ const Link = /*#__PURE__*/_react.default.forwardRef(({
116
118
  isMenuItem: inMenu
117
119
  }, (0, _tags.default)("link", rest), isSkipLink && {
118
120
  "data-element": "skip-link"
121
+ }, {
122
+ hasFocus: hasFocus
119
123
  }), createLinkBasedOnType());
120
124
  });
121
125
  exports.Link = Link;
@@ -172,6 +176,7 @@ Link.propTypes = {
172
176
  "children": _propTypes.default.node,
173
177
  "className": _propTypes.default.string,
174
178
  "disabled": _propTypes.default.bool,
179
+ "hasFocus": _propTypes.default.bool,
175
180
  "href": _propTypes.default.string,
176
181
  "icon": _propTypes.default.oneOf(["accessibility_web", "add", "admin", "alert_on", "alert", "analysis", "app_facebook", "app_instagram", "app_tiktok", "app_twitter", "app_youtube", "apps", "arrow_bottom_right_circle", "arrow_down", "arrow_left_boxed", "arrow_left_right_small", "arrow_left_small", "arrow_left", "arrow_right_small", "arrow_right", "arrow_top_left_circle", "arrow_up", "arrow", "arrows_left_right", "attach", "bank_with_card", "bank", "basket_with_squares", "basket", "bed", "bill_paid", "bin", "block_arrow_right", "blocked_square", "blocked", "bold", "box_arrow_left", "box_arrow_right", "boxed_shapes", "bulk_destroy", "bullet_list_dotted", "bullet_list_numbers", "bullet_list", "business", "calendar_pay_date", "calendar_today", "calendar", "call", "camera", "car_lock", "car_money", "car_repair", "card_view", "card_wallet", "caret_down", "caret_large_down", "caret_large_left", "caret_large_right", "caret_large_up", "caret_left", "caret_right", "caret_up", "cart", "cash", "chart_bar", "chart_line", "chart_pie", "chat_notes", "chat", "check_all", "check_none", "chevron_down_thick", "chevron_down", "chevron_left_thick", "chevron_left", "chevron_right_thick", "chevron_right", "chevron_up_thick", "chevron_up", "circle_with_dots", "circles_connection", "clock", "close", "coins", "collaborate", "computer_clock", "connect_off", "connect", "construction", "contacts", "copy", "create", "credit_card_slash", "credit_card", "cross_circle", "cross", "csv", "dashboard", "delete", "delivery", "disconnect", "disputed", "document_right_align", "document_tick", "document_vertical_lines", "download", "draft", "drag_vertical", "drag", "drill", "dropdown", "duplicate", "edit", "edited", "ellipsis_horizontal", "ellipsis_vertical", "email_switch", "email", "entry", "envelope_dollar", "envelope_euro", "error_square", "error", "euro", "expand", "factory", "favourite_lined", "favourite", "fax", "feedback", "file_excel", "file_generic", "file_image", "file_pdf", "file_word", "files_leaning", "filter_new", "filter", "fit_height", "fit_width", "flag", "folder", "form_refresh", "gift", "go", "graduation_hat", "graph", "grid", "hand_cash_coins", "hand_cash_note", "heart_pulse", "help", "hide", "home", "image", "in_progress", "in_transit", "individual", "info", "intranet", "italic", "job_seeked", "key", "laptop", "ledger_arrow_left", "ledger_arrow_right", "ledger", "lightbulb_off", "lightbulb_on", "like", "link_cloud", "link_on", "link", "list_view", "location", "locked", "logout", "lookup", "marker", "message", "microphone", "minus_large", "minus", "mobile", "money_bag", "none", "old_warning", "palm_tree", "pause_circle", "pause", "pdf", "people_switch", "people", "percentage_boxed", "person_info", "person_tick", "person", "petrol_pump", "phone", "piggy_bank", "plane", "play_circle", "play", "plus_large", "plus", "pound", "print", "progress", "progressed", "protect", "question_hollow", "question_mark", "question", "recruiting", "refresh_clock", "refresh", "remove", "sage_coin", "save", "scan", "search", "send", "services", "settings_old", "settings", "share", "shop", "sort_down", "sort_up", "spanner", "split_container", "split", "square_dot", "squares_nine", "stacked_boxes", "stacked_squares", "submitted", "support_online", "sync", "tag", "talk", "target_man", "target", "theatre_masks", "three_boxes", "tick_circle", "tick_thick", "tick", "true_tick", "u_turn_left", "u_turn_right", "undo", "unlocked", "upload", "uploaded", "video", "view", "volunteering", "warning", "website", "welfare"]),
177
182
  "iconAlign": _propTypes.default.oneOf(["left", "right"]),
@@ -10,6 +10,7 @@ export interface StyledLinkProps {
10
10
  isDarkBackground?: boolean;
11
11
  /** Allows link styling to be updated for light or dark backgrounds */
12
12
  variant?: Variants;
13
+ hasFocus?: boolean;
13
14
  }
14
15
  interface PrivateStyledLinkProps {
15
16
  hasContent: boolean;
@@ -51,7 +51,8 @@ const StyledLink = _styledComponents.default.span`
51
51
  disabled,
52
52
  variant,
53
53
  isDarkBackground,
54
- isMenuItem
54
+ isMenuItem,
55
+ hasFocus
55
56
  }) => {
56
57
  const colorMapKey = isDarkBackground ? "dark" : "light";
57
58
  const {
@@ -126,21 +127,6 @@ const StyledLink = _styledComponents.default.span`
126
127
  }
127
128
  `}
128
129
  }
129
-
130
- ${!disabled && !theme.focusRedesignOptOut && (0, _styledComponents.css)`
131
- a,
132
- button {
133
- outline: none;
134
- text-decoration: none;
135
- border-bottom-left-radius: var(--borderRadius000);
136
- border-bottom-right-radius: var(--borderRadius000);
137
- }
138
- &:focus-within {
139
- box-shadow: 0 4px 0 0 var(--colorsUtilityYin090);
140
- border-bottom-left-radius: var(--borderRadius025);
141
- border-bottom-right-radius: var(--borderRadius025);
142
- }
143
- `}
144
130
  `}
145
131
 
146
132
  a,
@@ -182,6 +168,19 @@ const StyledLink = _styledComponents.default.span`
182
168
  `}
183
169
  }
184
170
 
171
+ ${!isSkipLink && !disabled && !theme.focusRedesignOptOut && hasFocus && (0, _styledComponents.css)`
172
+ a,
173
+ button {
174
+ outline: none;
175
+ text-decoration: none;
176
+ border-bottom-left-radius: var(--borderRadius000);
177
+ border-bottom-right-radius: var(--borderRadius000);
178
+ }
179
+ box-shadow: 0 4px 0 0 var(--colorsUtilityYin090);
180
+ border-bottom-left-radius: var(--borderRadius025);
181
+ border-bottom-right-radius: var(--borderRadius025);
182
+ `}
183
+
185
184
  button {
186
185
  background-color: transparent;
187
186
  border: none;
@@ -16,14 +16,6 @@ var _themes = require("../../../style/themes");
16
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
17
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
18
18
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
19
- const overrideLinkFocusStyling = fullScreenView => `
20
- &:focus-within {
21
- box-shadow: none;
22
- a {
23
- background-color: ${fullScreenView ? "var(--colorsComponentsMenuAutumnStandard600)" : "transparent"};
24
- }
25
- }
26
- `;
27
19
  const oldFocusStyling = `
28
20
  box-shadow: inset 0 0 0 var(--borderWidth300) var(--colorsSemanticFocus500);
29
21
  `;
@@ -54,19 +46,13 @@ const StyledMenuItemWrapper = _styledComponents.default.a.attrs({
54
46
  font-weight: 700;
55
47
  height: 40px;
56
48
  position: relative;
57
-
58
- && {
59
- :focus-within > a, > button {
60
- background-color: transparent;
61
- }
62
- }
49
+ box-shadow: none;
63
50
 
64
51
  a,
65
52
  button {
66
53
  cursor: pointer;
67
54
  }
68
55
 
69
- ${overrideLinkFocusStyling(inFullscreenView)}
70
56
  a:focus,
71
57
  button:focus {
72
58
  ${({
@@ -145,7 +145,6 @@ Number.propTypes = {
145
145
  "dir": _propTypes.default.string,
146
146
  "disabled": _propTypes.default.bool,
147
147
  "draggable": _propTypes.default.oneOfType([_propTypes.default.oneOf(["false", "true"]), _propTypes.default.bool]),
148
- "enforceCharacterLimit": _propTypes.default.bool,
149
148
  "enterKeyHint": _propTypes.default.oneOf(["done", "enter", "go", "next", "previous", "search", "send"]),
150
149
  "error": _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
151
150
  "fieldHelp": _propTypes.default.node,
@@ -26,8 +26,6 @@ export interface TextareaProps extends ValidationProps, MarginProps, Omit<Common
26
26
  cols?: number;
27
27
  /** If true, the component will be disabled */
28
28
  disabled?: boolean;
29
- /** Stop the user typing over the characterLimit */
30
- enforceCharacterLimit?: boolean;
31
29
  /** Indicate that error has occurred
32
30
  Pass string to display icon, tooltip and red border
33
31
  Pass true boolean to only display red border */
@@ -37,7 +37,6 @@ const Textarea = /*#__PURE__*/_react.default.forwardRef(({
37
37
  size,
38
38
  children,
39
39
  characterLimit,
40
- enforceCharacterLimit = true,
41
40
  onChange,
42
41
  disabled = false,
43
42
  labelInline,
@@ -128,7 +127,7 @@ const Textarea = /*#__PURE__*/_react.default.forwardRef(({
128
127
  label,
129
128
  fieldHelp
130
129
  });
131
- const [maxLength, characterCount, characterCountHintId, characterCountHint] = (0, _useCharacterCount.default)(value, characterLimit, enforceCharacterLimit);
130
+ const [characterCount, visuallyHiddenHintId] = (0, _useCharacterCount.default)(value, characterLimit);
132
131
  (0, _react.useEffect)(() => {
133
132
  if (rows) {
134
133
  minHeight.current = internalRef?.current?.scrollHeight || 0;
@@ -156,10 +155,8 @@ const Textarea = /*#__PURE__*/_react.default.forwardRef(({
156
155
  }, [expandable]);
157
156
  const hasIconInside = !!(inputIcon || validationId && !validationOnLabel);
158
157
  const hintId = (0, _react.useRef)((0, _guid.default)());
159
- const characterCountHintIdValue = characterCount ? characterCountHintId : undefined;
160
- const inputHintIdValue = inputHint ? hintId.current : undefined;
161
- const hintIdValue = characterLimit ? characterCountHintIdValue : inputHintIdValue;
162
- const combinedAriaDescribedBy = [ariaDescribedBy, hintIdValue].filter(Boolean).join(" ");
158
+ const inputHintId = inputHint ? hintId.current : undefined;
159
+ const combinedAriaDescribedBy = [ariaDescribedBy, inputHintId, visuallyHiddenHintId].filter(Boolean).join(" ");
163
160
  const input = /*#__PURE__*/_react.default.createElement(_input.InputPresentation, {
164
161
  size: size,
165
162
  disabled: disabled,
@@ -177,7 +174,6 @@ const Textarea = /*#__PURE__*/_react.default.forwardRef(({
177
174
  name: name,
178
175
  value: value,
179
176
  ref: callbackRef,
180
- maxLength: maxLength,
181
177
  onChange: onChange,
182
178
  disabled: disabled,
183
179
  readOnly: readOnly,
@@ -228,10 +224,10 @@ const Textarea = /*#__PURE__*/_react.default.forwardRef(({
228
224
  useValidationIcon: computeLabelPropValues(validationOnLabel),
229
225
  adaptiveLabelBreakpoint: adaptiveLabelBreakpoint,
230
226
  validationRedesignOptIn: validationRedesignOptIn
231
- }, characterLimit || inputHint ? /*#__PURE__*/_react.default.createElement(_textbox.StyledInputHint, {
232
- id: hintIdValue,
227
+ }, inputHint ? /*#__PURE__*/_react.default.createElement(_textbox.StyledInputHint, {
228
+ id: inputHintId,
233
229
  "data-element": "input-hint"
234
- }, characterCountHint || inputHint) : null, validationRedesignOptIn && labelHelp && /*#__PURE__*/_react.default.createElement(_textbox.StyledHintText, null, labelHelp), validationRedesignOptIn ? /*#__PURE__*/_react.default.createElement(_box.default, {
230
+ }, inputHint) : null, validationRedesignOptIn && labelHelp && /*#__PURE__*/_react.default.createElement(_textbox.StyledHintText, null, labelHelp), validationRedesignOptIn ? /*#__PURE__*/_react.default.createElement(_box.default, {
235
231
  position: "relative"
236
232
  }, /*#__PURE__*/_react.default.createElement(_validationMessage.default, {
237
233
  error: error,
@@ -327,7 +323,6 @@ Textarea.propTypes = {
327
323
  "dir": _propTypes.default.string,
328
324
  "disabled": _propTypes.default.bool,
329
325
  "draggable": _propTypes.default.oneOfType([_propTypes.default.oneOf(["false", "true"]), _propTypes.default.bool]),
330
- "enforceCharacterLimit": _propTypes.default.bool,
331
326
  "enterKeyHint": _propTypes.default.oneOf(["done", "enter", "go", "next", "previous", "search", "send"]),
332
327
  "error": _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
333
328
  "expandable": _propTypes.default.bool,
@@ -94,8 +94,6 @@ export interface TextboxProps extends CommonTextboxProps {
94
94
  positionedChildren?: React.ReactNode;
95
95
  /** Character limit of the textarea */
96
96
  characterLimit?: number;
97
- /** Stop the user typing over the characterLimit */
98
- enforceCharacterLimit?: boolean;
99
97
  }
100
98
  export declare const Textbox: React.ForwardRefExoticComponent<TextboxProps & React.RefAttributes<HTMLInputElement>>;
101
99
  export default Textbox;
@@ -79,13 +79,13 @@ const Textbox = /*#__PURE__*/_react.default.forwardRef(({
79
79
  "data-component": dataComponent,
80
80
  "data-element": dataElement,
81
81
  "data-role": dataRole,
82
- enforceCharacterLimit = true,
83
82
  characterLimit,
84
83
  helpAriaLabel,
85
84
  ...props
86
85
  }, ref) => {
87
86
  const characterCountValue = typeof value === "string" ? value : "";
88
- const [maxLength, characterCount, characterCountHintId, characterCountHint] = (0, _useCharacterCount.default)(characterCountValue, characterLimit, enforceCharacterLimit);
87
+ const [uniqueId, uniqueName] = (0, _useUniqueId.default)(id, name);
88
+ const [characterCount, visuallyHiddenHintId] = (0, _useCharacterCount.default)(characterCountValue, characterLimit);
89
89
  const {
90
90
  validationRedesignOptIn
91
91
  } = (0, _react.useContext)(_carbonProvider.NewValidationContext);
@@ -93,7 +93,6 @@ const Textbox = /*#__PURE__*/_react.default.forwardRef(({
93
93
  disableErrorBorder
94
94
  } = (0, _react.useContext)(_numeralDateContext.default);
95
95
  const computeLabelPropValues = prop => validationRedesignOptIn ? undefined : prop;
96
- const [uniqueId, uniqueName] = (0, _useUniqueId.default)(id, name);
97
96
  if (!deprecateInputRefWarnTriggered && inputRef) {
98
97
  deprecateInputRefWarnTriggered = true;
99
98
  _logger.default.deprecate("The `inputRef` prop in `Textbox` component is deprecated and will soon be removed. Please use `ref` instead.");
@@ -117,10 +116,8 @@ const Textbox = /*#__PURE__*/_react.default.forwardRef(({
117
116
  fieldHelp
118
117
  });
119
118
  const hintId = (0, _react.useRef)((0, _guid.default)());
120
- const characterCountHintIdValue = characterCount ? characterCountHintId : undefined;
121
- const inputHintIdValue = inputHint ? hintId.current : undefined;
122
- const hintIdValue = characterLimit ? characterCountHintIdValue : inputHintIdValue;
123
- const combinedAriaDescribedBy = [ariaDescribedBy, hintIdValue].filter(Boolean).join(" ");
119
+ const inputHintId = inputHint ? hintId.current : undefined;
120
+ const combinedAriaDescribedBy = [ariaDescribedBy, inputHintId, visuallyHiddenHintId].filter(Boolean).join(" ");
124
121
  const hasIconInside = !!(inputIcon || validationId && !validationOnLabel);
125
122
  const input = /*#__PURE__*/_react.default.createElement(_input.InputPresentation, {
126
123
  align: align,
@@ -161,7 +158,6 @@ const Textbox = /*#__PURE__*/_react.default.forwardRef(({
161
158
  placeholder: disabled || readOnly ? "" : placeholder,
162
159
  readOnly: readOnly,
163
160
  value: typeof formattedValue === "string" ? formattedValue : value,
164
- maxLength: maxLength,
165
161
  validationIconId: validationRedesignOptIn ? undefined : validationId
166
162
  }, props)), children, /*#__PURE__*/_react.default.createElement(_inputIconToggle.default, {
167
163
  align: align,
@@ -206,10 +202,10 @@ const Textbox = /*#__PURE__*/_react.default.forwardRef(({
206
202
  "data-element": dataElement,
207
203
  validationIconId: validationRedesignOptIn ? undefined : validationId,
208
204
  validationRedesignOptIn: validationRedesignOptIn
209
- }, (0, _utils.filterStyledSystemMarginProps)(props)), characterLimit || inputHint ? /*#__PURE__*/_react.default.createElement(_textbox.StyledInputHint, {
210
- id: hintIdValue,
205
+ }, (0, _utils.filterStyledSystemMarginProps)(props)), inputHint ? /*#__PURE__*/_react.default.createElement(_textbox.StyledInputHint, {
206
+ id: inputHintId,
211
207
  "data-element": "input-hint"
212
- }, characterCountHint || inputHint) : null, validationRedesignOptIn && labelHelp && /*#__PURE__*/_react.default.createElement(_textbox.StyledHintText, null, labelHelp), validationRedesignOptIn ? /*#__PURE__*/_react.default.createElement(_box.default, {
208
+ }, inputHint) : null, validationRedesignOptIn && labelHelp && /*#__PURE__*/_react.default.createElement(_textbox.StyledHintText, null, labelHelp), validationRedesignOptIn ? /*#__PURE__*/_react.default.createElement(_box.default, {
213
209
  position: "relative"
214
210
  }, /*#__PURE__*/_react.default.createElement(_validationMessage.default, {
215
211
  error: error,
@@ -305,7 +301,6 @@ Textbox.propTypes = {
305
301
  "dir": _propTypes.default.string,
306
302
  "disabled": _propTypes.default.bool,
307
303
  "draggable": _propTypes.default.oneOfType([_propTypes.default.oneOf(["false", "true"]), _propTypes.default.bool]),
308
- "enforceCharacterLimit": _propTypes.default.bool,
309
304
  "enterKeyHint": _propTypes.default.oneOf(["done", "enter", "go", "next", "previous", "search", "send"]),
310
305
  "error": _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
311
306
  "fieldHelp": _propTypes.default.node,
@@ -23,6 +23,10 @@ const ErrorBorder = _styledComponents.default.span`
23
23
  `;
24
24
  exports.ErrorBorder = ErrorBorder;
25
25
  const StyledInputHint = _styledComponents.default.p`
26
+ ::after {
27
+ content: " ";
28
+ }
29
+
26
30
  display: block;
27
31
  flex: 1;
28
32
  margin-top: -3px;
@@ -1,8 +1,3 @@
1
1
  /// <reference types="react" />
2
- declare const useCharacterCount: (value?: string, characterLimit?: number, enforceCharacterLimit?: boolean) => [
3
- number | undefined,
4
- JSX.Element | null,
5
- string | undefined,
6
- string | null
7
- ];
2
+ declare const useCharacterCount: (value?: string, characterLimit?: number) => [JSX.Element | null, string | undefined];
8
3
  export default useCharacterCount;
@@ -6,15 +6,23 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _characterCount = _interopRequireDefault(require("../../../__internal__/character-count"));
9
- var _useLocale = _interopRequireDefault(require("../useLocale"));
10
9
  var _guid = _interopRequireDefault(require("../../../__internal__/utils/helpers/guid"));
10
+ var _useDebounce = _interopRequireDefault(require("../useDebounce"));
11
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
12
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
13
13
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
14
- const useCharacterCount = (value = "", characterLimit, enforceCharacterLimit = true) => {
14
+ const useCharacterCount = (value = "", characterLimit) => {
15
15
  const isCharacterLimitValid = typeof characterLimit === "number" && !Number.isNaN(characterLimit);
16
- const l = (0, _useLocale.default)();
17
- const hintString = l.characterCount.hintString();
16
+ const [debouncedValue, setDebouncedValue] = (0, _react.useState)(value);
17
+ const debounceWaitTime = 2000;
18
+ const updateDebouncedValue = (0, _useDebounce.default)(newValue => {
19
+ setDebouncedValue(newValue);
20
+ }, debounceWaitTime);
21
+ (0, _react.useEffect)(() => {
22
+ if (characterLimit) {
23
+ updateDebouncedValue(value);
24
+ }
25
+ }, [value, characterLimit, updateDebouncedValue]);
18
26
  const hintId = (0, _react.useRef)((0, _guid.default)());
19
27
  const isOverLimit = (0, _react.useMemo)(() => {
20
28
  if (value && isCharacterLimitValid) {
@@ -22,12 +30,20 @@ const useCharacterCount = (value = "", characterLimit, enforceCharacterLimit = t
22
30
  }
23
31
  return false;
24
32
  }, [value, characterLimit, isCharacterLimitValid]);
25
- return [enforceCharacterLimit && isCharacterLimitValid ? characterLimit : undefined, isCharacterLimitValid ? /*#__PURE__*/_react.default.createElement(_characterCount.default, {
33
+ const isDebouncedOverLimit = (0, _react.useMemo)(() => {
34
+ if (debouncedValue && isCharacterLimitValid) {
35
+ return debouncedValue.length > characterLimit;
36
+ }
37
+ return false;
38
+ }, [debouncedValue, characterLimit, isCharacterLimitValid]);
39
+ return [isCharacterLimitValid ? /*#__PURE__*/_react.default.createElement(_characterCount.default, {
26
40
  isOverLimit: isOverLimit,
41
+ isDebouncedOverLimit: isDebouncedOverLimit,
27
42
  value: value.length,
43
+ debouncedValue: debouncedValue.length,
28
44
  limit: characterLimit,
29
- "data-element": "character-limit"
30
- }) : null, hintId.current, isCharacterLimitValid ? hintString : null];
45
+ visuallyHiddenHintId: hintId.current
46
+ }) : null, isCharacterLimitValid ? hintId.current : undefined];
31
47
  };
32
48
  var _default = useCharacterCount;
33
49
  exports.default = _default;
@@ -0,0 +1 @@
1
+ export { default } from "./useDebounce";
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "default", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _useDebounce.default;
10
+ }
11
+ });
12
+ var _useDebounce = _interopRequireDefault(require("./useDebounce"));
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -0,0 +1,6 @@
1
+ {
2
+ "sideEffects": false,
3
+ "module": "../../../../esm/hooks/__internal__/useDebounce/index.js",
4
+ "main": "./index.js",
5
+ "types": "./index.d.ts"
6
+ }
@@ -0,0 +1,4 @@
1
+ import { DebouncedFunc } from "lodash";
2
+ declare type Callback = (...args: any[]) => void;
3
+ declare const useDebounce: <T extends Callback>(callback: T, delay: number) => DebouncedFunc<T>;
4
+ export default useDebounce;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = require("react");
8
+ var _debounce = _interopRequireDefault(require("lodash/debounce"));
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+
12
+ const useDebounce = (callback, delay) => {
13
+ const callbackRef = (0, _react.useRef)(callback);
14
+ (0, _react.useEffect)(() => {
15
+ callbackRef.current = callback;
16
+ });
17
+ const debouncedCallback = (0, _react.useMemo)(() => (0, _debounce.default)(callbackRef.current, delay), [delay]);
18
+ (0, _react.useEffect)(() => {
19
+ return () => {
20
+ debouncedCallback.cancel();
21
+ };
22
+ });
23
+ return debouncedCallback;
24
+ };
25
+ var _default = useDebounce;
26
+ exports.default = _default;
@@ -31,9 +31,9 @@ const enGB = {
31
31
  yes: () => "Yes"
32
32
  },
33
33
  characterCount: {
34
- hintString: () => "Input contains a character counter",
35
- tooManyCharacters: (count, formattedCount) => count === 1 ? `You have ${formattedCount} character too many` : `You have ${formattedCount} characters too many`,
36
- charactersLeft: (count, formattedCount) => count === 1 ? `You have ${formattedCount} character remaining` : `You have ${formattedCount} characters remaining`
34
+ tooManyCharacters: (count, formattedCount) => count === 1 ? `${formattedCount} character too many` : `${formattedCount} characters too many`,
35
+ charactersLeft: (count, formattedCount) => count === 1 ? `${formattedCount} character left` : `${formattedCount} characters left`,
36
+ visuallyHiddenHint: formattedCount => `You can enter up to ${formattedCount} characters`
37
37
  },
38
38
  date: {
39
39
  dateFnsLocale: () => _dateFnsLocales.enGB
@@ -20,9 +20,9 @@ interface Locale {
20
20
  ariaLabel: () => string;
21
21
  };
22
22
  characterCount: {
23
- hintString: () => string;
24
23
  tooManyCharacters: (count: number, formattedCount: string) => string;
25
24
  charactersLeft: (count: number, formattedCount: string) => string;
25
+ visuallyHiddenHint: (formattedCount: string) => string;
26
26
  };
27
27
  confirm: {
28
28
  no: () => string;
@@ -69,9 +69,9 @@ const plPL = {
69
69
  yes: () => "Tak"
70
70
  },
71
71
  characterCount: {
72
- hintString: () => "Pole zawiera licznik znaków",
73
72
  tooManyCharacters: (count, formattedCount) => `Masz o ${formattedCount} ${PolishPlural("znak", "znaki", "znaków", count)} za dużo`,
74
- charactersLeft: (count, formattedCount) => `Masz ${formattedCount} ${PolishPlural("pozostały", "pozostałe", "pozostałych", count)} ${PolishPlural("znak", "znaki", "znaków", count)}`
73
+ charactersLeft: (count, formattedCount) => `Masz ${formattedCount} ${PolishPlural("pozostały", "pozostałe", "pozostałych", count)} ${PolishPlural("znak", "znaki", "znaków", count)}`,
74
+ visuallyHiddenHint: formattedCount => `Można wprowadzić do ${formattedCount} znaków`
75
75
  },
76
76
  date: {
77
77
  dateFnsLocale: () => _dateFnsLocales.pl
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carbon-react",
3
- "version": "120.6.1",
3
+ "version": "121.0.1",
4
4
  "description": "A library of reusable React components for easily building user interfaces.",
5
5
  "files": [
6
6
  "lib",