carbon-react 109.3.2 → 109.3.5

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 (57) hide show
  1. package/esm/__internal__/fieldset/fieldset.component.d.ts +25 -0
  2. package/esm/__internal__/fieldset/fieldset.component.js +167 -50
  3. package/esm/__internal__/fieldset/fieldset.style.d.ts +13 -0
  4. package/esm/__internal__/fieldset/fieldset.style.js +0 -10
  5. package/esm/__internal__/fieldset/index.d.ts +2 -1
  6. package/esm/__internal__/popover/index.d.ts +2 -1
  7. package/esm/__internal__/popover/popover.component.d.ts +18 -0
  8. package/esm/__internal__/popover/popover.component.js +23 -21
  9. package/esm/__internal__/popover/popover.style.d.ts +2 -0
  10. package/esm/components/button/button.component.d.ts +2 -0
  11. package/esm/components/button/button.component.js +2 -0
  12. package/esm/components/multi-action-button/multi-action-button.component.js +1 -0
  13. package/esm/components/pager/pager.component.js +1 -1
  14. package/esm/components/pager/pager.style.js +1 -1
  15. package/esm/components/select/multi-select/multi-select.component.js +36 -34
  16. package/esm/components/select/select-list/select-list.component.js +9 -1
  17. package/esm/components/select/select-list/select-list.style.js +8 -1
  18. package/esm/components/split-button/index.d.ts +2 -2
  19. package/esm/components/split-button/split-button-children.style.d.ts +8 -0
  20. package/esm/components/split-button/split-button-children.style.js +3 -4
  21. package/esm/components/split-button/split-button-toggle.style.d.ts +10 -0
  22. package/esm/components/split-button/split-button.component.d.ts +29 -0
  23. package/esm/components/split-button/split-button.component.js +534 -87
  24. package/esm/components/split-button/split-button.config.d.ts +4 -0
  25. package/esm/components/split-button/split-button.style.d.ts +2 -0
  26. package/lib/__internal__/fieldset/fieldset.component.d.ts +25 -0
  27. package/lib/__internal__/fieldset/fieldset.component.js +167 -53
  28. package/lib/__internal__/fieldset/fieldset.style.d.ts +13 -0
  29. package/lib/__internal__/fieldset/fieldset.style.js +1 -12
  30. package/lib/__internal__/fieldset/index.d.ts +2 -1
  31. package/lib/__internal__/popover/index.d.ts +2 -1
  32. package/lib/__internal__/popover/popover.component.d.ts +18 -0
  33. package/lib/__internal__/popover/popover.component.js +24 -22
  34. package/lib/__internal__/popover/popover.style.d.ts +2 -0
  35. package/lib/components/button/button.component.d.ts +2 -0
  36. package/lib/components/button/button.component.js +2 -0
  37. package/lib/components/multi-action-button/multi-action-button.component.js +1 -0
  38. package/lib/components/pager/pager.component.js +1 -1
  39. package/lib/components/pager/pager.style.js +1 -1
  40. package/lib/components/select/multi-select/multi-select.component.js +36 -34
  41. package/lib/components/select/select-list/select-list.component.js +9 -1
  42. package/lib/components/select/select-list/select-list.style.js +8 -1
  43. package/lib/components/split-button/index.d.ts +2 -2
  44. package/lib/components/split-button/split-button-children.style.d.ts +8 -0
  45. package/lib/components/split-button/split-button-children.style.js +3 -4
  46. package/lib/components/split-button/split-button-toggle.style.d.ts +10 -0
  47. package/lib/components/split-button/split-button.component.d.ts +29 -0
  48. package/lib/components/split-button/split-button.component.js +535 -89
  49. package/lib/components/split-button/split-button.config.d.ts +4 -0
  50. package/lib/components/split-button/split-button.style.d.ts +2 -0
  51. package/package.json +2 -2
  52. package/esm/__internal__/fieldset/fieldset.d.ts +0 -37
  53. package/esm/__internal__/popover/popover.d.ts +0 -46
  54. package/esm/components/split-button/split-button.d.ts +0 -29
  55. package/lib/__internal__/fieldset/fieldset.d.ts +0 -37
  56. package/lib/__internal__/popover/popover.d.ts +0 -46
  57. package/lib/components/split-button/split-button.d.ts +0 -29
@@ -64,6 +64,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
64
64
  const [highlightedValue, setHighlightedValue] = useState("");
65
65
  const [filterText, setFilterText] = useState("");
66
66
  const [placeholderOverride, setPlaceholderOverride] = useState();
67
+ const actualValue = isControlled.current ? value : selectedValue;
67
68
  const setOpen = useCallback(() => {
68
69
  setOpenState(isAlreadyOpen => {
69
70
  if (!isAlreadyOpen && onOpen) {
@@ -86,6 +87,23 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
86
87
  };
87
88
  return customEvent;
88
89
  }, [name, id]);
90
+ /* generic value update function which can be used for both controlled and uncontrolled
91
+ * components, both with and without onChange.
92
+ * It accepts a function to update the value, which is assumed to be have no side effects and therefore
93
+ * be safe to run more than once if needed. */
94
+
95
+ const updateValue = useCallback(updateFunction => {
96
+ const newValue = updateFunction(actualValue); // only call onChange if an option has been selected or deselected
97
+
98
+ if (onChange && newValue.length !== actualValue.length) {
99
+ onChange(createCustomEvent(newValue));
100
+ } // no need to update selectedValue if the component is controlled: onChange should take care of updating the value
101
+
102
+
103
+ if (!isControlled.current) {
104
+ setSelectedValue(updateFunction);
105
+ }
106
+ }, [createCustomEvent, onChange, actualValue]);
89
107
  const handleTextboxChange = useCallback(event => {
90
108
  const newValue = event.target.value;
91
109
  const match = findElementWithMatchingText(newValue, children);
@@ -99,24 +117,17 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
99
117
  setOpen();
100
118
  }, [children, setOpen]);
101
119
  const removeSelectedValue = useCallback(index => {
102
- setSelectedValue(previousValue => {
103
- isClickTriggeredBySelect.current = true;
104
-
120
+ isClickTriggeredBySelect.current = true;
121
+ updateValue(previousValue => {
105
122
  if (!previousValue.length) {
106
123
  return previousValue;
107
124
  }
108
125
 
109
126
  const newValue = [...previousValue];
110
127
  newValue.splice(index, 1);
111
-
112
- if (onChange) {
113
- onChange(createCustomEvent(newValue));
114
- return newValue;
115
- }
116
-
117
128
  return newValue;
118
129
  });
119
- }, [createCustomEvent, onChange]);
130
+ }, [updateValue]);
120
131
  const handleTextboxKeydown = useCallback(event => {
121
132
  const {
122
133
  key
@@ -142,12 +153,12 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
142
153
 
143
154
  }, [onKeyDown, readOnly, filterText, textValue, setOpen, removeSelectedValue]);
144
155
  const accessibilityLabel = useMemo(() => {
145
- return selectedValue && selectedValue.length ? React.Children.map(children, child => {
146
- return selectedValue.includes(child.props.value) ? child.props.text : false;
156
+ return actualValue && actualValue.length ? React.Children.map(children, child => {
157
+ return actualValue.includes(child.props.value) ? child.props.text : false;
147
158
  }).filter(child => child).reduce((acc, item) => {
148
159
  return acc ? `${acc}, ${item}` : item;
149
160
  }, "") : null;
150
- }, [children, selectedValue]);
161
+ }, [children, actualValue]);
151
162
  const handleGlobalClick = useCallback(event => {
152
163
  isMouseDownReported.current = false;
153
164
 
@@ -170,11 +181,11 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
170
181
  const mapValuesToPills = useMemo(() => {
171
182
  const canDelete = !disabled && !readOnly;
172
183
 
173
- if (!selectedValue.length) {
184
+ if (!actualValue.length) {
174
185
  return "";
175
186
  }
176
187
 
177
- return selectedValue.map((singleValue, index) => {
188
+ return actualValue.map((singleValue, index) => {
178
189
  const matchingOption = React.Children.toArray(children).find(child => isExpectedOption(child, singleValue));
179
190
  let pillProps = {};
180
191
 
@@ -203,22 +214,18 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
203
214
  const onChangeMissingMessage = "onChange prop required when using a controlled input element";
204
215
  !(isControlled.current === (value !== undefined)) ? process.env.NODE_ENV !== "production" ? invariant(false, modeSwitchedMessage) : invariant(false) : void 0;
205
216
  !(!isControlled.current || isControlled.current && onChange) ? process.env.NODE_ENV !== "production" ? invariant(false, onChangeMissingMessage) : invariant(false) : void 0;
206
-
207
- if (isControlled.current) {
208
- setSelectedValue(value);
209
- }
210
217
  }, [value, onChange]); // removes placeholder when a value is present
211
218
 
212
219
  useEffect(() => {
213
220
  const hasValue = value === null || value === void 0 ? void 0 : value.length;
214
- const hasSelectedValue = selectedValue === null || selectedValue === void 0 ? void 0 : selectedValue.length;
221
+ const hasSelectedValue = actualValue === null || actualValue === void 0 ? void 0 : actualValue.length;
215
222
 
216
223
  if (hasValue || hasSelectedValue) {
217
224
  setPlaceholderOverride(" ");
218
225
  } else {
219
226
  setPlaceholderOverride(placeholder);
220
227
  }
221
- }, [value, selectedValue, placeholder]);
228
+ }, [value, actualValue, placeholder]);
222
229
  useEffect(() => {
223
230
  const clickEvent = "click";
224
231
  window.addEventListener(clickEvent, handleGlobalClick);
@@ -335,27 +342,22 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
335
342
  }
336
343
 
337
344
  setTextValue("");
338
- const isAlreadySelected = selectedValue.findIndex(val => isExpectedValue(val, newValue)) !== -1;
345
+ const isAlreadySelected = actualValue.findIndex(val => isExpectedValue(val, newValue)) !== -1;
339
346
 
340
347
  if (!isAlreadySelected && isControlled.current && onChange) {
341
- onChange(createCustomEvent([...selectedValue, newValue]));
348
+ onChange(createCustomEvent([...actualValue, newValue]));
342
349
  }
343
350
 
344
- setSelectedValue(previousValue => {
345
- textboxRef.focus();
346
- isMouseDownReported.current = false;
347
-
351
+ textboxRef.focus();
352
+ isMouseDownReported.current = false;
353
+ updateValue(previousValue => {
348
354
  if (isAlreadySelected) {
349
355
  return previousValue;
350
356
  }
351
357
 
352
- if (onChange) {
353
- onChange(createCustomEvent([...previousValue, newValue]));
354
- }
355
-
356
358
  return [...previousValue, newValue];
357
359
  });
358
- }, [createCustomEvent, onChange, textboxRef, selectedValue]);
360
+ }, [createCustomEvent, onChange, textboxRef, actualValue, updateValue]);
359
361
 
360
362
  function onSelectListClose() {
361
363
  setOpenState(false);
@@ -389,7 +391,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
389
391
  leftChildren: mapValuesToPills,
390
392
  inputRef: assignInput,
391
393
  formattedValue: textValue,
392
- selectedValue,
394
+ selectedValue: actualValue,
393
395
  onClick: handleTextboxClick,
394
396
  onMouseDown: handleTextboxMouseDown,
395
397
  onFocus: handleTextboxFocus,
@@ -423,7 +425,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
423
425
  listPlacement: listPlacement,
424
426
  flipEnabled: flipEnabled,
425
427
  loaderDataRole: "multi-select-list-loader",
426
- multiselectValues: selectedValue
428
+ multiselectValues: actualValue
427
429
  }, children);
428
430
  return /*#__PURE__*/React.createElement(StyledSelectMultiSelect, _extends({
429
431
  disabled: disabled,
@@ -51,6 +51,7 @@ const SelectList = /*#__PURE__*/React.forwardRef(({
51
51
  const [currentOptionsListIndex, setCurrentOptionsListIndex] = useState(-1);
52
52
  const [listHeight, setListHeight] = useState(0);
53
53
  const [listWidth, setListWidth] = useState(null);
54
+ const [scrollbarWidth, setScrollbarWidth] = useState(0);
54
55
  const placement = useRef("bottom");
55
56
  const lastFilter = useRef("");
56
57
  const listRef = useRef();
@@ -66,6 +67,11 @@ const SelectList = /*#__PURE__*/React.forwardRef(({
66
67
  allowScroll();
67
68
  };
68
69
  }, [allowScroll, blockScroll]);
70
+ useLayoutEffect(() => {
71
+ if (multiColumn) {
72
+ setScrollbarWidth(tableRef.current.offsetWidth - tableRef.current.clientWidth);
73
+ }
74
+ }, [multiColumn]);
69
75
  const setPlacementCallback = useCallback(popper => {
70
76
  placement.current = popper.placement;
71
77
  }, [placement]);
@@ -287,7 +293,9 @@ const SelectList = /*#__PURE__*/React.forwardRef(({
287
293
  let selectListContent = childrenWithListProps;
288
294
 
289
295
  if (multiColumn) {
290
- selectListContent = /*#__PURE__*/React.createElement(StyledSelectListTable, null, /*#__PURE__*/React.createElement(StyledSelectListTableHeader, null, tableHeader), /*#__PURE__*/React.createElement(StyledSelectListTableBody, {
296
+ selectListContent = /*#__PURE__*/React.createElement(StyledSelectListTable, null, /*#__PURE__*/React.createElement(StyledSelectListTableHeader, {
297
+ scrollbarWidth: scrollbarWidth
298
+ }, tableHeader), /*#__PURE__*/React.createElement(StyledSelectListTableBody, {
291
299
  ref: tableRef
292
300
  }, childrenWithListProps));
293
301
  }
@@ -74,11 +74,18 @@ const StyledSelectListTable = styled.table`
74
74
  `; // TODO (design-tokens): to match current style for border bottom colorsUtilityMajor100
75
75
 
76
76
  const StyledSelectListTableHeader = styled.thead`
77
+ border-bottom: 1px solid var(--colorsUtilityMajor050);
78
+
79
+ tr {
80
+ width: ${({
81
+ scrollbarWidth
82
+ }) => `calc(100% - ${scrollbarWidth}px)`};
83
+ }
84
+
77
85
  th {
78
86
  position: sticky;
79
87
  top: 0;
80
88
  padding: var(--spacing200);
81
- border-bottom: 1px solid var(--colorsUtilityMajor050);
82
89
  background-color: white;
83
90
  text-align: left;
84
91
  font-weight: 900;
@@ -1,2 +1,2 @@
1
- export { default } from "./split-button";
2
- export type { SplitButtonProps } from "./split-button";
1
+ export { default } from "./split-button.component";
2
+ export type { SplitButtonProps } from "./split-button.component";
@@ -0,0 +1,8 @@
1
+ import { ThemeObject } from "../../style/themes/base";
2
+ declare type StyledSplitButtonChildrenContainerProps = {
3
+ theme: ThemeObject;
4
+ align: "left" | "right";
5
+ minWidth: number;
6
+ };
7
+ declare const StyledSplitButtonChildrenContainer: import("styled-components").StyledComponent<"div", any, StyledSplitButtonChildrenContainerProps, never>;
8
+ export default StyledSplitButtonChildrenContainer;
@@ -4,12 +4,11 @@ import StyledButton from "../button/button.style";
4
4
  const StyledSplitButtonChildrenContainer = styled.div`
5
5
  ${({
6
6
  theme,
7
- align
7
+ align,
8
+ minWidth
8
9
  }) => css`
9
10
  background-color: var(--colorsActionMajorYang100);
10
- min-width: ${({
11
- minWidth
12
- }) => minWidth}px;
11
+ min-width: ${minWidth}px;
13
12
  white-space: nowrap;
14
13
  z-index: ${theme.zIndex.popover};
15
14
  box-shadow: var(--boxShadow100);
@@ -0,0 +1,10 @@
1
+ declare type StyledSplitButtonToggleProps = {
2
+ buttonType: "primary" | "secondary";
3
+ disabled: boolean;
4
+ displayed: boolean;
5
+ size: "small" | "medium" | "large";
6
+ };
7
+ declare const StyledSplitButtonToggle: import("styled-components").StyledComponent<"button", any, import("styled-system").SpaceProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>, string | number | symbol> & import("../button").ButtonProps & {
8
+ iconOnly?: boolean | undefined;
9
+ } & StyledSplitButtonToggleProps, never>;
10
+ export default StyledSplitButtonToggle;
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import { MarginProps } from "styled-system";
3
+ import { IconType } from "../icon";
4
+ export interface SplitButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, MarginProps {
5
+ /** Set align of the rendered content */
6
+ align?: "left" | "right";
7
+ /** Button type: "primary" | "secondary" */
8
+ buttonType?: "primary" | "secondary";
9
+ /** The additional button to display. */
10
+ children: React.ReactNode;
11
+ /** A custom value for the data-element attribute */
12
+ "data-element"?: string;
13
+ /** A custom value for the data-role attribute */
14
+ "data-role"?: string;
15
+ /** Gives the button a disabled state. */
16
+ disabled?: boolean;
17
+ /** Defines an Icon position within the button: "before" | "after" */
18
+ iconPosition?: "before" | "after";
19
+ /** Defines an Icon type within the button */
20
+ iconType?: IconType;
21
+ /** The size of the buttons in the SplitButton. */
22
+ size?: "small" | "medium" | "large";
23
+ /** Second text child, renders under main text, only when size is "large" */
24
+ subtext?: string;
25
+ /** The text to be displayed in the SplitButton. */
26
+ text: string;
27
+ }
28
+ export declare const SplitButton: ({ align, buttonType, children, disabled, iconPosition, iconType, onClick, size, subtext, text, "data-element": dataElement, "data-role": dataRole, ...rest }: SplitButtonProps) => JSX.Element;
29
+ export default SplitButton;