@navikt/ds-react 7.32.0 → 7.32.2
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/cjs/copybutton/CopyButton.js +4 -9
- package/cjs/copybutton/CopyButton.js.map +1 -1
- package/cjs/date/date-utils/dropdown-options.d.ts +11 -2
- package/cjs/date/date-utils/dropdown-options.js +5 -3
- package/cjs/date/date-utils/dropdown-options.js.map +1 -1
- package/cjs/date/datepicker/parts/DatePicker.Months.js +7 -2
- package/cjs/date/datepicker/parts/DatePicker.Months.js.map +1 -1
- package/cjs/form/combobox/Combobox.js +1 -3
- package/cjs/form/combobox/Combobox.js.map +1 -1
- package/cjs/form/combobox/ComboboxWrapper.d.ts +1 -2
- package/cjs/form/combobox/ComboboxWrapper.js +1 -2
- package/cjs/form/combobox/ComboboxWrapper.js.map +1 -1
- package/cjs/form/combobox/FilteredOptions/FilteredOptions.js +28 -19
- package/cjs/form/combobox/FilteredOptions/FilteredOptions.js.map +1 -1
- package/cjs/form/combobox/FilteredOptions/useVirtualFocus.js.map +1 -1
- package/cjs/form/combobox/Input/Input.context.d.ts +2 -0
- package/cjs/form/combobox/Input/Input.context.js +4 -1
- package/cjs/form/combobox/Input/Input.context.js.map +1 -1
- package/cjs/form/combobox/Input/InputController.js +2 -2
- package/cjs/form/combobox/Input/InputController.js.map +1 -1
- package/cjs/help-text/HelpText.js +3 -3
- package/cjs/help-text/HelpText.js.map +1 -1
- package/cjs/help-text/HelpTextIcon.d.ts +1 -2
- package/cjs/help-text/HelpTextIcon.js +3 -7
- package/cjs/help-text/HelpTextIcon.js.map +1 -1
- package/cjs/layout/page/parts/PageBlock.d.ts +9 -2
- package/cjs/layout/page/parts/PageBlock.js.map +1 -1
- package/cjs/modal/ModalUtils.js +6 -4
- package/cjs/modal/ModalUtils.js.map +1 -1
- package/cjs/overlays/dismissablelayer/DismissableLayer.js +9 -19
- package/cjs/overlays/dismissablelayer/DismissableLayer.js.map +1 -1
- package/cjs/overlays/dismissablelayer/util/usePointerDownOutside.js +5 -4
- package/cjs/overlays/dismissablelayer/util/usePointerDownOutside.js.map +1 -1
- package/cjs/overlays/floating-menu/Menu.d.ts +4 -4
- package/cjs/overlays/floating-menu/Menu.js +7 -4
- package/cjs/overlays/floating-menu/Menu.js.map +1 -1
- package/cjs/overlays/floating-menu/parts/RovingFocus.js +3 -3
- package/cjs/overlays/floating-menu/parts/RovingFocus.js.map +1 -1
- package/cjs/overlays/overlay/hooks/useAnimationsFinished.js +1 -1
- package/cjs/overlays/overlay/hooks/useAnimationsFinished.js.map +1 -1
- package/cjs/overlays/overlay/hooks/useOpenChangeAnimationComplete.js +2 -2
- package/cjs/overlays/overlay/hooks/useOpenChangeAnimationComplete.js.map +1 -1
- package/cjs/progress-bar/ProgressBar.js +9 -6
- package/cjs/progress-bar/ProgressBar.js.map +1 -1
- package/cjs/table/AnimateHeight.js +12 -13
- package/cjs/table/AnimateHeight.js.map +1 -1
- package/cjs/tabs/parts/tablist/useScrollButtons.d.ts +1 -1
- package/cjs/tabs/parts/tablist/useScrollButtons.js +4 -4
- package/cjs/tabs/parts/tablist/useScrollButtons.js.map +1 -1
- package/cjs/util/TextareaAutoSize.js +3 -10
- package/cjs/util/TextareaAutoSize.js.map +1 -1
- package/cjs/util/create-context.d.ts +0 -1
- package/cjs/util/create-context.js.map +1 -1
- package/cjs/util/debounce.d.ts +1 -1
- package/cjs/util/debounce.js +5 -8
- package/cjs/util/debounce.js.map +1 -1
- package/cjs/util/detectBrowser.d.ts +2 -0
- package/cjs/util/detectBrowser.js +7 -0
- package/cjs/util/detectBrowser.js.map +1 -0
- package/cjs/util/focus-boundary/FocusBoundary.d.ts +44 -0
- package/cjs/util/focus-boundary/FocusBoundary.js +365 -0
- package/cjs/util/focus-boundary/FocusBoundary.js.map +1 -0
- package/cjs/util/focus-guards/FocusGuards.d.ts +8 -0
- package/cjs/util/focus-guards/FocusGuards.js +36 -0
- package/cjs/util/focus-guards/FocusGuards.js.map +1 -0
- package/cjs/util/hooks/useEventCallback.js.map +1 -0
- package/cjs/{overlays/overlay → util}/hooks/useLatestRef.js +2 -2
- package/cjs/util/hooks/useLatestRef.js.map +1 -0
- package/cjs/util/hooks/useRefWithInit.js.map +1 -0
- package/cjs/util/hooks/useTimeout.d.ts +16 -0
- package/cjs/util/hooks/useTimeout.js +49 -0
- package/cjs/util/hooks/useTimeout.js.map +1 -0
- package/cjs/util/link-anchor/LinkAnchor.js +6 -7
- package/cjs/util/link-anchor/LinkAnchor.js.map +1 -1
- package/cjs/util/owner.d.ts +29 -0
- package/cjs/util/owner.js +38 -0
- package/cjs/util/owner.js.map +1 -0
- package/esm/copybutton/CopyButton.js +5 -10
- package/esm/copybutton/CopyButton.js.map +1 -1
- package/esm/date/date-utils/dropdown-options.d.ts +11 -2
- package/esm/date/date-utils/dropdown-options.js +5 -3
- package/esm/date/date-utils/dropdown-options.js.map +1 -1
- package/esm/date/datepicker/parts/DatePicker.Months.js +7 -2
- package/esm/date/datepicker/parts/DatePicker.Months.js.map +1 -1
- package/esm/form/combobox/Combobox.js +1 -3
- package/esm/form/combobox/Combobox.js.map +1 -1
- package/esm/form/combobox/ComboboxWrapper.d.ts +1 -2
- package/esm/form/combobox/ComboboxWrapper.js +1 -2
- package/esm/form/combobox/ComboboxWrapper.js.map +1 -1
- package/esm/form/combobox/FilteredOptions/FilteredOptions.js +29 -20
- package/esm/form/combobox/FilteredOptions/FilteredOptions.js.map +1 -1
- package/esm/form/combobox/FilteredOptions/useVirtualFocus.js.map +1 -1
- package/esm/form/combobox/Input/Input.context.d.ts +2 -0
- package/esm/form/combobox/Input/Input.context.js +4 -1
- package/esm/form/combobox/Input/Input.context.js.map +1 -1
- package/esm/form/combobox/Input/InputController.js +2 -2
- package/esm/form/combobox/Input/InputController.js.map +1 -1
- package/esm/help-text/HelpText.js +3 -3
- package/esm/help-text/HelpText.js.map +1 -1
- package/esm/help-text/HelpTextIcon.d.ts +1 -2
- package/esm/help-text/HelpTextIcon.js +3 -7
- package/esm/help-text/HelpTextIcon.js.map +1 -1
- package/esm/layout/page/parts/PageBlock.d.ts +9 -2
- package/esm/layout/page/parts/PageBlock.js.map +1 -1
- package/esm/modal/ModalUtils.js +6 -4
- package/esm/modal/ModalUtils.js.map +1 -1
- package/esm/overlays/dismissablelayer/DismissableLayer.js +9 -19
- package/esm/overlays/dismissablelayer/DismissableLayer.js.map +1 -1
- package/esm/overlays/dismissablelayer/util/usePointerDownOutside.js +5 -4
- package/esm/overlays/dismissablelayer/util/usePointerDownOutside.js.map +1 -1
- package/esm/overlays/floating-menu/Menu.d.ts +4 -4
- package/esm/overlays/floating-menu/Menu.js +7 -4
- package/esm/overlays/floating-menu/Menu.js.map +1 -1
- package/esm/overlays/floating-menu/parts/RovingFocus.js +3 -3
- package/esm/overlays/floating-menu/parts/RovingFocus.js.map +1 -1
- package/esm/overlays/overlay/hooks/useAnimationsFinished.js +1 -1
- package/esm/overlays/overlay/hooks/useAnimationsFinished.js.map +1 -1
- package/esm/overlays/overlay/hooks/useOpenChangeAnimationComplete.js +2 -2
- package/esm/overlays/overlay/hooks/useOpenChangeAnimationComplete.js.map +1 -1
- package/esm/progress-bar/ProgressBar.js +10 -7
- package/esm/progress-bar/ProgressBar.js.map +1 -1
- package/esm/table/AnimateHeight.js +12 -13
- package/esm/table/AnimateHeight.js.map +1 -1
- package/esm/tabs/parts/tablist/useScrollButtons.d.ts +1 -1
- package/esm/tabs/parts/tablist/useScrollButtons.js +4 -4
- package/esm/tabs/parts/tablist/useScrollButtons.js.map +1 -1
- package/esm/util/TextareaAutoSize.js +1 -8
- package/esm/util/TextareaAutoSize.js.map +1 -1
- package/esm/util/create-context.d.ts +0 -1
- package/esm/util/create-context.js.map +1 -1
- package/esm/util/debounce.d.ts +1 -1
- package/esm/util/debounce.js +5 -8
- package/esm/util/debounce.js.map +1 -1
- package/esm/util/detectBrowser.d.ts +2 -0
- package/esm/util/detectBrowser.js +4 -0
- package/esm/util/detectBrowser.js.map +1 -0
- package/esm/util/focus-boundary/FocusBoundary.d.ts +44 -0
- package/esm/util/focus-boundary/FocusBoundary.js +329 -0
- package/esm/util/focus-boundary/FocusBoundary.js.map +1 -0
- package/esm/util/focus-guards/FocusGuards.d.ts +8 -0
- package/esm/util/focus-guards/FocusGuards.js +31 -0
- package/esm/util/focus-guards/FocusGuards.js.map +1 -0
- package/esm/util/hooks/useEventCallback.js.map +1 -0
- package/esm/{overlays/overlay → util}/hooks/useLatestRef.js +1 -1
- package/esm/util/hooks/useLatestRef.js.map +1 -0
- package/esm/util/hooks/useRefWithInit.js.map +1 -0
- package/esm/util/hooks/useTimeout.d.ts +16 -0
- package/esm/util/hooks/useTimeout.js +45 -0
- package/esm/util/hooks/useTimeout.js.map +1 -0
- package/esm/util/link-anchor/LinkAnchor.js +6 -7
- package/esm/util/link-anchor/LinkAnchor.js.map +1 -1
- package/esm/util/owner.d.ts +29 -0
- package/esm/util/owner.js +35 -0
- package/esm/util/owner.js.map +1 -0
- package/package.json +8 -8
- package/src/copybutton/CopyButton.tsx +5 -17
- package/src/date/date-utils/dropdown-options.test.ts +37 -9
- package/src/date/date-utils/dropdown-options.ts +23 -12
- package/src/date/datepicker/parts/DatePicker.Months.tsx +8 -2
- package/src/form/combobox/Combobox.tsx +0 -4
- package/src/form/combobox/ComboboxWrapper.tsx +0 -3
- package/src/form/combobox/FilteredOptions/FilteredOptions.tsx +65 -45
- package/src/form/combobox/FilteredOptions/useVirtualFocus.ts +1 -0
- package/src/form/combobox/Input/Input.context.tsx +5 -0
- package/src/form/combobox/Input/InputController.tsx +2 -1
- package/src/form/file-upload/parts/item/utils/format-file-size.test.ts +2 -2
- package/src/help-text/HelpText.tsx +3 -2
- package/src/help-text/HelpTextIcon.tsx +2 -12
- package/src/layout/page/parts/PageBlock.tsx +9 -2
- package/src/modal/ModalUtils.ts +7 -4
- package/src/overlays/dismissablelayer/DismissableLayer.tsx +9 -18
- package/src/overlays/dismissablelayer/util/usePointerDownOutside.ts +5 -4
- package/src/overlays/floating-menu/Menu.tsx +13 -9
- package/src/overlays/floating-menu/parts/RovingFocus.tsx +3 -3
- package/src/overlays/overlay/hooks/useAnimationsFinished.ts +1 -1
- package/src/overlays/overlay/hooks/useOpenChangeAnimationComplete.ts +2 -2
- package/src/progress-bar/ProgressBar.tsx +12 -10
- package/src/table/AnimateHeight.tsx +12 -15
- package/src/tabs/parts/tablist/useScrollButtons.ts +4 -3
- package/src/util/TextareaAutoSize.tsx +1 -9
- package/src/util/create-context.tsx +0 -1
- package/src/util/debounce.ts +7 -8
- package/src/util/detectBrowser.ts +5 -0
- package/src/util/focus-boundary/FocusBoundary.tsx +453 -0
- package/src/util/focus-guards/FocusGuards.tsx +56 -0
- package/src/{overlays/overlay → util}/hooks/useLatestRef.ts +1 -1
- package/src/util/hooks/useTimeout.ts +54 -0
- package/src/util/link-anchor/LinkAnchor.tsx +7 -6
- package/src/util/owner.ts +35 -0
- package/cjs/overlays/floating-menu/parts/FocusScope.d.ts +0 -22
- package/cjs/overlays/floating-menu/parts/FocusScope.js +0 -98
- package/cjs/overlays/floating-menu/parts/FocusScope.js.map +0 -1
- package/cjs/overlays/overlay/hooks/useEventCallback.js.map +0 -1
- package/cjs/overlays/overlay/hooks/useLatestRef.js.map +0 -1
- package/cjs/overlays/overlay/hooks/useRefWithInit.js.map +0 -1
- package/esm/overlays/floating-menu/parts/FocusScope.d.ts +0 -22
- package/esm/overlays/floating-menu/parts/FocusScope.js +0 -62
- package/esm/overlays/floating-menu/parts/FocusScope.js.map +0 -1
- package/esm/overlays/overlay/hooks/useEventCallback.js.map +0 -1
- package/esm/overlays/overlay/hooks/useLatestRef.js.map +0 -1
- package/esm/overlays/overlay/hooks/useRefWithInit.js.map +0 -1
- package/src/overlays/floating-menu/parts/FocusScope.tsx +0 -83
- /package/cjs/{overlays/overlay → util}/hooks/useEventCallback.d.ts +0 -0
- /package/cjs/{overlays/overlay → util}/hooks/useEventCallback.js +0 -0
- /package/cjs/{overlays/overlay → util}/hooks/useLatestRef.d.ts +0 -0
- /package/cjs/{overlays/overlay → util}/hooks/useRefWithInit.d.ts +0 -0
- /package/cjs/{overlays/overlay → util}/hooks/useRefWithInit.js +0 -0
- /package/esm/{overlays/overlay → util}/hooks/useEventCallback.d.ts +0 -0
- /package/esm/{overlays/overlay → util}/hooks/useEventCallback.js +0 -0
- /package/esm/{overlays/overlay → util}/hooks/useLatestRef.d.ts +0 -0
- /package/esm/{overlays/overlay → util}/hooks/useRefWithInit.d.ts +0 -0
- /package/esm/{overlays/overlay → util}/hooks/useRefWithInit.js +0 -0
- /package/src/{overlays/overlay → util}/hooks/useEventCallback.ts +0 -0
- /package/src/{overlays/overlay → util}/hooks/useRefWithInit.ts +0 -0
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
ButtonHTMLAttributes,
|
|
3
|
-
forwardRef,
|
|
4
|
-
useEffect,
|
|
5
|
-
useRef,
|
|
6
|
-
useState,
|
|
7
|
-
} from "react";
|
|
1
|
+
import React, { ButtonHTMLAttributes, forwardRef, useState } from "react";
|
|
8
2
|
import { CheckmarkIcon, FilesIcon } from "@navikt/aksel-icons";
|
|
9
3
|
import { Button, ButtonProps } from "../button";
|
|
10
4
|
import { useRenameCSS, useThemeInternal } from "../theme/Theme";
|
|
11
5
|
import { Label } from "../typography";
|
|
12
6
|
import { composeEventHandlers } from "../util/composeEventHandlers";
|
|
13
7
|
import copy from "../util/copy";
|
|
8
|
+
import { useTimeout } from "../util/hooks/useTimeout";
|
|
14
9
|
import { useI18n } from "../util/i18n/i18n.hooks";
|
|
15
10
|
|
|
16
11
|
export interface CopyButtonProps
|
|
@@ -94,29 +89,22 @@ export const CopyButton = forwardRef<HTMLButtonElement, CopyButtonProps>(
|
|
|
94
89
|
ref,
|
|
95
90
|
) => {
|
|
96
91
|
const [active, setActive] = useState(false);
|
|
97
|
-
const timeoutRef = useRef<number>(undefined);
|
|
98
92
|
const translate = useI18n("CopyButton");
|
|
93
|
+
const timeout = useTimeout();
|
|
99
94
|
|
|
100
95
|
const { cn } = useRenameCSS();
|
|
101
96
|
|
|
102
97
|
const themeContext = useThemeInternal(false);
|
|
103
98
|
|
|
104
|
-
useEffect(() => {
|
|
105
|
-
return () => {
|
|
106
|
-
timeoutRef.current && clearTimeout(timeoutRef.current);
|
|
107
|
-
};
|
|
108
|
-
}, []);
|
|
109
|
-
|
|
110
99
|
const handleClick = () => {
|
|
111
|
-
timeoutRef.current && clearTimeout(timeoutRef.current);
|
|
112
100
|
copy(copyText);
|
|
113
101
|
setActive(true);
|
|
114
102
|
onActiveChange?.(true);
|
|
115
103
|
|
|
116
|
-
|
|
104
|
+
timeout.start(activeDuration, () => {
|
|
117
105
|
setActive(false);
|
|
118
106
|
onActiveChange?.(false);
|
|
119
|
-
}
|
|
107
|
+
});
|
|
120
108
|
};
|
|
121
109
|
|
|
122
110
|
const activeString = activeText || translate("activeText");
|
|
@@ -4,19 +4,27 @@ import { getMonthOptions, getYearOptions } from "./dropdown-options";
|
|
|
4
4
|
|
|
5
5
|
describe("getYearOptions", () => {
|
|
6
6
|
test("should return undefined if navStart is undefined", () => {
|
|
7
|
-
const result = getYearOptions(
|
|
7
|
+
const result = getYearOptions({
|
|
8
|
+
navStart: undefined,
|
|
9
|
+
navEnd: new Date(),
|
|
10
|
+
locale: nb,
|
|
11
|
+
});
|
|
8
12
|
expect(result).toBeUndefined();
|
|
9
13
|
});
|
|
10
14
|
|
|
11
15
|
test("should return undefined if navEnd is undefined", () => {
|
|
12
|
-
const result = getYearOptions(
|
|
16
|
+
const result = getYearOptions({
|
|
17
|
+
navStart: new Date(),
|
|
18
|
+
navEnd: undefined,
|
|
19
|
+
locale: nb,
|
|
20
|
+
});
|
|
13
21
|
expect(result).toBeUndefined();
|
|
14
22
|
});
|
|
15
23
|
|
|
16
24
|
test("should return the correct year options within the interval", () => {
|
|
17
25
|
const navStart = new Date(2020, 0, 1); // Januar 1, 2020
|
|
18
26
|
const navEnd = new Date(2022, 11, 31); // Desember 31, 2022
|
|
19
|
-
const result = getYearOptions(navStart, navEnd, nb);
|
|
27
|
+
const result = getYearOptions({ navStart, navEnd, locale: nb });
|
|
20
28
|
|
|
21
29
|
const expected = [
|
|
22
30
|
{ value: 2020, label: "2020", disabled: false },
|
|
@@ -30,7 +38,7 @@ describe("getYearOptions", () => {
|
|
|
30
38
|
test("should return the correct year options for a single year", () => {
|
|
31
39
|
const navStart = new Date(2021, 0, 1); // Januar 1, 2021
|
|
32
40
|
const navEnd = new Date(2021, 11, 31); // Desember 31, 2021
|
|
33
|
-
const result = getYearOptions(navStart, navEnd, nb);
|
|
41
|
+
const result = getYearOptions({ navStart, navEnd, locale: nb });
|
|
34
42
|
|
|
35
43
|
const expected = [{ value: 2021, label: "2021", disabled: false }];
|
|
36
44
|
|
|
@@ -40,7 +48,7 @@ describe("getYearOptions", () => {
|
|
|
40
48
|
test("should return the correct year options when navStart and navEnd are the same date", () => {
|
|
41
49
|
const navStart = new Date(2021, 0, 1); // Januar 1, 2021
|
|
42
50
|
const navEnd = new Date(2021, 0, 1); // Januar 1, 2021
|
|
43
|
-
const result = getYearOptions(navStart, navEnd, nb);
|
|
51
|
+
const result = getYearOptions({ navStart, navEnd, locale: nb });
|
|
44
52
|
|
|
45
53
|
const expected = [{ value: 2021, label: "2021", disabled: false }];
|
|
46
54
|
|
|
@@ -51,7 +59,12 @@ describe("getYearOptions", () => {
|
|
|
51
59
|
describe("getMonthOptions", () => {
|
|
52
60
|
test("should return the correct month options for the given year", () => {
|
|
53
61
|
const displayMonth = new Date(2021, 0, 1); // Januar 1, 2021
|
|
54
|
-
const result = getMonthOptions(
|
|
62
|
+
const result = getMonthOptions({
|
|
63
|
+
displayMonth,
|
|
64
|
+
navStart: undefined,
|
|
65
|
+
navEnd: undefined,
|
|
66
|
+
locale: nb,
|
|
67
|
+
});
|
|
55
68
|
|
|
56
69
|
const expected = [
|
|
57
70
|
{ value: 0, label: "januar", disabled: false },
|
|
@@ -74,7 +87,12 @@ describe("getMonthOptions", () => {
|
|
|
74
87
|
test("should disable months before navStart", () => {
|
|
75
88
|
const displayMonth = new Date(2021, 0, 1); // Januar 1, 2021
|
|
76
89
|
const navStart = new Date(2021, 5, 1); // Juni 1, 2021
|
|
77
|
-
const result = getMonthOptions(
|
|
90
|
+
const result = getMonthOptions({
|
|
91
|
+
displayMonth,
|
|
92
|
+
navStart,
|
|
93
|
+
navEnd: undefined,
|
|
94
|
+
locale: nb,
|
|
95
|
+
});
|
|
78
96
|
|
|
79
97
|
const expected = [
|
|
80
98
|
{ value: 0, label: "januar", disabled: true },
|
|
@@ -97,7 +115,12 @@ describe("getMonthOptions", () => {
|
|
|
97
115
|
test("should disable months after navEnd", () => {
|
|
98
116
|
const displayMonth = new Date(2021, 0, 1); // Januar 1, 2021
|
|
99
117
|
const navEnd = new Date(2021, 5, 1); // Juni 1, 2021
|
|
100
|
-
const result = getMonthOptions(
|
|
118
|
+
const result = getMonthOptions({
|
|
119
|
+
displayMonth,
|
|
120
|
+
navStart: undefined,
|
|
121
|
+
navEnd,
|
|
122
|
+
locale: nb,
|
|
123
|
+
});
|
|
101
124
|
|
|
102
125
|
const expected = [
|
|
103
126
|
{ value: 0, label: "januar", disabled: false },
|
|
@@ -121,7 +144,12 @@ describe("getMonthOptions", () => {
|
|
|
121
144
|
const displayMonth = new Date(2021, 0, 1); // Januar 1, 2021
|
|
122
145
|
const navStart = new Date(2021, 3, 1); // April 1, 2021
|
|
123
146
|
const navEnd = new Date(2021, 8, 1); // September 1, 2021
|
|
124
|
-
const result = getMonthOptions(
|
|
147
|
+
const result = getMonthOptions({
|
|
148
|
+
displayMonth,
|
|
149
|
+
navStart,
|
|
150
|
+
navEnd,
|
|
151
|
+
locale: nb,
|
|
152
|
+
});
|
|
125
153
|
|
|
126
154
|
const expected = [
|
|
127
155
|
{ value: 0, label: "januar", disabled: true },
|
|
@@ -13,12 +13,17 @@ import {
|
|
|
13
13
|
} from "date-fns";
|
|
14
14
|
|
|
15
15
|
/** Return the months to show in the dropdown. */
|
|
16
|
-
export function getMonthOptions(
|
|
17
|
-
displayMonth
|
|
18
|
-
navStart
|
|
19
|
-
navEnd
|
|
20
|
-
locale
|
|
21
|
-
|
|
16
|
+
export function getMonthOptions({
|
|
17
|
+
displayMonth,
|
|
18
|
+
navStart,
|
|
19
|
+
navEnd,
|
|
20
|
+
locale,
|
|
21
|
+
}: {
|
|
22
|
+
displayMonth: Date;
|
|
23
|
+
navStart: Date | undefined;
|
|
24
|
+
navEnd: Date | undefined;
|
|
25
|
+
locale: Locale;
|
|
26
|
+
}):
|
|
22
27
|
| {
|
|
23
28
|
value: number;
|
|
24
29
|
label: string;
|
|
@@ -31,7 +36,9 @@ export function getMonthOptions(
|
|
|
31
36
|
});
|
|
32
37
|
|
|
33
38
|
const options = months.map((month) => {
|
|
34
|
-
const label = format(month, "LLLL", {
|
|
39
|
+
const label = format(month, "LLLL", {
|
|
40
|
+
locale,
|
|
41
|
+
}).replace(".", "");
|
|
35
42
|
const value = getMonth(month);
|
|
36
43
|
const disabled =
|
|
37
44
|
(navStart && month < startOfMonth(navStart)) ||
|
|
@@ -44,11 +51,15 @@ export function getMonthOptions(
|
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
/** Return the years to show in the dropdown. */
|
|
47
|
-
export function getYearOptions(
|
|
48
|
-
navStart
|
|
49
|
-
navEnd
|
|
50
|
-
locale
|
|
51
|
-
|
|
54
|
+
export function getYearOptions({
|
|
55
|
+
navStart,
|
|
56
|
+
navEnd,
|
|
57
|
+
locale,
|
|
58
|
+
}: {
|
|
59
|
+
navStart: Date | undefined;
|
|
60
|
+
navEnd: Date | undefined;
|
|
61
|
+
locale: Locale;
|
|
62
|
+
}):
|
|
52
63
|
| {
|
|
53
64
|
value: number;
|
|
54
65
|
label: string;
|
|
@@ -69,8 +69,14 @@ const DatePickerMonths = ({
|
|
|
69
69
|
today: dayPickerProps.today,
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
const months = getMonthOptions(
|
|
73
|
-
|
|
72
|
+
const months = getMonthOptions({
|
|
73
|
+
displayMonth: calendarMonth.date,
|
|
74
|
+
navStart,
|
|
75
|
+
navEnd,
|
|
76
|
+
locale,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const dropdownYears = getYearOptions({ navStart, navEnd, locale });
|
|
74
80
|
|
|
75
81
|
return (
|
|
76
82
|
<div {...omit(rest, ["displayIndex"])}>
|
|
@@ -5,7 +5,6 @@ import { BodyShort, ErrorMessage, Label } from "../../typography";
|
|
|
5
5
|
import { ReadOnlyIconWithTitle } from "../ReadOnlyIcon";
|
|
6
6
|
import ComboboxWrapper from "./ComboboxWrapper";
|
|
7
7
|
import FilteredOptions from "./FilteredOptions/FilteredOptions";
|
|
8
|
-
import { useFilteredOptionsContext } from "./FilteredOptions/filteredOptionsContext";
|
|
9
8
|
import { useInputContext } from "./Input/Input.context";
|
|
10
9
|
import { InputController } from "./Input/InputController";
|
|
11
10
|
import { ComboboxProps } from "./types";
|
|
@@ -21,8 +20,6 @@ export const Combobox = forwardRef<
|
|
|
21
20
|
|
|
22
21
|
const { cn } = useRenameCSS();
|
|
23
22
|
|
|
24
|
-
const { toggleIsListOpen } = useFilteredOptionsContext();
|
|
25
|
-
|
|
26
23
|
const {
|
|
27
24
|
error,
|
|
28
25
|
errorId,
|
|
@@ -41,7 +38,6 @@ export const Combobox = forwardRef<
|
|
|
41
38
|
hasError={hasError}
|
|
42
39
|
inputProps={inputProps}
|
|
43
40
|
inputSize={size}
|
|
44
|
-
toggleIsListOpen={toggleIsListOpen}
|
|
45
41
|
>
|
|
46
42
|
<Label
|
|
47
43
|
htmlFor={inputProps.id}
|
|
@@ -11,7 +11,6 @@ type ComboboxWrapperProps = {
|
|
|
11
11
|
};
|
|
12
12
|
readOnly?: boolean;
|
|
13
13
|
inputSize: string;
|
|
14
|
-
toggleIsListOpen: (isListOpen: boolean) => void;
|
|
15
14
|
};
|
|
16
15
|
|
|
17
16
|
const ComboboxWrapper = ({
|
|
@@ -20,7 +19,6 @@ const ComboboxWrapper = ({
|
|
|
20
19
|
hasError,
|
|
21
20
|
inputProps,
|
|
22
21
|
inputSize,
|
|
23
|
-
toggleIsListOpen,
|
|
24
22
|
}: ComboboxWrapperProps) => {
|
|
25
23
|
const { cn } = useRenameCSS();
|
|
26
24
|
const { toggleOpenButtonRef, clearInput, readOnly } = useInputContext();
|
|
@@ -39,7 +37,6 @@ const ComboboxWrapper = ({
|
|
|
39
37
|
|
|
40
38
|
function onBlurWrapper(event: React.FocusEvent<HTMLDivElement>) {
|
|
41
39
|
if (!wrapperRef.current?.contains(event.relatedTarget)) {
|
|
42
|
-
toggleIsListOpen(false);
|
|
43
40
|
setHasFocusWithin(false);
|
|
44
41
|
clearInput(event);
|
|
45
42
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
1
|
+
import React, { useRef, useState } from "react";
|
|
2
|
+
import { DismissableLayer } from "../../../overlays/dismissablelayer/DismissableLayer";
|
|
2
3
|
import { Floating } from "../../../overlays/floating/Floating";
|
|
3
4
|
import { useRenameCSS, useThemeInternal } from "../../../theme/Theme";
|
|
4
5
|
import { useClientLayoutEffect } from "../../../util";
|
|
@@ -17,6 +18,7 @@ const FilteredOptions = () => {
|
|
|
17
18
|
const themeContext = useThemeInternal(false);
|
|
18
19
|
const {
|
|
19
20
|
inputProps: { id },
|
|
21
|
+
anchorRef,
|
|
20
22
|
} = useInputContext();
|
|
21
23
|
|
|
22
24
|
const {
|
|
@@ -27,9 +29,12 @@ const FilteredOptions = () => {
|
|
|
27
29
|
setFilteredOptionsRef,
|
|
28
30
|
isMouseLastUsedInputDevice,
|
|
29
31
|
isValueNew,
|
|
32
|
+
toggleIsListOpen,
|
|
30
33
|
} = useFilteredOptionsContext();
|
|
31
34
|
const [localOpen, setLocalOpen] = useState(isListOpen);
|
|
32
35
|
|
|
36
|
+
const floatingRef = useRef<HTMLDivElement | null>(null);
|
|
37
|
+
|
|
33
38
|
/**
|
|
34
39
|
* This is a dirty hack to make the positioning-logic in Floating base the "flip" on the static 290px max-height,
|
|
35
40
|
* instead of the dynamic one based on available space. Without this, the list won't flip to top when there's
|
|
@@ -53,53 +58,68 @@ const FilteredOptions = () => {
|
|
|
53
58
|
const height = themeContext?.isDarkside ? "316px" : "290px";
|
|
54
59
|
|
|
55
60
|
return (
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
enabled={isListOpen}
|
|
67
|
-
style={{
|
|
68
|
-
maxHeight: localOpen
|
|
69
|
-
? `min(${height}, var(--ac-floating-available-height))`
|
|
70
|
-
: `${height}`,
|
|
61
|
+
<DismissableLayer
|
|
62
|
+
asChild
|
|
63
|
+
safeZone={{
|
|
64
|
+
anchor: anchorRef,
|
|
65
|
+
dismissable: floatingRef.current,
|
|
66
|
+
}}
|
|
67
|
+
onDismiss={() => localOpen && toggleIsListOpen(false)}
|
|
68
|
+
onEscapeKeyDown={(event) => {
|
|
69
|
+
/* We handle this manually in Input */
|
|
70
|
+
event.preventDefault();
|
|
71
71
|
}}
|
|
72
|
-
|
|
72
|
+
enabled={localOpen}
|
|
73
73
|
>
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
74
|
+
<Floating.Content
|
|
75
|
+
ref={floatingRef}
|
|
76
|
+
className={cn("navds-combobox__list", {
|
|
77
|
+
"navds-combobox__list--closed": !isListOpen,
|
|
78
|
+
"navds-combobox__list--with-hover": isMouseLastUsedInputDevice,
|
|
79
|
+
})}
|
|
80
|
+
id={filteredOptionsUtil.getFilteredOptionsId(id)}
|
|
81
|
+
tabIndex={-1}
|
|
82
|
+
sideOffset={8}
|
|
83
|
+
side="bottom"
|
|
84
|
+
fallbackPlacements={["top"]}
|
|
85
|
+
enabled={isListOpen}
|
|
86
|
+
style={{
|
|
87
|
+
maxHeight: localOpen
|
|
88
|
+
? `min(${height}, var(--ac-floating-available-height))`
|
|
89
|
+
: `${height}`,
|
|
90
|
+
}}
|
|
91
|
+
autoUpdateWhileMounted={false}
|
|
92
|
+
>
|
|
93
|
+
{shouldRenderNonSelectables && (
|
|
94
|
+
<div
|
|
95
|
+
className={cn("navds-combobox__list_non-selectables")}
|
|
96
|
+
role="status"
|
|
97
|
+
>
|
|
98
|
+
{isMultiSelect && maxSelected.limit && <MaxSelectedMessage />}
|
|
99
|
+
{isLoading && <LoadingMessage />}
|
|
100
|
+
{!isLoading && filteredOptions.length === 0 && !allowNewValues && (
|
|
101
|
+
<NoSearchHitsMessage />
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
)}
|
|
86
105
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
{shouldRenderFilteredOptionsList && (
|
|
107
|
+
/* biome-ignore lint/a11y/useFocusableInteractive: Interaction is not handeled by listbox itself. */
|
|
108
|
+
<ul
|
|
109
|
+
ref={setFilteredOptionsRef}
|
|
110
|
+
role="listbox"
|
|
111
|
+
className={cn("navds-combobox__list-options")}
|
|
112
|
+
>
|
|
113
|
+
{isValueNew && !maxSelected.isLimitReached && allowNewValues && (
|
|
114
|
+
<AddNewOption />
|
|
115
|
+
)}
|
|
116
|
+
{filteredOptions.map((option) => (
|
|
117
|
+
<FilteredOptionsItem key={option.value} option={option} />
|
|
118
|
+
))}
|
|
119
|
+
</ul>
|
|
120
|
+
)}
|
|
121
|
+
</Floating.Content>
|
|
122
|
+
</DismissableLayer>
|
|
103
123
|
);
|
|
104
124
|
};
|
|
105
125
|
|
|
@@ -18,6 +18,8 @@ interface InputContextValue extends FormFieldType {
|
|
|
18
18
|
toggleOpenButtonRef: React.MutableRefObject<HTMLDivElement | null>;
|
|
19
19
|
hideCaret: boolean;
|
|
20
20
|
setHideCaret: React.Dispatch<React.SetStateAction<boolean>>;
|
|
21
|
+
anchorRef: HTMLDivElement | null;
|
|
22
|
+
setAnchorRef: React.Dispatch<React.SetStateAction<HTMLDivElement | null>>;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
const [InputContextProvider, useInputContext] =
|
|
@@ -75,6 +77,7 @@ const InputProvider = ({ children, value: props }: Props) => {
|
|
|
75
77
|
const toggleOpenButtonRef = useRef<HTMLDivElement>(null);
|
|
76
78
|
const [internalValue, setInternalValue] = useState<string>(defaultValue);
|
|
77
79
|
const [hideCaret, setHideCaret] = useState(false);
|
|
80
|
+
const [anchorRef, setAnchorRef] = useState<HTMLDivElement | null>(null);
|
|
78
81
|
|
|
79
82
|
const value = useMemo(
|
|
80
83
|
() => String(externalValue ?? internalValue),
|
|
@@ -127,6 +130,8 @@ const InputProvider = ({ children, value: props }: Props) => {
|
|
|
127
130
|
toggleOpenButtonRef,
|
|
128
131
|
hideCaret,
|
|
129
132
|
setHideCaret,
|
|
133
|
+
anchorRef,
|
|
134
|
+
setAnchorRef,
|
|
130
135
|
};
|
|
131
136
|
|
|
132
137
|
return (
|
|
@@ -49,6 +49,7 @@ export const InputController = forwardRef<
|
|
|
49
49
|
inputRef,
|
|
50
50
|
toggleOpenButtonRef,
|
|
51
51
|
readOnly,
|
|
52
|
+
setAnchorRef,
|
|
52
53
|
} = useInputContext();
|
|
53
54
|
|
|
54
55
|
const { activeDecendantId, toggleIsListOpen } = useFilteredOptionsContext();
|
|
@@ -57,7 +58,7 @@ export const InputController = forwardRef<
|
|
|
57
58
|
const mergedInputRef = useMergeRefs(inputRef, ref);
|
|
58
59
|
|
|
59
60
|
return (
|
|
60
|
-
<Floating.Anchor asChild>
|
|
61
|
+
<Floating.Anchor asChild ref={setAnchorRef}>
|
|
61
62
|
<div
|
|
62
63
|
className={cn("navds-combobox__wrapper-inner navds-text-field__input", {
|
|
63
64
|
"navds-combobox__wrapper-inner--virtually-unfocused":
|
|
@@ -60,13 +60,13 @@ describe("format-file-size", () => {
|
|
|
60
60
|
|
|
61
61
|
function createLargeMockFile(sizeInBytes: number): File {
|
|
62
62
|
const chunkSize = 1024 * 1024; // 1MB chunk size
|
|
63
|
-
const chunks:
|
|
63
|
+
const chunks: ArrayBuffer[] = [];
|
|
64
64
|
|
|
65
65
|
for (let i = 0; i < sizeInBytes; i += chunkSize) {
|
|
66
66
|
const size = Math.min(chunkSize, sizeInBytes - i);
|
|
67
67
|
const chunk = new Uint8Array(size);
|
|
68
68
|
chunk.fill("a".charCodeAt(0));
|
|
69
|
-
chunks.push(chunk);
|
|
69
|
+
chunks.push(chunk.buffer);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const blob = new Blob(chunks, { type: "text/plain" });
|
|
@@ -70,9 +70,10 @@ export const HelpText = forwardRef<HTMLButtonElement, HelpTextProps>(
|
|
|
70
70
|
className={cn(className, "navds-help-text__button")}
|
|
71
71
|
type="button"
|
|
72
72
|
aria-expanded={open}
|
|
73
|
+
aria-label={titleWithFallback}
|
|
73
74
|
>
|
|
74
|
-
<HelpTextIcon
|
|
75
|
-
<HelpTextIcon filled
|
|
75
|
+
<HelpTextIcon />
|
|
76
|
+
<HelpTextIcon filled />
|
|
76
77
|
</button>
|
|
77
78
|
<Popover
|
|
78
79
|
onClose={() => setOpen(false)}
|
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { useRenameCSS } from "../theme/Theme";
|
|
3
|
-
import { useId } from "../util/hooks";
|
|
4
3
|
|
|
5
|
-
export const HelpTextIcon = ({
|
|
6
|
-
title,
|
|
7
|
-
filled = false,
|
|
8
|
-
}: {
|
|
9
|
-
title: string;
|
|
10
|
-
filled?: boolean;
|
|
11
|
-
}) => {
|
|
4
|
+
export const HelpTextIcon = ({ filled = false }: { filled?: boolean }) => {
|
|
12
5
|
const { cn } = useRenameCSS();
|
|
13
6
|
|
|
14
|
-
let titleId: string | undefined = useId();
|
|
15
|
-
titleId = title ? `title-${titleId}` : undefined;
|
|
16
7
|
return (
|
|
17
8
|
<svg
|
|
18
9
|
width="1em"
|
|
@@ -22,12 +13,11 @@ export const HelpTextIcon = ({
|
|
|
22
13
|
xmlns="http://www.w3.org/2000/svg"
|
|
23
14
|
focusable={false}
|
|
24
15
|
role="img"
|
|
25
|
-
aria-labelledby={titleId}
|
|
26
16
|
className={cn("navds-help-text__icon", {
|
|
27
17
|
"navds-help-text__icon--filled": filled,
|
|
28
18
|
})}
|
|
19
|
+
aria-hidden
|
|
29
20
|
>
|
|
30
|
-
{title ? <title id={titleId}>{title}</title> : null}
|
|
31
21
|
<circle
|
|
32
22
|
cx="12"
|
|
33
23
|
cy="12"
|
|
@@ -7,20 +7,27 @@ export const widths = ["text", "md", "lg", "xl", "2xl"] as const;
|
|
|
7
7
|
export interface PageBlockProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
8
8
|
/**
|
|
9
9
|
* Predefined max-width
|
|
10
|
-
*
|
|
10
|
+
*
|
|
11
11
|
* text: 576px + dynamic gutters
|
|
12
|
+
*
|
|
12
13
|
* md: 768px
|
|
14
|
+
*
|
|
13
15
|
* lg: 1024px
|
|
16
|
+
*
|
|
14
17
|
* xl: 1280px
|
|
18
|
+
*
|
|
15
19
|
* 2xl: 1440px
|
|
20
|
+
*
|
|
16
21
|
* @default max-width: 100%;
|
|
17
22
|
*/
|
|
18
23
|
width?: (typeof widths)[number];
|
|
19
24
|
/**
|
|
20
25
|
* Adds a standardised responsive padding-inline
|
|
21
|
-
*
|
|
26
|
+
*
|
|
22
27
|
* 3rem on > md
|
|
28
|
+
*
|
|
23
29
|
* 1rem on < md
|
|
30
|
+
*
|
|
24
31
|
* @default false
|
|
25
32
|
*/
|
|
26
33
|
gutters?: boolean;
|
package/src/modal/ModalUtils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { ownerDocument } from "../util/owner";
|
|
2
3
|
import type { ModalProps } from "./types";
|
|
3
4
|
|
|
4
5
|
export interface MouseCoordinates {
|
|
@@ -45,16 +46,18 @@ export function useBodyScrollLock(
|
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
const ownerDoc = ownerDocument(modalRef.current);
|
|
50
|
+
|
|
48
51
|
// In case `open` is true initially
|
|
49
52
|
if (modalRef.current.open) {
|
|
50
|
-
|
|
53
|
+
ownerDoc.body.classList.add(BODY_CLASS, BODY_CLASS_LEGACY);
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
const observer = new MutationObserver(() => {
|
|
54
57
|
if (modalRef.current?.open) {
|
|
55
|
-
|
|
58
|
+
ownerDoc.body.classList.add(BODY_CLASS, BODY_CLASS_LEGACY);
|
|
56
59
|
} else {
|
|
57
|
-
|
|
60
|
+
ownerDoc.body.classList.remove(BODY_CLASS, BODY_CLASS_LEGACY);
|
|
58
61
|
}
|
|
59
62
|
});
|
|
60
63
|
|
|
@@ -66,7 +69,7 @@ export function useBodyScrollLock(
|
|
|
66
69
|
return () => {
|
|
67
70
|
observer.disconnect();
|
|
68
71
|
// In case modal is unmounted before it's closed
|
|
69
|
-
|
|
72
|
+
ownerDoc.body.classList.remove(BODY_CLASS, BODY_CLASS_LEGACY);
|
|
70
73
|
};
|
|
71
74
|
}, [modalRef, portalNode, isNested]);
|
|
72
75
|
}
|