@db-ux/react-core-components 4.0.4 → 4.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @db-ux/react-core-components
2
2
 
3
+ ## 4.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - refactor(notification): update and simplify grid layout for block link variant - [see commit cb83f96](https://github.com/db-ux-design-system/core-web/commit/cb83f966eaf29c85b4cf0079750bdd563f216d6e)
8
+
9
+ - fix(DBCustomSelect): properly announce selected options - [see commit 773edeb](https://github.com/db-ux-design-system/core-web/commit/773edeb943a085eb79e1c8d59059137b2830fbf0):
10
+ - feat(DBCustomSelect): introduce new property `selectedPrefix`
11
+
12
+ ### Patch Changes
13
+
14
+ - fix(DBCustomSelect): automatically handle form reset events - [see commit 6af5246](https://github.com/db-ux-design-system/core-web/commit/6af5246b3b2e6febdc6ff6342ba1a8eb10184d14):
15
+ - An event listener is now added for every form component (input, custom-select, etc.) when a `form` property is passed.
16
+ - This listener detects form resets and updates the component's internal value/checked state accordingly.
17
+ - > **Note**: This does not work for `ngModel` in Angular.
18
+
19
+ - fix(button): Replace fixed height with min-height for buttons to allow dynamic height adjustment when text wraps - [see commit d1fd2c4](https://github.com/db-ux-design-system/core-web/commit/d1fd2c4e58a5ed6f75fab44700cd2d93c7232474)
20
+
3
21
  ## 4.0.4
4
22
 
5
23
  ### Patch Changes
@@ -4,6 +4,7 @@ import { filterPassingProps, getRootProps } from "../../utils/react";
4
4
  import { useState, useRef, useEffect, forwardRef } from "react";
5
5
  import { DEFAULT_INVALID_MESSAGE, DEFAULT_INVALID_MESSAGE_ID_SUFFIX, DEFAULT_MESSAGE_ID_SUFFIX, DEFAULT_VALID_MESSAGE, DEFAULT_VALID_MESSAGE_ID_SUFFIX, } from "../../shared/constants";
6
6
  import { cls, delay, getBoolean, getHideProp, hasVoiceOver, stringPropVisible, uuid, } from "../../utils";
7
+ import { addCheckedResetEventListener, } from "../../utils/form-components";
7
8
  import DBInfotext from "../infotext/infotext";
8
9
  function DBCheckboxFn(props, component) {
9
10
  var _a;
@@ -16,6 +17,7 @@ function DBCheckboxFn(props, component) {
16
17
  const [_invalidMessage, set_invalidMessage] = useState(() => undefined);
17
18
  const [_descByIds, set_descByIds] = useState(() => undefined);
18
19
  const [_voiceOverFallback, set_voiceOverFallback] = useState(() => "");
20
+ const [abortController, setAbortController] = useState(() => undefined);
19
21
  function hasValidState() {
20
22
  var _a;
21
23
  return !!((_a = props.validMessage) !== null && _a !== void 0 ? _a : props.validation === "valid");
@@ -49,7 +51,7 @@ function DBCheckboxFn(props, component) {
49
51
  set_descByIds(undefined);
50
52
  }
51
53
  }
52
- function handleChange(event) {
54
+ function handleChange(event, reset) {
53
55
  if (props.onChange) {
54
56
  props.onChange(event);
55
57
  }
@@ -111,6 +113,27 @@ function DBCheckboxFn(props, component) {
111
113
  setInitialized(false);
112
114
  }
113
115
  }, [initialized, _ref.current, props.checked]);
116
+ useEffect(() => {
117
+ if (_ref.current) {
118
+ const defaultChecked = props.defaultChecked;
119
+ let controller = abortController;
120
+ if (!controller) {
121
+ controller = new AbortController();
122
+ setAbortController(controller);
123
+ }
124
+ addCheckedResetEventListener(_ref.current, {
125
+ checked: props.checked,
126
+ defaultChecked,
127
+ }, (event) => {
128
+ handleChange(event, true);
129
+ }, controller.signal);
130
+ }
131
+ }, [_ref.current]);
132
+ useEffect(() => {
133
+ return () => {
134
+ abortController === null || abortController === void 0 ? void 0 : abortController.abort();
135
+ };
136
+ }, []);
114
137
  return (React.createElement("div", Object.assign({}, getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-checkbox", props.className), "data-size": props.size, "data-hide-asterisk": getHideProp(props.showRequiredAsterisk), "data-hide-label": getHideProp(props.showLabel) }),
115
138
  React.createElement("label", { htmlFor: _id },
116
139
  React.createElement("input", Object.assign({ type: "checkbox", "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { id: _id, name: props.name, checked: getBoolean(props.checked, "checked"), disabled: getBoolean(props.disabled, "disabled"), value: props.value, required: getBoolean(props.required, "required"), onChange: (event) => handleChange(event), onBlur: (event) => handleBlur(event), onFocus: (event) => handleFocus(event), "aria-describedby": (_a = props.ariaDescribedBy) !== null && _a !== void 0 ? _a : _descByIds })),
@@ -7,6 +7,7 @@ import { cls, delay, getBoolean, getBooleanAsString, getHideProp, getOptionKey,
7
7
  import { DocumentClickListener } from "../../utils/document-click-listener";
8
8
  import { DocumentScrollListener } from "../../utils/document-scroll-listener";
9
9
  import { handleFixedDropdown } from "../../utils/floating-components";
10
+ import { addResetEventListener, } from "../../utils/form-components";
10
11
  import DBButton from "../button/button";
11
12
  import DBCustomSelectDropdown from "../custom-select-dropdown/custom-select-dropdown";
12
13
  import DBCustomSelectListItem from "../custom-select-list-item/custom-select-list-item";
@@ -35,6 +36,7 @@ function DBCustomSelectFn(props, component) {
35
36
  const [_infoTextId, set_infoTextId] = useState(() => undefined);
36
37
  const [_validity, set_validity] = useState(() => "no-validation");
37
38
  const [_userInteraction, set_userInteraction] = useState(() => false);
39
+ const [abortController, setAbortController] = useState(() => undefined);
38
40
  const [_descByIds, set_descByIds] = useState(() => undefined);
39
41
  const [_selectedLabels, set_selectedLabels] = useState(() => "");
40
42
  const [_selectedLabelsId, set_selectedLabelsId] = useState(() => undefined);
@@ -69,7 +71,7 @@ function DBCustomSelectFn(props, component) {
69
71
  }
70
72
  /* For a11y reasons we need to map the correct message with the select */
71
73
  if (!((_a = selectRef.current) === null || _a === void 0 ? void 0 : _a.validity.valid) || props.validation === "invalid") {
72
- set_descByIds(_invalidMessageId);
74
+ setDescById(_invalidMessageId);
73
75
  set_invalidMessage(props.invalidMessage ||
74
76
  ((_b = selectRef.current) === null || _b === void 0 ? void 0 : _b.validationMessage) ||
75
77
  DEFAULT_INVALID_MESSAGE);
@@ -84,7 +86,7 @@ function DBCustomSelectFn(props, component) {
84
86
  else if (hasValidState() &&
85
87
  ((_d = selectRef.current) === null || _d === void 0 ? void 0 : _d.validity.valid) &&
86
88
  props.required) {
87
- set_descByIds(_validMessageId);
89
+ setDescById(_validMessageId);
88
90
  if (hasVoiceOver()) {
89
91
  set_voiceOverFallback((_e = props.validMessage) !== null && _e !== void 0 ? _e : DEFAULT_VALID_MESSAGE);
90
92
  delay(() => set_voiceOverFallback(""), 1000);
@@ -92,11 +94,11 @@ function DBCustomSelectFn(props, component) {
92
94
  set_validity((_f = props.validation) !== null && _f !== void 0 ? _f : "valid");
93
95
  }
94
96
  else if (stringPropVisible(props.message, props.showMessage)) {
95
- set_descByIds(_messageId);
97
+ setDescById(_messageId);
96
98
  set_validity((_g = props.validation) !== null && _g !== void 0 ? _g : "no-validation");
97
99
  }
98
100
  else {
99
- set_descByIds(_placeholderId);
101
+ setDescById(_placeholderId);
100
102
  set_validity((_h = props.validation) !== null && _h !== void 0 ? _h : "no-validation");
101
103
  }
102
104
  }
@@ -547,6 +549,25 @@ function DBCustomSelectFn(props, component) {
547
549
  handleValidation();
548
550
  }
549
551
  }, [_values, selectRef.current]);
552
+ useEffect(() => {
553
+ if (selectRef.current) {
554
+ let controller = abortController;
555
+ if (!controller) {
556
+ controller = new AbortController();
557
+ setAbortController(controller);
558
+ }
559
+ const initialValues = props.values;
560
+ addResetEventListener(selectRef.current, () => {
561
+ const resetValue = initialValues
562
+ ? initialValues
563
+ : selectRef.current.value
564
+ ? [selectRef.current.value]
565
+ : [];
566
+ handleOptionSelected(resetValue);
567
+ handleValidation();
568
+ }, controller.signal);
569
+ }
570
+ }, [selectRef.current]);
550
571
  useEffect(() => {
551
572
  set_validity(props.validation);
552
573
  }, [props.validation]);
@@ -635,6 +656,11 @@ function DBCustomSelectFn(props, component) {
635
656
  ((_a = selectRef.current) === null || _a === void 0 ? void 0 : _a.validationMessage) ||
636
657
  DEFAULT_INVALID_MESSAGE);
637
658
  }, [selectRef.current, props.invalidMessage]);
659
+ useEffect(() => {
660
+ return () => {
661
+ abortController === null || abortController === void 0 ? void 0 : abortController.abort();
662
+ };
663
+ }, []);
638
664
  return (React.createElement("div", Object.assign({ id: _id, ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font", "onOptionSelected", "onAmountChange", "onDropdownToggle"]), getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-custom-select", props.className), "aria-invalid": _validity === "invalid", "data-custom-validity": _validity, "data-width": props.formFieldWidth, "data-variant": props.variant === "floating" &&
639
665
  props.selectedType === "tag" &&
640
666
  props.multiple
@@ -646,7 +672,9 @@ function DBCustomSelectFn(props, component) {
646
672
  props.children,
647
673
  props.options ? (React.createElement(React.Fragment, null,
648
674
  React.createElement("summary", { className: "db-custom-select-form-field", id: _summaryId, "aria-disabled": getBooleanAsString(props.disabled), "aria-labelledby": _labelId },
649
- (_selectedLabels === null || _selectedLabels === void 0 ? void 0 : _selectedLabels.length) ? (React.createElement("span", { "data-visually-hidden": getBooleanAsString(props.selectedType === "tag"), id: _selectedLabelsId }, _selectedLabels)) : null,
675
+ (_selectedLabels === null || _selectedLabels === void 0 ? void 0 : _selectedLabels.length) ? (React.createElement("span", { "data-visually-hidden": getBooleanAsString(props.selectedType === "tag"), id: _selectedLabelsId },
676
+ props.selectedPrefix ? (React.createElement("span", { "data-visually-hidden": "true" }, props.selectedPrefix)) : null,
677
+ _selectedLabels)) : null,
650
678
  props.selectedType === "tag" ? (React.createElement("div", null, _selectedOptions === null || _selectedOptions === void 0 ? void 0 : _selectedOptions.map((option, index) => (React.createElement(DBTag, { emphasis: "strong", behavior: "removable", removeButton: getTagRemoveLabel(option), onRemove: (event) => handleTagRemove(option, event), key: getOptionKey(option, "tag-") }, getOptionLabel(option)))))) : null),
651
679
  React.createElement(DBCustomSelectDropdown, { width: props.dropdownWidth },
652
680
  searchEnabled ? (React.createElement("div", null,
@@ -140,6 +140,11 @@ export type DBCustomSelectDefaultProps = {
140
140
  * You need to define the empty state as well based on selected options.
141
141
  */
142
142
  selectedLabels?: string;
143
+ /**
144
+ * Optional: Prefix text announced by screen readers before the selection
145
+ * (e.g., "Ausgewählt" or "Selected").
146
+ */
147
+ selectedPrefix?: string;
143
148
  /**
144
149
  * Change the selected type for values shown in multi select
145
150
  */
@@ -4,6 +4,7 @@ import { filterPassingProps, getRootProps } from "../../utils/react";
4
4
  import { useState, useRef, useEffect, forwardRef } from "react";
5
5
  import { DEFAULT_DATALIST_ID_SUFFIX, DEFAULT_INVALID_MESSAGE, DEFAULT_INVALID_MESSAGE_ID_SUFFIX, DEFAULT_LABEL, DEFAULT_MESSAGE_ID_SUFFIX, DEFAULT_PLACEHOLDER, DEFAULT_VALID_MESSAGE, DEFAULT_VALID_MESSAGE_ID_SUFFIX, } from "../../shared/constants";
6
6
  import { cls, delay, getBoolean, getBooleanAsString, getHideProp, getInputValue, getNumber, hasVoiceOver, isArrayOfStrings, isIOSSafari, stringPropVisible, uuid, } from "../../utils";
7
+ import { addValueResetEventListener, } from "../../utils/form-components";
7
8
  import DBInfotext from "../infotext/infotext";
8
9
  function DBInputFn(props, component) {
9
10
  var _a, _b, _c, _d, _e, _f, _g;
@@ -17,6 +18,7 @@ function DBInputFn(props, component) {
17
18
  const [_descByIds, set_descByIds] = useState(() => undefined);
18
19
  const [_value, set_value] = useState(() => undefined);
19
20
  const [_voiceOverFallback, set_voiceOverFallback] = useState(() => "");
21
+ const [abortController, setAbortController] = useState(() => undefined);
20
22
  function hasValidState() {
21
23
  var _a;
22
24
  return !!((_a = props.validMessage) !== null && _a !== void 0 ? _a : props.validation === "valid");
@@ -50,13 +52,13 @@ function DBInputFn(props, component) {
50
52
  set_descByIds(undefined);
51
53
  }
52
54
  }
53
- function handleInput(event) {
55
+ function handleInput(event, reset) {
54
56
  if (props.onInput) {
55
57
  props.onInput(event);
56
58
  }
57
59
  handleValidation();
58
60
  }
59
- function handleChange(event) {
61
+ function handleChange(event, reset) {
60
62
  if (props.onChange) {
61
63
  props.onChange(event);
62
64
  }
@@ -114,6 +116,28 @@ function DBInputFn(props, component) {
114
116
  useEffect(() => {
115
117
  set_value(props.value);
116
118
  }, [props.value]);
119
+ useEffect(() => {
120
+ if (_ref.current) {
121
+ const defaultValue = props.defaultValue;
122
+ let controller = abortController;
123
+ if (!controller) {
124
+ controller = new AbortController();
125
+ setAbortController(controller);
126
+ }
127
+ addValueResetEventListener(_ref.current, {
128
+ value: props.value,
129
+ defaultValue,
130
+ }, (event) => {
131
+ handleChange(event, true);
132
+ handleInput(event, true);
133
+ }, controller.signal);
134
+ }
135
+ }, [_ref.current]);
136
+ useEffect(() => {
137
+ return () => {
138
+ abortController === null || abortController === void 0 ? void 0 : abortController.abort();
139
+ };
140
+ }, []);
117
141
  return (React.createElement("div", Object.assign({}, getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-input", props.className), "data-variant": props.variant, "data-hide-label": getHideProp(props.showLabel), "data-show-icon": getBooleanAsString((_a = props.showIconLeading) !== null && _a !== void 0 ? _a : props.showIcon), "data-icon": (_b = props.iconLeading) !== null && _b !== void 0 ? _b : props.icon, "data-icon-trailing": props.iconTrailing, "data-hide-asterisk": getHideProp(props.showRequiredAsterisk), "data-show-icon-trailing": getBooleanAsString(props.showIconTrailing) }),
118
142
  React.createElement("label", { htmlFor: _id }, (_c = props.label) !== null && _c !== void 0 ? _c : DEFAULT_LABEL),
119
143
  React.createElement("input", Object.assign({ "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, "data-field-sizing": props.fieldSizing, ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { id: _id, name: props.name, type: props.type || "text", multiple: getBoolean(props.multiple, "multiple"), placeholder: (_d = props.placeholder) !== null && _d !== void 0 ? _d : DEFAULT_PLACEHOLDER, disabled: getBoolean(props.disabled, "disabled"), required: getBoolean(props.required, "required"), step: getNumber(props.step), value: props.value, maxLength: getNumber(props.maxLength, props.maxlength), minLength: getNumber(props.minLength, props.minlength), max: getInputValue(props.max, props.type), min: getInputValue(props.min, props.type), readOnly: getBoolean(props.readOnly, "readOnly") ||
@@ -16,7 +16,7 @@ function DBNotificationFn(props, component) {
16
16
  props.onClose(event);
17
17
  }
18
18
  }
19
- return (React.createElement("article", Object.assign({ ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font", "onClose"]), { id: props.id }, getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-notification", props.className), "aria-live": props.ariaLive, "data-semantic": props.semantic, "data-variant": props.variant, "data-icon": props.icon, "data-show-icon": getBooleanAsString(props.showIcon), "data-link-variant": props.linkVariant }),
19
+ return (React.createElement("article", Object.assign({ ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font", "onClose"]), { id: props.id }, getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-notification", props.className), "aria-live": props.ariaLive, "data-semantic": props.semantic, "data-variant": props.variant, "data-icon": getBoolean(props.showIcon) !== false ? props.icon : undefined, "data-show-icon": getBooleanAsString(props.showIcon), "data-link-variant": props.linkVariant }),
20
20
  React.createElement(React.Fragment, null, props.image),
21
21
  stringPropVisible(props.headline, props.showHeadline) ? (React.createElement("header", null, props.headline)) : null,
22
22
  React.createElement("p", null, props.text ? React.createElement(React.Fragment, null, props.text) : React.createElement(React.Fragment, null, props.children)),
@@ -1,5 +1,5 @@
1
- import { ChangeEventProps, ChangeEventState, FocusEventProps, FocusEventState, FormCheckProps, FormProps, FormState, GlobalProps, GlobalState, InitializedState, SizeProps } from '../../shared/model';
1
+ import { ChangeEventProps, ChangeEventState, FocusEventProps, FocusEventState, FormCheckProps, FormProps, FormState, GlobalProps, GlobalState, InitializedState, InputEventProps, InputEventState, SizeProps } from '../../shared/model';
2
2
  export type DBRadioDefaultProps = {};
3
- export type DBRadioProps = DBRadioDefaultProps & GlobalProps & ChangeEventProps<HTMLInputElement> & FocusEventProps<HTMLInputElement> & FormProps & FormCheckProps & SizeProps;
3
+ export type DBRadioProps = DBRadioDefaultProps & GlobalProps & InputEventProps<HTMLInputElement> & ChangeEventProps<HTMLInputElement> & FocusEventProps<HTMLInputElement> & FormProps & FormCheckProps & SizeProps;
4
4
  export type DBRadioDefaultState = {};
5
- export type DBRadioState = DBRadioDefaultState & GlobalState & ChangeEventState<HTMLInputElement> & FocusEventState<HTMLInputElement> & FormState & InitializedState;
5
+ export type DBRadioState = DBRadioDefaultState & GlobalState & InputEventState<HTMLInputElement> & ChangeEventState<HTMLInputElement> & FocusEventState<HTMLInputElement> & FormState & InitializedState;
@@ -1,3 +1,3 @@
1
1
  import * as React from "react";
2
- declare const DBRadio: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<any>, "value" | "size" | "checked" | keyof import("../../shared/model").GlobalProps | keyof import("../../shared/model").ChangeEventProps<HTMLInputElement> | keyof import("../../shared/model").FocusEventProps<HTMLInputElement> | keyof import("../../shared/model").CustomFormProps | keyof import("../../shared/model").BaseFormProps | keyof import("../../shared/model").RequiredProps | "showLabel"> & import("../../shared/model").GlobalProps & import("../../shared/model").ChangeEventProps<HTMLInputElement> & import("../../shared/model").FocusEventProps<HTMLInputElement> & import("../../shared/model").CustomFormProps & import("../../shared/model").BaseFormProps & import("../../shared/model").RequiredProps & import("../../shared/model").ShowLabelProps & import("../../shared/model").ValueProps & import("../../shared/model").FormCheckProps & import("../../shared/model").SizeProps & React.RefAttributes<any>>;
2
+ declare const DBRadio: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<any>, "value" | "size" | "checked" | keyof import("../../shared/model").GlobalProps | keyof import("../../shared/model").ChangeEventProps<HTMLInputElement> | keyof import("../../shared/model").FocusEventProps<HTMLInputElement> | keyof import("../../shared/model").CustomFormProps | keyof import("../../shared/model").BaseFormProps | keyof import("../../shared/model").RequiredProps | "showLabel" | keyof import("../../shared/model").InputEventProps<HTMLInputElement>> & import("../../shared/model").GlobalProps & import("../../shared/model").InputEventProps<HTMLInputElement> & import("../../shared/model").ChangeEventProps<HTMLInputElement> & import("../../shared/model").FocusEventProps<HTMLInputElement> & import("../../shared/model").CustomFormProps & import("../../shared/model").BaseFormProps & import("../../shared/model").RequiredProps & import("../../shared/model").ShowLabelProps & import("../../shared/model").ValueProps & import("../../shared/model").FormCheckProps & import("../../shared/model").SizeProps & React.RefAttributes<any>>;
3
3
  export default DBRadio;
@@ -2,12 +2,19 @@
2
2
  import * as React from "react";
3
3
  import { filterPassingProps, getRootProps } from "../../utils/react";
4
4
  import { useState, useRef, useEffect, forwardRef } from "react";
5
- import { cls, getBoolean, getHideProp, uuid } from "../../utils";
5
+ import { cls, delay, getBoolean, getHideProp, uuid } from "../../utils";
6
+ import { addResetEventListener, } from "../../utils/form-components";
6
7
  function DBRadioFn(props, component) {
7
8
  const _ref = component || useRef(component);
8
9
  const [initialized, setInitialized] = useState(() => false);
9
10
  const [_id, set_id] = useState(() => undefined);
10
- function handleChange(event) {
11
+ const [abortController, setAbortController] = useState(() => undefined);
12
+ function handleInput(event, reset) {
13
+ if (props.onInput) {
14
+ props.onInput(event);
15
+ }
16
+ }
17
+ function handleChange(event, reset) {
11
18
  if (props.onChange) {
12
19
  props.onChange(event);
13
20
  }
@@ -32,8 +39,35 @@ function DBRadioFn(props, component) {
32
39
  _ref.current.checked = true;
33
40
  }
34
41
  }, [initialized, _ref.current, props.checked]);
42
+ useEffect(() => {
43
+ if (_ref.current) {
44
+ const defaultChecked = props.defaultChecked;
45
+ let controller = abortController;
46
+ if (!controller) {
47
+ controller = new AbortController();
48
+ setAbortController(controller);
49
+ }
50
+ addResetEventListener(_ref.current, (event) => {
51
+ void delay(() => {
52
+ const resetChecked = props.checked
53
+ ? props.checked
54
+ : defaultChecked
55
+ ? defaultChecked
56
+ : _ref.current.checked;
57
+ const valueEvent = Object.assign(Object.assign({}, event), { target: Object.assign(Object.assign({}, event.target), { value: "", checked: resetChecked }) });
58
+ handleChange(valueEvent, true);
59
+ handleInput(valueEvent, true);
60
+ }, 1);
61
+ }, controller.signal);
62
+ }
63
+ }, [_ref.current]);
64
+ useEffect(() => {
65
+ return () => {
66
+ abortController === null || abortController === void 0 ? void 0 : abortController.abort();
67
+ };
68
+ }, []);
35
69
  return (React.createElement("label", Object.assign({ "data-size": props.size, "data-hide-label": getHideProp(props.showLabel), "data-hide-asterisk": getHideProp(props.showRequiredAsterisk) }, getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-radio", props.className), htmlFor: _id }),
36
- React.createElement("input", Object.assign({ type: "radio", "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { id: _id, name: props.name, checked: getBoolean(props.checked, "checked"), disabled: getBoolean(props.disabled, "disabled"), value: props.value, required: getBoolean(props.required, "required"), onChange: (event) => handleChange(event), onBlur: (event) => handleBlur(event), onFocus: (event) => handleFocus(event) })),
70
+ React.createElement("input", Object.assign({ type: "radio", "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { id: _id, name: props.name, checked: getBoolean(props.checked, "checked"), disabled: getBoolean(props.disabled, "disabled"), value: props.value, required: getBoolean(props.required, "required"), onInput: (event) => handleInput(event), onChange: (event) => handleChange(event), onBlur: (event) => handleBlur(event), onFocus: (event) => handleFocus(event) })),
37
71
  props.label ? React.createElement(React.Fragment, null, props.label) : React.createElement(React.Fragment, null, props.children)));
38
72
  }
39
73
  const DBRadio = forwardRef(DBRadioFn);
@@ -4,6 +4,7 @@ import { filterPassingProps, getRootProps } from "../../utils/react";
4
4
  import { useState, useRef, useEffect, forwardRef } from "react";
5
5
  import { DEFAULT_INVALID_MESSAGE, DEFAULT_INVALID_MESSAGE_ID_SUFFIX, DEFAULT_LABEL, DEFAULT_MESSAGE_ID_SUFFIX, DEFAULT_PLACEHOLDER_ID_SUFFIX, DEFAULT_VALID_MESSAGE, DEFAULT_VALID_MESSAGE_ID_SUFFIX, } from "../../shared/constants";
6
6
  import { cls, delay, getBoolean, getBooleanAsString, getHideProp, getOptionKey, hasVoiceOver, stringPropVisible, uuid, } from "../../utils";
7
+ import { addValueResetEventListener, } from "../../utils/form-components";
7
8
  import DBInfotext from "../infotext/infotext";
8
9
  function DBSelectFn(props, component) {
9
10
  var _a, _b, _c, _d;
@@ -18,6 +19,7 @@ function DBSelectFn(props, component) {
18
19
  const [_value, set_value] = useState(() => "");
19
20
  const [initialized, setInitialized] = useState(() => false);
20
21
  const [_voiceOverFallback, set_voiceOverFallback] = useState(() => "");
22
+ const [abortController, setAbortController] = useState(() => undefined);
21
23
  function hasValidState() {
22
24
  var _a;
23
25
  return !!((_a = props.validMessage) !== null && _a !== void 0 ? _a : props.validation === "valid");
@@ -59,13 +61,13 @@ function DBSelectFn(props, component) {
59
61
  props.onClick(event);
60
62
  }
61
63
  }
62
- function handleInput(event) {
64
+ function handleInput(event, reset) {
63
65
  if (props.onInput) {
64
66
  props.onInput(event);
65
67
  }
66
68
  handleValidation();
67
69
  }
68
- function handleChange(event) {
70
+ function handleChange(event, reset) {
69
71
  if (props.onChange) {
70
72
  props.onChange(event);
71
73
  }
@@ -126,6 +128,28 @@ function DBSelectFn(props, component) {
126
128
  useEffect(() => {
127
129
  set_value(props.value);
128
130
  }, [props.value]);
131
+ useEffect(() => {
132
+ if (_ref.current) {
133
+ const defaultValue = props.defaultValue;
134
+ let controller = abortController;
135
+ if (!controller) {
136
+ controller = new AbortController();
137
+ setAbortController(controller);
138
+ }
139
+ addValueResetEventListener(_ref.current, {
140
+ value: props.value,
141
+ defaultValue,
142
+ }, (event) => {
143
+ handleChange(event, true);
144
+ handleInput(event, true);
145
+ }, controller.signal);
146
+ }
147
+ }, [_ref.current]);
148
+ useEffect(() => {
149
+ return () => {
150
+ abortController === null || abortController === void 0 ? void 0 : abortController.abort();
151
+ };
152
+ }, []);
129
153
  return (React.createElement("div", Object.assign({}, getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-select", props.className), "data-variant": props.variant, "data-hide-label": getHideProp(props.showLabel), "data-hide-asterisk": getHideProp(props.showRequiredAsterisk), "data-icon": props.icon, "data-show-icon": getBooleanAsString(props.showIcon) }),
130
154
  React.createElement("label", { htmlFor: _id }, (_a = props.label) !== null && _a !== void 0 ? _a : DEFAULT_LABEL),
131
155
  React.createElement("select", Object.assign({ "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { required: getBoolean(props.required, "required"), disabled: getBoolean(props.disabled, "disabled"), id: _id, name: props.name, size: props.size, value: props.value, autoComplete: props.autocomplete, multiple: props.multiple, onInput: (event) => handleInput(event), onClick: (event) => handleClick(event), onChange: (event) => handleChange(event), onBlur: (event) => handleBlur(event), onFocus: (event) => handleFocus(event), "aria-describedby": (_b = props.ariaDescribedBy) !== null && _b !== void 0 ? _b : _descByIds }),
@@ -4,6 +4,7 @@ import { filterPassingProps, getRootProps } from "../../utils/react";
4
4
  import { useState, useRef, useEffect, forwardRef } from "react";
5
5
  import { DEFAULT_INVALID_MESSAGE, DEFAULT_INVALID_MESSAGE_ID_SUFFIX, DEFAULT_MESSAGE_ID_SUFFIX, DEFAULT_VALID_MESSAGE, DEFAULT_VALID_MESSAGE_ID_SUFFIX, } from "../../shared/constants";
6
6
  import { cls, delay, getBoolean, getBooleanAsString, getHideProp, hasVoiceOver, stringPropVisible, uuid, } from "../../utils";
7
+ import { addCheckedResetEventListener, } from "../../utils/form-components";
7
8
  import DBInfotext from "../infotext/infotext";
8
9
  function DBSwitchFn(props, component) {
9
10
  var _a, _b, _c;
@@ -15,6 +16,7 @@ function DBSwitchFn(props, component) {
15
16
  const [_invalidMessage, set_invalidMessage] = useState(() => undefined);
16
17
  const [_descByIds, set_descByIds] = useState(() => undefined);
17
18
  const [_voiceOverFallback, set_voiceOverFallback] = useState(() => "");
19
+ const [abortController, setAbortController] = useState(() => undefined);
18
20
  function hasValidState() {
19
21
  var _a;
20
22
  return !!((_a = props.validMessage) !== null && _a !== void 0 ? _a : props.validation === "valid");
@@ -50,7 +52,7 @@ function DBSwitchFn(props, component) {
50
52
  }
51
53
  set_descByIds(undefined);
52
54
  }
53
- function handleChange(event) {
55
+ function handleChange(event, reset) {
54
56
  if (props.onChange) {
55
57
  props.onChange(event);
56
58
  }
@@ -85,6 +87,27 @@ function DBSwitchFn(props, component) {
85
87
  props.invalidMessage,
86
88
  props.checked,
87
89
  ]);
90
+ useEffect(() => {
91
+ if (_ref.current) {
92
+ const defaultChecked = props.defaultChecked;
93
+ let controller = abortController;
94
+ if (!controller) {
95
+ controller = new AbortController();
96
+ setAbortController(controller);
97
+ }
98
+ addCheckedResetEventListener(_ref.current, {
99
+ checked: props.checked,
100
+ defaultChecked,
101
+ }, (event) => {
102
+ handleChange(event, true);
103
+ }, controller.signal);
104
+ }
105
+ }, [_ref.current]);
106
+ useEffect(() => {
107
+ return () => {
108
+ abortController === null || abortController === void 0 ? void 0 : abortController.abort();
109
+ };
110
+ }, []);
88
111
  return (React.createElement("div", Object.assign({ "data-visual-aid": getBooleanAsString(props.visualAid), "data-size": props.size, "data-hide-label": getHideProp(props.showLabel), "data-variant": props.variant, "data-hide-asterisk": getHideProp(props.showRequiredAsterisk), "data-custom-validity": props.validation }, getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-switch", props.className) }),
89
112
  React.createElement("label", { htmlFor: _id },
90
113
  React.createElement("input", Object.assign({ type: "checkbox", role: "switch", id: _id, ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { checked: getBoolean(props.checked, "checked"), value: props.value, disabled: getBoolean(props.disabled, "disabled"), "aria-invalid": props.validation === "invalid" ? "true" : undefined, "aria-describedby": _descByIds, name: props.name, required: getBoolean(props.required, "required"), "data-aid-icon": (_a = props.iconLeading) !== null && _a !== void 0 ? _a : props.icon, "data-aid-icon-trailing": props.iconTrailing, onChange: (event) => handleChange(event), onBlur: (event) => handleBlur(event), onFocus: (event) => handleFocus(event) })),
@@ -4,6 +4,7 @@ import { filterPassingProps, getRootProps } from "../../utils/react";
4
4
  import { useState, useRef, useEffect, forwardRef } from "react";
5
5
  import { DEFAULT_INVALID_MESSAGE, DEFAULT_INVALID_MESSAGE_ID_SUFFIX, DEFAULT_LABEL, DEFAULT_MESSAGE_ID_SUFFIX, DEFAULT_PLACEHOLDER, DEFAULT_ROWS, DEFAULT_VALID_MESSAGE, DEFAULT_VALID_MESSAGE_ID_SUFFIX, } from "../../shared/constants";
6
6
  import { cls, delay, getBoolean, getHideProp, getNumber, hasVoiceOver, stringPropVisible, uuid, } from "../../utils";
7
+ import { addValueResetEventListener, } from "../../utils/form-components";
7
8
  import DBInfotext from "../infotext/infotext";
8
9
  function DBTextareaFn(props, component) {
9
10
  var _a, _b, _c, _d;
@@ -16,6 +17,7 @@ function DBTextareaFn(props, component) {
16
17
  const [_descByIds, set_descByIds] = useState(() => undefined);
17
18
  const [_value, set_value] = useState(() => "");
18
19
  const [_voiceOverFallback, set_voiceOverFallback] = useState(() => "");
20
+ const [abortController, setAbortController] = useState(() => undefined);
19
21
  function hasValidState() {
20
22
  var _a;
21
23
  return !!((_a = props.validMessage) !== null && _a !== void 0 ? _a : props.validation === "valid");
@@ -49,13 +51,13 @@ function DBTextareaFn(props, component) {
49
51
  set_descByIds(undefined);
50
52
  }
51
53
  }
52
- function handleInput(event) {
54
+ function handleInput(event, reset) {
53
55
  if (props.onInput) {
54
56
  props.onInput(event);
55
57
  }
56
58
  handleValidation();
57
59
  }
58
- function handleChange(event) {
60
+ function handleChange(event, reset) {
59
61
  if (props.onChange) {
60
62
  props.onChange(event);
61
63
  }
@@ -101,6 +103,28 @@ function DBTextareaFn(props, component) {
101
103
  useEffect(() => {
102
104
  set_value(props.value);
103
105
  }, [props.value]);
106
+ useEffect(() => {
107
+ if (_ref.current) {
108
+ const defaultValue = props.defaultValue;
109
+ let controller = abortController;
110
+ if (!controller) {
111
+ controller = new AbortController();
112
+ setAbortController(controller);
113
+ }
114
+ addValueResetEventListener(_ref.current, {
115
+ value: props.value,
116
+ defaultValue,
117
+ }, (event) => {
118
+ handleChange(event, true);
119
+ handleInput(event, true);
120
+ }, controller.signal);
121
+ }
122
+ }, [_ref.current]);
123
+ useEffect(() => {
124
+ return () => {
125
+ abortController === null || abortController === void 0 ? void 0 : abortController.abort();
126
+ };
127
+ }, []);
104
128
  return (React.createElement("div", Object.assign({}, getRootProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { className: cls("db-textarea", props.className), "data-variant": props.variant, "data-hide-asterisk": getHideProp(props.showRequiredAsterisk), "data-hide-label": getHideProp(props.showLabel) }),
105
129
  React.createElement("label", { htmlFor: _id }, (_a = props.label) !== null && _a !== void 0 ? _a : DEFAULT_LABEL),
106
130
  React.createElement("textarea", Object.assign({ "aria-invalid": props.validation === "invalid", "data-custom-validity": props.validation, "data-field-sizing": props.fieldSizing, ref: _ref }, filterPassingProps(props, ["data-icon-variant", "data-icon-variant-before", "data-icon-variant-after", "data-icon-weight", "data-icon-weight-before", "data-icon-weight-after", "data-interactive", "data-force-mobile", "data-color", "data-container-color", "data-bg-color", "data-on-bg-color", "data-color-scheme", "data-font-size", "data-headline-size", "data-divider", "data-focus", "data-font"]), { id: _id, "data-resize": props.resize, "data-hide-resizer": getHideProp((_b = props.showResizer) !== null && _b !== void 0 ? _b : true), disabled: getBoolean(props.disabled, "disabled"), required: getBoolean(props.required, "required"), readOnly: getBoolean(props.readOnly, "readOnly") ||
@@ -365,6 +365,10 @@ export type FormState = {
365
365
  * This is an internal Fallback
366
366
  */
367
367
  _voiceOverFallback?: string;
368
+ /**
369
+ * We use this to remove form event listener
370
+ */
371
+ abortController?: AbortController;
368
372
  };
369
373
  export type InitializedState = {
370
374
  initialized: boolean;
@@ -461,7 +465,7 @@ export type InputEventProps<T> = {
461
465
  onInput?: (event: InputEvent<T>) => void;
462
466
  };
463
467
  export type InputEventState<T> = {
464
- handleInput: (event: InputEvent<T> | any) => void;
468
+ handleInput: (event: InputEvent<T> | any, reset?: boolean) => void;
465
469
  };
466
470
  export type ChangeEvent<T> = React.ChangeEvent<T>;
467
471
  export type ChangeEventProps<T> = {
@@ -469,7 +473,7 @@ export type ChangeEventProps<T> = {
469
473
  onChange?: (event: ChangeEvent<T>) => void;
470
474
  };
471
475
  export type ChangeEventState<T> = {
472
- handleChange: (event: ChangeEvent<T> | any) => void;
476
+ handleChange: (event: ChangeEvent<T> | any, reset?: boolean) => void;
473
477
  };
474
478
  export type InteractionEvent<T> = React.FocusEvent<T>;
475
479
  export type FocusEventProps<T> = {
@@ -1,2 +1,11 @@
1
1
  export declare const handleFrameworkEventAngular: (component: any, event: any, modelValue?: string) => void;
2
2
  export declare const handleFrameworkEventVue: (emit: (event: string, ...args: any[]) => void, event: any, modelValue?: string) => void;
3
+ export declare const addResetEventListener: (element: any, resetFunction: (event: Event) => void, signal: AbortSignal) => void;
4
+ export declare const addCheckedResetEventListener: (element: any, props: {
5
+ checked?: boolean | string;
6
+ defaultChecked?: boolean;
7
+ }, resetFunction: (event: any) => void, signal: AbortSignal) => void;
8
+ export declare const addValueResetEventListener: (element: any, props: {
9
+ value?: string;
10
+ defaultValue?: string;
11
+ }, resetFunction: (event: any) => void, signal: AbortSignal) => void;
@@ -1,8 +1,39 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { delay } from './index';
2
3
  export const handleFrameworkEventAngular = (component, event, modelValue = 'value') => {
3
4
  component.propagateChange(event.target[modelValue]);
5
+ component.writeValue(event.target[modelValue]);
4
6
  };
5
7
  export const handleFrameworkEventVue = (emit, event, modelValue = 'value') => {
6
8
  // TODO: Replace this with the solution out of https://github.com/BuilderIO/mitosis/issues/833 after this has been "solved"
7
9
  emit(`update:${modelValue}`, event.target[modelValue]);
8
10
  };
11
+ export const addResetEventListener = (element, resetFunction, signal) => {
12
+ if (element.form && !element._dbFormResetListenerAdded) {
13
+ element.form.addEventListener('reset', (event) => {
14
+ resetFunction(event);
15
+ }, {
16
+ signal
17
+ });
18
+ // Mark as added to avoid duplicate listeners
19
+ element._dbFormResetListenerAdded = true;
20
+ }
21
+ };
22
+ export const addCheckedResetEventListener = (element, props, resetFunction, signal) => {
23
+ addResetEventListener(element, (event) => {
24
+ void delay(() => {
25
+ const resetValue = props.checked ? props.checked : props.defaultChecked ? props.defaultChecked : element.checked;
26
+ const valueEvent = Object.assign(Object.assign({}, event), { target: Object.assign(Object.assign({}, event.target), { checked: resetValue }) });
27
+ resetFunction(valueEvent);
28
+ }, 1);
29
+ }, signal);
30
+ };
31
+ export const addValueResetEventListener = (element, props, resetFunction, signal) => {
32
+ addResetEventListener(element, (event) => {
33
+ void delay(() => {
34
+ const resetValue = props.value ? props.value : props.defaultValue ? props.defaultValue : element.value;
35
+ const valueEvent = Object.assign(Object.assign({}, event), { target: Object.assign(Object.assign({}, event.target), { value: resetValue }) });
36
+ resetFunction(valueEvent);
37
+ }, 1);
38
+ }, signal);
39
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@db-ux/react-core-components",
3
- "version": "4.0.4",
3
+ "version": "4.1.0",
4
4
  "description": "React components for @db-ux/core-components",
5
5
  "repository": {
6
6
  "type": "git",
@@ -42,7 +42,7 @@
42
42
  },
43
43
  "sideEffects": false,
44
44
  "dependencies": {
45
- "@db-ux/core-components": "4.0.4",
46
- "@db-ux/core-foundations": "4.0.4"
45
+ "@db-ux/core-components": "4.1.0",
46
+ "@db-ux/core-foundations": "4.1.0"
47
47
  }
48
48
  }