@scm-manager/ui-core 4.0.0-REACT18-20250701-125025 → 4.0.0-REACT19
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/{src/base/buttons/a11y.test.ts → .storybook/i18n.ts} +27 -9
- package/.storybook/main.ts +54 -0
- package/.storybook/preview-head.html +6 -1
- package/.storybook/preview.tsx +125 -0
- package/.turbo/turbo-test.log +164 -0
- package/.turbo/turbo-typecheck.log +3 -2
- package/package.json +37 -42
- package/src/base/buttons/Button.stories.tsx +179 -70
- package/src/base/buttons/Button.tsx +9 -9
- package/src/base/forms/AddListEntryForm.tsx +8 -8
- package/src/base/forms/ConfigurationForm.tsx +14 -5
- package/src/base/forms/Form.stories.tsx +599 -289
- package/src/base/forms/Form.tsx +8 -8
- package/src/base/forms/FormPathContext.tsx +3 -3
- package/src/base/forms/ScmFormContext.tsx +7 -4
- package/src/base/forms/ScmFormListContext.tsx +2 -1
- package/src/base/forms/base/Field.tsx +1 -1
- package/src/base/forms/base/label/Label.tsx +1 -1
- package/src/base/forms/chip-input/ChipInputField.stories.tsx +109 -28
- package/src/base/forms/chip-input/ChipInputField.tsx +20 -8
- package/src/base/forms/chip-input/ControlledChipInputField.tsx +3 -1
- package/src/base/forms/combobox/Combobox.stories.tsx +216 -89
- package/src/base/forms/combobox/Combobox.tsx +4 -2
- package/src/base/forms/combobox/ComboboxField.tsx +2 -1
- package/src/base/forms/headless-chip-input/ChipInput.tsx +9 -9
- package/src/base/forms/helpers.ts +12 -9
- package/src/base/forms/input/ControlledSecretConfirmationField.tsx +4 -2
- package/src/base/forms/radio-button/RadioButton.stories.tsx +317 -124
- package/src/base/forms/radio-button/RadioButton.tsx +8 -4
- package/src/base/forms/radio-button/RadioButtonContext.tsx +2 -1
- package/src/base/forms/table/ControlledColumn.tsx +1 -1
- package/src/base/forms/table/ControlledTable.tsx +12 -4
- package/src/base/helpers/useDocumentTitle.test.ts +15 -7
- package/src/base/layout/card/Card.stories.tsx +171 -72
- package/src/base/layout/card/Card.tsx +4 -4
- package/src/base/layout/card/CardDetail.tsx +2 -3
- package/src/base/layout/card-list/CardList.stories.tsx +283 -169
- package/src/base/layout/collapsible/Collapsible.stories.tsx +54 -16
- package/src/base/layout/index.ts +2 -5
- package/src/base/layout/tabs/Tabs.stories.tsx +58 -16
- package/src/base/layout/templates/data-page/DataPage.stories.tsx +289 -156
- package/src/base/layout/templates/data-page/DataPageHeader.tsx +1 -1
- package/src/base/overlays/dialog/Dialog.stories.tsx +94 -34
- package/src/base/overlays/menu/Menu.stories.tsx +116 -48
- package/src/base/overlays/menu/Menu.tsx +1 -0
- package/src/base/overlays/popover/Popover.stories.tsx +50 -37
- package/src/base/shortcuts/iterator/keyboardIterator.test.tsx +16 -7
- package/src/base/shortcuts/iterator/keyboardIterator.tsx +13 -5
- package/src/base/status/StatusIcon.stories.tsx +76 -27
- package/src/base/status/index.ts +1 -1
- package/src/base/text/SplitAndReplace.stories.tsx +128 -50
- package/src/base/text/index.ts +1 -1
- package/.storybook/RemoveThemesPlugin.js +0 -49
- package/.storybook/main.js +0 -86
- package/.storybook/preview.js +0 -87
- package/src/base/buttons/image-snapshot.test.ts +0 -26
|
@@ -14,104 +14,231 @@
|
|
|
14
14
|
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { storiesOf } from "@storybook/react";
|
|
17
|
+
// import { storiesOf } from "@storybook/react";
|
|
18
|
+
// import React, { Fragment, useState } from "react";
|
|
19
|
+
// import Combobox from "./Combobox";
|
|
20
|
+
// import { Combobox as HeadlessCombobox } from "@headlessui/react";
|
|
21
|
+
// import { Option } from "@scm-manager/ui-types";
|
|
22
|
+
// import { Link, BrowserRouter } from "react-router-dom";
|
|
23
|
+
//
|
|
24
|
+
// const waitFor = (ms: number) =>
|
|
25
|
+
// function <T>(result: T) {
|
|
26
|
+
// return new Promise<T>((resolve) => setTimeout(() => resolve(result), ms));
|
|
27
|
+
// };
|
|
28
|
+
//
|
|
29
|
+
// const data = [
|
|
30
|
+
// { label: "Trillian", value: "1" },
|
|
31
|
+
// { label: "Arthur", value: "2" },
|
|
32
|
+
// { label: "Zaphod", value: "3" },
|
|
33
|
+
// ];
|
|
34
|
+
//
|
|
35
|
+
// const linkData = [{ label: "Link111111111111111111111111111111111111", value: "1" }];
|
|
36
|
+
//
|
|
37
|
+
// storiesOf("Combobox", module)
|
|
38
|
+
// .add("Options array", () => {
|
|
39
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
40
|
+
// return <Combobox options={data} value={value} onChange={setValue} />;
|
|
41
|
+
// })
|
|
42
|
+
// .add("Options function", () => {
|
|
43
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
44
|
+
// return <Combobox options={() => data} value={value} onChange={setValue} />;
|
|
45
|
+
// })
|
|
46
|
+
// .add("Options function as promise", () => {
|
|
47
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
48
|
+
// return (
|
|
49
|
+
// <Combobox
|
|
50
|
+
// value={value}
|
|
51
|
+
// onChange={setValue}
|
|
52
|
+
// options={(query) => Promise.resolve(data.filter((t) => t.label.startsWith(query))).then(waitFor(1000))}
|
|
53
|
+
// />
|
|
54
|
+
// );
|
|
55
|
+
// })
|
|
56
|
+
// .add("Children as Element", () => {
|
|
57
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
58
|
+
// const [query, setQuery] = useState("");
|
|
59
|
+
//
|
|
60
|
+
// return (
|
|
61
|
+
// <Combobox value={value} onChange={setValue} onQueryChange={setQuery}>
|
|
62
|
+
// {query ? (
|
|
63
|
+
// <HeadlessCombobox.Option value={{ label: query, value: query }} key={query} as={Fragment}>
|
|
64
|
+
// {({ active }) => <Combobox.Option isActive={active}>{`Create ${query}`}</Combobox.Option>}
|
|
65
|
+
// </HeadlessCombobox.Option>
|
|
66
|
+
// ) : null}
|
|
67
|
+
// <HeadlessCombobox.Option value={{ label: "All", value: "All" }} key="all" as={Fragment}>
|
|
68
|
+
// {({ active }) => <Combobox.Option isActive={active}>All</Combobox.Option>}
|
|
69
|
+
// </HeadlessCombobox.Option>
|
|
70
|
+
// <>
|
|
71
|
+
// {data.map((o) => (
|
|
72
|
+
// <HeadlessCombobox.Option value={o} key={o.value} as={Fragment}>
|
|
73
|
+
// {({ active }) => <Combobox.Option isActive={active}>{o.label}</Combobox.Option>}
|
|
74
|
+
// </HeadlessCombobox.Option>
|
|
75
|
+
// ))}
|
|
76
|
+
// </>
|
|
77
|
+
// </Combobox>
|
|
78
|
+
// );
|
|
79
|
+
// })
|
|
80
|
+
// .add("Children as render props", () => {
|
|
81
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
82
|
+
// return (
|
|
83
|
+
// <Combobox options={data} value={value} onChange={setValue}>
|
|
84
|
+
// {(o) => (
|
|
85
|
+
// <HeadlessCombobox.Option value={o} key={o.value} as={Fragment}>
|
|
86
|
+
// {({ active }) => <Combobox.Option isActive={active}>{o.label}</Combobox.Option>}
|
|
87
|
+
// </HeadlessCombobox.Option>
|
|
88
|
+
// )}
|
|
89
|
+
// </Combobox>
|
|
90
|
+
// );
|
|
91
|
+
// })
|
|
92
|
+
// .add("Links as render props", () => {
|
|
93
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
94
|
+
// const [query, setQuery] = useState("Hello");
|
|
95
|
+
// return (
|
|
96
|
+
// <BrowserRouter>
|
|
97
|
+
// <Combobox
|
|
98
|
+
// className="input is-small omni-search-bar"
|
|
99
|
+
// placeholder={"Placeholder"}
|
|
100
|
+
// value={value}
|
|
101
|
+
// options={linkData}
|
|
102
|
+
// onChange={setValue}
|
|
103
|
+
// onQueryChange={setQuery}
|
|
104
|
+
// >
|
|
105
|
+
// {(o) => (
|
|
106
|
+
// <HeadlessCombobox.Option value={{ label: o.label, value: query, displayValue: o.value }} key={o.value} as={Fragment}>
|
|
107
|
+
// {({ active }) => (
|
|
108
|
+
// <Combobox.Option isActive={active}>
|
|
109
|
+
// <Link to={o.label}>{o.label}</Link>
|
|
110
|
+
// </Combobox.Option>
|
|
111
|
+
// )}
|
|
112
|
+
// </HeadlessCombobox.Option>
|
|
113
|
+
// )}
|
|
114
|
+
// </Combobox>
|
|
115
|
+
// </BrowserRouter>
|
|
116
|
+
// );
|
|
117
|
+
// });
|
|
118
|
+
|
|
18
119
|
import React, { Fragment, useState } from "react";
|
|
19
|
-
import
|
|
120
|
+
import { BrowserRouter, Link } from "react-router-dom";
|
|
121
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
20
122
|
import { Combobox as HeadlessCombobox } from "@headlessui/react";
|
|
21
123
|
import { Option } from "@scm-manager/ui-types";
|
|
22
|
-
import { Link, BrowserRouter } from "react-router-dom";
|
|
23
124
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
125
|
+
import Combobox from "./Combobox";
|
|
126
|
+
|
|
127
|
+
const waitFor =
|
|
128
|
+
(ms: number) =>
|
|
129
|
+
<T,>(result: T) =>
|
|
130
|
+
new Promise<T>((resolve) => setTimeout(() => resolve(result), ms));
|
|
28
131
|
|
|
29
|
-
const data = [
|
|
132
|
+
const data: Option<string>[] = [
|
|
30
133
|
{ label: "Trillian", value: "1" },
|
|
31
134
|
{ label: "Arthur", value: "2" },
|
|
32
135
|
{ label: "Zaphod", value: "3" },
|
|
33
136
|
];
|
|
34
137
|
|
|
35
|
-
const linkData = [{ label: "
|
|
138
|
+
const linkData: Option<string>[] = [{ label: "/user/trillian", value: "1" }];
|
|
139
|
+
|
|
140
|
+
const meta: Meta<typeof Combobox> = {
|
|
141
|
+
title: "Forms/Combobox",
|
|
142
|
+
// @ts-ignore
|
|
143
|
+
component: Combobox,
|
|
144
|
+
decorators: [(Story) => <div style={{ margin: "2rem", maxWidth: "20rem", minHeight: "15rem" }}>{Story()}</div>],
|
|
145
|
+
tags: ["autodocs"],
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export default meta;
|
|
149
|
+
|
|
150
|
+
type Story = StoryObj<typeof meta>;
|
|
36
151
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
152
|
+
// export const OptionsAsArray: Story = {
|
|
153
|
+
// name: "Options from Array",
|
|
154
|
+
// render: () => {
|
|
155
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
156
|
+
// return <Combobox options={data} value={value} onChange={setValue} />;
|
|
157
|
+
// },
|
|
158
|
+
// };
|
|
159
|
+
//
|
|
160
|
+
// export const OptionsAsFunction: Story = {
|
|
161
|
+
// name: "Options from Function",
|
|
162
|
+
// render: () => {
|
|
163
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
164
|
+
// return <Combobox options={() => data} value={value} onChange={setValue} />;
|
|
165
|
+
// },
|
|
166
|
+
// };
|
|
167
|
+
//
|
|
168
|
+
// export const OptionsAsPromise: Story = {
|
|
169
|
+
// name: "Options from Promise",
|
|
170
|
+
// render: () => {
|
|
171
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
172
|
+
// return (
|
|
173
|
+
// <Combobox
|
|
174
|
+
// value={value}
|
|
175
|
+
// onChange={setValue}
|
|
176
|
+
// options={(query) => Promise.resolve(data.filter((t) => t.label.startsWith(query))).then(waitFor(1000))}
|
|
177
|
+
// />
|
|
178
|
+
// );
|
|
179
|
+
// },
|
|
180
|
+
// };
|
|
59
181
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
182
|
+
// export const ChildrenAsElement: Story = {
|
|
183
|
+
// name: "Children as Element",
|
|
184
|
+
// render: () => {
|
|
185
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
186
|
+
// const [query, setQuery] = useState("");
|
|
187
|
+
// return (
|
|
188
|
+
// <Combobox value={value} onChange={setValue} onQueryChange={setQuery}>
|
|
189
|
+
// {query ? (
|
|
190
|
+
// <HeadlessCombobox.Option value={{ label: query, value: query }} key={query} as={Fragment}>
|
|
191
|
+
// {({ active }) => <Combobox.Option isActive={active}>{`Create ${query}`}</Combobox.Option>}
|
|
192
|
+
// </HeadlessCombobox.Option>
|
|
193
|
+
// ) : null}
|
|
194
|
+
// <HeadlessCombobox.Option value={{ label: "All", value: "All" }} key="all" as={Fragment}>
|
|
195
|
+
// {({ active }) => <Combobox.Option isActive={active}>All</Combobox.Option>}
|
|
196
|
+
// </HeadlessCombobox.Option>
|
|
197
|
+
// {data.map((o) => (
|
|
198
|
+
// <HeadlessCombobox.Option value={o} key={o.value} as={Fragment}>
|
|
199
|
+
// {({ active }) => <Combobox.Option isActive={active}>{o.label}</Combobox.Option>}
|
|
200
|
+
// </HeadlessCombobox.Option>
|
|
201
|
+
// ))}
|
|
202
|
+
// </Combobox>
|
|
203
|
+
// );
|
|
204
|
+
// },
|
|
205
|
+
// };
|
|
206
|
+
//
|
|
207
|
+
// export const ChildrenAsRenderProps: Story = {
|
|
208
|
+
// name: "Children as Render Props",
|
|
209
|
+
// render: () => {
|
|
210
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
211
|
+
// return (
|
|
212
|
+
// <Combobox options={data} value={value} onChange={setValue}>
|
|
213
|
+
// {(o) => (
|
|
214
|
+
// <HeadlessCombobox.Option value={o} key={o.value} as={Fragment}>
|
|
215
|
+
// {({ active }) => <Combobox.Option isActive={active}>{o.label}</Combobox.Option>}
|
|
216
|
+
// </HeadlessCombobox.Option>
|
|
217
|
+
// )}
|
|
218
|
+
// </Combobox>
|
|
219
|
+
// );
|
|
220
|
+
// },
|
|
221
|
+
// };
|
|
222
|
+
//
|
|
223
|
+
// export const LinksAsRenderProps: Story = {
|
|
224
|
+
// name: "Links as Render Props",
|
|
225
|
+
// render: () => {
|
|
226
|
+
// const [value, setValue] = useState<Option<string>>();
|
|
227
|
+
// return (
|
|
228
|
+
// // Diese Story benötigt ihren eigenen Router-Kontext, um die `Link`-Komponente zu rendern.
|
|
229
|
+
// <BrowserRouter>
|
|
230
|
+
// <Combobox placeholder="Placeholder" value={value} options={linkData} onChange={setValue}>
|
|
231
|
+
// {(o) => (
|
|
232
|
+
// <HeadlessCombobox.Option value={o} key={o.value} as={Fragment}>
|
|
233
|
+
// {({ active }) => (
|
|
234
|
+
// <Combobox.Option isActive={active}>
|
|
235
|
+
// <Link to={o.label}>{o.label}</Link>
|
|
236
|
+
// </Combobox.Option>
|
|
237
|
+
// )}
|
|
238
|
+
// </HeadlessCombobox.Option>
|
|
239
|
+
// )}
|
|
240
|
+
// </Combobox>
|
|
241
|
+
// </BrowserRouter>
|
|
242
|
+
// );
|
|
243
|
+
// },
|
|
244
|
+
// };
|
|
@@ -124,7 +124,7 @@ function ComboboxComponent<T>(props: ComboboxProps<T>, ref: ForwardedRef<HTMLInp
|
|
|
124
124
|
<HeadlessCombobox.Option value={o} key={o.label} as={Fragment}>
|
|
125
125
|
{({ active }) => <StyledComboboxOption isActive={active}>{o.displayValue ?? o.label}</StyledComboboxOption>}
|
|
126
126
|
</HeadlessCombobox.Option>
|
|
127
|
-
)
|
|
127
|
+
),
|
|
128
128
|
);
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -132,6 +132,7 @@ function ComboboxComponent<T>(props: ComboboxProps<T>, ref: ForwardedRef<HTMLInp
|
|
|
132
132
|
<HeadlessCombobox
|
|
133
133
|
as="div"
|
|
134
134
|
value={props.value}
|
|
135
|
+
// @ts-ignore
|
|
135
136
|
onChange={(e?: Option<T>) => props.onChange && props.onChange(e)}
|
|
136
137
|
disabled={props.disabled || props.readOnly}
|
|
137
138
|
name={props.name}
|
|
@@ -173,6 +174,7 @@ type ComboboxOptionsProps<T> = {
|
|
|
173
174
|
|
|
174
175
|
function ComboboxOptions<T>({ query, options, children }: ComboboxOptionsProps<T>) {
|
|
175
176
|
const [optionsData, setOptionsData] = useState<Array<Option<T>>>([]);
|
|
177
|
+
// @ts-ignore
|
|
176
178
|
const activePromise = useRef<Promise<Array<Option<T>>>>();
|
|
177
179
|
|
|
178
180
|
useEffect(() => {
|
|
@@ -204,7 +206,7 @@ function ComboboxOptions<T>({ query, options, children }: ComboboxOptionsProps<T
|
|
|
204
206
|
<HeadlessCombobox.Option value={o} key={o.label} as={Fragment}>
|
|
205
207
|
{({ active }) => <StyledComboboxOption isActive={active}>{o.displayValue ?? o.label}</StyledComboboxOption>}
|
|
206
208
|
</HeadlessCombobox.Option>
|
|
207
|
-
)
|
|
209
|
+
),
|
|
208
210
|
)}
|
|
209
211
|
</>
|
|
210
212
|
);
|
|
@@ -38,7 +38,7 @@ const ComboboxField = function ComboboxField<T>(
|
|
|
38
38
|
required,
|
|
39
39
|
...props
|
|
40
40
|
}: ComboboxProps<T> & { label: string; helpText?: string; error?: string; isLoading?: boolean; required?: boolean },
|
|
41
|
-
ref: React.ForwardedRef<HTMLInputElement
|
|
41
|
+
ref: React.ForwardedRef<HTMLInputElement>,
|
|
42
42
|
) {
|
|
43
43
|
const labelId = useAriaId();
|
|
44
44
|
return (
|
|
@@ -49,6 +49,7 @@ const ComboboxField = function ComboboxField<T>(
|
|
|
49
49
|
{helpText ? <Help className="ml-1" text={helpText} /> : null}
|
|
50
50
|
</Label>
|
|
51
51
|
<div className={classNames("control", { "is-loading": isLoading })}>
|
|
52
|
+
{/* @ts-ignore */}
|
|
52
53
|
<Combobox {...props} ref={ref} aria-labelledby={labelId} />
|
|
53
54
|
</div>
|
|
54
55
|
</Field>
|
|
@@ -38,7 +38,7 @@ import { Button } from "../../buttons";
|
|
|
38
38
|
type ChipInputContextType<T> = {
|
|
39
39
|
add(newValue: Option<T>): void;
|
|
40
40
|
remove(index: number): void;
|
|
41
|
-
inputRef: RefObject<HTMLInputElement>;
|
|
41
|
+
inputRef: RefObject<HTMLInputElement | null>;
|
|
42
42
|
disabled?: boolean;
|
|
43
43
|
readOnly?: boolean;
|
|
44
44
|
};
|
|
@@ -73,7 +73,7 @@ const DefaultNewChipInput = React.forwardRef<HTMLInputElement, CustomNewChipInpu
|
|
|
73
73
|
return false;
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
|
-
[onChange]
|
|
76
|
+
[onChange],
|
|
77
77
|
);
|
|
78
78
|
|
|
79
79
|
return (
|
|
@@ -81,7 +81,7 @@ const DefaultNewChipInput = React.forwardRef<HTMLInputElement, CustomNewChipInpu
|
|
|
81
81
|
<input onKeyDown={handleKeyDown} {...props} ref={ref} />
|
|
82
82
|
</div>
|
|
83
83
|
);
|
|
84
|
-
}
|
|
84
|
+
},
|
|
85
85
|
);
|
|
86
86
|
|
|
87
87
|
type ChipDeleteProps = {
|
|
@@ -119,7 +119,7 @@ type NewChipInputProps = {
|
|
|
119
119
|
*/
|
|
120
120
|
export const NewChipInput = withForwardRef(function NewChipInput<T>(
|
|
121
121
|
props: NewChipInputProps,
|
|
122
|
-
ref: React.ForwardedRef<HTMLInputElement
|
|
122
|
+
ref: React.ForwardedRef<HTMLInputElement>,
|
|
123
123
|
) {
|
|
124
124
|
const { add, disabled, readOnly, inputRef } = useContext(getChipInputContext<T>());
|
|
125
125
|
|
|
@@ -160,7 +160,7 @@ type Props<T> = {
|
|
|
160
160
|
*/
|
|
161
161
|
const ChipInput = withForwardRef(function ChipInput<T>(
|
|
162
162
|
{ children, value = [], disabled, readOnly, onChange, isNewItemDuplicate, ...props }: Props<T>,
|
|
163
|
-
ref: React.ForwardedRef<HTMLUListElement
|
|
163
|
+
ref: React.ForwardedRef<HTMLUListElement>,
|
|
164
164
|
) {
|
|
165
165
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
166
166
|
const isInactive = useMemo(() => disabled || readOnly, [disabled, readOnly]);
|
|
@@ -171,7 +171,7 @@ const ChipInput = withForwardRef(function ChipInput<T>(
|
|
|
171
171
|
!value?.some((item) =>
|
|
172
172
|
isNewItemDuplicate
|
|
173
173
|
? isNewItemDuplicate(item, newItem)
|
|
174
|
-
: item.label === newItem.label || item.value === newItem.value
|
|
174
|
+
: item.label === newItem.label || item.value === newItem.value,
|
|
175
175
|
)
|
|
176
176
|
) {
|
|
177
177
|
if (onChange) {
|
|
@@ -182,11 +182,11 @@ const ChipInput = withForwardRef(function ChipInput<T>(
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
},
|
|
185
|
-
[isInactive, isNewItemDuplicate, onChange, value]
|
|
185
|
+
[isInactive, isNewItemDuplicate, onChange, value],
|
|
186
186
|
);
|
|
187
187
|
const remove = useCallback(
|
|
188
188
|
(index: number) => !isInactive && onChange && onChange(value?.filter((_, itdx) => itdx !== index)),
|
|
189
|
-
[isInactive, onChange, value]
|
|
189
|
+
[isInactive, onChange, value],
|
|
190
190
|
);
|
|
191
191
|
const Context = getChipInputContext<T>();
|
|
192
192
|
return (
|
|
@@ -199,7 +199,7 @@ const ChipInput = withForwardRef(function ChipInput<T>(
|
|
|
199
199
|
remove,
|
|
200
200
|
inputRef,
|
|
201
201
|
}),
|
|
202
|
-
[add, disabled, readOnly, remove]
|
|
202
|
+
[add, disabled, readOnly, remove],
|
|
203
203
|
)}
|
|
204
204
|
>
|
|
205
205
|
<ul {...props} ref={ref}>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { UseFormReturn } from "react-hook-form";
|
|
17
|
+
import { FieldValues, DefaultValues, UseFormReturn } from "react-hook-form";
|
|
18
18
|
import { ForwardedRef, forwardRef, MutableRefObject, Ref, RefCallback } from "react";
|
|
19
19
|
|
|
20
20
|
export function prefixWithoutIndices(path: string): string {
|
|
@@ -28,14 +28,17 @@ export function prefixWithoutIndices(path: string): string {
|
|
|
28
28
|
* > but does **NOT** add or remove items to existing arrays.
|
|
29
29
|
* > This can therefore not be used to clear lists.
|
|
30
30
|
*/
|
|
31
|
-
export function setValues<T
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
export function setValues<T extends FieldValues>(
|
|
32
|
+
newValues: DefaultValues<T>,
|
|
33
|
+
setValue: UseFormReturn<T>["setValue"],
|
|
34
|
+
path = ""
|
|
35
|
+
) {
|
|
36
|
+
for (const key of Object.keys(newValues)) {
|
|
37
|
+
const val = newValues[key as keyof typeof newValues];
|
|
38
|
+
const fullPath = path ? `${path}.${key}` : key;
|
|
39
|
+
|
|
40
|
+
if (val !== null && typeof val === "object" && !Array.isArray(val)) {
|
|
41
|
+
setValues(val as DefaultValues<T>, setValue, fullPath);
|
|
39
42
|
} else {
|
|
40
43
|
const fullPath = path ? `${path}.${key}` : key;
|
|
41
44
|
setValue(fullPath as any, val, { shouldValidate: !fullPath.endsWith("Confirmation"), shouldDirty: true });
|
|
@@ -33,6 +33,7 @@ type Props<T extends Record<string, unknown>> = Omit<
|
|
|
33
33
|
confirmationHelpText?: string;
|
|
34
34
|
confirmationErrorMessage?: string;
|
|
35
35
|
confirmationTestId?: string;
|
|
36
|
+
disabled?: boolean;
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
export default function ControlledSecretConfirmationField<T extends Record<string, unknown>>({
|
|
@@ -48,6 +49,7 @@ export default function ControlledSecretConfirmationField<T extends Record<strin
|
|
|
48
49
|
confirmationTestId,
|
|
49
50
|
defaultValue,
|
|
50
51
|
readOnly,
|
|
52
|
+
disabled,
|
|
51
53
|
...props
|
|
52
54
|
}: Props<T>) {
|
|
53
55
|
const { control, watch, t, readOnly: formReadonly, formId } = useScmFormContext();
|
|
@@ -63,7 +65,7 @@ export default function ControlledSecretConfirmationField<T extends Record<strin
|
|
|
63
65
|
confirmationErrorMessage || t(`${prefixedNameWithoutIndices}.confirmation.errorMessage`);
|
|
64
66
|
const secretValue = watch(nameWithPrefix);
|
|
65
67
|
const validateConfirmField = useCallback(
|
|
66
|
-
(value) => secretValue === value || confirmationErrorMessageTranslation,
|
|
68
|
+
(value: any) => secretValue === value || confirmationErrorMessageTranslation,
|
|
67
69
|
[confirmationErrorMessageTranslation, secretValue]
|
|
68
70
|
);
|
|
69
71
|
const confirmFieldRules = useMemo(
|
|
@@ -112,7 +114,7 @@ export default function ControlledSecretConfirmationField<T extends Record<strin
|
|
|
112
114
|
className={classNames("column", className)}
|
|
113
115
|
type="password"
|
|
114
116
|
readOnly={readOnly ?? formReadonly}
|
|
115
|
-
disabled={
|
|
117
|
+
disabled={disabled}
|
|
116
118
|
{...field}
|
|
117
119
|
form={formId}
|
|
118
120
|
label={confirmationLabelTranslation}
|