@inera/ids-react 9.2.1 → 9.3.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/components/accordion/accordion-base.d.ts +2 -1
- package/components/accordion/accordion-base.js +3 -4
- package/components/accordion/accordion.js +5 -2
- package/components/alert/alert-base.js +2 -2
- package/components/breadcrumbs/breadcrumbs.js +6 -1
- package/components/button/button.d.ts +1 -0
- package/components/button/button.js +2 -2
- package/components/button/control-button.d.ts +6 -0
- package/components/button/control-button.js +9 -0
- package/components/carousel/carousel.js +1 -1
- package/components/dialog/dialog-base.js +1 -1
- package/components/form/checkbox/checkbox-base.js +2 -3
- package/components/form/checkbox/checkbox-group-base.d.ts +2 -1
- package/components/form/checkbox/checkbox-group-base.js +3 -3
- package/components/form/checkbox/checkbox-group.d.ts +2 -1
- package/components/form/checkbox/checkbox-group.js +2 -2
- package/components/form/checkbox/checkbox.js +3 -4
- package/components/form/datepicker/datepicker.d.ts +3 -1
- package/components/form/datepicker/datepicker.js +142 -110
- package/components/form/form-hooks/useInputValidity.d.ts +1 -1
- package/components/form/form-hooks/useInputValidity.js +28 -12
- package/components/form/form-props/form-props.d.ts +1 -0
- package/components/form/input/input-base.d.ts +4 -2
- package/components/form/input/input-base.js +14 -9
- package/components/form/input/input.d.ts +3 -0
- package/components/form/input/input.js +1 -1
- package/components/form/radio/radio-base.js +1 -2
- package/components/form/radio/radio-group-base.d.ts +2 -1
- package/components/form/radio/radio-group-base.js +3 -3
- package/components/form/radio/radio-group.d.ts +2 -1
- package/components/form/radio/radio-group.js +2 -2
- package/components/form/range/range-base.d.ts +1 -1
- package/components/form/range/range-base.js +2 -2
- package/components/form/select/select-base.d.ts +3 -3
- package/components/form/select/select-base.js +3 -5
- package/components/form/select/select.d.ts +2 -2
- package/components/form/select/select.js +1 -1
- package/components/form/select-multiple/select-multiple-base.d.ts +1 -1
- package/components/form/select-multiple/select-multiple-base.js +2 -2
- package/components/form/textarea/textarea-base.d.ts +1 -1
- package/components/form/textarea/textarea-base.js +3 -5
- package/components/form/textarea/textarea.js +1 -1
- package/components/form/time/time-base.d.ts +1 -1
- package/components/form/time/time-base.js +2 -4
- package/components/form/time/time.js +4 -5
- package/components/header-1177/header-1177-region-picker-base.d.ts +3 -1
- package/components/header-1177/header-1177-region-picker-base.js +8 -3
- package/components/header-1177/header-1177-region-picker-mobile-base.d.ts +3 -1
- package/components/header-1177/header-1177-region-picker-mobile-base.js +8 -3
- package/components/header-1177/header-1177-region-picker-mobile.d.ts +2 -0
- package/components/header-1177/header-1177-region-picker.d.ts +2 -0
- package/components/header-1177-pro/header-1177-pro-region-picker-base.d.ts +3 -1
- package/components/header-1177-pro/header-1177-pro-region-picker-base.js +8 -3
- package/components/header-1177-pro/header-1177-pro-region-picker-mobile-base.d.ts +3 -1
- package/components/header-1177-pro/header-1177-pro-region-picker-mobile-base.js +8 -3
- package/components/header-1177-pro/header-1177-pro-region-picker-mobile.d.ts +3 -1
- package/components/header-1177-pro/header-1177-pro-region-picker-mobile.js +1 -1
- package/components/header-1177-pro/header-1177-pro-region-picker.d.ts +3 -1
- package/components/header-1177-pro/header-1177-pro-region-picker.js +1 -1
- package/components/popover/popover-content.js +1 -1
- package/components/popover/popover.d.ts +2 -1
- package/components/popover/popover.js +28 -14
- package/components/puff-list/puff-list-item-header.d.ts +1 -1
- package/components/puff-list/puff-list-item.d.ts +2 -1
- package/components/puff-list/puff-list-item.js +2 -2
- package/components/side-panel/side-panel-base.d.ts +1 -0
- package/components/side-panel/side-panel-base.js +4 -2
- package/components/side-panel/side-panel.d.ts +2 -1
- package/components/side-panel/side-panel.js +2 -2
- package/components/stepper/step-base.d.ts +1 -1
- package/components/stepper/step-base.js +1 -1
- package/components/stepper/step.d.ts +1 -1
- package/components/stepper/step.js +2 -11
- package/components/tag/tag.js +8 -2
- package/components/tooltip/tooltip-base.d.ts +1 -3
- package/components/tooltip/tooltip-base.js +14 -10
- package/components/tooltip/tooltip.js +1 -41
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +4 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useId, useRef, useState, useEffect } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { getWeek, isValid, format, subMonths, addMonths } from 'date-fns';
|
|
4
4
|
import { sv } from 'react-day-picker/locale';
|
|
5
5
|
import clsx from 'clsx';
|
|
6
6
|
import { IDSErrorMessage } from '../error-message/error-message.js';
|
|
@@ -10,6 +10,8 @@ import { useAriaDescribedBy } from '../form-hooks/useAriaDescribedBy.js';
|
|
|
10
10
|
import { useClickOutside } from '../../utils/hooks/useClickOutside.js';
|
|
11
11
|
|
|
12
12
|
const locale = { locale: sv };
|
|
13
|
+
const datePattern = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
|
|
14
|
+
const datePatternString = "\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])";
|
|
13
15
|
const createNewDate = (dateString) => {
|
|
14
16
|
return new Date(dateString + "T00:00:00Z");
|
|
15
17
|
};
|
|
@@ -25,7 +27,17 @@ const getPrevMonthYear = (date) => {
|
|
|
25
27
|
const getNextMonthYear = (date) => {
|
|
26
28
|
return `${getSweMonth(addMonths(date, 1))} ${getSweYear(addMonths(date, 1))}`;
|
|
27
29
|
};
|
|
28
|
-
|
|
30
|
+
const parseDateValue = (value) => {
|
|
31
|
+
if (!datePattern.test(value))
|
|
32
|
+
return undefined;
|
|
33
|
+
const parsedDate = createNewDate(value);
|
|
34
|
+
if (!isValid(parsedDate))
|
|
35
|
+
return undefined;
|
|
36
|
+
const [year, month, day] = value.split("-").map(Number);
|
|
37
|
+
const isSameDate = parsedDate.getUTCFullYear() === year && parsedDate.getUTCMonth() === month - 1 && parsedDate.getUTCDate() === day;
|
|
38
|
+
return isSameDate ? parsedDate : undefined;
|
|
39
|
+
};
|
|
40
|
+
function IDSDatePicker({ label, id, value, light = false, placeholder = "åååå-mm-dd", subtitle, dataTestId, errorMsg = "", missingDateErrorMsg = "Datum saknas", invalidDateErrorMsg = "Ogiltigt datum", calendarHeader = "Välj datum", srOpenText = "Öppna kalendern", srCloseText = "Stäng kalendern", validationOnBlur = false, defaultMonth, startMonth = new Date(1900, 0, 1), endMonth = new Date(2050, 0, 1), noValidation = false, disabled = false, required, invalid = false, readOnly = false, tooltip, disableNavigation = false, modifiers, focusedDay, onChange, onFocus, onBlur, onOpen, onClose, onDayClick, className, ...props }) {
|
|
29
41
|
const reactId = useId();
|
|
30
42
|
const dialogId = `datepicker-dialog-${reactId}`;
|
|
31
43
|
const headerId = `datepicker-header-${reactId}`;
|
|
@@ -38,24 +50,82 @@ function IDSDatePicker({ label, id, value, light = false, placeholder = "ååå
|
|
|
38
50
|
const headerRef = useRef(null);
|
|
39
51
|
const prevMonthButtonRef = useRef(null);
|
|
40
52
|
const nextMonthButtonRef = useRef(null);
|
|
53
|
+
const wasValidationEnabledRef = useRef(false);
|
|
54
|
+
const shouldRunRequiredValidation = required === true && !noValidation && !disabled;
|
|
55
|
+
const shouldShowCustomError = invalid === true && !!errorMsg && !noValidation && !disabled;
|
|
41
56
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
42
|
-
const [inputValue, setInputValue] = useState(value);
|
|
43
|
-
const initialSelectedDate =
|
|
57
|
+
const [inputValue, setInputValue] = useState(value ?? "");
|
|
58
|
+
const initialSelectedDate = value ? parseDateValue(value) : undefined;
|
|
44
59
|
const [selectedDate, setSelectedDate] = useState(initialSelectedDate || defaultMonth);
|
|
45
60
|
const [month, setMonth] = useState(initialSelectedDate || defaultMonth || new Date());
|
|
46
|
-
const [
|
|
47
|
-
const [
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
const [showValidationErrors, setShowValidationErrors] = useState(false);
|
|
62
|
+
const [validationError, setValidationError] = useState(null);
|
|
63
|
+
const hasValidationError = showValidationErrors && validationError !== null;
|
|
64
|
+
const hasCustomError = shouldShowCustomError;
|
|
65
|
+
const hasError = hasValidationError || hasCustomError;
|
|
66
|
+
const getValidationError = (nextValue) => {
|
|
67
|
+
if (noValidation || disabled)
|
|
68
|
+
return null;
|
|
69
|
+
const trimmedValue = nextValue.trim();
|
|
70
|
+
if (shouldRunRequiredValidation) {
|
|
71
|
+
if (!trimmedValue)
|
|
72
|
+
return "missing";
|
|
73
|
+
if (!parseDateValue(trimmedValue))
|
|
74
|
+
return "invalid";
|
|
75
|
+
}
|
|
76
|
+
if (shouldShowCustomError)
|
|
77
|
+
return "custom";
|
|
78
|
+
return null;
|
|
79
|
+
};
|
|
80
|
+
const getErrorMessage = (error) => {
|
|
81
|
+
if (error === "missing")
|
|
82
|
+
return missingDateErrorMsg;
|
|
83
|
+
if (error === "invalid")
|
|
84
|
+
return invalidDateErrorMsg;
|
|
85
|
+
if (error === "custom")
|
|
86
|
+
return errorMsg;
|
|
87
|
+
return "";
|
|
88
|
+
};
|
|
89
|
+
const syncNativeValidity = (nextValue) => {
|
|
90
|
+
if (!shouldRunRequiredValidation || !inputRef.current)
|
|
91
|
+
return;
|
|
92
|
+
const nextError = getValidationError(nextValue);
|
|
93
|
+
inputRef.current.setCustomValidity(getErrorMessage(nextError));
|
|
94
|
+
};
|
|
95
|
+
const updateVisibleValidation = (nextValue, shouldShow) => {
|
|
96
|
+
if (!shouldRunRequiredValidation) {
|
|
97
|
+
setValidationError(null);
|
|
98
|
+
setShowValidationErrors(false);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const nextError = getValidationError(nextValue);
|
|
102
|
+
setValidationError(nextError);
|
|
103
|
+
setShowValidationErrors(shouldShow);
|
|
104
|
+
};
|
|
105
|
+
const resetVisibleValidation = () => {
|
|
106
|
+
setValidationError(null);
|
|
107
|
+
setShowValidationErrors(false);
|
|
108
|
+
};
|
|
109
|
+
useAriaDescribedBy(inputRef, errorMsgId, hasError, hasError);
|
|
54
110
|
useFocusTrap(dialogRef.current, isDialogOpen);
|
|
55
111
|
useClickOutside(() => {
|
|
56
112
|
setIsDialogOpen(false);
|
|
57
113
|
onClose?.();
|
|
58
114
|
}, [dialogRef, triggerRef], triggerRef, isDialogOpen);
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (!inputRef.current)
|
|
117
|
+
return;
|
|
118
|
+
if (!shouldRunRequiredValidation) {
|
|
119
|
+
if (wasValidationEnabledRef.current) {
|
|
120
|
+
inputRef.current.setCustomValidity("");
|
|
121
|
+
}
|
|
122
|
+
wasValidationEnabledRef.current = false;
|
|
123
|
+
resetVisibleValidation();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
wasValidationEnabledRef.current = true;
|
|
127
|
+
syncNativeValidity(inputValue);
|
|
128
|
+
}, [shouldRunRequiredValidation, inputValue, invalid, errorMsg, missingDateErrorMsg, invalidDateErrorMsg]);
|
|
59
129
|
const handleOpenDialog = (e) => {
|
|
60
130
|
e.preventDefault();
|
|
61
131
|
setIsDialogOpen(true);
|
|
@@ -63,7 +133,7 @@ function IDSDatePicker({ label, id, value, light = false, placeholder = "ååå
|
|
|
63
133
|
};
|
|
64
134
|
const closeDialog = () => {
|
|
65
135
|
setIsDialogOpen(false);
|
|
66
|
-
triggerRef.current
|
|
136
|
+
triggerRef.current?.focus();
|
|
67
137
|
onClose?.();
|
|
68
138
|
};
|
|
69
139
|
useEffect(() => {
|
|
@@ -79,113 +149,78 @@ function IDSDatePicker({ label, id, value, light = false, placeholder = "ååå
|
|
|
79
149
|
document.addEventListener("keydown", handleKeyDown);
|
|
80
150
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
81
151
|
}, [isDialogOpen]);
|
|
152
|
+
const emitValue = (nextValue, parsedDate) => {
|
|
153
|
+
const trimmedValue = nextValue.trim();
|
|
154
|
+
const isMissing = shouldRunRequiredValidation && !trimmedValue;
|
|
155
|
+
const isInvalidDate = shouldRunRequiredValidation && !!trimmedValue && !parsedDate;
|
|
156
|
+
onChange?.({
|
|
157
|
+
value: nextValue,
|
|
158
|
+
valueAsDate: parsedDate,
|
|
159
|
+
invalidDate: isInvalidDate,
|
|
160
|
+
missingDate: isMissing
|
|
161
|
+
});
|
|
162
|
+
};
|
|
82
163
|
const handleDayPickerSelect = (date) => {
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
else {
|
|
90
|
-
setSelectedDate(date);
|
|
91
|
-
setInputValue(dateString);
|
|
164
|
+
const nextValue = date ? format(date, "yyyy-MM-dd") : "";
|
|
165
|
+
resetVisibleValidation();
|
|
166
|
+
setInputValue(nextValue);
|
|
167
|
+
setSelectedDate(date);
|
|
168
|
+
if (date) {
|
|
169
|
+
setMonth(date);
|
|
92
170
|
}
|
|
171
|
+
emitValue(nextValue, date);
|
|
93
172
|
requestAnimationFrame(() => {
|
|
94
|
-
if (inputRef.current)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
173
|
+
if (!inputRef.current)
|
|
174
|
+
return;
|
|
175
|
+
if (shouldRunRequiredValidation) {
|
|
176
|
+
syncNativeValidity(nextValue);
|
|
98
177
|
}
|
|
178
|
+
inputRef.current.dispatchEvent(new Event("input", { bubbles: true }));
|
|
179
|
+
inputRef.current.dispatchEvent(new Event("change", { bubbles: true }));
|
|
99
180
|
});
|
|
100
|
-
emitValue(dateString, date);
|
|
101
181
|
closeDialog();
|
|
102
182
|
};
|
|
103
|
-
const updateErrors = (validity, isNotADate) => {
|
|
104
|
-
if (!noValidation) {
|
|
105
|
-
setHasMissingError(validity.valueMissing);
|
|
106
|
-
setHasOtherError(!validity.valid);
|
|
107
|
-
if (validity.valueMissing) {
|
|
108
|
-
setHasDateError(false);
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
setHasDateError(!!isNotADate || validity.patternMismatch);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
const resetErrors = () => {
|
|
116
|
-
setHasMissingError(false);
|
|
117
|
-
setHasDateError(false);
|
|
118
|
-
setHasOtherError(false);
|
|
119
|
-
};
|
|
120
183
|
const handleInputChange = (e) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
184
|
+
const nextValue = e.currentTarget.value;
|
|
185
|
+
const parsedDate = parseDateValue(nextValue.trim());
|
|
186
|
+
resetVisibleValidation();
|
|
187
|
+
setInputValue(nextValue);
|
|
188
|
+
setSelectedDate(parsedDate);
|
|
189
|
+
if (parsedDate) {
|
|
127
190
|
setMonth(parsedDate);
|
|
128
191
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
setSelectedDate(undefined);
|
|
192
|
+
if (shouldRunRequiredValidation) {
|
|
193
|
+
syncNativeValidity(nextValue);
|
|
132
194
|
}
|
|
133
|
-
emitValue(
|
|
195
|
+
emitValue(nextValue, parsedDate);
|
|
134
196
|
};
|
|
135
|
-
// if the input value is changed programmatically
|
|
136
197
|
useEffect(() => {
|
|
137
|
-
if (value
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
setSelectedDate(undefined);
|
|
149
|
-
setHasDateError(true);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
198
|
+
if (value === inputValue)
|
|
199
|
+
return;
|
|
200
|
+
const nextValue = value ?? "";
|
|
201
|
+
const parsedDate = nextValue ? parseDateValue(nextValue.trim()) : undefined;
|
|
202
|
+
resetVisibleValidation();
|
|
203
|
+
setInputValue(nextValue);
|
|
204
|
+
setSelectedDate(parsedDate);
|
|
205
|
+
if (parsedDate) {
|
|
206
|
+
setMonth(parsedDate);
|
|
152
207
|
}
|
|
153
|
-
}, [value
|
|
154
|
-
const emitValue = (val, parsedDate) => {
|
|
155
|
-
const isMissing = required && !val;
|
|
156
|
-
const isValidDate = parsedDate && parsedDate instanceof Date && isValid(parsedDate);
|
|
157
|
-
onChange?.({
|
|
158
|
-
value: val,
|
|
159
|
-
valueAsDate: isValidDate ? createNewDate(val) : undefined,
|
|
160
|
-
invalidDate: !isValid(parsedDate),
|
|
161
|
-
missingDate: isMissing
|
|
162
|
-
});
|
|
163
|
-
};
|
|
208
|
+
}, [value]);
|
|
164
209
|
const handleInvalid = (e) => {
|
|
165
|
-
|
|
210
|
+
if (!shouldRunRequiredValidation)
|
|
211
|
+
return;
|
|
212
|
+
e.preventDefault();
|
|
213
|
+
syncNativeValidity(e.currentTarget.value);
|
|
214
|
+
updateVisibleValidation(e.currentTarget.value, true);
|
|
166
215
|
};
|
|
167
216
|
const handleBlur = (e) => {
|
|
168
|
-
if (validationOnBlur) {
|
|
169
|
-
|
|
217
|
+
if (shouldRunRequiredValidation && validationOnBlur) {
|
|
218
|
+
syncNativeValidity(e.currentTarget.value);
|
|
219
|
+
updateVisibleValidation(e.currentTarget.value, true);
|
|
170
220
|
}
|
|
171
221
|
onBlur?.(e);
|
|
172
222
|
};
|
|
173
|
-
useEffect(() => {
|
|
174
|
-
const form = inputRef.current?.form;
|
|
175
|
-
if (!form)
|
|
176
|
-
return;
|
|
177
|
-
const handleSubmit = (_e) => {
|
|
178
|
-
if (!noValidation) {
|
|
179
|
-
requestAnimationFrame(() => {
|
|
180
|
-
updateErrors(inputRef.current.validity, !isValid(createNewDate(inputRef.current.value)));
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
form.addEventListener("submit", handleSubmit);
|
|
185
|
-
return () => form.removeEventListener("submit", handleSubmit);
|
|
186
|
-
}, []);
|
|
187
223
|
function CustomNav(props) {
|
|
188
|
-
// Add the nav buttons after the dropdowns for correct tab order
|
|
189
224
|
const { children } = props;
|
|
190
225
|
const { goToMonth, previousMonth, nextMonth } = useDayPicker();
|
|
191
226
|
const currentMonth = "aktuell månad";
|
|
@@ -193,28 +228,25 @@ function IDSDatePicker({ label, id, value, light = false, placeholder = "ååå
|
|
|
193
228
|
const goToPrevMonth = () => {
|
|
194
229
|
previousMonth && goToMonth(previousMonth);
|
|
195
230
|
requestAnimationFrame(() => {
|
|
196
|
-
|
|
197
|
-
prevMonthButtonRef.current.focus();
|
|
198
|
-
}
|
|
231
|
+
prevMonthButtonRef.current?.focus();
|
|
199
232
|
});
|
|
200
233
|
};
|
|
201
234
|
const goToNextMonth = () => {
|
|
202
235
|
nextMonth && goToMonth(nextMonth);
|
|
203
236
|
requestAnimationFrame(() => {
|
|
204
|
-
|
|
205
|
-
nextMonthButtonRef.current.focus();
|
|
206
|
-
}
|
|
237
|
+
nextMonthButtonRef.current?.focus();
|
|
207
238
|
});
|
|
208
239
|
};
|
|
209
240
|
return (jsxs(DropdownNav, { className: "ids-datepicker__nav", ...props, children: [jsx("div", { className: "ids-datepicker__nav-dropdowns", children: children }), jsxs("div", { className: "ids-datepicker__nav-buttons", children: [jsx("button", { type: "button", ref: prevMonthButtonRef, className: "ids-datepicker__nav-prev", onClick: goToPrevMonth, disabled: !previousMonth || disableNavigation, "aria-label": `${currentMonth} ${getSweMonth(month)}. ${goTo} ${getPrevMonthYear(month)}` }), jsx("button", { type: "button", ref: nextMonthButtonRef, className: "ids-datepicker__nav-next", onClick: goToNextMonth, disabled: !nextMonth || disableNavigation, "aria-label": `${currentMonth} ${getSweMonth(month)}. ${goTo} ${getNextMonthYear(month)}` })] })] }));
|
|
210
241
|
}
|
|
211
242
|
useEffect(() => {
|
|
212
|
-
|
|
213
|
-
if (!header)
|
|
243
|
+
if (!isDialogOpen)
|
|
214
244
|
return;
|
|
215
|
-
|
|
245
|
+
headerRef.current?.focus();
|
|
216
246
|
}, [isDialogOpen]);
|
|
217
|
-
|
|
247
|
+
const visibleErrorType = hasValidationError ? validationError : hasCustomError ? "custom" : null;
|
|
248
|
+
const visibleErrorMessage = visibleErrorType ? getErrorMessage(visibleErrorType) : "";
|
|
249
|
+
return (jsxs("div", { className: clsx("ids-datepicker", { "ids-datepicker--invalid": hasError }, className), "data-testid": dataTestId, children: [isDialogOpen && jsx("div", { className: "ids-datepicker__overlay" }), label && (jsxs("div", { className: "ids-label-wrapper ids-label-wrapper--margin-bottom", children: [jsx("label", { htmlFor: inputId, className: clsx("ids-label", { "ids-label--disabled": disabled }), children: label }), tooltip && jsx("span", { className: "ids-label__tooltip", children: tooltip })] })), subtitle && jsx("div", { className: clsx("ids-subtitle", { "ids-subtitle--disabled": disabled }), children: subtitle }), jsxs("div", { className: "ids-datepicker__input-wrapper", children: [jsx("input", { className: clsx("ids-datepicker__input", { "ids-input--light": light }), ref: inputRef, style: { fontSize: "inherit" }, id: inputId, type: "text", value: inputValue, required: shouldRunRequiredValidation || undefined, pattern: shouldRunRequiredValidation ? datePatternString : undefined, "aria-invalid": hasError || undefined, disabled: disabled, readOnly: readOnly, placeholder: placeholder, onChange: handleInputChange, onFocus: onFocus, onInvalid: handleInvalid, onBlur: handleBlur, ...props }), jsx("button", { ref: triggerRef, type: "button", className: "ids-datepicker__trigger", style: { fontSize: "inherit" }, disabled: disabled || readOnly, onClick: handleOpenDialog, "aria-controls": dialogId, "aria-haspopup": "dialog", "aria-expanded": isDialogOpen, "aria-label": srOpenText }), jsxs("div", { className: clsx("ids-datepicker__dialog", { "ids-datepicker__dialog--show": isDialogOpen }), role: "dialog", ref: dialogRef, id: dialogId, "aria-modal": true, "aria-labelledby": headerId, children: [jsxs("div", { className: "ids-datepicker__dialog-bar", children: [jsx("div", { className: "ids-datepicker__dialog-header", id: headerId, ref: headerRef, tabIndex: -1, children: calendarHeader }), jsx("button", { className: "ids-datepicker__dialog-close-button", type: "button", onClick: closeDialog, "aria-label": srCloseText })] }), jsx(DayPicker, { mode: "single", locale: sv, labels: {
|
|
218
250
|
labelWeekNumberHeader: () => "Veckonumer",
|
|
219
251
|
labelWeekNumber: (_weekNumber) => `vecka`,
|
|
220
252
|
labelDayButton(date, _modifiers, _options, dateLib) {
|
|
@@ -235,7 +267,7 @@ function IDSDatePicker({ label, id, value, light = false, placeholder = "ååå
|
|
|
235
267
|
WeekNumberHeader: props => (jsx(WeekNumberHeader, { ...props, className: "ids-datepicker__week-number-header", children: shortWeek })),
|
|
236
268
|
MonthsDropdown: props => (jsx(MonthsDropdown, { ...props, disabled: disableNavigation, className: "ids-datepicker__month-select" })),
|
|
237
269
|
YearsDropdown: props => (jsx(YearsDropdown, { ...props, disabled: disableNavigation, className: "ids-datepicker__year-select" }))
|
|
238
|
-
}, startMonth: startMonth, endMonth: endMonth, month: month, onMonthChange: setMonth, defaultMonth: defaultMonth, selected: selectedDate, onSelect: handleDayPickerSelect, onDayClick: onDayClick })] })] }),
|
|
270
|
+
}, startMonth: startMonth, endMonth: endMonth, month: month, onMonthChange: setMonth, defaultMonth: defaultMonth, selected: selectedDate, onSelect: handleDayPickerSelect, onDayClick: onDayClick })] })] }), visibleErrorMessage && (jsx(IDSErrorMessage, { id: errorMsgId, show: true, children: visibleErrorMessage }))] }));
|
|
239
271
|
}
|
|
240
272
|
IDSDatePicker.displayName = "IDSDatePicker";
|
|
241
273
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function useInputValidity(ref: React.RefObject<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>, validateOnBlur?: boolean): boolean;
|
|
1
|
+
export declare function useInputValidity(ref: React.RefObject<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>, validateOnBlur?: boolean, skipValidation?: boolean): boolean;
|
|
@@ -1,30 +1,46 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react';
|
|
1
|
+
import { useState, useRef, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
-
function useInputValidity(ref, validateOnBlur) {
|
|
3
|
+
function useInputValidity(ref, validateOnBlur, skipValidation) {
|
|
4
4
|
const [isValid, setIsValid] = useState(true);
|
|
5
|
+
const validationStartedRef = useRef(false);
|
|
5
6
|
useEffect(() => {
|
|
7
|
+
if (skipValidation) {
|
|
8
|
+
validationStartedRef.current = false;
|
|
9
|
+
setIsValid(true);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
6
12
|
const inputEl = ref.current;
|
|
7
13
|
if (!inputEl)
|
|
8
14
|
return;
|
|
9
15
|
const updateValidity = () => {
|
|
10
|
-
|
|
16
|
+
const isOptionalEmpty = !inputEl.required && inputEl.value === "";
|
|
17
|
+
setIsValid(isOptionalEmpty || inputEl.validity.valid);
|
|
18
|
+
};
|
|
19
|
+
const startValidation = () => {
|
|
20
|
+
validationStartedRef.current = true;
|
|
21
|
+
updateValidity();
|
|
22
|
+
};
|
|
23
|
+
const updateValidityAfterValidationStarted = () => {
|
|
24
|
+
if (validationStartedRef.current) {
|
|
25
|
+
updateValidity();
|
|
26
|
+
}
|
|
11
27
|
};
|
|
12
28
|
const form = inputEl.closest("form");
|
|
13
|
-
form?.addEventListener("submit",
|
|
29
|
+
form?.addEventListener("submit", startValidation);
|
|
30
|
+
inputEl.addEventListener("invalid", startValidation);
|
|
31
|
+
inputEl.addEventListener("change", updateValidityAfterValidationStarted);
|
|
14
32
|
if (validateOnBlur) {
|
|
15
|
-
inputEl.addEventListener("blur",
|
|
33
|
+
inputEl.addEventListener("blur", startValidation);
|
|
16
34
|
}
|
|
17
|
-
inputEl.addEventListener("change", updateValidity);
|
|
18
|
-
inputEl.addEventListener("invalid", updateValidity);
|
|
19
35
|
return () => {
|
|
20
|
-
form?.removeEventListener("submit",
|
|
36
|
+
form?.removeEventListener("submit", startValidation);
|
|
37
|
+
inputEl.removeEventListener("invalid", startValidation);
|
|
38
|
+
inputEl.removeEventListener("change", updateValidityAfterValidationStarted);
|
|
21
39
|
if (validateOnBlur) {
|
|
22
|
-
inputEl.removeEventListener("blur",
|
|
40
|
+
inputEl.removeEventListener("blur", startValidation);
|
|
23
41
|
}
|
|
24
|
-
inputEl.removeEventListener("change", updateValidity);
|
|
25
|
-
inputEl.removeEventListener("invalid", updateValidity);
|
|
26
42
|
};
|
|
27
|
-
}, [ref]);
|
|
43
|
+
}, [ref, validateOnBlur, skipValidation]);
|
|
28
44
|
return isValid;
|
|
29
45
|
}
|
|
30
46
|
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import React, { ReactNode, CSSProperties } from "react";
|
|
2
2
|
import { CommonFormPropsWithReadOnly } from "../form-props/form-props";
|
|
3
3
|
export interface IDSInputBaseProps extends React.InputHTMLAttributes<HTMLInputElement>, CommonFormPropsWithReadOnly {
|
|
4
|
-
icon?: string;
|
|
5
4
|
unit?: string;
|
|
5
|
+
subtitle?: string;
|
|
6
6
|
showSearchLabel?: boolean;
|
|
7
7
|
submitButton?: ReactNode;
|
|
8
8
|
hintId?: string;
|
|
9
9
|
errorMsgId?: string;
|
|
10
10
|
inputRef?: React.Ref<HTMLInputElement>;
|
|
11
11
|
style?: CSSProperties;
|
|
12
|
+
icon?: string;
|
|
13
|
+
clearButton?: ReactNode;
|
|
12
14
|
}
|
|
13
|
-
export declare function IDSInputBase({ label, type, icon, hint, unit, showSearchLabel, errorMsg, dataTestId, disabled, invalid, required, focusAnchor, light, readOnly, tooltip, submitButton, className, id, hintId, errorMsgId, inputRef, ...props }: IDSInputBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function IDSInputBase({ label, type, icon, clearButton, hint, unit, subtitle, showSearchLabel, errorMsg, dataTestId, disabled, invalid, required, focusAnchor, light, readOnly, tooltip, submitButton, className, id, hintId, errorMsgId, inputRef, ...props }: IDSInputBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
14
16
|
export declare namespace IDSInputBase {
|
|
15
17
|
var displayName: string;
|
|
16
18
|
}
|
|
@@ -3,7 +3,7 @@ import { useId } from 'react';
|
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
import { IDSErrorMessage } from '../error-message/error-message.js';
|
|
5
5
|
|
|
6
|
-
function IDSInputBase({ label, type = "text", icon, hint, unit, showSearchLabel = false, errorMsg, dataTestId, disabled = false, invalid = false, required = false, focusAnchor = false, light = false, readOnly = false, tooltip, submitButton, className, id, hintId, errorMsgId, inputRef, ...props }) {
|
|
6
|
+
function IDSInputBase({ label, type = "text", icon, clearButton, hint, unit, subtitle, showSearchLabel = false, errorMsg, dataTestId, disabled = false, invalid = false, required = false, focusAnchor = false, light = false, readOnly = false, tooltip, submitButton, className, id, hintId, errorMsgId, inputRef, ...props }) {
|
|
7
7
|
const reactId = useId();
|
|
8
8
|
const inputId = id ?? `input-base-${reactId}`;
|
|
9
9
|
const baseHintId = hintId ?? `input-base-hint-${reactId}`;
|
|
@@ -17,15 +17,20 @@ function IDSInputBase({ label, type = "text", icon, hint, unit, showSearchLabel
|
|
|
17
17
|
if (type === "search" && !showSearchLabel && label) {
|
|
18
18
|
ariaHandler["aria-label"] = label;
|
|
19
19
|
}
|
|
20
|
-
return (jsxs(Fragment, { children: [jsxs("div", { className: clsx("ids-input", {
|
|
21
|
-
|
|
20
|
+
return (jsxs(Fragment, { children: [jsxs("div", { className: clsx("ids-input", {
|
|
21
|
+
"ids-input--search": type === "search",
|
|
22
|
+
"ids-input--icon": !!icon && !clearButton,
|
|
23
|
+
"ids-input--clear-button": !!clearButton,
|
|
24
|
+
"ids-input--unit": !!unit
|
|
25
|
+
}, className), "data-testid": dataTestId, children: [jsxs("div", { className: "ids-input__wrapper", children: [label && (jsxs("div", { className: clsx("ids-label-wrapper", "ids-label-wrapper--margin-bottom", {
|
|
26
|
+
"ids-label-wrapper--sr-only": type === "search" && !showSearchLabel
|
|
22
27
|
}), children: [jsx("label", { className: clsx("ids-label", {
|
|
23
|
-
"ids-label--
|
|
24
|
-
}), htmlFor: inputId, children: label }), tooltip && jsx("span", { className: "ids-label__tooltip", children: tooltip })] })),
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
"ids-label--sr-only": type === "search" && !showSearchLabel
|
|
29
|
+
}), htmlFor: inputId, children: label }), tooltip && jsx("span", { className: "ids-label__tooltip", children: tooltip })] })), subtitle && jsx("div", { className: "ids-subtitle", children: subtitle }), jsxs("div", { className: "ids-input__input-wrapper", children: [type === "search" && jsx("span", { className: "ids-input__search-icon" }), jsx("input", { ref: inputRef, id: inputId, type: type, readOnly: readOnly, className: clsx("ids-input__input", {
|
|
30
|
+
"ids-input--light": light,
|
|
31
|
+
"ids-input--invalid": invalid,
|
|
32
|
+
"ids-focus-anchor": focusAnchor
|
|
33
|
+
}), "aria-invalid": invalid, required: required, disabled: disabled, ...ariaHandler, ...props }), icon && !clearButton && jsx("span", { className: `ids-input__icon ids-icon-${icon}` }), clearButton && jsx("span", { className: "ids-input__clear-button", children: clearButton }), unit && (jsx("div", { className: "ids-input__unit", "aria-hidden": "true", children: unit }))] }), hint && (jsx("div", { className: "ids-input__hint", id: baseHintId, children: hint }))] }), !!submitButton && submitButton] }), showErrorMsg && (jsx(IDSErrorMessage, { id: baseErrorMsgId, show: true, children: errorMsg }))] }));
|
|
29
34
|
}
|
|
30
35
|
IDSInputBase.displayName = "IDSInputBase";
|
|
31
36
|
|
|
@@ -2,7 +2,10 @@ import { ReactNode } from "react";
|
|
|
2
2
|
import { CommonFormPropsWithReadOnly } from "../form-props/form-props";
|
|
3
3
|
interface IDSInputProps extends React.InputHTMLAttributes<HTMLInputElement>, CommonFormPropsWithReadOnly {
|
|
4
4
|
icon?: string;
|
|
5
|
+
clearButton?: ReactNode;
|
|
5
6
|
unit?: string;
|
|
7
|
+
hint?: string | ReactNode;
|
|
8
|
+
subtitle?: string;
|
|
6
9
|
showSearchLabel?: boolean;
|
|
7
10
|
submitButton?: ReactNode;
|
|
8
11
|
}
|
|
@@ -6,7 +6,7 @@ import { IDSInputBase } from './input-base.js';
|
|
|
6
6
|
|
|
7
7
|
const IDSInput = forwardRef(({ invalid = false, noValidation = false, style, validationOnBlur = false, ...props }, ref) => {
|
|
8
8
|
const inputRef = useRef(null);
|
|
9
|
-
const hasValidValue = useInputValidity(inputRef, validationOnBlur);
|
|
9
|
+
const hasValidValue = useInputValidity(inputRef, validationOnBlur, noValidation);
|
|
10
10
|
const computedInvalid = (invalid || !hasValidValue) && !noValidation;
|
|
11
11
|
// Merge forwarded + local ref
|
|
12
12
|
const mergedRef = (node) => {
|
|
@@ -13,8 +13,7 @@ function IDSRadioBase({ id, name, light, disabled, focusAnchor, tooltip, dataTes
|
|
|
13
13
|
"ids-input--light": light,
|
|
14
14
|
"ids-focus-anchor": focusAnchor
|
|
15
15
|
}), name: name, disabled: disabled, "aria-invalid": invalid, ...ariaHandler, ...props }), !!children && (jsxs("div", { className: "ids-label-wrapper", children: [jsx("label", { htmlFor: inputId, className: clsx("ids-radio__label ids-label", {
|
|
16
|
-
"ids-label--clickable": !disabled
|
|
17
|
-
"ids-label--disabled": disabled
|
|
16
|
+
"ids-label--clickable": !disabled
|
|
18
17
|
}), children: children }), tooltip && jsx("span", { className: "ids-label__tooltip", children: tooltip })] }))] }));
|
|
19
18
|
}
|
|
20
19
|
IDSRadioBase.displayName = "IDSRadioBase";
|
|
@@ -7,10 +7,11 @@ interface IDSRadioGroupBaseProps extends FieldsetHTMLAttributes<HTMLFieldSetElem
|
|
|
7
7
|
required?: boolean;
|
|
8
8
|
tooltip?: ReactNode;
|
|
9
9
|
invalid?: boolean;
|
|
10
|
+
subtitle?: string | ReactNode;
|
|
10
11
|
errorMsgId?: string;
|
|
11
12
|
groupRef?: React.Ref<HTMLFieldSetElement>;
|
|
12
13
|
}
|
|
13
|
-
export declare function IDSRadioGroupBase({ legend, hideLegend, errorMsg, errorMsgId, compact, required, tooltip, className, children, invalid, groupRef, ...props }: IDSRadioGroupBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare function IDSRadioGroupBase({ legend, hideLegend, errorMsg, errorMsgId, compact, required, tooltip, subtitle, className, children, invalid, groupRef, ...props }: IDSRadioGroupBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
14
15
|
export declare namespace IDSRadioGroupBase {
|
|
15
16
|
var displayName: string;
|
|
16
17
|
}
|
|
@@ -2,11 +2,11 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { IDSErrorMessage } from '../error-message/error-message.js';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
|
|
5
|
-
function IDSRadioGroupBase({ legend, hideLegend, errorMsg, errorMsgId, compact = false, required = false, tooltip, className, children, invalid, groupRef, ...props }) {
|
|
5
|
+
function IDSRadioGroupBase({ legend, hideLegend, errorMsg, errorMsgId, compact = false, required = false, tooltip, subtitle, className, children, invalid, groupRef, ...props }) {
|
|
6
6
|
const showErrorMsg = invalid && !!errorMsg && !!errorMsgId;
|
|
7
|
-
return (jsxs("fieldset", { ref: groupRef, "aria-required": required, className: clsx("ids-form-group__fieldset", { "ids-form-group__fieldset--compact": compact }, className), ...props, children: [legend && (
|
|
7
|
+
return (jsxs("fieldset", { ref: groupRef, "aria-required": required, className: clsx("ids-form-group__fieldset", { "ids-form-group__fieldset--compact": compact }, className), ...props, children: [legend && (jsxs("div", { className: clsx("ids-label-wrapper", {
|
|
8
8
|
"ids-label-wrapper--sr-only": hideLegend
|
|
9
|
-
}, className), children: jsxs("legend", { children: [legend, tooltip && jsx("span", { className: "ids-legend__tooltip", children: tooltip })] }) })), children, showErrorMsg && (jsx(IDSErrorMessage, { id: errorMsgId, show: true, style: { marginTop: compact ? "0.75rem" : "auto" }, children: errorMsg }))] }));
|
|
9
|
+
}, className), children: [jsxs("legend", { children: [legend, tooltip && jsx("span", { className: "ids-legend__tooltip", children: tooltip })] }), subtitle && jsx("div", { className: "ids-subtitle ids-subtitle--group", children: subtitle })] })), children, showErrorMsg && (jsx(IDSErrorMessage, { id: errorMsgId, show: true, style: { marginTop: compact ? "0.75rem" : "auto" }, children: errorMsg }))] }));
|
|
10
10
|
}
|
|
11
11
|
IDSRadioGroupBase.displayName = "IDSRadioGroupBase";
|
|
12
12
|
|
|
@@ -7,11 +7,12 @@ interface IDSRadioGroupProps extends FieldsetHTMLAttributes<HTMLFieldSetElement>
|
|
|
7
7
|
compact?: boolean;
|
|
8
8
|
invalid?: boolean;
|
|
9
9
|
required?: boolean;
|
|
10
|
+
subtitle?: string | ReactNode;
|
|
10
11
|
tooltip?: ReactNode;
|
|
11
12
|
noValidation?: boolean;
|
|
12
13
|
onRadioChange?: (e: ChangeEvent<HTMLInputElement>) => void;
|
|
13
14
|
}
|
|
14
|
-
export declare function IDSRadioGroup({ name, required, noValidation, invalid, errorMsg, children, onRadioChange, ...props }: IDSRadioGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function IDSRadioGroup({ name, required, noValidation, invalid, errorMsg, subtitle, children, onRadioChange, ...props }: IDSRadioGroupProps): import("react/jsx-runtime").JSX.Element;
|
|
15
16
|
export declare namespace IDSRadioGroup {
|
|
16
17
|
var displayName: string;
|
|
17
18
|
}
|
|
@@ -5,7 +5,7 @@ import { IDSRadioGroupBase } from './radio-group-base.js';
|
|
|
5
5
|
import { IDSRadio } from './radio.js';
|
|
6
6
|
import { useGroupValidity } from '../form-hooks/useGroupValidity.js';
|
|
7
7
|
|
|
8
|
-
function IDSRadioGroup({ name, required, noValidation, invalid, errorMsg, children, onRadioChange, ...props }) {
|
|
8
|
+
function IDSRadioGroup({ name, required, noValidation, invalid, errorMsg, subtitle, children, onRadioChange, ...props }) {
|
|
9
9
|
const groupRef = useRef(null);
|
|
10
10
|
const { isValid, hasInteracted } = useGroupValidity(groupRef, "radio");
|
|
11
11
|
const reactId = useId();
|
|
@@ -31,7 +31,7 @@ function IDSRadioGroup({ name, required, noValidation, invalid, errorMsg, childr
|
|
|
31
31
|
}
|
|
32
32
|
return child;
|
|
33
33
|
});
|
|
34
|
-
return (jsx(IDSRadioGroupBase, { ...props, groupRef: groupRef, required: required, invalid: groupInvalid || invalid, errorMsg: !noValidation && errorMsg, errorMsgId: errorMsgId, children: clonedChildren }));
|
|
34
|
+
return (jsx(IDSRadioGroupBase, { ...props, groupRef: groupRef, required: required, subtitle: subtitle, invalid: groupInvalid || invalid, errorMsg: !noValidation && errorMsg, errorMsgId: errorMsgId, children: clonedChildren }));
|
|
35
35
|
}
|
|
36
36
|
IDSRadioGroup.displayName = "IDSRadioGroup";
|
|
37
37
|
|
|
@@ -10,7 +10,7 @@ export interface IDSRangeBaseProps extends React.InputHTMLAttributes<HTMLInputEl
|
|
|
10
10
|
inputRef?: Ref<HTMLInputElement>;
|
|
11
11
|
style?: CSSProperties;
|
|
12
12
|
}
|
|
13
|
-
export declare function IDSRangeBase({ id, label, showTicks, ticks, disabled, focusAnchor, dataTestId, tooltip, valueNow, min, max, step, inputRef, style, className, ...props }: IDSRangeBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function IDSRangeBase({ id, label, showTicks, ticks, disabled, focusAnchor, dataTestId, tooltip, valueNow, min, max, step, inputRef, style, className, subtitle, ...props }: IDSRangeBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
14
14
|
export declare namespace IDSRangeBase {
|
|
15
15
|
var displayName: string;
|
|
16
16
|
}
|
|
@@ -2,9 +2,9 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { useId } from 'react';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
4
|
|
|
5
|
-
function IDSRangeBase({ id, label, showTicks, ticks = [], disabled, focusAnchor, dataTestId, tooltip, valueNow, min = 0, max = 10, step = 1, inputRef, style, className, ...props }) {
|
|
5
|
+
function IDSRangeBase({ id, label, showTicks, ticks = [], disabled, focusAnchor, dataTestId, tooltip, valueNow, min = 0, max = 10, step = 1, inputRef, style, className, subtitle, ...props }) {
|
|
6
6
|
const inputId = !!id ? id : `range-${useId()}`;
|
|
7
|
-
return (jsxs("div", { className: clsx("ids-range", className), "data-testid": dataTestId, style: style, children: [label && (jsxs("div", { className: "ids-label-wrapper ids-label-wrapper--margin-bottom", children: [jsx("label", { htmlFor: inputId, className:
|
|
7
|
+
return (jsxs("div", { className: clsx("ids-range", className), "data-testid": dataTestId, style: style, children: [label && (jsxs("div", { className: "ids-label-wrapper ids-label-wrapper--margin-bottom", children: [jsx("label", { htmlFor: inputId, className: "ids-label", children: label }), tooltip && jsx("span", { className: "ids-label__tooltip", children: tooltip })] })), subtitle && jsx("div", { className: "ids-subtitle", children: subtitle }), jsx("input", { id: inputId, ref: inputRef, type: "range", className: clsx("ids-range__input", {
|
|
8
8
|
"ids-focus-anchor": focusAnchor
|
|
9
9
|
}), min: min, "aria-valuemin": min, max: max, "aria-valuemax": max, "aria-valuenow": valueNow, "aria-disabled": disabled, disabled: disabled, step: step, style: {
|
|
10
10
|
backgroundSize: ((valueNow - (min ?? 0)) * 100) / ((max ?? 100) - (min ?? 0)) + "% 100%"
|