@navikt/ds-react 4.4.2 → 4.6.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/_docs.json +325 -0
- package/cjs/alert/Alert.js +9 -3
- package/cjs/date/DateInput.js +9 -4
- package/cjs/date/hooks/useDatepicker.js +3 -0
- package/cjs/date/hooks/useMonthPicker.js +3 -0
- package/cjs/date/hooks/useRangeDatepicker.js +3 -0
- package/cjs/form/Fieldset/Fieldset.js +11 -4
- package/cjs/form/ReadOnlyIcon.js +15 -0
- package/cjs/form/Select.js +23 -3
- package/cjs/form/Switch.js +21 -8
- package/cjs/form/TextField.js +7 -3
- package/cjs/form/Textarea.js +7 -3
- package/cjs/form/checkbox/Checkbox.js +7 -2
- package/cjs/form/checkbox/CheckboxGroup.js +1 -1
- package/cjs/form/checkbox/useCheckbox.js +12 -2
- package/cjs/form/radio/Radio.js +3 -2
- package/cjs/form/radio/RadioGroup.js +2 -2
- package/cjs/form/radio/useRadio.js +12 -2
- package/cjs/form/search/Search.js +1 -1
- package/cjs/form/useFormField.js +11 -9
- package/esm/alert/Alert.d.ts +11 -0
- package/esm/alert/Alert.js +10 -4
- package/esm/alert/Alert.js.map +1 -1
- package/esm/date/DateInput.js +9 -4
- package/esm/date/DateInput.js.map +1 -1
- package/esm/date/hooks/useDatepicker.js +3 -0
- package/esm/date/hooks/useDatepicker.js.map +1 -1
- package/esm/date/hooks/useMonthPicker.js +3 -0
- package/esm/date/hooks/useMonthPicker.js.map +1 -1
- package/esm/date/hooks/useRangeDatepicker.js +3 -0
- package/esm/date/hooks/useRangeDatepicker.js.map +1 -1
- package/esm/form/ConfirmationPanel.d.ts +1 -1
- package/esm/form/Fieldset/Fieldset.d.ts +5 -0
- package/esm/form/Fieldset/Fieldset.js +11 -4
- package/esm/form/Fieldset/Fieldset.js.map +1 -1
- package/esm/form/Fieldset/useFieldset.d.ts +2 -1
- package/esm/form/ReadOnlyIcon.d.ts +5 -0
- package/esm/form/ReadOnlyIcon.js +9 -0
- package/esm/form/ReadOnlyIcon.js.map +1 -0
- package/esm/form/Select.js +23 -3
- package/esm/form/Select.js.map +1 -1
- package/esm/form/Switch.d.ts +1 -1
- package/esm/form/Switch.js +21 -8
- package/esm/form/Switch.js.map +1 -1
- package/esm/form/TextField.js +7 -3
- package/esm/form/TextField.js.map +1 -1
- package/esm/form/Textarea.js +7 -3
- package/esm/form/Textarea.js.map +1 -1
- package/esm/form/checkbox/Checkbox.js +7 -2
- package/esm/form/checkbox/Checkbox.js.map +1 -1
- package/esm/form/checkbox/CheckboxGroup.js +1 -1
- package/esm/form/checkbox/CheckboxGroup.js.map +1 -1
- package/esm/form/checkbox/useCheckbox.d.ts +5 -2
- package/esm/form/checkbox/useCheckbox.js +12 -2
- package/esm/form/checkbox/useCheckbox.js.map +1 -1
- package/esm/form/radio/Radio.d.ts +1 -1
- package/esm/form/radio/Radio.js +3 -2
- package/esm/form/radio/Radio.js.map +1 -1
- package/esm/form/radio/RadioGroup.js +2 -2
- package/esm/form/radio/RadioGroup.js.map +1 -1
- package/esm/form/radio/useRadio.d.ts +4 -2
- package/esm/form/radio/useRadio.js +12 -2
- package/esm/form/radio/useRadio.js.map +1 -1
- package/esm/form/search/Search.d.ts +1 -1
- package/esm/form/search/Search.js +1 -1
- package/esm/form/search/Search.js.map +1 -1
- package/esm/form/useFormField.d.ts +7 -2
- package/esm/form/useFormField.js +11 -9
- package/esm/form/useFormField.js.map +1 -1
- package/package.json +2 -2
- package/src/alert/Alert.tsx +49 -18
- package/src/alert/alert.stories.tsx +75 -22
- package/src/date/DateInput.tsx +8 -2
- package/src/date/datepicker/datepicker.stories.tsx +22 -0
- package/src/date/hooks/useDatepicker.tsx +3 -0
- package/src/date/hooks/useMonthPicker.tsx +3 -0
- package/src/date/hooks/useRangeDatepicker.tsx +3 -0
- package/src/form/ConfirmationPanel.tsx +1 -1
- package/src/form/Fieldset/Fieldset.tsx +15 -2
- package/src/form/ReadOnlyIcon.tsx +20 -0
- package/src/form/Select.tsx +28 -2
- package/src/form/Switch.tsx +20 -9
- package/src/form/TextField.tsx +5 -0
- package/src/form/Textarea.tsx +5 -0
- package/src/form/checkbox/Checkbox.tsx +7 -1
- package/src/form/checkbox/CheckboxGroup.tsx +1 -0
- package/src/form/checkbox/checkbox.stories.tsx +35 -1
- package/src/form/checkbox/useCheckbox.ts +13 -1
- package/src/form/radio/Radio.tsx +4 -3
- package/src/form/radio/RadioGroup.tsx +3 -0
- package/src/form/radio/radio.stories.tsx +27 -0
- package/src/form/radio/useRadio.ts +12 -1
- package/src/form/search/Search.tsx +2 -2
- package/src/form/stories/select.stories.tsx +17 -0
- package/src/form/stories/switch.stories.tsx +14 -0
- package/src/form/stories/text-field.stories.tsx +14 -0
- package/src/form/stories/textarea.stories.tsx +19 -0
- package/src/form/useFormField.ts +25 -3
|
@@ -3,6 +3,7 @@ import React, { FieldsetHTMLAttributes, forwardRef, useContext } from "react";
|
|
|
3
3
|
import { BodyShort, ErrorMessage, Label, omit } from "../..";
|
|
4
4
|
import { FormFieldProps } from "../useFormField";
|
|
5
5
|
import { useFieldset } from "./useFieldset";
|
|
6
|
+
import { ReadOnlyIcon } from "../ReadOnlyIcon";
|
|
6
7
|
|
|
7
8
|
export type FieldsetContextProps = {
|
|
8
9
|
/**
|
|
@@ -21,6 +22,10 @@ export type FieldsetContextProps = {
|
|
|
21
22
|
* Sets fieldset and all form-children to disabled
|
|
22
23
|
*/
|
|
23
24
|
disabled: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Read only-state
|
|
27
|
+
*/
|
|
28
|
+
readOnly?: boolean;
|
|
24
29
|
};
|
|
25
30
|
|
|
26
31
|
export const FieldsetContext = React.createContext<FieldsetContextProps | null>(
|
|
@@ -47,6 +52,7 @@ export interface FieldsetProps
|
|
|
47
52
|
* @default true
|
|
48
53
|
*/
|
|
49
54
|
errorPropagation?: boolean;
|
|
55
|
+
nativeReadOnly?: boolean;
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
export const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
|
@@ -57,6 +63,7 @@ export const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
|
|
57
63
|
showErrorMsg,
|
|
58
64
|
hasError,
|
|
59
65
|
size,
|
|
66
|
+
readOnly,
|
|
60
67
|
inputDescriptionId,
|
|
61
68
|
} = useFieldset(props);
|
|
62
69
|
|
|
@@ -69,6 +76,7 @@ export const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
|
|
69
76
|
legend,
|
|
70
77
|
description,
|
|
71
78
|
hideLegend,
|
|
79
|
+
nativeReadOnly = true,
|
|
72
80
|
...rest
|
|
73
81
|
} = props;
|
|
74
82
|
|
|
@@ -82,17 +90,21 @@ export const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
|
|
82
90
|
}),
|
|
83
91
|
size,
|
|
84
92
|
disabled: props.disabled ?? false,
|
|
93
|
+
readOnly,
|
|
85
94
|
}}
|
|
86
95
|
>
|
|
87
96
|
<fieldset
|
|
88
|
-
{...omit(rest, ["errorId", "error", "size"])}
|
|
97
|
+
{...omit(rest, ["errorId", "error", "size", "readOnly"])}
|
|
89
98
|
{...inputProps}
|
|
90
99
|
ref={ref}
|
|
91
100
|
className={cl(
|
|
92
101
|
className,
|
|
93
102
|
"navds-fieldset",
|
|
94
103
|
`navds-fieldset--${size}`,
|
|
95
|
-
{
|
|
104
|
+
{
|
|
105
|
+
"navds-fieldset--error": hasError,
|
|
106
|
+
"navds-fieldset--readonly": readOnly,
|
|
107
|
+
}
|
|
96
108
|
)}
|
|
97
109
|
>
|
|
98
110
|
<Label
|
|
@@ -102,6 +114,7 @@ export const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
|
|
102
114
|
"navds-sr-only": !!hideLegend,
|
|
103
115
|
})}
|
|
104
116
|
>
|
|
117
|
+
<ReadOnlyIcon readOnly={readOnly} nativeReadOnly={nativeReadOnly} />
|
|
105
118
|
{legend}
|
|
106
119
|
</Label>
|
|
107
120
|
{!!description && (
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PadlockLockedFillIcon } from "@navikt/aksel-icons";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
export const ReadOnlyIcon = ({
|
|
5
|
+
readOnly,
|
|
6
|
+
nativeReadOnly = true,
|
|
7
|
+
}: {
|
|
8
|
+
readOnly?: boolean;
|
|
9
|
+
nativeReadOnly?: boolean;
|
|
10
|
+
}) => {
|
|
11
|
+
if (readOnly) {
|
|
12
|
+
return (
|
|
13
|
+
<PadlockLockedFillIcon
|
|
14
|
+
{...(nativeReadOnly ? { "aria-hidden": true } : { title: "readonly" })}
|
|
15
|
+
className="navds-form-field__readonly-icon"
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
};
|
package/src/form/Select.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import React, { forwardRef, SelectHTMLAttributes } from "react";
|
|
|
4
4
|
import { ChevronDownIcon } from "@navikt/aksel-icons";
|
|
5
5
|
import { BodyShort, ErrorMessage, Label, omit } from "..";
|
|
6
6
|
import { FormFieldProps, useFormField } from "./useFormField";
|
|
7
|
+
import { ReadOnlyIcon } from "./ReadOnlyIcon";
|
|
7
8
|
|
|
8
9
|
export interface SelectProps
|
|
9
10
|
extends FormFieldProps,
|
|
@@ -55,7 +56,8 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
|
|
55
56
|
hasError,
|
|
56
57
|
size,
|
|
57
58
|
inputDescriptionId,
|
|
58
|
-
|
|
59
|
+
readOnly,
|
|
60
|
+
} = useFormField(props, "select");
|
|
59
61
|
|
|
60
62
|
const {
|
|
61
63
|
children,
|
|
@@ -68,6 +70,27 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
|
|
68
70
|
...rest
|
|
69
71
|
} = props;
|
|
70
72
|
|
|
73
|
+
const readOnlyEventHandlers = {
|
|
74
|
+
onMouseDown: (evt) => {
|
|
75
|
+
// NOTE: does not prevent click
|
|
76
|
+
if (readOnly) {
|
|
77
|
+
evt.preventDefault();
|
|
78
|
+
// focus on the element as per readonly input behavior
|
|
79
|
+
evt.target.focus();
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
onKeyDown: (evt) => {
|
|
83
|
+
if (
|
|
84
|
+
readOnly &&
|
|
85
|
+
["ArrowDown", "ArrowUp", "ArrowRight", "ArrowLeft", " "].includes(
|
|
86
|
+
evt.key
|
|
87
|
+
)
|
|
88
|
+
) {
|
|
89
|
+
evt.preventDefault();
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
71
94
|
return (
|
|
72
95
|
<div
|
|
73
96
|
className={cl(
|
|
@@ -77,6 +100,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
|
|
77
100
|
{
|
|
78
101
|
"navds-form-field--disabled": !!inputProps.disabled,
|
|
79
102
|
"navds-select--error": hasError,
|
|
103
|
+
"navds-select--readonly": readOnly,
|
|
80
104
|
}
|
|
81
105
|
)}
|
|
82
106
|
>
|
|
@@ -87,6 +111,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
|
|
87
111
|
"navds-sr-only": hideLabel,
|
|
88
112
|
})}
|
|
89
113
|
>
|
|
114
|
+
<ReadOnlyIcon readOnly={readOnly} nativeReadOnly={false} />
|
|
90
115
|
{label}
|
|
91
116
|
</Label>
|
|
92
117
|
{!!description && (
|
|
@@ -103,8 +128,9 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
|
|
103
128
|
)}
|
|
104
129
|
<div className="navds-select__container" style={style}>
|
|
105
130
|
<select
|
|
106
|
-
{...omit(rest, ["error", "errorId", "size"])}
|
|
131
|
+
{...omit(rest, ["error", "errorId", "size", "readOnly"])}
|
|
107
132
|
{...inputProps}
|
|
133
|
+
{...readOnlyEventHandlers}
|
|
108
134
|
ref={ref}
|
|
109
135
|
className={cl(
|
|
110
136
|
"navds-select__input",
|
package/src/form/Switch.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import React, {
|
|
|
7
7
|
} from "react";
|
|
8
8
|
import { BodyShort, Loader, omit } from "..";
|
|
9
9
|
import { FormFieldProps, useFormField } from "./useFormField";
|
|
10
|
+
import { ReadOnlyIcon } from "./ReadOnlyIcon";
|
|
10
11
|
|
|
11
12
|
const SelectedIcon = () => (
|
|
12
13
|
<svg
|
|
@@ -63,12 +64,12 @@ export interface SwitchProps
|
|
|
63
64
|
*
|
|
64
65
|
* @example
|
|
65
66
|
* ```jsx
|
|
66
|
-
* <Switch>
|
|
67
|
+
* <Switch>Varsle med SMS</Switch>
|
|
67
68
|
* ```
|
|
68
69
|
*/
|
|
69
70
|
export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
|
|
70
71
|
(props, ref) => {
|
|
71
|
-
const { inputProps, size } = useFormField(props, "switch");
|
|
72
|
+
const { inputProps, size, readOnly } = useFormField(props, "switch");
|
|
72
73
|
|
|
73
74
|
const {
|
|
74
75
|
children,
|
|
@@ -90,11 +91,6 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
|
|
|
90
91
|
checkedProp !== undefined && setChecked(checkedProp);
|
|
91
92
|
}, [checkedProp]);
|
|
92
93
|
|
|
93
|
-
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
94
|
-
setChecked(e.target.checked);
|
|
95
|
-
props.onChange && props.onChange(e);
|
|
96
|
-
};
|
|
97
|
-
|
|
98
94
|
return (
|
|
99
95
|
<div
|
|
100
96
|
className={cl(
|
|
@@ -105,18 +101,32 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
|
|
|
105
101
|
{
|
|
106
102
|
"navds-switch--loading": loading,
|
|
107
103
|
"navds-switch--disabled": inputProps.disabled ?? loading,
|
|
104
|
+
"navds-switch--readonly": readOnly,
|
|
108
105
|
}
|
|
109
106
|
)}
|
|
110
107
|
>
|
|
111
108
|
<input
|
|
112
|
-
{...omit(rest, ["size"])}
|
|
109
|
+
{...omit(rest, ["size", "readOnly"])}
|
|
113
110
|
{...omit(inputProps, ["aria-invalid", "aria-describedby"])}
|
|
114
111
|
disabled={inputProps.disabled ?? loading}
|
|
115
112
|
checked={checkedProp}
|
|
116
113
|
defaultChecked={defaultChecked}
|
|
117
114
|
ref={ref}
|
|
118
115
|
type="checkbox"
|
|
119
|
-
onChange={(e) =>
|
|
116
|
+
onChange={(e) => {
|
|
117
|
+
if (readOnly) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
setChecked(e.target.checked);
|
|
121
|
+
props.onChange && props.onChange(e);
|
|
122
|
+
}}
|
|
123
|
+
onClick={(e) => {
|
|
124
|
+
if (readOnly) {
|
|
125
|
+
e.preventDefault();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
props?.onClick?.(e);
|
|
129
|
+
}}
|
|
120
130
|
className={cl(className, "navds-switch__input")}
|
|
121
131
|
/>
|
|
122
132
|
<span className="navds-switch__track">
|
|
@@ -136,6 +146,7 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
|
|
|
136
146
|
})}
|
|
137
147
|
>
|
|
138
148
|
<BodyShort as="div" size={size} className="navds-switch__label">
|
|
149
|
+
<ReadOnlyIcon readOnly={readOnly} nativeReadOnly={false} />
|
|
139
150
|
{children}
|
|
140
151
|
</BodyShort>
|
|
141
152
|
{description && (
|
package/src/form/TextField.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import cl from "clsx";
|
|
2
2
|
import React, { forwardRef, InputHTMLAttributes } from "react";
|
|
3
3
|
import { BodyShort, ErrorMessage, Label, omit } from "..";
|
|
4
|
+
import { ReadOnlyIcon } from "./ReadOnlyIcon";
|
|
4
5
|
import { FormFieldProps, useFormField } from "./useFormField";
|
|
5
6
|
|
|
6
7
|
export interface TextFieldProps
|
|
@@ -62,6 +63,7 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
62
63
|
htmlSize,
|
|
63
64
|
hideLabel = false,
|
|
64
65
|
type = "text",
|
|
66
|
+
readOnly,
|
|
65
67
|
...rest
|
|
66
68
|
} = props;
|
|
67
69
|
|
|
@@ -75,6 +77,7 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
75
77
|
"navds-text-field--error": hasError,
|
|
76
78
|
"navds-text-field--disabled": !!inputProps.disabled,
|
|
77
79
|
"navds-form-field--disabled": !!inputProps.disabled,
|
|
80
|
+
"navds-text-field--readonly": readOnly,
|
|
78
81
|
}
|
|
79
82
|
)}
|
|
80
83
|
>
|
|
@@ -85,6 +88,7 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
85
88
|
"navds-sr-only": hideLabel,
|
|
86
89
|
})}
|
|
87
90
|
>
|
|
91
|
+
<ReadOnlyIcon readOnly={readOnly} />
|
|
88
92
|
{label}
|
|
89
93
|
</Label>
|
|
90
94
|
|
|
@@ -105,6 +109,7 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
|
|
105
109
|
{...inputProps}
|
|
106
110
|
ref={ref}
|
|
107
111
|
type={type}
|
|
112
|
+
readOnly={readOnly}
|
|
108
113
|
className={cl(
|
|
109
114
|
"navds-text-field__input",
|
|
110
115
|
"navds-body-short",
|
package/src/form/Textarea.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import React, { forwardRef, useState } from "react";
|
|
|
3
3
|
import { BodyShort, ErrorMessage, Label, omit, useId } from "..";
|
|
4
4
|
import TextareaAutosize from "../util/TextareaAutoSize";
|
|
5
5
|
import { FormFieldProps, useFormField } from "./useFormField";
|
|
6
|
+
import { ReadOnlyIcon } from "./ReadOnlyIcon";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* TODO: Mulighet for lokalisering av sr-only/counter text
|
|
@@ -85,6 +86,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
85
86
|
hideLabel = false,
|
|
86
87
|
resize,
|
|
87
88
|
i18n,
|
|
89
|
+
readOnly,
|
|
88
90
|
...rest
|
|
89
91
|
} = props;
|
|
90
92
|
|
|
@@ -115,6 +117,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
115
117
|
`navds-form-field--${size}`,
|
|
116
118
|
{
|
|
117
119
|
"navds-form-field--disabled": !!inputProps.disabled,
|
|
120
|
+
"navds-textarea--readonly": readOnly,
|
|
118
121
|
"navds-textarea--error": hasError,
|
|
119
122
|
"navds-textarea--resize": resize,
|
|
120
123
|
}
|
|
@@ -127,6 +130,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
127
130
|
"navds-sr-only": hideLabel,
|
|
128
131
|
})}
|
|
129
132
|
>
|
|
133
|
+
<ReadOnlyIcon readOnly={readOnly} />
|
|
130
134
|
{label}
|
|
131
135
|
</Label>
|
|
132
136
|
{!!description && (
|
|
@@ -152,6 +156,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
152
156
|
}
|
|
153
157
|
minRows={getMinRows()}
|
|
154
158
|
ref={ref}
|
|
159
|
+
readOnly={readOnly}
|
|
155
160
|
className={cl(
|
|
156
161
|
"navds-textarea__input",
|
|
157
162
|
"navds-body-short",
|
|
@@ -4,6 +4,7 @@ import { BodyShort } from "../../typography";
|
|
|
4
4
|
import { omit } from "../../util";
|
|
5
5
|
import { FormFieldProps } from "../useFormField";
|
|
6
6
|
import useCheckbox from "./useCheckbox";
|
|
7
|
+
import { ReadOnlyIcon } from "../ReadOnlyIcon";
|
|
7
8
|
|
|
8
9
|
export interface CheckboxProps
|
|
9
10
|
extends FormFieldProps,
|
|
@@ -42,7 +43,7 @@ export interface CheckboxProps
|
|
|
42
43
|
|
|
43
44
|
export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
44
45
|
(props, ref) => {
|
|
45
|
-
const { inputProps, hasError, size } = useCheckbox(props);
|
|
46
|
+
const { inputProps, hasError, size, readOnly, nested } = useCheckbox(props);
|
|
46
47
|
|
|
47
48
|
return (
|
|
48
49
|
<div
|
|
@@ -53,6 +54,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
53
54
|
{
|
|
54
55
|
"navds-checkbox--error": hasError,
|
|
55
56
|
"navds-checkbox--disabled": inputProps.disabled,
|
|
57
|
+
"navds-checkbox--readonly": readOnly,
|
|
56
58
|
}
|
|
57
59
|
)}
|
|
58
60
|
>
|
|
@@ -65,6 +67,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
65
67
|
"hideLabel",
|
|
66
68
|
"indeterminate",
|
|
67
69
|
"errorId",
|
|
70
|
+
"readOnly",
|
|
68
71
|
])}
|
|
69
72
|
{...inputProps}
|
|
70
73
|
type="checkbox"
|
|
@@ -89,6 +92,9 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|
|
89
92
|
})}
|
|
90
93
|
>
|
|
91
94
|
<BodyShort as="span" size={size}>
|
|
95
|
+
{!nested && (
|
|
96
|
+
<ReadOnlyIcon readOnly={readOnly} nativeReadOnly={false} />
|
|
97
|
+
)}
|
|
92
98
|
{props.children}
|
|
93
99
|
</BodyShort>
|
|
94
100
|
{props.description && (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
|
+
import { Meta } from "@storybook/react";
|
|
2
3
|
import React, { useState } from "react";
|
|
3
4
|
import { Checkbox, CheckboxGroup } from "../../index";
|
|
4
|
-
import { Meta } from "@storybook/react";
|
|
5
5
|
|
|
6
6
|
export default {
|
|
7
7
|
title: "ds-react/Checkbox",
|
|
@@ -190,3 +190,37 @@ export const Indeterminate = () => {
|
|
|
190
190
|
</>
|
|
191
191
|
);
|
|
192
192
|
};
|
|
193
|
+
|
|
194
|
+
export const Readonly = () => (
|
|
195
|
+
<div className="colgap">
|
|
196
|
+
<CheckboxGroup
|
|
197
|
+
legend="Hvilken frukt liker du?"
|
|
198
|
+
defaultValue={["banan"]}
|
|
199
|
+
readOnly
|
|
200
|
+
>
|
|
201
|
+
<Checkbox value="banan">Banan</Checkbox>
|
|
202
|
+
<Checkbox value="eple">Eple</Checkbox>
|
|
203
|
+
<Checkbox value="druer" indeterminate>
|
|
204
|
+
Druer
|
|
205
|
+
</Checkbox>
|
|
206
|
+
</CheckboxGroup>
|
|
207
|
+
<CheckboxGroup
|
|
208
|
+
legend="Hvilken frukt liker du?"
|
|
209
|
+
error="feilmelding"
|
|
210
|
+
defaultValue={["Eple"]}
|
|
211
|
+
readOnly
|
|
212
|
+
>
|
|
213
|
+
<Checkbox value="eple" description="Epler kommer i 4 varianter">
|
|
214
|
+
Eple
|
|
215
|
+
</Checkbox>
|
|
216
|
+
<Checkbox value="banan">Banan</Checkbox>
|
|
217
|
+
</CheckboxGroup>
|
|
218
|
+
<hr />
|
|
219
|
+
<Checkbox value="tekst1" readOnly>
|
|
220
|
+
Eple single
|
|
221
|
+
</Checkbox>
|
|
222
|
+
<Checkbox value="tekst1" checked readOnly>
|
|
223
|
+
Banan single
|
|
224
|
+
</Checkbox>
|
|
225
|
+
</div>
|
|
226
|
+
);
|
|
@@ -10,7 +10,7 @@ import { omit } from "../..";
|
|
|
10
10
|
const useCheckbox = ({ children, ...props }: CheckboxProps) => {
|
|
11
11
|
const checkboxGroup = useContext(CheckboxGroupContext);
|
|
12
12
|
|
|
13
|
-
const { inputProps, ...rest } = useFormField(
|
|
13
|
+
const { inputProps, readOnly, ...rest } = useFormField(
|
|
14
14
|
omit(props, ["description"]),
|
|
15
15
|
"checkbox"
|
|
16
16
|
);
|
|
@@ -30,6 +30,8 @@ const useCheckbox = ({ children, ...props }: CheckboxProps) => {
|
|
|
30
30
|
|
|
31
31
|
return {
|
|
32
32
|
...rest,
|
|
33
|
+
readOnly,
|
|
34
|
+
nested: !!checkboxGroup,
|
|
33
35
|
inputProps: {
|
|
34
36
|
...inputProps,
|
|
35
37
|
checked: checkboxGroup?.value
|
|
@@ -39,9 +41,19 @@ const useCheckbox = ({ children, ...props }: CheckboxProps) => {
|
|
|
39
41
|
? checkboxGroup.defaultValue.includes(props.value)
|
|
40
42
|
: props.defaultChecked,
|
|
41
43
|
onChange: (e) => {
|
|
44
|
+
if (readOnly) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
42
47
|
props.onChange && props.onChange(e);
|
|
43
48
|
checkboxGroup && checkboxGroup.toggleValue(props.value);
|
|
44
49
|
},
|
|
50
|
+
onClick: (e) => {
|
|
51
|
+
if (readOnly) {
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
props?.onClick?.(e);
|
|
56
|
+
},
|
|
45
57
|
},
|
|
46
58
|
};
|
|
47
59
|
};
|
package/src/form/radio/Radio.tsx
CHANGED
|
@@ -6,7 +6,7 @@ import { FormFieldProps } from "../useFormField";
|
|
|
6
6
|
import { useRadio } from "./useRadio";
|
|
7
7
|
|
|
8
8
|
export interface RadioProps
|
|
9
|
-
extends Omit<FormFieldProps, "error" | "errorId">,
|
|
9
|
+
extends Omit<FormFieldProps, "error" | "errorId" | "readOnly">,
|
|
10
10
|
Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "value"> {
|
|
11
11
|
/**
|
|
12
12
|
* Radio label
|
|
@@ -23,17 +23,18 @@ export interface RadioProps
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export const Radio = forwardRef<HTMLInputElement, RadioProps>((props, ref) => {
|
|
26
|
-
const { inputProps, size, hasError } = useRadio(props);
|
|
26
|
+
const { inputProps, size, hasError, readOnly } = useRadio(props);
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
29
|
<div
|
|
30
30
|
className={cl(props.className, "navds-radio", `navds-radio--${size}`, {
|
|
31
31
|
"navds-radio--error": hasError,
|
|
32
32
|
"navds-radio--disabled": inputProps.disabled,
|
|
33
|
+
"navds-radio--readonly": readOnly,
|
|
33
34
|
})}
|
|
34
35
|
>
|
|
35
36
|
<input
|
|
36
|
-
{...omit(props, ["children", "size", "description"])}
|
|
37
|
+
{...omit(props, ["children", "size", "description", "readOnly"])}
|
|
37
38
|
{...inputProps}
|
|
38
39
|
className="navds-radio__input"
|
|
39
40
|
ref={ref}
|
|
@@ -65,6 +65,7 @@ export const RadioGroup = forwardRef<HTMLFieldSetElement, RadioGroupProps>(
|
|
|
65
65
|
value,
|
|
66
66
|
onChange = () => {},
|
|
67
67
|
required,
|
|
68
|
+
readOnly,
|
|
68
69
|
...rest
|
|
69
70
|
},
|
|
70
71
|
ref
|
|
@@ -76,12 +77,14 @@ export const RadioGroup = forwardRef<HTMLFieldSetElement, RadioGroupProps>(
|
|
|
76
77
|
return (
|
|
77
78
|
<Fieldset
|
|
78
79
|
{...rest}
|
|
80
|
+
readOnly={readOnly}
|
|
79
81
|
ref={ref}
|
|
80
82
|
className={cl(
|
|
81
83
|
className,
|
|
82
84
|
"navds-radio-group",
|
|
83
85
|
`navds-radio-group--${rest.size ?? fieldset?.size ?? "medium"}`
|
|
84
86
|
)}
|
|
87
|
+
nativeReadOnly={false}
|
|
85
88
|
>
|
|
86
89
|
<RadioGroupContext.Provider
|
|
87
90
|
value={{
|
|
@@ -92,3 +92,30 @@ export const GroupDescription = () => (
|
|
|
92
92
|
<Radio value="tekst2">Radiotekst</Radio>
|
|
93
93
|
</RadioGroup>
|
|
94
94
|
);
|
|
95
|
+
|
|
96
|
+
export const UUDemo = () => (
|
|
97
|
+
<div className="colgap">
|
|
98
|
+
<RadioGroup
|
|
99
|
+
legend="Hvilken frukt vil du ha?"
|
|
100
|
+
description="Du kan bare velge en frukt"
|
|
101
|
+
defaultValue="eple"
|
|
102
|
+
readOnly
|
|
103
|
+
>
|
|
104
|
+
<Radio value="eple">Eple</Radio>
|
|
105
|
+
<Radio value="banan" description="Bananer er importert fra X">
|
|
106
|
+
Banan
|
|
107
|
+
</Radio>
|
|
108
|
+
<Radio value="druer">Druer</Radio>
|
|
109
|
+
</RadioGroup>
|
|
110
|
+
<RadioGroup
|
|
111
|
+
legend="Når har du ferie?"
|
|
112
|
+
defaultValue="1"
|
|
113
|
+
readOnly
|
|
114
|
+
error="du må velge en ferie"
|
|
115
|
+
>
|
|
116
|
+
<Radio value="1">August</Radio>
|
|
117
|
+
<Radio value="2">Juli</Radio>
|
|
118
|
+
<Radio value="3">Juni</Radio>
|
|
119
|
+
</RadioGroup>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
@@ -10,7 +10,7 @@ import { omit } from "../..";
|
|
|
10
10
|
export const useRadio = (props: RadioProps) => {
|
|
11
11
|
const radioGroup = useContext(RadioGroupContext);
|
|
12
12
|
|
|
13
|
-
const { inputProps, ...rest } = useFormField(
|
|
13
|
+
const { inputProps, readOnly, ...rest } = useFormField(
|
|
14
14
|
omit(props, ["description"]),
|
|
15
15
|
"radio"
|
|
16
16
|
);
|
|
@@ -25,6 +25,7 @@ export const useRadio = (props: RadioProps) => {
|
|
|
25
25
|
|
|
26
26
|
return {
|
|
27
27
|
...rest,
|
|
28
|
+
readOnly,
|
|
28
29
|
inputProps: {
|
|
29
30
|
...inputProps,
|
|
30
31
|
name: radioGroup?.name,
|
|
@@ -37,9 +38,19 @@ export const useRadio = (props: RadioProps) => {
|
|
|
37
38
|
? undefined
|
|
38
39
|
: radioGroup?.value === props.value,
|
|
39
40
|
onChange: (e) => {
|
|
41
|
+
if (readOnly) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
40
44
|
props.onChange && props.onChange(e);
|
|
41
45
|
radioGroup?.onChange && radioGroup.onChange(props.value);
|
|
42
46
|
},
|
|
47
|
+
onClick: (e) => {
|
|
48
|
+
if (readOnly) {
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
props?.onClick?.(e);
|
|
53
|
+
},
|
|
43
54
|
required: radioGroup?.required,
|
|
44
55
|
type: "radio",
|
|
45
56
|
},
|
|
@@ -27,7 +27,7 @@ export type SearchClearEvent =
|
|
|
27
27
|
| { trigger: "Escape"; event: React.KeyboardEvent<HTMLDivElement> };
|
|
28
28
|
|
|
29
29
|
export interface SearchProps
|
|
30
|
-
extends FormFieldProps,
|
|
30
|
+
extends Omit<FormFieldProps, "readOnly">,
|
|
31
31
|
Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "onChange"> {
|
|
32
32
|
children?: React.ReactNode;
|
|
33
33
|
/**
|
|
@@ -221,7 +221,7 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
|
|
|
221
221
|
)}
|
|
222
222
|
<input
|
|
223
223
|
ref={mergedRef}
|
|
224
|
-
{...omit(rest, ["error", "errorId", "size"])}
|
|
224
|
+
{...omit(rest, ["error", "errorId", "size", "readOnly"])}
|
|
225
225
|
{...inputProps}
|
|
226
226
|
value={value ?? internalValue}
|
|
227
227
|
onChange={(e) => handleChange(e.target.value)}
|
|
@@ -114,3 +114,20 @@ export const HideLabel = () => {
|
|
|
114
114
|
</Select>
|
|
115
115
|
);
|
|
116
116
|
};
|
|
117
|
+
|
|
118
|
+
export const Readonly = () => {
|
|
119
|
+
return (
|
|
120
|
+
<div className="colgap">
|
|
121
|
+
<Select
|
|
122
|
+
label="Hvilkets land er du fra?"
|
|
123
|
+
description="Velg landet du bor 180 dagen i året"
|
|
124
|
+
readOnly
|
|
125
|
+
>
|
|
126
|
+
{content}
|
|
127
|
+
</Select>
|
|
128
|
+
<Select label="Hvilkets land er du fra?" readOnly error="feilmelding">
|
|
129
|
+
{content}
|
|
130
|
+
</Select>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
};
|
|
@@ -116,3 +116,17 @@ export const HideLabel = () => {
|
|
|
116
116
|
</div>
|
|
117
117
|
);
|
|
118
118
|
};
|
|
119
|
+
|
|
120
|
+
export const Readonly = () => {
|
|
121
|
+
return (
|
|
122
|
+
<div className="colgap">
|
|
123
|
+
<Switch description="Slår av alle notifikasjoner" readOnly>
|
|
124
|
+
Notifikasjoner
|
|
125
|
+
</Switch>
|
|
126
|
+
|
|
127
|
+
<Switch checked readOnly>
|
|
128
|
+
Notifikasjoner
|
|
129
|
+
</Switch>
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
@@ -83,3 +83,17 @@ export const Disabled = () => {
|
|
|
83
83
|
export const HideLabel = () => {
|
|
84
84
|
return <TextField label="Ipsum enim quis culpa" hideLabel />;
|
|
85
85
|
};
|
|
86
|
+
|
|
87
|
+
export const Readonly = () => {
|
|
88
|
+
return (
|
|
89
|
+
<div className="colgap">
|
|
90
|
+
<TextField
|
|
91
|
+
label="Bosted"
|
|
92
|
+
description="Skriv bosted i Norge"
|
|
93
|
+
readOnly
|
|
94
|
+
value="Oslo"
|
|
95
|
+
/>
|
|
96
|
+
<TextField label="Bosted" readOnly error="feilmelding" value="Oslo" />
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
};
|
|
@@ -120,3 +120,22 @@ export const MaxRows = () => {
|
|
|
120
120
|
export const Resize = () => {
|
|
121
121
|
return <Textarea resize label="Ipsum enim quis culpa" />;
|
|
122
122
|
};
|
|
123
|
+
|
|
124
|
+
export const Readonly = () => {
|
|
125
|
+
return (
|
|
126
|
+
<div className="colgap">
|
|
127
|
+
<Textarea
|
|
128
|
+
label="På hvilket grunnlag har du tatt denne vurderingen?"
|
|
129
|
+
description="Beskriv i korte punkter"
|
|
130
|
+
value="Denne vurderingen ble gjort på grunnlag av X og Y"
|
|
131
|
+
readOnly
|
|
132
|
+
/>
|
|
133
|
+
<Textarea
|
|
134
|
+
label="På hvilket grunnlag har du tatt denne vurderingen?"
|
|
135
|
+
readOnly
|
|
136
|
+
value="Denne vurderingen ble gjort på grunnlag av X og Y"
|
|
137
|
+
error="feilmelding"
|
|
138
|
+
/>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
};
|