carbon-react 123.5.1 → 123.7.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.
Files changed (29) hide show
  1. package/esm/components/select/filterable-select/filterable-select.component.js +17 -15
  2. package/esm/components/select/index.d.ts +1 -1
  3. package/esm/components/select/multi-select/multi-select.component.js +16 -9
  4. package/esm/components/select/option/option.component.js +3 -1
  5. package/esm/components/select/select-list/select-list.component.d.ts +1 -0
  6. package/esm/components/select/select-list/select-list.component.js +8 -4
  7. package/esm/components/select/select-textbox/select-textbox.component.d.ts +3 -2
  8. package/esm/components/select/simple-select/index.d.ts +1 -1
  9. package/esm/components/select/simple-select/simple-select.component.d.ts +10 -0
  10. package/esm/components/select/simple-select/simple-select.component.js +8 -6
  11. package/esm/components/toast/toast.component.d.ts +4 -1
  12. package/esm/components/toast/toast.component.js +4 -0
  13. package/esm/components/toast/toast.style.d.ts +2 -0
  14. package/esm/components/toast/toast.style.js +37 -12
  15. package/lib/components/select/filterable-select/filterable-select.component.js +17 -15
  16. package/lib/components/select/index.d.ts +1 -1
  17. package/lib/components/select/multi-select/multi-select.component.js +16 -9
  18. package/lib/components/select/option/option.component.js +3 -1
  19. package/lib/components/select/select-list/select-list.component.d.ts +1 -0
  20. package/lib/components/select/select-list/select-list.component.js +8 -4
  21. package/lib/components/select/select-textbox/select-textbox.component.d.ts +3 -2
  22. package/lib/components/select/simple-select/index.d.ts +1 -1
  23. package/lib/components/select/simple-select/simple-select.component.d.ts +10 -0
  24. package/lib/components/select/simple-select/simple-select.component.js +8 -6
  25. package/lib/components/toast/toast.component.d.ts +4 -1
  26. package/lib/components/toast/toast.component.js +4 -0
  27. package/lib/components/toast/toast.style.d.ts +2 -0
  28. package/lib/components/toast/toast.style.js +37 -12
  29. package/package.json +1 -1
@@ -86,7 +86,7 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
86
86
  deprecateUncontrolledWarnTriggered = true;
87
87
  Logger.deprecate("Uncontrolled behaviour in `Filterable Select` is deprecated and support will soon be removed. Please make sure all your inputs are controlled.");
88
88
  }
89
- const createCustomEvent = useCallback(newValue => {
89
+ const createCustomEvent = useCallback((newValue, selectionConfirmed) => {
90
90
  const customEvent = {
91
91
  target: {
92
92
  ...(name && {
@@ -96,13 +96,14 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
96
96
  id
97
97
  }),
98
98
  value: newValue
99
- }
99
+ },
100
+ selectionConfirmed
100
101
  };
101
102
  return customEvent;
102
103
  }, [name, id]);
103
- const triggerChange = useCallback(newValue => {
104
+ const triggerChange = useCallback((newValue, selectionConfirmed) => {
104
105
  if (onChange) {
105
- onChange(createCustomEvent(newValue));
106
+ onChange(createCustomEvent(newValue, selectionConfirmed));
106
107
  }
107
108
  }, [onChange, createCustomEvent]);
108
109
  function findElementWithMatchingText(textToMatch, list) {
@@ -110,7 +111,7 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
110
111
  const {
111
112
  text
112
113
  } = child.props;
113
- return text && text.toLowerCase().indexOf(textToMatch.toLowerCase()) !== -1;
114
+ return text?.toLowerCase().indexOf(textToMatch?.toLowerCase()) !== -1;
114
115
  });
115
116
  }
116
117
  const updateValues = useCallback((newFilterText, isDeleteEvent) => {
@@ -119,15 +120,15 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
119
120
  const isFilterCleared = isDeleteEvent && newFilterText === "";
120
121
  if (!match || isFilterCleared) {
121
122
  setTextValue(newFilterText);
122
- triggerChange("");
123
+ triggerChange("", false);
123
124
  return "";
124
125
  }
125
126
  if (isDeleteEvent) {
126
127
  setTextValue(newFilterText);
127
128
  return match.props.value;
128
129
  }
129
- triggerChange(match.props.value);
130
- if (match.props.text.toLowerCase().startsWith(newFilterText.toLowerCase())) {
130
+ triggerChange(match.props.value, false);
131
+ if (match.props.text?.toLowerCase().startsWith(newFilterText.toLowerCase())) {
131
132
  setTextValue(match.props.text);
132
133
  } else {
133
134
  setTextValue(newFilterText);
@@ -143,7 +144,7 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
143
144
  const matchingOption = React.Children.toArray(children).find(child => /*#__PURE__*/React.isValidElement(child) && isExpectedOption(child, newValue));
144
145
  if (!matchingOption || matchingOption.props.text === undefined) {
145
146
  setTextValue(filterText || "");
146
- } else if (isClosing || matchingOption.props.text.toLowerCase().startsWith(filterText.toLowerCase())) {
147
+ } else if (isClosing || matchingOption.props.text?.toLowerCase().startsWith(filterText?.toLowerCase())) {
147
148
  setTextValue(matchingOption.props.text);
148
149
  }
149
150
  }, [children, filterText]);
@@ -156,7 +157,7 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
156
157
  }, [updateValues]);
157
158
  const fillLastFilterCharacter = useCallback(key => {
158
159
  setFilterText(previousFilterText => {
159
- if (previousFilterText.length === textValue.length - 1 && key === textValue.slice(-1)) {
160
+ if (previousFilterText?.length === textValue?.length - 1 && key === textValue.slice(-1)) {
160
161
  return textValue;
161
162
  }
162
163
  return previousFilterText;
@@ -251,9 +252,9 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
251
252
  };
252
253
  }, [handleGlobalClick]);
253
254
  useEffect(() => {
254
- const textStartsWithFilter = textValue.toLowerCase().startsWith(filterText.toLowerCase());
255
+ const textStartsWithFilter = textValue?.toLowerCase().startsWith(filterText?.toLowerCase());
255
256
  const isTextboxActive = !disabled && !readOnly;
256
- if (isTextboxActive && textboxRef && filterText.length && textValue.length > filterText.length && textStartsWithFilter) {
257
+ if (isTextboxActive && textboxRef && filterText?.length && textValue?.length > filterText?.length && textStartsWithFilter) {
257
258
  textboxRef.selectionStart = filterText.length;
258
259
  }
259
260
  }, [textValue, filterText, textboxRef, disabled, readOnly]);
@@ -262,7 +263,8 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
262
263
  id: selectedOptionId,
263
264
  text,
264
265
  value: newValue,
265
- selectionType
266
+ selectionType,
267
+ selectionConfirmed
266
268
  } = optionData;
267
269
  if (selectionType === "tab") {
268
270
  setOpen(false);
@@ -273,8 +275,8 @@ const FilterableSelect = /*#__PURE__*/React.forwardRef(({
273
275
  setSelectedValue(newValue);
274
276
  setHighlightedValue(newValue);
275
277
  }
276
- setTextValue(text);
277
- triggerChange(newValue);
278
+ setTextValue(text || /* istanbul ignore next */"");
279
+ triggerChange(newValue, selectionConfirmed);
278
280
  setActiveDescendantId(selectedOptionId);
279
281
  if (selectionType !== "navigationKey") {
280
282
  setOpen(false);
@@ -5,7 +5,7 @@ export type { OptionRowProps } from "./option-row";
5
5
  export { default as OptionGroupHeader } from "./option-group-header";
6
6
  export type { OptionGroupHeaderProps } from "./option-group-header";
7
7
  export { default as Select } from "./simple-select";
8
- export type { SimpleSelectProps } from "./simple-select";
8
+ export type { SimpleSelectProps, CustomSelectChangeEvent, } from "./simple-select";
9
9
  export { default as FilterableSelect } from "./filterable-select";
10
10
  export type { FilterableSelectProps } from "./filterable-select";
11
11
  export { default as MultiSelect } from "./multi-select";
@@ -100,7 +100,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
100
100
  return true;
101
101
  });
102
102
  }, [onOpen]);
103
- const createCustomEvent = useCallback(newValue => {
103
+ const createCustomEvent = useCallback((newValue, selectionConfirmed) => {
104
104
  const customEvent = {
105
105
  target: {
106
106
  ...(name && {
@@ -110,7 +110,8 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
110
110
  id
111
111
  }),
112
112
  value: newValue
113
- }
113
+ },
114
+ selectionConfirmed
114
115
  };
115
116
  return customEvent;
116
117
  }, [name, id]);
@@ -119,11 +120,11 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
119
120
  * components, both with and without onChange.
120
121
  * It accepts a function to update the value, which is assumed to be have no side effects and therefore
121
122
  * be safe to run more than once if needed. */
122
- const updateValue = useCallback(updateFunction => {
123
+ const updateValue = useCallback((updateFunction, selectionConfirmed) => {
123
124
  const newValue = updateFunction(actualValue);
124
125
  // only call onChange if an option has been selected or deselected
125
126
  if (onChange && newValue.length !== actualValue?.length) {
126
- onChange(createCustomEvent(newValue));
127
+ onChange(createCustomEvent(newValue, selectionConfirmed));
127
128
  }
128
129
 
129
130
  // no need to update selectedValue if the component is controlled: onChange should take care of updating the value
@@ -158,7 +159,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
158
159
  const newValue = previousValue.slice(); // spreading does not work but slice does - see https://github.com/microsoft/TypeScript/issues/53670
159
160
  newValue.splice(index, 1);
160
161
  return newValue;
161
- });
162
+ }, true);
162
163
  }, [updateValue]);
163
164
  const handleTextboxKeydown = useCallback(event => {
164
165
  const {
@@ -210,6 +211,11 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
210
211
  return actualValue.map((singleValue, index) => {
211
212
  const matchingOption = React.Children.toArray(children).find(child => /*#__PURE__*/React.isValidElement(child) && isExpectedOption(child, singleValue));
212
213
  let pillProps = {};
214
+ if (!matchingOption) {
215
+ return null;
216
+ }
217
+
218
+ /* istanbul ignore else */
213
219
  if ( /*#__PURE__*/React.isValidElement(matchingOption)) {
214
220
  pillProps = {
215
221
  title: matchingOption.props.text,
@@ -217,8 +223,8 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
217
223
  borderColor: matchingOption.props.borderColor
218
224
  };
219
225
  }
220
- const title = pillProps.title || "";
221
- const key = title + ( /*#__PURE__*/React.isValidElement(matchingOption) && matchingOption.props.value || index);
226
+ const title = pillProps.title || /* istanbul ignore next */"";
227
+ const key = title + ( /*#__PURE__*/React.isValidElement(matchingOption) && matchingOption.props.value || /* istanbul ignore next */index);
222
228
  return /*#__PURE__*/React.createElement(StyledSelectPillContainer, {
223
229
  key: key
224
230
  }, /*#__PURE__*/React.createElement(Pill, _extends({
@@ -331,7 +337,8 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
331
337
  const {
332
338
  value: newValue,
333
339
  selectionType,
334
- id: selectedOptionId
340
+ id: selectedOptionId,
341
+ selectionConfirmed
335
342
  } = optionData;
336
343
  if (selectionType === "navigationKey") {
337
344
  setHighlightedValue(newValue);
@@ -350,7 +357,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
350
357
  return previousValue;
351
358
  }
352
359
  return [...previousValue, newValue];
353
- });
360
+ }, selectionConfirmed);
354
361
  }, [textboxRef, actualValue, updateValue]);
355
362
  const onSelectListClose = useCallback(() => {
356
363
  setOpenState(false);
@@ -42,7 +42,9 @@ const Option = /*#__PURE__*/React.forwardRef(({
42
42
  role: "option",
43
43
  hidden: hidden,
44
44
  style: style
45
- }, rest), children || text);
45
+ }, rest, {
46
+ fill: undefined
47
+ }), children || text);
46
48
  });
47
49
  Option.propTypes = {
48
50
  "about": PropTypes.string,
@@ -17,6 +17,7 @@ export interface SelectListProps {
17
17
  value?: string | Record<string, unknown>;
18
18
  id?: string;
19
19
  selectionType: string;
20
+ selectionConfirmed: boolean;
20
21
  }) => void;
21
22
  /** A callback for when the list should be closed */
22
23
  onSelectListClose: () => void;
@@ -93,7 +93,8 @@ const SelectList = /*#__PURE__*/React.forwardRef(({
93
93
  const handleSelect = useCallback(optionData => {
94
94
  onSelect({
95
95
  ...optionData,
96
- selectionType: "click"
96
+ selectionType: "click",
97
+ selectionConfirmed: true
97
98
  });
98
99
  }, [onSelect]);
99
100
  const childIdsRef = useRef(null);
@@ -177,13 +178,15 @@ const SelectList = /*#__PURE__*/React.forwardRef(({
177
178
  text,
178
179
  value,
179
180
  selectionType: "navigationKey",
180
- id: childIds ? childIds[nextIndex] : /* istanbul ignore next */undefined
181
+ id: childIds ? childIds[nextIndex] : /* istanbul ignore next */undefined,
182
+ selectionConfirmed: false
181
183
  });
182
184
  }, [childrenList, currentOptionsListIndex, getIndexOfMatch, getNextHighlightableItemIndex, highlightedValue, onSelect, childIds]);
183
185
  const handleActionButtonTab = useCallback((event, isActionButtonFocused) => {
184
186
  if (isActionButtonFocused) {
185
187
  onSelect({
186
- selectionType: "tab"
188
+ selectionType: "tab",
189
+ selectionConfirmed: false
187
190
  });
188
191
  } else {
189
192
  event.preventDefault();
@@ -222,7 +225,8 @@ const SelectList = /*#__PURE__*/React.forwardRef(({
222
225
  id: childIds ? childIds[currentOptionsListIndex] : /* istanbul ignore next */undefined,
223
226
  text,
224
227
  value,
225
- selectionType: "enterKey"
228
+ selectionType: "enterKey",
229
+ selectionConfirmed: true
226
230
  });
227
231
  } else if (isNavigationKey(key)) {
228
232
  focusOnAnchor();
@@ -1,7 +1,8 @@
1
1
  import React from "react";
2
2
  import { CommonTextboxProps } from "../../textbox";
3
3
  import { ValidationProps } from "../../../__internal__/validations";
4
- export interface FormInputPropTypes extends ValidationProps, Omit<CommonTextboxProps, "onClick"> {
4
+ import { CustomSelectChangeEvent } from "../simple-select/simple-select.component";
5
+ export interface FormInputPropTypes extends ValidationProps, Omit<CommonTextboxProps, "onClick" | "onChange"> {
5
6
  /** Breakpoint for adaptive label (inline labels change to top aligned). Enables the adaptive behaviour when set */
6
7
  adaptiveLabelBreakpoint?: number;
7
8
  /** Prop to specify the aria-label attribute of the component input */
@@ -29,7 +30,7 @@ export interface FormInputPropTypes extends ValidationProps, Omit<CommonTextboxP
29
30
  /** Specify a callback triggered on blur */
30
31
  onBlur?: (ev: React.FocusEvent<HTMLInputElement>) => void;
31
32
  /** Specify a callback triggered on change */
32
- onChange?: (ev: React.ChangeEvent<HTMLInputElement>) => void;
33
+ onChange?: (ev: CustomSelectChangeEvent | React.ChangeEvent<HTMLInputElement>) => void;
33
34
  /** Specify a callback triggered on click */
34
35
  onClick?: (ev: React.MouseEvent<HTMLInputElement>) => void;
35
36
  /** Specify a callback triggered on focus */
@@ -1,2 +1,2 @@
1
1
  export { default } from "./simple-select.component";
2
- export type { SimpleSelectProps } from "./simple-select.component";
2
+ export type { SimpleSelectProps, CustomSelectChangeEvent, } from "./simple-select.component";
@@ -1,6 +1,16 @@
1
1
  import React from "react";
2
2
  import { Side } from "@floating-ui/dom";
3
3
  import { FormInputPropTypes } from "../select-textbox";
4
+ export interface OptionData {
5
+ text?: string;
6
+ value?: string | Record<string, unknown>;
7
+ id?: string;
8
+ selectionType: string;
9
+ selectionConfirmed?: boolean;
10
+ }
11
+ export interface CustomSelectChangeEvent extends React.ChangeEvent<HTMLInputElement> {
12
+ selectionConfirmed?: boolean;
13
+ }
4
14
  export interface SimpleSelectProps extends Omit<FormInputPropTypes, "defaultValue" | "value"> {
5
15
  /** Prop to specify the aria-label attribute of the component input */
6
16
  "aria-label"?: string;
@@ -82,7 +82,7 @@ const SimpleSelect = /*#__PURE__*/React.forwardRef(({
82
82
  Logger.deprecate("Uncontrolled behaviour in `Simple Select` is deprecated and support will soon be removed. Please make sure all your inputs are controlled.");
83
83
  }
84
84
  const childOptions = useMemo(() => React.Children.toArray(children), [children]);
85
- const createCustomEvent = useCallback(newValue => {
85
+ const createCustomEvent = useCallback((newValue, selectionConfirmed = false) => {
86
86
  const customEvent = {
87
87
  target: {
88
88
  ...(name && {
@@ -92,7 +92,8 @@ const SimpleSelect = /*#__PURE__*/React.forwardRef(({
92
92
  id
93
93
  }),
94
94
  value: newValue
95
- }
95
+ },
96
+ selectionConfirmed
96
97
  };
97
98
  return customEvent;
98
99
  }, [name, id]);
@@ -245,13 +246,13 @@ const SimpleSelect = /*#__PURE__*/React.forwardRef(({
245
246
  });
246
247
  }
247
248
  }
248
- function updateValue(newValue, text) {
249
+ function updateValue(newValue, text, selectionConfirmed) {
249
250
  if (!isControlled.current) {
250
251
  setSelectedValue(newValue);
251
252
  setTextValue(text);
252
253
  }
253
254
  if (onChange) {
254
- onChange(createCustomEvent(newValue));
255
+ onChange(createCustomEvent(newValue, selectionConfirmed));
255
256
  }
256
257
  }
257
258
  function onSelectOption(optionData) {
@@ -259,10 +260,11 @@ const SimpleSelect = /*#__PURE__*/React.forwardRef(({
259
260
  text,
260
261
  value: newValue,
261
262
  selectionType,
262
- id: selectedOptionId
263
+ id: selectedOptionId,
264
+ selectionConfirmed
263
265
  } = optionData;
264
266
  const isClickTriggered = selectionType === "click";
265
- updateValue(newValue, text);
267
+ updateValue(newValue, text, selectionConfirmed);
266
268
  setActiveDescendantId(selectedOptionId);
267
269
  if (selectionType !== "navigationKey") {
268
270
  setOpenState(false);
@@ -1,9 +1,12 @@
1
1
  import React from "react";
2
2
  declare type ToastVariants = "error" | "info" | "success" | "warning" | "notice" | "neutral" | "notification";
3
3
  declare type AlignOptions = "left" | "center" | "right";
4
+ declare type AlignYOptions = "top" | "center" | "bottom";
4
5
  export interface ToastProps {
5
- /** Sets the alignment of the component. */
6
+ /** Sets the horizontal alignment of the component. */
6
7
  align?: AlignOptions;
8
+ /** Sets the vertical alignment of the component */
9
+ alignY?: AlignYOptions;
7
10
  /** The rendered children of the component. */
8
11
  children: React.ReactNode;
9
12
  /** Customizes the appearance in the DLS theme */
@@ -13,6 +13,7 @@ import Logger from "../../__internal__/utils/logger";
13
13
  let isDeprecationWarningTriggered = false;
14
14
  const Toast = /*#__PURE__*/React.forwardRef(({
15
15
  align,
16
+ alignY,
16
17
  children,
17
18
  className,
18
19
  id,
@@ -121,6 +122,7 @@ const Toast = /*#__PURE__*/React.forwardRef(({
121
122
  nodeRef: toastContentNodeRef
122
123
  }, /*#__PURE__*/React.createElement(ToastStyle, _extends({
123
124
  align: align,
125
+ alignY: alignY,
124
126
  isNotice: isNotice,
125
127
  isNotification: isNotification,
126
128
  className: className
@@ -145,6 +147,7 @@ const Toast = /*#__PURE__*/React.forwardRef(({
145
147
  return /*#__PURE__*/React.createElement(StyledPortal, {
146
148
  id: targetPortalId,
147
149
  align: align,
150
+ alignY: alignY,
148
151
  isCenter: isCenter,
149
152
  isNotice: isNotice
150
153
  }, /*#__PURE__*/React.createElement(ToastWrapper, {
@@ -156,6 +159,7 @@ const Toast = /*#__PURE__*/React.forwardRef(({
156
159
  });
157
160
  Toast.propTypes = {
158
161
  "align": PropTypes.oneOf(["center", "left", "right"]),
162
+ "alignY": PropTypes.oneOf(["bottom", "center", "top"]),
159
163
  "children": PropTypes.node,
160
164
  "className": PropTypes.string,
161
165
  "data-component": PropTypes.string,
@@ -2,6 +2,7 @@
2
2
  import TypeIcon from "../message/type-icon/type-icon.style";
3
3
  declare const StyledPortal: import("styled-components").StyledComponent<({ children, className, id, onReposition }: import("../portal/portal").PortalProps) => import("react").JSX.Element, any, {
4
4
  align?: "left" | "right" | "center" | undefined;
5
+ alignY?: "bottom" | "top" | "center" | undefined;
5
6
  isCenter?: boolean | undefined;
6
7
  isNotice?: boolean | undefined;
7
8
  }, never>;
@@ -10,6 +11,7 @@ declare const ToastStyle: import("styled-components").StyledComponent<"div", any
10
11
  transparent?: boolean | undefined;
11
12
  } & import("styled-system").MarginProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & {
12
13
  align?: "left" | "right" | "center" | undefined;
14
+ alignY?: "bottom" | "top" | "center" | undefined;
13
15
  maxWidth?: string | undefined;
14
16
  isCenter?: boolean | undefined;
15
17
  isNotice?: boolean | undefined;
@@ -11,7 +11,8 @@ const StyledPortal = styled(Portal)`
11
11
  theme,
12
12
  isCenter,
13
13
  isNotice,
14
- align
14
+ align,
15
+ alignY
15
16
  }) => css`
16
17
  position: fixed;
17
18
  top: 0;
@@ -24,8 +25,8 @@ const StyledPortal = styled(Portal)`
24
25
  `}
25
26
 
26
27
  ${align === "left" && css`
27
- left: 12%;
28
- transform: translateX(-50%);
28
+ left: 0;
29
+ transform: translateX(50%);
29
30
  `}
30
31
 
31
32
  ${align === "center" && css`
@@ -34,7 +35,6 @@ const StyledPortal = styled(Portal)`
34
35
  `}
35
36
 
36
37
  ${align === "right" && css`
37
- display: flex;
38
38
  right: 0;
39
39
  transform: translateX(-50%);
40
40
  `}
@@ -43,6 +43,23 @@ const StyledPortal = styled(Portal)`
43
43
  bottom: 0;
44
44
  top: auto;
45
45
  width: 100%;
46
+ `}
47
+
48
+ ${alignY === "top" && css`
49
+ top: 0;
50
+ bottom: auto;
51
+ `}
52
+
53
+ ${alignY === "center" && css`
54
+ top: 50%;
55
+ transform: translate(${align === "left" ? "50%" : "-50%"}, -50%);
56
+ `}
57
+
58
+ ${alignY === "bottom" && css`
59
+ bottom: 0;
60
+ top: auto;
61
+ display: flex;
62
+ flex-direction: column-reverse;
46
63
  `}
47
64
  `}
48
65
  `;
@@ -56,15 +73,19 @@ const ToastStyle = styled(MessageStyle)`
56
73
  maxWidth,
57
74
  isCenter,
58
75
  align,
59
- isNotification
76
+ isNotification,
77
+ alignY,
78
+ isNotice
60
79
  }) => css`
61
80
  box-shadow: 0 10px 30px 0 rgba(0, 20, 29, 0.1),
62
81
  0 30px 60px 0 rgba(0, 20, 29, 0.1);
63
82
  line-height: 22px;
64
- margin-top: 30px;
83
+ margin-top: ${alignY === "top" && isNotice || alignY === "center" ? "0" : "30px"};
84
+ margin-bottom: ${alignY === "bottom" && !isNotice ? "30px" : "0"};
65
85
  max-width: ${!maxWidth ? "300px" : maxWidth};
66
86
  position: relative;
67
87
  margin-right: ${isCenter || align === "right" ? "auto" : "30px"};
88
+ margin-left: ${isCenter || align === "left" ? "auto" : "30px"};
68
89
 
69
90
  ${isNotification && css`
70
91
  border: 1px solid var(--colorsSemanticInfo500);
@@ -91,7 +112,10 @@ const ToastStyle = styled(MessageStyle)`
91
112
 
92
113
  &${animationName}-exit${animationName}-exit-active {
93
114
  opacity: 0;
94
- margin-top: -40px;
115
+
116
+ ${({
117
+ alignY
118
+ }) => alignY === "bottom" ? "margin-bottom: -40px" : "margin-top: -40px"};
95
119
  transition: all 150ms ease-out;
96
120
  }
97
121
 
@@ -103,7 +127,8 @@ const ToastStyle = styled(MessageStyle)`
103
127
  }
104
128
 
105
129
  ${({
106
- isNotice
130
+ isNotice,
131
+ alignY
107
132
  }) => isNotice && css`
108
133
  background-color: var(--colorsUtilityMajor400);
109
134
  border: none;
@@ -120,24 +145,24 @@ const ToastStyle = styled(MessageStyle)`
120
145
  }
121
146
 
122
147
  &${alternativeAnimationName}-appear, &${alternativeAnimationName}-enter {
123
- bottom: -40px;
148
+ ${alignY === "top" ? "top: -40px" : "bottom: -40px"};
124
149
  opacity: 0;
125
150
  }
126
151
 
127
152
  &${alternativeAnimationName}-exit {
128
- bottom: 0;
153
+ ${alignY === "top" ? "top: 0" : "bottom: 0"};
129
154
  opacity: 1;
130
155
  }
131
156
 
132
157
  &${alternativeAnimationName}-appear${alternativeAnimationName}-appear-active,
133
158
  &${alternativeAnimationName}-enter${alternativeAnimationName}-enter-active {
134
- bottom: 0;
159
+ ${alignY === "top" ? "top: 0" : "bottom: 0"};
135
160
  opacity: 1;
136
161
  transition: all 400ms ease;
137
162
  }
138
163
 
139
164
  &${alternativeAnimationName}-exit${alternativeAnimationName}-exit-active {
140
- bottom: -40px;
165
+ ${alignY === "top" ? "top: -40px" : "bottom: -40px"};
141
166
  opacity: 0;
142
167
  transition: all 200ms ease;
143
168
  }
@@ -95,7 +95,7 @@ const FilterableSelect = /*#__PURE__*/_react.default.forwardRef(({
95
95
  deprecateUncontrolledWarnTriggered = true;
96
96
  _logger.default.deprecate("Uncontrolled behaviour in `Filterable Select` is deprecated and support will soon be removed. Please make sure all your inputs are controlled.");
97
97
  }
98
- const createCustomEvent = (0, _react.useCallback)(newValue => {
98
+ const createCustomEvent = (0, _react.useCallback)((newValue, selectionConfirmed) => {
99
99
  const customEvent = {
100
100
  target: {
101
101
  ...(name && {
@@ -105,13 +105,14 @@ const FilterableSelect = /*#__PURE__*/_react.default.forwardRef(({
105
105
  id
106
106
  }),
107
107
  value: newValue
108
- }
108
+ },
109
+ selectionConfirmed
109
110
  };
110
111
  return customEvent;
111
112
  }, [name, id]);
112
- const triggerChange = (0, _react.useCallback)(newValue => {
113
+ const triggerChange = (0, _react.useCallback)((newValue, selectionConfirmed) => {
113
114
  if (onChange) {
114
- onChange(createCustomEvent(newValue));
115
+ onChange(createCustomEvent(newValue, selectionConfirmed));
115
116
  }
116
117
  }, [onChange, createCustomEvent]);
117
118
  function findElementWithMatchingText(textToMatch, list) {
@@ -119,7 +120,7 @@ const FilterableSelect = /*#__PURE__*/_react.default.forwardRef(({
119
120
  const {
120
121
  text
121
122
  } = child.props;
122
- return text && text.toLowerCase().indexOf(textToMatch.toLowerCase()) !== -1;
123
+ return text?.toLowerCase().indexOf(textToMatch?.toLowerCase()) !== -1;
123
124
  });
124
125
  }
125
126
  const updateValues = (0, _react.useCallback)((newFilterText, isDeleteEvent) => {
@@ -128,15 +129,15 @@ const FilterableSelect = /*#__PURE__*/_react.default.forwardRef(({
128
129
  const isFilterCleared = isDeleteEvent && newFilterText === "";
129
130
  if (!match || isFilterCleared) {
130
131
  setTextValue(newFilterText);
131
- triggerChange("");
132
+ triggerChange("", false);
132
133
  return "";
133
134
  }
134
135
  if (isDeleteEvent) {
135
136
  setTextValue(newFilterText);
136
137
  return match.props.value;
137
138
  }
138
- triggerChange(match.props.value);
139
- if (match.props.text.toLowerCase().startsWith(newFilterText.toLowerCase())) {
139
+ triggerChange(match.props.value, false);
140
+ if (match.props.text?.toLowerCase().startsWith(newFilterText.toLowerCase())) {
140
141
  setTextValue(match.props.text);
141
142
  } else {
142
143
  setTextValue(newFilterText);
@@ -152,7 +153,7 @@ const FilterableSelect = /*#__PURE__*/_react.default.forwardRef(({
152
153
  const matchingOption = _react.default.Children.toArray(children).find(child => /*#__PURE__*/_react.default.isValidElement(child) && (0, _isExpectedOption.default)(child, newValue));
153
154
  if (!matchingOption || matchingOption.props.text === undefined) {
154
155
  setTextValue(filterText || "");
155
- } else if (isClosing || matchingOption.props.text.toLowerCase().startsWith(filterText.toLowerCase())) {
156
+ } else if (isClosing || matchingOption.props.text?.toLowerCase().startsWith(filterText?.toLowerCase())) {
156
157
  setTextValue(matchingOption.props.text);
157
158
  }
158
159
  }, [children, filterText]);
@@ -165,7 +166,7 @@ const FilterableSelect = /*#__PURE__*/_react.default.forwardRef(({
165
166
  }, [updateValues]);
166
167
  const fillLastFilterCharacter = (0, _react.useCallback)(key => {
167
168
  setFilterText(previousFilterText => {
168
- if (previousFilterText.length === textValue.length - 1 && key === textValue.slice(-1)) {
169
+ if (previousFilterText?.length === textValue?.length - 1 && key === textValue.slice(-1)) {
169
170
  return textValue;
170
171
  }
171
172
  return previousFilterText;
@@ -260,9 +261,9 @@ const FilterableSelect = /*#__PURE__*/_react.default.forwardRef(({
260
261
  };
261
262
  }, [handleGlobalClick]);
262
263
  (0, _react.useEffect)(() => {
263
- const textStartsWithFilter = textValue.toLowerCase().startsWith(filterText.toLowerCase());
264
+ const textStartsWithFilter = textValue?.toLowerCase().startsWith(filterText?.toLowerCase());
264
265
  const isTextboxActive = !disabled && !readOnly;
265
- if (isTextboxActive && textboxRef && filterText.length && textValue.length > filterText.length && textStartsWithFilter) {
266
+ if (isTextboxActive && textboxRef && filterText?.length && textValue?.length > filterText?.length && textStartsWithFilter) {
266
267
  textboxRef.selectionStart = filterText.length;
267
268
  }
268
269
  }, [textValue, filterText, textboxRef, disabled, readOnly]);
@@ -271,7 +272,8 @@ const FilterableSelect = /*#__PURE__*/_react.default.forwardRef(({
271
272
  id: selectedOptionId,
272
273
  text,
273
274
  value: newValue,
274
- selectionType
275
+ selectionType,
276
+ selectionConfirmed
275
277
  } = optionData;
276
278
  if (selectionType === "tab") {
277
279
  setOpen(false);
@@ -282,8 +284,8 @@ const FilterableSelect = /*#__PURE__*/_react.default.forwardRef(({
282
284
  setSelectedValue(newValue);
283
285
  setHighlightedValue(newValue);
284
286
  }
285
- setTextValue(text);
286
- triggerChange(newValue);
287
+ setTextValue(text || /* istanbul ignore next */"");
288
+ triggerChange(newValue, selectionConfirmed);
287
289
  setActiveDescendantId(selectedOptionId);
288
290
  if (selectionType !== "navigationKey") {
289
291
  setOpen(false);
@@ -5,7 +5,7 @@ export type { OptionRowProps } from "./option-row";
5
5
  export { default as OptionGroupHeader } from "./option-group-header";
6
6
  export type { OptionGroupHeaderProps } from "./option-group-header";
7
7
  export { default as Select } from "./simple-select";
8
- export type { SimpleSelectProps } from "./simple-select";
8
+ export type { SimpleSelectProps, CustomSelectChangeEvent, } from "./simple-select";
9
9
  export { default as FilterableSelect } from "./filterable-select";
10
10
  export type { FilterableSelectProps } from "./filterable-select";
11
11
  export { default as MultiSelect } from "./multi-select";
@@ -109,7 +109,7 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
109
109
  return true;
110
110
  });
111
111
  }, [onOpen]);
112
- const createCustomEvent = (0, _react.useCallback)(newValue => {
112
+ const createCustomEvent = (0, _react.useCallback)((newValue, selectionConfirmed) => {
113
113
  const customEvent = {
114
114
  target: {
115
115
  ...(name && {
@@ -119,7 +119,8 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
119
119
  id
120
120
  }),
121
121
  value: newValue
122
- }
122
+ },
123
+ selectionConfirmed
123
124
  };
124
125
  return customEvent;
125
126
  }, [name, id]);
@@ -128,11 +129,11 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
128
129
  * components, both with and without onChange.
129
130
  * It accepts a function to update the value, which is assumed to be have no side effects and therefore
130
131
  * be safe to run more than once if needed. */
131
- const updateValue = (0, _react.useCallback)(updateFunction => {
132
+ const updateValue = (0, _react.useCallback)((updateFunction, selectionConfirmed) => {
132
133
  const newValue = updateFunction(actualValue);
133
134
  // only call onChange if an option has been selected or deselected
134
135
  if (onChange && newValue.length !== actualValue?.length) {
135
- onChange(createCustomEvent(newValue));
136
+ onChange(createCustomEvent(newValue, selectionConfirmed));
136
137
  }
137
138
 
138
139
  // no need to update selectedValue if the component is controlled: onChange should take care of updating the value
@@ -167,7 +168,7 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
167
168
  const newValue = previousValue.slice(); // spreading does not work but slice does - see https://github.com/microsoft/TypeScript/issues/53670
168
169
  newValue.splice(index, 1);
169
170
  return newValue;
170
- });
171
+ }, true);
171
172
  }, [updateValue]);
172
173
  const handleTextboxKeydown = (0, _react.useCallback)(event => {
173
174
  const {
@@ -219,6 +220,11 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
219
220
  return actualValue.map((singleValue, index) => {
220
221
  const matchingOption = _react.default.Children.toArray(children).find(child => /*#__PURE__*/_react.default.isValidElement(child) && (0, _isExpectedOption.default)(child, singleValue));
221
222
  let pillProps = {};
223
+ if (!matchingOption) {
224
+ return null;
225
+ }
226
+
227
+ /* istanbul ignore else */
222
228
  if ( /*#__PURE__*/_react.default.isValidElement(matchingOption)) {
223
229
  pillProps = {
224
230
  title: matchingOption.props.text,
@@ -226,8 +232,8 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
226
232
  borderColor: matchingOption.props.borderColor
227
233
  };
228
234
  }
229
- const title = pillProps.title || "";
230
- const key = title + ( /*#__PURE__*/_react.default.isValidElement(matchingOption) && matchingOption.props.value || index);
235
+ const title = pillProps.title || /* istanbul ignore next */"";
236
+ const key = title + ( /*#__PURE__*/_react.default.isValidElement(matchingOption) && matchingOption.props.value || /* istanbul ignore next */index);
231
237
  return /*#__PURE__*/_react.default.createElement(_multiSelect.StyledSelectPillContainer, {
232
238
  key: key
233
239
  }, /*#__PURE__*/_react.default.createElement(_pill.default, _extends({
@@ -340,7 +346,8 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
340
346
  const {
341
347
  value: newValue,
342
348
  selectionType,
343
- id: selectedOptionId
349
+ id: selectedOptionId,
350
+ selectionConfirmed
344
351
  } = optionData;
345
352
  if (selectionType === "navigationKey") {
346
353
  setHighlightedValue(newValue);
@@ -359,7 +366,7 @@ const MultiSelect = /*#__PURE__*/_react.default.forwardRef(({
359
366
  return previousValue;
360
367
  }
361
368
  return [...previousValue, newValue];
362
- });
369
+ }, selectionConfirmed);
363
370
  }, [textboxRef, actualValue, updateValue]);
364
371
  const onSelectListClose = (0, _react.useCallback)(() => {
365
372
  setOpenState(false);
@@ -51,7 +51,9 @@ const Option = /*#__PURE__*/_react.default.forwardRef(({
51
51
  role: "option",
52
52
  hidden: hidden,
53
53
  style: style
54
- }, rest), children || text);
54
+ }, rest, {
55
+ fill: undefined
56
+ }), children || text);
55
57
  });
56
58
  Option.propTypes = {
57
59
  "about": _propTypes.default.string,
@@ -17,6 +17,7 @@ export interface SelectListProps {
17
17
  value?: string | Record<string, unknown>;
18
18
  id?: string;
19
19
  selectionType: string;
20
+ selectionConfirmed: boolean;
20
21
  }) => void;
21
22
  /** A callback for when the list should be closed */
22
23
  onSelectListClose: () => void;
@@ -102,7 +102,8 @@ const SelectList = /*#__PURE__*/_react.default.forwardRef(({
102
102
  const handleSelect = (0, _react.useCallback)(optionData => {
103
103
  onSelect({
104
104
  ...optionData,
105
- selectionType: "click"
105
+ selectionType: "click",
106
+ selectionConfirmed: true
106
107
  });
107
108
  }, [onSelect]);
108
109
  const childIdsRef = (0, _react.useRef)(null);
@@ -186,13 +187,15 @@ const SelectList = /*#__PURE__*/_react.default.forwardRef(({
186
187
  text,
187
188
  value,
188
189
  selectionType: "navigationKey",
189
- id: childIds ? childIds[nextIndex] : /* istanbul ignore next */undefined
190
+ id: childIds ? childIds[nextIndex] : /* istanbul ignore next */undefined,
191
+ selectionConfirmed: false
190
192
  });
191
193
  }, [childrenList, currentOptionsListIndex, getIndexOfMatch, getNextHighlightableItemIndex, highlightedValue, onSelect, childIds]);
192
194
  const handleActionButtonTab = (0, _react.useCallback)((event, isActionButtonFocused) => {
193
195
  if (isActionButtonFocused) {
194
196
  onSelect({
195
- selectionType: "tab"
197
+ selectionType: "tab",
198
+ selectionConfirmed: false
196
199
  });
197
200
  } else {
198
201
  event.preventDefault();
@@ -231,7 +234,8 @@ const SelectList = /*#__PURE__*/_react.default.forwardRef(({
231
234
  id: childIds ? childIds[currentOptionsListIndex] : /* istanbul ignore next */undefined,
232
235
  text,
233
236
  value,
234
- selectionType: "enterKey"
237
+ selectionType: "enterKey",
238
+ selectionConfirmed: true
235
239
  });
236
240
  } else if ((0, _isNavigationKey.default)(key)) {
237
241
  focusOnAnchor();
@@ -1,7 +1,8 @@
1
1
  import React from "react";
2
2
  import { CommonTextboxProps } from "../../textbox";
3
3
  import { ValidationProps } from "../../../__internal__/validations";
4
- export interface FormInputPropTypes extends ValidationProps, Omit<CommonTextboxProps, "onClick"> {
4
+ import { CustomSelectChangeEvent } from "../simple-select/simple-select.component";
5
+ export interface FormInputPropTypes extends ValidationProps, Omit<CommonTextboxProps, "onClick" | "onChange"> {
5
6
  /** Breakpoint for adaptive label (inline labels change to top aligned). Enables the adaptive behaviour when set */
6
7
  adaptiveLabelBreakpoint?: number;
7
8
  /** Prop to specify the aria-label attribute of the component input */
@@ -29,7 +30,7 @@ export interface FormInputPropTypes extends ValidationProps, Omit<CommonTextboxP
29
30
  /** Specify a callback triggered on blur */
30
31
  onBlur?: (ev: React.FocusEvent<HTMLInputElement>) => void;
31
32
  /** Specify a callback triggered on change */
32
- onChange?: (ev: React.ChangeEvent<HTMLInputElement>) => void;
33
+ onChange?: (ev: CustomSelectChangeEvent | React.ChangeEvent<HTMLInputElement>) => void;
33
34
  /** Specify a callback triggered on click */
34
35
  onClick?: (ev: React.MouseEvent<HTMLInputElement>) => void;
35
36
  /** Specify a callback triggered on focus */
@@ -1,2 +1,2 @@
1
1
  export { default } from "./simple-select.component";
2
- export type { SimpleSelectProps } from "./simple-select.component";
2
+ export type { SimpleSelectProps, CustomSelectChangeEvent, } from "./simple-select.component";
@@ -1,6 +1,16 @@
1
1
  import React from "react";
2
2
  import { Side } from "@floating-ui/dom";
3
3
  import { FormInputPropTypes } from "../select-textbox";
4
+ export interface OptionData {
5
+ text?: string;
6
+ value?: string | Record<string, unknown>;
7
+ id?: string;
8
+ selectionType: string;
9
+ selectionConfirmed?: boolean;
10
+ }
11
+ export interface CustomSelectChangeEvent extends React.ChangeEvent<HTMLInputElement> {
12
+ selectionConfirmed?: boolean;
13
+ }
4
14
  export interface SimpleSelectProps extends Omit<FormInputPropTypes, "defaultValue" | "value"> {
5
15
  /** Prop to specify the aria-label attribute of the component input */
6
16
  "aria-label"?: string;
@@ -91,7 +91,7 @@ const SimpleSelect = /*#__PURE__*/_react.default.forwardRef(({
91
91
  _logger.default.deprecate("Uncontrolled behaviour in `Simple Select` is deprecated and support will soon be removed. Please make sure all your inputs are controlled.");
92
92
  }
93
93
  const childOptions = (0, _react.useMemo)(() => _react.default.Children.toArray(children), [children]);
94
- const createCustomEvent = (0, _react.useCallback)(newValue => {
94
+ const createCustomEvent = (0, _react.useCallback)((newValue, selectionConfirmed = false) => {
95
95
  const customEvent = {
96
96
  target: {
97
97
  ...(name && {
@@ -101,7 +101,8 @@ const SimpleSelect = /*#__PURE__*/_react.default.forwardRef(({
101
101
  id
102
102
  }),
103
103
  value: newValue
104
- }
104
+ },
105
+ selectionConfirmed
105
106
  };
106
107
  return customEvent;
107
108
  }, [name, id]);
@@ -254,13 +255,13 @@ const SimpleSelect = /*#__PURE__*/_react.default.forwardRef(({
254
255
  });
255
256
  }
256
257
  }
257
- function updateValue(newValue, text) {
258
+ function updateValue(newValue, text, selectionConfirmed) {
258
259
  if (!isControlled.current) {
259
260
  setSelectedValue(newValue);
260
261
  setTextValue(text);
261
262
  }
262
263
  if (onChange) {
263
- onChange(createCustomEvent(newValue));
264
+ onChange(createCustomEvent(newValue, selectionConfirmed));
264
265
  }
265
266
  }
266
267
  function onSelectOption(optionData) {
@@ -268,10 +269,11 @@ const SimpleSelect = /*#__PURE__*/_react.default.forwardRef(({
268
269
  text,
269
270
  value: newValue,
270
271
  selectionType,
271
- id: selectedOptionId
272
+ id: selectedOptionId,
273
+ selectionConfirmed
272
274
  } = optionData;
273
275
  const isClickTriggered = selectionType === "click";
274
- updateValue(newValue, text);
276
+ updateValue(newValue, text, selectionConfirmed);
275
277
  setActiveDescendantId(selectedOptionId);
276
278
  if (selectionType !== "navigationKey") {
277
279
  setOpenState(false);
@@ -1,9 +1,12 @@
1
1
  import React from "react";
2
2
  declare type ToastVariants = "error" | "info" | "success" | "warning" | "notice" | "neutral" | "notification";
3
3
  declare type AlignOptions = "left" | "center" | "right";
4
+ declare type AlignYOptions = "top" | "center" | "bottom";
4
5
  export interface ToastProps {
5
- /** Sets the alignment of the component. */
6
+ /** Sets the horizontal alignment of the component. */
6
7
  align?: AlignOptions;
8
+ /** Sets the vertical alignment of the component */
9
+ alignY?: AlignYOptions;
7
10
  /** The rendered children of the component. */
8
11
  children: React.ReactNode;
9
12
  /** Customizes the appearance in the DLS theme */
@@ -22,6 +22,7 @@ function _extends() { _extends = Object.assign ? Object.assign.bind() : function
22
22
  let isDeprecationWarningTriggered = false;
23
23
  const Toast = /*#__PURE__*/_react.default.forwardRef(({
24
24
  align,
25
+ alignY,
25
26
  children,
26
27
  className,
27
28
  id,
@@ -130,6 +131,7 @@ const Toast = /*#__PURE__*/_react.default.forwardRef(({
130
131
  nodeRef: toastContentNodeRef
131
132
  }, /*#__PURE__*/_react.default.createElement(_toast.ToastStyle, _extends({
132
133
  align: align,
134
+ alignY: alignY,
133
135
  isNotice: isNotice,
134
136
  isNotification: isNotification,
135
137
  className: className
@@ -154,6 +156,7 @@ const Toast = /*#__PURE__*/_react.default.forwardRef(({
154
156
  return /*#__PURE__*/_react.default.createElement(_toast.StyledPortal, {
155
157
  id: targetPortalId,
156
158
  align: align,
159
+ alignY: alignY,
157
160
  isCenter: isCenter,
158
161
  isNotice: isNotice
159
162
  }, /*#__PURE__*/_react.default.createElement(_toast.ToastWrapper, {
@@ -166,6 +169,7 @@ const Toast = /*#__PURE__*/_react.default.forwardRef(({
166
169
  exports.Toast = Toast;
167
170
  Toast.propTypes = {
168
171
  "align": _propTypes.default.oneOf(["center", "left", "right"]),
172
+ "alignY": _propTypes.default.oneOf(["bottom", "center", "top"]),
169
173
  "children": _propTypes.default.node,
170
174
  "className": _propTypes.default.string,
171
175
  "data-component": _propTypes.default.string,
@@ -2,6 +2,7 @@
2
2
  import TypeIcon from "../message/type-icon/type-icon.style";
3
3
  declare const StyledPortal: import("styled-components").StyledComponent<({ children, className, id, onReposition }: import("../portal/portal").PortalProps) => import("react").JSX.Element, any, {
4
4
  align?: "left" | "right" | "center" | undefined;
5
+ alignY?: "bottom" | "top" | "center" | undefined;
5
6
  isCenter?: boolean | undefined;
6
7
  isNotice?: boolean | undefined;
7
8
  }, never>;
@@ -10,6 +11,7 @@ declare const ToastStyle: import("styled-components").StyledComponent<"div", any
10
11
  transparent?: boolean | undefined;
11
12
  } & import("styled-system").MarginProps<Required<import("styled-system").Theme<import("styled-system").TLengthStyledSystem>>> & {
12
13
  align?: "left" | "right" | "center" | undefined;
14
+ alignY?: "bottom" | "top" | "center" | undefined;
13
15
  maxWidth?: string | undefined;
14
16
  isCenter?: boolean | undefined;
15
17
  isNotice?: boolean | undefined;
@@ -26,7 +26,8 @@ const StyledPortal = (0, _styledComponents.default)(_portal.default)`
26
26
  theme,
27
27
  isCenter,
28
28
  isNotice,
29
- align
29
+ align,
30
+ alignY
30
31
  }) => (0, _styledComponents.css)`
31
32
  position: fixed;
32
33
  top: 0;
@@ -39,8 +40,8 @@ const StyledPortal = (0, _styledComponents.default)(_portal.default)`
39
40
  `}
40
41
 
41
42
  ${align === "left" && (0, _styledComponents.css)`
42
- left: 12%;
43
- transform: translateX(-50%);
43
+ left: 0;
44
+ transform: translateX(50%);
44
45
  `}
45
46
 
46
47
  ${align === "center" && (0, _styledComponents.css)`
@@ -49,7 +50,6 @@ const StyledPortal = (0, _styledComponents.default)(_portal.default)`
49
50
  `}
50
51
 
51
52
  ${align === "right" && (0, _styledComponents.css)`
52
- display: flex;
53
53
  right: 0;
54
54
  transform: translateX(-50%);
55
55
  `}
@@ -58,6 +58,23 @@ const StyledPortal = (0, _styledComponents.default)(_portal.default)`
58
58
  bottom: 0;
59
59
  top: auto;
60
60
  width: 100%;
61
+ `}
62
+
63
+ ${alignY === "top" && (0, _styledComponents.css)`
64
+ top: 0;
65
+ bottom: auto;
66
+ `}
67
+
68
+ ${alignY === "center" && (0, _styledComponents.css)`
69
+ top: 50%;
70
+ transform: translate(${align === "left" ? "50%" : "-50%"}, -50%);
71
+ `}
72
+
73
+ ${alignY === "bottom" && (0, _styledComponents.css)`
74
+ bottom: 0;
75
+ top: auto;
76
+ display: flex;
77
+ flex-direction: column-reverse;
61
78
  `}
62
79
  `}
63
80
  `;
@@ -72,15 +89,19 @@ const ToastStyle = (0, _styledComponents.default)(_message.default)`
72
89
  maxWidth,
73
90
  isCenter,
74
91
  align,
75
- isNotification
92
+ isNotification,
93
+ alignY,
94
+ isNotice
76
95
  }) => (0, _styledComponents.css)`
77
96
  box-shadow: 0 10px 30px 0 rgba(0, 20, 29, 0.1),
78
97
  0 30px 60px 0 rgba(0, 20, 29, 0.1);
79
98
  line-height: 22px;
80
- margin-top: 30px;
99
+ margin-top: ${alignY === "top" && isNotice || alignY === "center" ? "0" : "30px"};
100
+ margin-bottom: ${alignY === "bottom" && !isNotice ? "30px" : "0"};
81
101
  max-width: ${!maxWidth ? "300px" : maxWidth};
82
102
  position: relative;
83
103
  margin-right: ${isCenter || align === "right" ? "auto" : "30px"};
104
+ margin-left: ${isCenter || align === "left" ? "auto" : "30px"};
84
105
 
85
106
  ${isNotification && (0, _styledComponents.css)`
86
107
  border: 1px solid var(--colorsSemanticInfo500);
@@ -107,7 +128,10 @@ const ToastStyle = (0, _styledComponents.default)(_message.default)`
107
128
 
108
129
  &${animationName}-exit${animationName}-exit-active {
109
130
  opacity: 0;
110
- margin-top: -40px;
131
+
132
+ ${({
133
+ alignY
134
+ }) => alignY === "bottom" ? "margin-bottom: -40px" : "margin-top: -40px"};
111
135
  transition: all 150ms ease-out;
112
136
  }
113
137
 
@@ -119,7 +143,8 @@ const ToastStyle = (0, _styledComponents.default)(_message.default)`
119
143
  }
120
144
 
121
145
  ${({
122
- isNotice
146
+ isNotice,
147
+ alignY
123
148
  }) => isNotice && (0, _styledComponents.css)`
124
149
  background-color: var(--colorsUtilityMajor400);
125
150
  border: none;
@@ -136,24 +161,24 @@ const ToastStyle = (0, _styledComponents.default)(_message.default)`
136
161
  }
137
162
 
138
163
  &${alternativeAnimationName}-appear, &${alternativeAnimationName}-enter {
139
- bottom: -40px;
164
+ ${alignY === "top" ? "top: -40px" : "bottom: -40px"};
140
165
  opacity: 0;
141
166
  }
142
167
 
143
168
  &${alternativeAnimationName}-exit {
144
- bottom: 0;
169
+ ${alignY === "top" ? "top: 0" : "bottom: 0"};
145
170
  opacity: 1;
146
171
  }
147
172
 
148
173
  &${alternativeAnimationName}-appear${alternativeAnimationName}-appear-active,
149
174
  &${alternativeAnimationName}-enter${alternativeAnimationName}-enter-active {
150
- bottom: 0;
175
+ ${alignY === "top" ? "top: 0" : "bottom: 0"};
151
176
  opacity: 1;
152
177
  transition: all 400ms ease;
153
178
  }
154
179
 
155
180
  &${alternativeAnimationName}-exit${alternativeAnimationName}-exit-active {
156
- bottom: -40px;
181
+ ${alignY === "top" ? "top: -40px" : "bottom: -40px"};
157
182
  opacity: 0;
158
183
  transition: all 200ms ease;
159
184
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carbon-react",
3
- "version": "123.5.1",
3
+ "version": "123.7.0",
4
4
  "description": "A library of reusable React components for easily building user interfaces.",
5
5
  "files": [
6
6
  "lib",