@navikt/ds-react 7.2.0 → 7.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/cjs/accordion/AccordionHeader.js +1 -1
- package/cjs/accordion/AccordionHeader.js.map +1 -1
- package/cjs/alert/Alert.d.ts +0 -3
- package/cjs/alert/Alert.js +11 -17
- package/cjs/alert/Alert.js.map +1 -1
- package/cjs/chips/Removable.d.ts +5 -5
- package/cjs/chips/Removable.js +4 -2
- package/cjs/chips/Removable.js.map +1 -1
- package/cjs/collapsible/Collapsible.context.d.ts +1 -1
- package/cjs/date/datepicker/DatePicker.d.ts +2 -2
- package/cjs/date/monthpicker/MonthPicker.d.ts +2 -2
- package/cjs/dropdown/Menu/index.js +1 -1
- package/cjs/dropdown/Menu/index.js.map +1 -1
- package/cjs/form/checkbox/useCheckbox.js +3 -2
- package/cjs/form/checkbox/useCheckbox.js.map +1 -1
- package/cjs/form/combobox/ComboboxProvider.js +4 -1
- package/cjs/form/combobox/ComboboxProvider.js.map +1 -1
- package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js +1 -1
- package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
- package/cjs/form/combobox/FilteredOptions/useVirtualFocus.d.ts +3 -0
- package/cjs/form/combobox/FilteredOptions/useVirtualFocus.js +33 -10
- package/cjs/form/combobox/FilteredOptions/useVirtualFocus.js.map +1 -1
- package/cjs/form/combobox/Input/Input.js +23 -10
- package/cjs/form/combobox/Input/Input.js.map +1 -1
- package/cjs/form/file-upload/FileUpload.context.d.ts +1 -1
- package/cjs/form/radio/useRadio.js +3 -2
- package/cjs/form/radio/useRadio.js.map +1 -1
- package/cjs/form/search/Search.js +1 -1
- package/cjs/form/search/Search.js.map +1 -1
- package/cjs/form/switch/Switch.js +2 -1
- package/cjs/form/switch/Switch.js.map +1 -1
- package/cjs/index.d.ts +1 -0
- package/cjs/index.js +4 -2
- package/cjs/index.js.map +1 -1
- package/cjs/layout/base/BasePrimitive.d.ts +3 -0
- package/cjs/layout/base/BasePrimitive.js.map +1 -1
- package/cjs/layout/box/Box.d.ts +2 -2
- package/cjs/layout/box/Box.js.map +1 -1
- package/cjs/layout/grid/HGrid.d.ts +2 -2
- package/cjs/layout/grid/HGrid.js.map +1 -1
- package/cjs/layout/stack/Stack.d.ts +2 -2
- package/cjs/layout/stack/Stack.js.map +1 -1
- package/cjs/modal/ModalHeader.js +6 -1
- package/cjs/modal/ModalHeader.js.map +1 -1
- package/cjs/modal/dialog-polyfill.js +2 -2
- package/cjs/modal/dialog-polyfill.js.map +1 -1
- package/cjs/overlays/action-menu/ActionMenu.d.ts +310 -0
- package/cjs/overlays/action-menu/ActionMenu.js +227 -0
- package/cjs/overlays/action-menu/ActionMenu.js.map +1 -0
- package/cjs/overlays/action-menu/index.d.ts +1 -0
- package/cjs/overlays/action-menu/index.js +19 -0
- package/cjs/overlays/action-menu/index.js.map +1 -0
- package/cjs/overlays/floating/Floating.js +9 -10
- package/cjs/overlays/floating/Floating.js.map +1 -1
- package/cjs/overlays/floating/Floating.utils.d.ts +3 -5
- package/cjs/overlays/floating/Floating.utils.js +0 -2
- package/cjs/overlays/floating/Floating.utils.js.map +1 -1
- package/cjs/overlays/floating-menu/Menu.d.ts +15 -21
- package/cjs/overlays/floating-menu/Menu.js +119 -230
- package/cjs/overlays/floating-menu/Menu.js.map +1 -1
- package/cjs/overlays/floating-menu/parts/RovingFocus.d.ts +1 -1
- package/cjs/overlays/floating-menu/parts/RovingFocus.js +4 -4
- package/cjs/overlays/floating-menu/parts/RovingFocus.js.map +1 -1
- package/cjs/pagination/Pagination.d.ts +1 -6
- package/cjs/pagination/Pagination.js.map +1 -1
- package/cjs/provider/i18n/LanguageProvider.d.ts +3 -3
- package/cjs/stepper/context.d.ts +1 -1
- package/cjs/table/Body.d.ts +2 -4
- package/cjs/table/Body.js.map +1 -1
- package/cjs/table/ColumnHeader.d.ts +1 -2
- package/cjs/table/ColumnHeader.js.map +1 -1
- package/cjs/table/ExpandableRow.d.ts +1 -2
- package/cjs/table/ExpandableRow.js.map +1 -1
- package/cjs/table/Header.d.ts +2 -4
- package/cjs/table/Header.js.map +1 -1
- package/cjs/table/HeaderCell.d.ts +1 -2
- package/cjs/table/HeaderCell.js.map +1 -1
- package/cjs/table/Row.d.ts +1 -2
- package/cjs/table/Row.js.map +1 -1
- package/cjs/tabs/Tabs.context.d.ts +1 -1
- package/cjs/tabs/parts/tablist/useScrollButtons.js +1 -1
- package/cjs/tabs/parts/tablist/useScrollButtons.js.map +1 -1
- package/cjs/tabs/parts/tablist/useTabList.js +4 -4
- package/cjs/tabs/parts/tablist/useTabList.js.map +1 -1
- package/cjs/timeline/TimelineRow.js +9 -10
- package/cjs/timeline/TimelineRow.js.map +1 -1
- package/cjs/toggle-group/ToggleGroup.context.d.ts +1 -1
- package/cjs/toggle-group/parts/useToggleItem.js +4 -4
- package/cjs/toggle-group/parts/useToggleItem.js.map +1 -1
- package/cjs/util/TextareaAutoSize.js +2 -2
- package/cjs/util/TextareaAutoSize.js.map +1 -1
- package/cjs/util/hooks/descendants/descendant.js +1 -1
- package/cjs/util/hooks/descendants/descendant.js.map +1 -1
- package/cjs/util/hooks/descendants/useDescendant.js +1 -1
- package/cjs/util/hooks/descendants/useDescendant.js.map +1 -1
- package/cjs/util/i18n/get.d.ts +2 -2
- package/cjs/util/i18n/get.js.map +1 -1
- package/cjs/util/i18n/i18n.context.d.ts +2 -3
- package/cjs/util/i18n/i18n.context.js.map +1 -1
- package/cjs/util/i18n/i18n.types.d.ts +5 -9
- package/cjs/util/i18n/locales/en.d.ts +39 -0
- package/cjs/util/i18n/locales/en.js +41 -0
- package/cjs/util/i18n/locales/en.js.map +1 -0
- package/cjs/util/i18n/locales/nb.d.ts +14 -0
- package/cjs/util/i18n/locales/nb.js +14 -0
- package/cjs/util/i18n/locales/nb.js.map +1 -1
- package/cjs/util/i18n/locales/nn.d.ts +39 -0
- package/cjs/util/i18n/locales/nn.js +41 -0
- package/cjs/util/i18n/locales/nn.js.map +1 -0
- package/cjs/util/requireReactElement.d.ts +2 -0
- package/cjs/util/requireReactElement.js +22 -0
- package/cjs/util/requireReactElement.js.map +1 -0
- package/cjs/util/virtualfocus/Context.d.ts +1 -1
- package/cjs/util/virtualfocus/parts/VirtualFocusContent.d.ts +1 -2
- package/cjs/util/virtualfocus/parts/VirtualFocusContent.js.map +1 -1
- package/esm/accordion/AccordionHeader.js +1 -1
- package/esm/accordion/AccordionHeader.js.map +1 -1
- package/esm/alert/Alert.d.ts +0 -3
- package/esm/alert/Alert.js +11 -17
- package/esm/alert/Alert.js.map +1 -1
- package/esm/chips/Removable.d.ts +5 -5
- package/esm/chips/Removable.js +4 -2
- package/esm/chips/Removable.js.map +1 -1
- package/esm/collapsible/Collapsible.context.d.ts +1 -1
- package/esm/date/datepicker/DatePicker.d.ts +2 -2
- package/esm/date/monthpicker/MonthPicker.d.ts +2 -2
- package/esm/dropdown/Menu/index.js +1 -1
- package/esm/dropdown/Menu/index.js.map +1 -1
- package/esm/form/checkbox/useCheckbox.js +3 -2
- package/esm/form/checkbox/useCheckbox.js.map +1 -1
- package/esm/form/combobox/ComboboxProvider.js +4 -1
- package/esm/form/combobox/ComboboxProvider.js.map +1 -1
- package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js +1 -1
- package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
- package/esm/form/combobox/FilteredOptions/useVirtualFocus.d.ts +3 -0
- package/esm/form/combobox/FilteredOptions/useVirtualFocus.js +34 -11
- package/esm/form/combobox/FilteredOptions/useVirtualFocus.js.map +1 -1
- package/esm/form/combobox/Input/Input.js +23 -10
- package/esm/form/combobox/Input/Input.js.map +1 -1
- package/esm/form/file-upload/FileUpload.context.d.ts +1 -1
- package/esm/form/radio/useRadio.js +3 -2
- package/esm/form/radio/useRadio.js.map +1 -1
- package/esm/form/search/Search.js +1 -1
- package/esm/form/search/Search.js.map +1 -1
- package/esm/form/switch/Switch.js +2 -1
- package/esm/form/switch/Switch.js.map +1 -1
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/index.js.map +1 -1
- package/esm/layout/base/BasePrimitive.d.ts +3 -0
- package/esm/layout/base/BasePrimitive.js.map +1 -1
- package/esm/layout/box/Box.d.ts +2 -2
- package/esm/layout/box/Box.js.map +1 -1
- package/esm/layout/grid/HGrid.d.ts +2 -2
- package/esm/layout/grid/HGrid.js.map +1 -1
- package/esm/layout/stack/Stack.d.ts +2 -2
- package/esm/layout/stack/Stack.js.map +1 -1
- package/esm/modal/ModalHeader.js +6 -1
- package/esm/modal/ModalHeader.js.map +1 -1
- package/esm/modal/dialog-polyfill.js +2 -2
- package/esm/modal/dialog-polyfill.js.map +1 -1
- package/esm/overlays/action-menu/ActionMenu.d.ts +310 -0
- package/esm/overlays/action-menu/ActionMenu.js +197 -0
- package/esm/overlays/action-menu/ActionMenu.js.map +1 -0
- package/esm/overlays/action-menu/index.d.ts +1 -0
- package/esm/overlays/action-menu/index.js +3 -0
- package/esm/overlays/action-menu/index.js.map +1 -0
- package/esm/overlays/floating/Floating.js +9 -10
- package/esm/overlays/floating/Floating.js.map +1 -1
- package/esm/overlays/floating/Floating.utils.d.ts +3 -5
- package/esm/overlays/floating/Floating.utils.js +0 -2
- package/esm/overlays/floating/Floating.utils.js.map +1 -1
- package/esm/overlays/floating-menu/Menu.d.ts +15 -21
- package/esm/overlays/floating-menu/Menu.js +119 -230
- package/esm/overlays/floating-menu/Menu.js.map +1 -1
- package/esm/overlays/floating-menu/parts/RovingFocus.d.ts +1 -1
- package/esm/overlays/floating-menu/parts/RovingFocus.js +4 -4
- package/esm/overlays/floating-menu/parts/RovingFocus.js.map +1 -1
- package/esm/pagination/Pagination.d.ts +1 -6
- package/esm/pagination/Pagination.js.map +1 -1
- package/esm/provider/i18n/LanguageProvider.d.ts +3 -3
- package/esm/stepper/context.d.ts +1 -1
- package/esm/table/Body.d.ts +2 -4
- package/esm/table/Body.js.map +1 -1
- package/esm/table/ColumnHeader.d.ts +1 -2
- package/esm/table/ColumnHeader.js.map +1 -1
- package/esm/table/ExpandableRow.d.ts +1 -2
- package/esm/table/ExpandableRow.js.map +1 -1
- package/esm/table/Header.d.ts +2 -4
- package/esm/table/Header.js.map +1 -1
- package/esm/table/HeaderCell.d.ts +1 -2
- package/esm/table/HeaderCell.js.map +1 -1
- package/esm/table/Row.d.ts +1 -2
- package/esm/table/Row.js.map +1 -1
- package/esm/tabs/Tabs.context.d.ts +1 -1
- package/esm/tabs/parts/tablist/useScrollButtons.js +1 -1
- package/esm/tabs/parts/tablist/useScrollButtons.js.map +1 -1
- package/esm/tabs/parts/tablist/useTabList.js +4 -4
- package/esm/tabs/parts/tablist/useTabList.js.map +1 -1
- package/esm/timeline/TimelineRow.js +9 -10
- package/esm/timeline/TimelineRow.js.map +1 -1
- package/esm/toggle-group/ToggleGroup.context.d.ts +1 -1
- package/esm/toggle-group/parts/useToggleItem.js +4 -4
- package/esm/toggle-group/parts/useToggleItem.js.map +1 -1
- package/esm/util/TextareaAutoSize.js +2 -2
- package/esm/util/TextareaAutoSize.js.map +1 -1
- package/esm/util/hooks/descendants/descendant.js +1 -1
- package/esm/util/hooks/descendants/descendant.js.map +1 -1
- package/esm/util/hooks/descendants/useDescendant.js +1 -1
- package/esm/util/hooks/descendants/useDescendant.js.map +1 -1
- package/esm/util/i18n/get.d.ts +2 -2
- package/esm/util/i18n/get.js.map +1 -1
- package/esm/util/i18n/i18n.context.d.ts +2 -3
- package/esm/util/i18n/i18n.context.js.map +1 -1
- package/esm/util/i18n/i18n.types.d.ts +5 -9
- package/esm/util/i18n/locales/en.d.ts +39 -0
- package/esm/util/i18n/locales/en.js +39 -0
- package/esm/util/i18n/locales/en.js.map +1 -0
- package/esm/util/i18n/locales/nb.d.ts +14 -0
- package/esm/util/i18n/locales/nb.js +14 -0
- package/esm/util/i18n/locales/nb.js.map +1 -1
- package/esm/util/i18n/locales/nn.d.ts +39 -0
- package/esm/util/i18n/locales/nn.js +39 -0
- package/esm/util/i18n/locales/nn.js.map +1 -0
- package/esm/util/requireReactElement.d.ts +2 -0
- package/esm/util/requireReactElement.js +15 -0
- package/esm/util/requireReactElement.js.map +1 -0
- package/esm/util/virtualfocus/Context.d.ts +1 -1
- package/esm/util/virtualfocus/parts/VirtualFocusContent.d.ts +1 -2
- package/esm/util/virtualfocus/parts/VirtualFocusContent.js.map +1 -1
- package/package.json +15 -7
- package/src/accordion/AccordionHeader.tsx +0 -1
- package/src/alert/Alert.tsx +11 -20
- package/src/chips/Removable.tsx +13 -9
- package/src/date/datepicker/DatePicker.tsx +2 -2
- package/src/date/monthpicker/MonthPicker.tsx +2 -2
- package/src/dropdown/Menu/index.tsx +1 -1
- package/src/form/checkbox/Checkbox.test.tsx +2 -3
- package/src/form/checkbox/useCheckbox.ts +2 -2
- package/src/form/combobox/ComboboxProvider.tsx +9 -1
- package/src/form/combobox/FilteredOptions/filteredOptionsContext.tsx +1 -1
- package/src/form/combobox/FilteredOptions/useVirtualFocus.ts +42 -11
- package/src/form/combobox/Input/Input.tsx +19 -10
- package/src/form/combobox/__tests__/combobox.test.tsx +36 -0
- package/src/form/confirmation-panel/ConfirmationPanel.test.tsx +1 -2
- package/src/form/radio/Radio.test.tsx +4 -5
- package/src/form/radio/useRadio.ts +2 -2
- package/src/form/search/Search.tsx +1 -1
- package/src/form/switch/Switch.tsx +1 -1
- package/src/index.ts +1 -0
- package/src/layout/base/BasePrimitive.tsx +3 -0
- package/src/layout/box/Box.tsx +35 -36
- package/src/layout/grid/HGrid.tsx +26 -27
- package/src/layout/stack/Stack.tsx +53 -54
- package/src/modal/ModalHeader.tsx +6 -0
- package/src/modal/dialog-polyfill.ts +2 -2
- package/src/overlays/action-menu/ActionMenu.tsx +971 -0
- package/src/overlays/action-menu/index.ts +29 -0
- package/src/overlays/floating/Floating.tsx +6 -12
- package/src/overlays/floating/Floating.utils.ts +2 -5
- package/src/overlays/floating-menu/Menu.tsx +183 -332
- package/src/overlays/floating-menu/parts/RovingFocus.tsx +7 -7
- package/src/pagination/Pagination.tsx +4 -1
- package/src/pagination/steps.test.ts +15 -16
- package/src/provider/i18n/LanguageProvider.tsx +3 -3
- package/src/table/Body.tsx +4 -6
- package/src/table/ColumnHeader.tsx +3 -4
- package/src/table/ExpandableRow.tsx +3 -4
- package/src/table/Header.tsx +4 -6
- package/src/table/HeaderCell.tsx +3 -4
- package/src/table/Row.tsx +3 -4
- package/src/tabs/parts/tablist/useScrollButtons.ts +1 -1
- package/src/tabs/parts/tablist/useTabList.ts +4 -4
- package/src/timeline/TimelineRow.tsx +20 -21
- package/src/toggle-group/parts/useToggleItem.ts +4 -4
- package/src/util/TextareaAutoSize.tsx +2 -2
- package/src/util/hooks/descendants/descendant.ts +1 -1
- package/src/util/hooks/descendants/useDescendant.tsx +1 -1
- package/src/util/i18n/get.ts +3 -3
- package/src/util/i18n/i18n.context.ts +2 -3
- package/src/util/i18n/i18n.types.ts +7 -11
- package/src/util/i18n/locales/en.ts +40 -0
- package/src/util/i18n/locales/nb.ts +23 -1
- package/src/util/i18n/locales/nn.ts +40 -0
- package/src/util/i18n/locales.test.tsx +23 -0
- package/src/util/requireReactElement.ts +25 -0
- package/src/util/virtualfocus/parts/VirtualFocusContent.tsx +4 -2
- package/cjs/util/i18n/merge.d.ts +0 -2
- package/cjs/util/i18n/merge.js +0 -28
- package/cjs/util/i18n/merge.js.map +0 -1
- package/esm/util/i18n/merge.d.ts +0 -2
- package/esm/util/i18n/merge.js +0 -25
- package/esm/util/i18n/merge.js.map +0 -1
- package/src/util/i18n/merge.ts +0 -35
|
@@ -51,13 +51,21 @@ const ComboboxProvider = forwardRef<HTMLInputElement, ComboboxProps>(
|
|
|
51
51
|
value,
|
|
52
52
|
onChange,
|
|
53
53
|
onClear,
|
|
54
|
-
shouldAutocomplete,
|
|
54
|
+
shouldAutocomplete: externalShouldAutocomplete,
|
|
55
55
|
size,
|
|
56
56
|
...rest
|
|
57
57
|
} = props;
|
|
58
58
|
const options = mapToComboboxOptionArray(externalOptions) || [];
|
|
59
59
|
const filteredOptions = mapToComboboxOptionArray(externalFilteredOptions);
|
|
60
60
|
const selectedOptions = mapToComboboxOptionArray(externalSelectedOptions);
|
|
61
|
+
|
|
62
|
+
const userAgent =
|
|
63
|
+
typeof navigator === "undefined" ? "" : navigator.userAgent;
|
|
64
|
+
const isFirefoxOnAndroid =
|
|
65
|
+
userAgent.includes("Android") && userAgent.includes("Firefox/");
|
|
66
|
+
const shouldAutocomplete =
|
|
67
|
+
!isFirefoxOnAndroid && externalShouldAutocomplete;
|
|
68
|
+
|
|
61
69
|
return (
|
|
62
70
|
<InputContextProvider
|
|
63
71
|
value={{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
2
|
|
|
3
3
|
export type VirtualFocusType = {
|
|
4
4
|
activeElement: HTMLElement | undefined;
|
|
@@ -10,6 +10,9 @@ export type VirtualFocusType = {
|
|
|
10
10
|
moveFocusToElement: (id: string) => void;
|
|
11
11
|
moveFocusToTop: () => void;
|
|
12
12
|
moveFocusToBottom: () => void;
|
|
13
|
+
moveFocusUpBy: (numberOfElements: number) => void;
|
|
14
|
+
moveFocusDownBy: (numberOfElements: number) => void;
|
|
15
|
+
resetFocus: () => void;
|
|
13
16
|
};
|
|
14
17
|
|
|
15
18
|
const useVirtualFocus = (
|
|
@@ -40,11 +43,6 @@ const useVirtualFocus = (
|
|
|
40
43
|
: false;
|
|
41
44
|
};
|
|
42
45
|
|
|
43
|
-
const _moveFocusAndScrollTo = (_element?: HTMLElement) => {
|
|
44
|
-
setActiveElement(_element);
|
|
45
|
-
_element?.scrollIntoView?.({ block: "nearest" });
|
|
46
|
-
};
|
|
47
|
-
|
|
48
46
|
const moveFocusUp = () => {
|
|
49
47
|
if (!activeElement) {
|
|
50
48
|
return;
|
|
@@ -55,14 +53,14 @@ const useVirtualFocus = (
|
|
|
55
53
|
if (_currentIndex === 0) {
|
|
56
54
|
setActiveElement(undefined);
|
|
57
55
|
} else {
|
|
58
|
-
|
|
56
|
+
setActiveElement(elementAbove);
|
|
59
57
|
}
|
|
60
58
|
};
|
|
61
59
|
|
|
62
60
|
const moveFocusDown = () => {
|
|
63
61
|
const elementsAbleToReceiveFocus = getElementsAbleToReceiveFocus();
|
|
64
62
|
if (!activeElement) {
|
|
65
|
-
|
|
63
|
+
setActiveElement(elementsAbleToReceiveFocus[0]);
|
|
66
64
|
return;
|
|
67
65
|
}
|
|
68
66
|
const _currentIndex = elementsAbleToReceiveFocus.indexOf(activeElement);
|
|
@@ -70,13 +68,17 @@ const useVirtualFocus = (
|
|
|
70
68
|
return;
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
setActiveElement(elementsAbleToReceiveFocus[_currentIndex + 1]);
|
|
74
72
|
};
|
|
75
73
|
|
|
76
|
-
const
|
|
74
|
+
const resetFocus = () => setActiveElement(undefined);
|
|
75
|
+
const moveFocusToTop = () => {
|
|
76
|
+
const elementsAbleToReceiveFocus = getElementsAbleToReceiveFocus();
|
|
77
|
+
setActiveElement(elementsAbleToReceiveFocus[0]);
|
|
78
|
+
};
|
|
77
79
|
const moveFocusToBottom = () => {
|
|
78
80
|
const elementsAbleToReceiveFocus = getElementsAbleToReceiveFocus();
|
|
79
|
-
|
|
81
|
+
setActiveElement(
|
|
80
82
|
elementsAbleToReceiveFocus[elementsAbleToReceiveFocus.length - 1],
|
|
81
83
|
);
|
|
82
84
|
};
|
|
@@ -89,6 +91,32 @@ const useVirtualFocus = (
|
|
|
89
91
|
}
|
|
90
92
|
};
|
|
91
93
|
|
|
94
|
+
const moveFocusUpBy = (numberOfElements: number) => {
|
|
95
|
+
if (!activeElement) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const elementsAbleToReceiveFocus = getElementsAbleToReceiveFocus();
|
|
99
|
+
const currentIndex = elementsAbleToReceiveFocus.indexOf(activeElement);
|
|
100
|
+
const newIndex = Math.max(currentIndex - numberOfElements, 0);
|
|
101
|
+
setActiveElement(elementsAbleToReceiveFocus[newIndex]);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const moveFocusDownBy = (numberOfElements: number) => {
|
|
105
|
+
const elementsAbleToReceiveFocus = getElementsAbleToReceiveFocus();
|
|
106
|
+
const currentIndex = activeElement
|
|
107
|
+
? elementsAbleToReceiveFocus.indexOf(activeElement)
|
|
108
|
+
: -1;
|
|
109
|
+
const newIndex = Math.min(
|
|
110
|
+
currentIndex + numberOfElements,
|
|
111
|
+
elementsAbleToReceiveFocus.length - 1,
|
|
112
|
+
);
|
|
113
|
+
setActiveElement(elementsAbleToReceiveFocus[newIndex]);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
activeElement?.scrollIntoView?.({ block: "nearest" });
|
|
118
|
+
}, [activeElement]);
|
|
119
|
+
|
|
92
120
|
return {
|
|
93
121
|
activeElement,
|
|
94
122
|
getElementById,
|
|
@@ -99,6 +127,9 @@ const useVirtualFocus = (
|
|
|
99
127
|
moveFocusToElement,
|
|
100
128
|
moveFocusToTop,
|
|
101
129
|
moveFocusToBottom,
|
|
130
|
+
moveFocusUpBy,
|
|
131
|
+
moveFocusDownBy,
|
|
132
|
+
resetFocus,
|
|
102
133
|
};
|
|
103
134
|
};
|
|
104
135
|
|
|
@@ -134,14 +134,6 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
134
134
|
case "Accept":
|
|
135
135
|
onEnter(e);
|
|
136
136
|
break;
|
|
137
|
-
case "Home":
|
|
138
|
-
toggleIsListOpen(false);
|
|
139
|
-
virtualFocus.moveFocusToTop();
|
|
140
|
-
break;
|
|
141
|
-
case "End":
|
|
142
|
-
toggleIsListOpen(true);
|
|
143
|
-
virtualFocus.moveFocusToBottom();
|
|
144
|
-
break;
|
|
145
137
|
default:
|
|
146
138
|
break;
|
|
147
139
|
}
|
|
@@ -202,6 +194,24 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
202
194
|
}
|
|
203
195
|
virtualFocus.moveFocusUp();
|
|
204
196
|
}
|
|
197
|
+
} else if (e.key === "Home") {
|
|
198
|
+
e.preventDefault();
|
|
199
|
+
virtualFocus.moveFocusToTop();
|
|
200
|
+
} else if (e.key === "End") {
|
|
201
|
+
e.preventDefault();
|
|
202
|
+
if (virtualFocus.activeElement === null || !isListOpen) {
|
|
203
|
+
toggleIsListOpen(true);
|
|
204
|
+
}
|
|
205
|
+
virtualFocus.moveFocusToBottom();
|
|
206
|
+
} else if (e.key === "PageUp") {
|
|
207
|
+
e.preventDefault();
|
|
208
|
+
virtualFocus.moveFocusUpBy(6);
|
|
209
|
+
} else if (e.key === "PageDown") {
|
|
210
|
+
e.preventDefault();
|
|
211
|
+
if (virtualFocus.activeElement === null || !isListOpen) {
|
|
212
|
+
toggleIsListOpen(true);
|
|
213
|
+
}
|
|
214
|
+
virtualFocus.moveFocusDownBy(6);
|
|
205
215
|
}
|
|
206
216
|
},
|
|
207
217
|
[
|
|
@@ -230,10 +240,9 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
230
240
|
} else if (filteredOptions.length === 0) {
|
|
231
241
|
toggleIsListOpen(false);
|
|
232
242
|
}
|
|
233
|
-
virtualFocus.moveFocusToTop();
|
|
234
243
|
onChange(newValue);
|
|
235
244
|
},
|
|
236
|
-
[filteredOptions.length,
|
|
245
|
+
[filteredOptions.length, onChange, toggleIsListOpen],
|
|
237
246
|
);
|
|
238
247
|
|
|
239
248
|
return (
|
|
@@ -291,4 +291,40 @@ describe("Render combobox", () => {
|
|
|
291
291
|
);
|
|
292
292
|
});
|
|
293
293
|
});
|
|
294
|
+
|
|
295
|
+
describe("has keyboard navigation", () => {
|
|
296
|
+
test("for PageDown and PageUp", async () => {
|
|
297
|
+
render(<App options={options} />);
|
|
298
|
+
|
|
299
|
+
const combobox = screen.getByRole("combobox", {
|
|
300
|
+
name: "Hva er dine favorittfrukter?",
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const pressKey = async (key: string) => {
|
|
304
|
+
await act(async () => {
|
|
305
|
+
await userEvent.keyboard(`{${key}}`);
|
|
306
|
+
});
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
const hasVirtualFocus = (option: string) =>
|
|
310
|
+
expect(combobox.getAttribute("aria-activedescendant")).toBe(
|
|
311
|
+
screen.getByRole("option", { name: option }).id,
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
await act(async () => {
|
|
315
|
+
await userEvent.click(combobox);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
await pressKey("ArrowDown");
|
|
319
|
+
hasVirtualFocus("apple");
|
|
320
|
+
await pressKey("PageDown");
|
|
321
|
+
hasVirtualFocus("mango");
|
|
322
|
+
await pressKey("PageDown");
|
|
323
|
+
hasVirtualFocus("watermelon");
|
|
324
|
+
await pressKey("PageUp");
|
|
325
|
+
hasVirtualFocus("mango");
|
|
326
|
+
await pressKey("PageUp");
|
|
327
|
+
hasVirtualFocus("apple");
|
|
328
|
+
});
|
|
329
|
+
});
|
|
294
330
|
});
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { render, screen } from "@testing-library/react";
|
|
2
|
-
import faker from "faker";
|
|
3
2
|
import React from "react";
|
|
4
3
|
import { expect, test } from "vitest";
|
|
5
4
|
import { ConfirmationPanel } from ".";
|
|
6
5
|
|
|
7
6
|
test("omits error id from input", async () => {
|
|
8
|
-
const label =
|
|
7
|
+
const label = "My label";
|
|
9
8
|
|
|
10
9
|
render(<ConfirmationPanel label={label} errorId="wat"></ConfirmationPanel>);
|
|
11
10
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { render, screen } from "@testing-library/react";
|
|
2
2
|
import userEvent from "@testing-library/user-event";
|
|
3
|
-
import faker from "faker";
|
|
4
3
|
import React from "react";
|
|
5
4
|
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
6
5
|
import { Radio, RadioGroup } from ".";
|
|
7
6
|
|
|
8
|
-
const value1 =
|
|
9
|
-
const label1 =
|
|
10
|
-
const value2 =
|
|
11
|
-
const label2 =
|
|
7
|
+
const value1 = "My first value";
|
|
8
|
+
const label1 = "World's best radio label";
|
|
9
|
+
const value2 = "Life changing value";
|
|
10
|
+
const label2 = "Radio label of the year";
|
|
12
11
|
|
|
13
12
|
const Group = (props) => (
|
|
14
13
|
<RadioGroup {...props} legend="legend">
|
|
@@ -41,8 +41,8 @@ export const useRadio = (props: RadioProps) => {
|
|
|
41
41
|
if (readOnly) {
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
|
-
props.onChange
|
|
45
|
-
radioGroup?.onChange
|
|
44
|
+
props.onChange?.(e);
|
|
45
|
+
radioGroup?.onChange?.(props.value);
|
|
46
46
|
},
|
|
47
47
|
onClick: (e) => {
|
|
48
48
|
if (readOnly) {
|
|
@@ -144,7 +144,7 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
|
|
|
144
144
|
(event: SearchClearEvent) => {
|
|
145
145
|
onClear?.(event);
|
|
146
146
|
handleChange("");
|
|
147
|
-
searchRef.current
|
|
147
|
+
searchRef.current?.focus?.();
|
|
148
148
|
},
|
|
149
149
|
[handleChange, onClear],
|
|
150
150
|
);
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
export { Accordion, type AccordionProps } from "./accordion";
|
|
3
|
+
export { ActionMenu, type ActionMenuProps } from "./overlays/action-menu";
|
|
3
4
|
export { Alert, type AlertProps } from "./alert";
|
|
4
5
|
export { Button, type ButtonProps } from "./button";
|
|
5
6
|
export { Chat, type ChatProps } from "./chat";
|
|
@@ -5,6 +5,9 @@ import { getResponsiveProps, getResponsiveValue } from "../utilities/css";
|
|
|
5
5
|
import { ResponsiveProp, SpacingScale } from "../utilities/types";
|
|
6
6
|
|
|
7
7
|
export type PrimitiveProps = {
|
|
8
|
+
/**
|
|
9
|
+
* @private Hides prop from documentation
|
|
10
|
+
*/
|
|
8
11
|
className?: string;
|
|
9
12
|
/**
|
|
10
13
|
* Padding around children.
|
package/src/layout/box/Box.tsx
CHANGED
|
@@ -19,42 +19,41 @@ import {
|
|
|
19
19
|
SurfaceColorToken,
|
|
20
20
|
} from "../utilities/types";
|
|
21
21
|
|
|
22
|
-
export type BoxProps =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
};
|
|
22
|
+
export type BoxProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
23
|
+
/**
|
|
24
|
+
* CSS `background-color` property.
|
|
25
|
+
* Accepts a [background/surface color token](https://aksel.nav.no/grunnleggende/styling/design-tokens#afff774dad80).
|
|
26
|
+
*/
|
|
27
|
+
background?: BackgroundColorToken | SurfaceColorToken;
|
|
28
|
+
/**
|
|
29
|
+
* CSS `border-color` property.
|
|
30
|
+
* Accepts a [border color token](https://aksel.nav.no/grunnleggende/styling/design-tokens#adb1767e2f87).
|
|
31
|
+
*/
|
|
32
|
+
borderColor?: BorderColorToken;
|
|
33
|
+
/**
|
|
34
|
+
* CSS `border-radius` property.
|
|
35
|
+
* Accepts a [radius token](https://aksel.nav.no/grunnleggende/styling/design-tokens#6d79c5605d31)
|
|
36
|
+
* or an object of radius tokens for different breakpoints.
|
|
37
|
+
* @example
|
|
38
|
+
* borderRadius='full'
|
|
39
|
+
* borderRadius='0 full large small'
|
|
40
|
+
* borderRadius={{xs: 'small large', sm: '0', md: 'large', lg: 'full'}}
|
|
41
|
+
*/
|
|
42
|
+
borderRadius?: ResponsiveProp<SpaceDelimitedAttribute<BorderRadiiToken>>;
|
|
43
|
+
/**
|
|
44
|
+
* CSS `border-width` property. If this is not set there will be no border.
|
|
45
|
+
* @example
|
|
46
|
+
* borderWidth='2'
|
|
47
|
+
* borderWidth='1 2 3 4'
|
|
48
|
+
*/
|
|
49
|
+
borderWidth?: SpaceDelimitedAttribute<"0" | "1" | "2" | "3" | "4" | "5">;
|
|
50
|
+
/** Shadow on box. Accepts a shadow token.
|
|
51
|
+
* @example
|
|
52
|
+
* shadow='small'
|
|
53
|
+
*/
|
|
54
|
+
shadow?: ShadowToken;
|
|
55
|
+
} & PrimitiveProps &
|
|
56
|
+
PrimitiveAsChildProps;
|
|
58
57
|
|
|
59
58
|
/**
|
|
60
59
|
* Foundational Layout-primitive for generic encapsulation & styling.
|
|
@@ -10,33 +10,32 @@ import { PrimitiveAsChildProps } from "../base/PrimitiveAsChildProps";
|
|
|
10
10
|
import { getResponsiveProps, getResponsiveValue } from "../utilities/css";
|
|
11
11
|
import { ResponsiveProp, SpacingScale } from "../utilities/types";
|
|
12
12
|
|
|
13
|
-
export type HGridProps =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
13
|
+
export type HGridProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
14
|
+
/**
|
|
15
|
+
* Number of columns to display. Can be a number, a string, or an object with values for specific breakpoints.
|
|
16
|
+
* Sets `grid-template-columns`, so `fr`, `minmax` etc. works.
|
|
17
|
+
* @example
|
|
18
|
+
* columns={{ sm: 1, md: 1, lg: "1fr auto", xl: "1fr auto"}}
|
|
19
|
+
* columns={3}
|
|
20
|
+
* columns="repeat(3, minmax(0, 1fr))"
|
|
21
|
+
*/
|
|
22
|
+
columns?: ResponsiveProp<number | string>;
|
|
23
|
+
/**
|
|
24
|
+
* Spacing between columns.
|
|
25
|
+
* Accepts a [spacing token](https://aksel.nav.no/grunnleggende/styling/design-tokens#0cc9fb32f213)
|
|
26
|
+
* or an object of spacing tokens for different breakpoints.
|
|
27
|
+
* @example
|
|
28
|
+
* gap="6"
|
|
29
|
+
* gap="8 4"
|
|
30
|
+
* gap={{ sm: "2", md: "2", lg: "6", xl: "6"}}
|
|
31
|
+
*/
|
|
32
|
+
gap?: ResponsiveProp<SpacingScale | `${SpacingScale} ${SpacingScale}`>;
|
|
33
|
+
/**
|
|
34
|
+
* Vertical alignment of children. Elements will by default stretch to the height of parent-element.
|
|
35
|
+
*/
|
|
36
|
+
align?: "start" | "center" | "end";
|
|
37
|
+
} & PrimitiveProps &
|
|
38
|
+
PrimitiveAsChildProps;
|
|
40
39
|
/**
|
|
41
40
|
* Horizontal Grid Primitive with dynamic columns and gap based on breakpoints.
|
|
42
41
|
*
|
|
@@ -11,60 +11,59 @@ import { PrimitiveAsChildProps } from "../base/PrimitiveAsChildProps";
|
|
|
11
11
|
import { getResponsiveProps, getResponsiveValue } from "../utilities/css";
|
|
12
12
|
import { ResponsiveProp, SpacingScale } from "../utilities/types";
|
|
13
13
|
|
|
14
|
-
export type StackProps =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
};
|
|
14
|
+
export type StackProps = HTMLAttributes<HTMLDivElement> & {
|
|
15
|
+
/**
|
|
16
|
+
* CSS `justify-content` property.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* justify='center'
|
|
20
|
+
* justify={{xs: 'start', sm: 'center', md: 'end', lg: 'space-around', xl: 'space-between'}}
|
|
21
|
+
*/
|
|
22
|
+
justify?: ResponsiveProp<
|
|
23
|
+
| "start"
|
|
24
|
+
| "center"
|
|
25
|
+
| "end"
|
|
26
|
+
| "space-around"
|
|
27
|
+
| "space-between"
|
|
28
|
+
| "space-evenly"
|
|
29
|
+
>;
|
|
30
|
+
/**
|
|
31
|
+
* CSS `align-items` property.
|
|
32
|
+
* @default "stretch"
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* align='center'
|
|
36
|
+
* align={{xs: 'start', sm: 'center', md: 'end', lg: 'baseline', xl: 'stretch'}}
|
|
37
|
+
*/
|
|
38
|
+
align?: ResponsiveProp<"start" | "center" | "end" | "baseline" | "stretch">;
|
|
39
|
+
/**
|
|
40
|
+
* Sets the CSS `flex-wrap` property.
|
|
41
|
+
*/
|
|
42
|
+
wrap?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* CSS `gap` property.
|
|
45
|
+
* Accepts a [spacing token](https://aksel.nav.no/grunnleggende/styling/design-tokens#0cc9fb32f213)
|
|
46
|
+
* or an object of spacing tokens for different breakpoints.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* gap='4'
|
|
50
|
+
* gap='8 4'
|
|
51
|
+
* gap={{xs: '2', sm: '3', md: '4', lg: '5', xl: '6'}}
|
|
52
|
+
*/
|
|
53
|
+
gap?: ResponsiveProp<SpacingScale | `${SpacingScale} ${SpacingScale}`>;
|
|
54
|
+
/**
|
|
55
|
+
* CSS `flex-direction` property.
|
|
56
|
+
* @default "row"
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* direction='row'
|
|
60
|
+
* direction={{xs: 'row', sm: 'column'}}
|
|
61
|
+
*/
|
|
62
|
+
direction?: ResponsiveProp<
|
|
63
|
+
"row" | "column" | "row-reverse" | "column-reverse"
|
|
64
|
+
>;
|
|
65
|
+
} & PrimitiveProps &
|
|
66
|
+
PrimitiveAsChildProps;
|
|
68
67
|
|
|
69
68
|
export const Stack: OverridableComponent<StackProps, HTMLDivElement> =
|
|
70
69
|
forwardRef(
|
|
@@ -25,6 +25,12 @@ const ModalHeader = forwardRef<HTMLDivElement, ModalHeaderProps>(
|
|
|
25
25
|
className="navds-modal__button"
|
|
26
26
|
size="small"
|
|
27
27
|
variant="tertiary-neutral"
|
|
28
|
+
onKeyDown={(event) => {
|
|
29
|
+
/* Prevents autofocus used in combination with holding down keys from closing modal */
|
|
30
|
+
if (["Enter", " "].includes(event.key) && event.repeat) {
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
}
|
|
33
|
+
}}
|
|
28
34
|
onClick={context.closeHandler}
|
|
29
35
|
icon={<XMarkIcon title="Lukk" />}
|
|
30
36
|
/>
|
|
@@ -518,7 +518,7 @@ dialogPolyfill.isInlinePositionSetByStylesheet = function (element) {
|
|
|
518
518
|
// Some browsers throw on cssRules.
|
|
519
519
|
try {
|
|
520
520
|
cssRules = styleSheet.cssRules;
|
|
521
|
-
} catch
|
|
521
|
+
} catch {
|
|
522
522
|
/* empty */
|
|
523
523
|
}
|
|
524
524
|
if (!cssRules) {
|
|
@@ -530,7 +530,7 @@ dialogPolyfill.isInlinePositionSetByStylesheet = function (element) {
|
|
|
530
530
|
// Ignore errors on invalid selector texts.
|
|
531
531
|
try {
|
|
532
532
|
selectedNodes = document.querySelectorAll(rule.selectorText);
|
|
533
|
-
} catch
|
|
533
|
+
} catch {
|
|
534
534
|
/* empty */
|
|
535
535
|
}
|
|
536
536
|
if (!selectedNodes || !inNodeList(selectedNodes, element)) {
|