@navikt/ds-react 7.37.0 → 7.38.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/date/Date.Dialog.js +5 -1
- package/cjs/date/Date.Dialog.js.map +1 -1
- package/cjs/dialog/index.d.ts +1 -1
- package/cjs/dialog/index.js +4 -1
- package/cjs/dialog/index.js.map +1 -1
- package/cjs/dialog/popup/DialogPopup.js +6 -1
- package/cjs/dialog/popup/DialogPopup.js.map +1 -1
- package/cjs/dialog/root/DialogRoot.d.ts +5 -5
- package/cjs/dialog/root/DialogRoot.js +12 -11
- package/cjs/dialog/root/DialogRoot.js.map +1 -1
- package/cjs/form/combobox/Combobox.d.ts +1 -1
- package/cjs/form/combobox/Input/InputController.d.ts +1 -1
- package/cjs/form/file-upload/useFileUpload.d.ts +1 -1
- package/cjs/layout/base/PrimitiveAsChildProps.d.ts +1 -4
- package/cjs/modal/Modal.js +9 -2
- package/cjs/modal/Modal.js.map +1 -1
- package/cjs/overlays/action-menu/ActionMenu.js +3 -1
- package/cjs/overlays/action-menu/ActionMenu.js.map +1 -1
- package/cjs/overlays/dismissablelayer/DismissableLayer.d.ts +1 -0
- package/cjs/overlays/dismissablelayer/DismissableLayer.js +33 -14
- package/cjs/overlays/dismissablelayer/DismissableLayer.js.map +1 -1
- package/cjs/overlays/dismissablelayer/util/useEscapeKeydown.js +7 -2
- package/cjs/overlays/dismissablelayer/util/useEscapeKeydown.js.map +1 -1
- package/cjs/provider/Provider.d.ts +1 -5
- package/cjs/provider/Provider.js +0 -2
- package/cjs/provider/Provider.js.map +1 -1
- package/cjs/slot/Slot.js +12 -5
- package/cjs/slot/Slot.js.map +1 -1
- package/cjs/tabs/Tabs.context.d.ts +1 -1
- package/cjs/tabs/parts/tab/useTab.d.ts +1 -1
- package/cjs/tabs/parts/tab/useTab.js +2 -1
- package/cjs/tabs/parts/tab/useTab.js.map +1 -1
- package/cjs/toggle-group/ToggleGroup.context.d.ts +1 -1
- package/cjs/toggle-group/parts/useToggleItem.d.ts +1 -1
- package/cjs/toggle-group/parts/useToggleItem.js +2 -1
- package/cjs/toggle-group/parts/useToggleItem.js.map +1 -1
- package/cjs/util/hooks/descendants/useDescendant.d.ts +1 -1
- package/cjs/util/hooks/descendants/useDescendant.js +2 -1
- package/cjs/util/hooks/descendants/useDescendant.js.map +1 -1
- package/cjs/util/hooks/useMergeRefs.d.ts +15 -9
- package/cjs/util/hooks/useMergeRefs.js +94 -29
- package/cjs/util/hooks/useMergeRefs.js.map +1 -1
- package/cjs/util/types/AsChildProps.d.ts +0 -4
- package/cjs/util/virtualfocus/Context.d.ts +1 -1
- package/esm/date/Date.Dialog.js +5 -1
- package/esm/date/Date.Dialog.js.map +1 -1
- package/esm/dialog/index.d.ts +1 -1
- package/esm/dialog/index.js +1 -1
- package/esm/dialog/index.js.map +1 -1
- package/esm/dialog/popup/DialogPopup.js +6 -1
- package/esm/dialog/popup/DialogPopup.js.map +1 -1
- package/esm/dialog/root/DialogRoot.d.ts +5 -5
- package/esm/dialog/root/DialogRoot.js +5 -5
- package/esm/dialog/root/DialogRoot.js.map +1 -1
- package/esm/form/combobox/Combobox.d.ts +1 -1
- package/esm/form/combobox/Input/InputController.d.ts +1 -1
- package/esm/form/file-upload/useFileUpload.d.ts +1 -1
- package/esm/layout/base/PrimitiveAsChildProps.d.ts +1 -4
- package/esm/modal/Modal.js +9 -2
- package/esm/modal/Modal.js.map +1 -1
- package/esm/overlays/action-menu/ActionMenu.js +3 -1
- package/esm/overlays/action-menu/ActionMenu.js.map +1 -1
- package/esm/overlays/dismissablelayer/DismissableLayer.d.ts +1 -0
- package/esm/overlays/dismissablelayer/DismissableLayer.js +34 -15
- package/esm/overlays/dismissablelayer/DismissableLayer.js.map +1 -1
- package/esm/overlays/dismissablelayer/util/useEscapeKeydown.js +7 -2
- package/esm/overlays/dismissablelayer/util/useEscapeKeydown.js.map +1 -1
- package/esm/provider/Provider.d.ts +1 -5
- package/esm/provider/Provider.js +0 -2
- package/esm/provider/Provider.js.map +1 -1
- package/esm/slot/Slot.js +12 -5
- package/esm/slot/Slot.js.map +1 -1
- package/esm/tabs/Tabs.context.d.ts +1 -1
- package/esm/tabs/parts/tab/useTab.d.ts +1 -1
- package/esm/tabs/parts/tab/useTab.js +3 -2
- package/esm/tabs/parts/tab/useTab.js.map +1 -1
- package/esm/toggle-group/ToggleGroup.context.d.ts +1 -1
- package/esm/toggle-group/parts/useToggleItem.d.ts +1 -1
- package/esm/toggle-group/parts/useToggleItem.js +3 -2
- package/esm/toggle-group/parts/useToggleItem.js.map +1 -1
- package/esm/util/hooks/descendants/useDescendant.d.ts +1 -1
- package/esm/util/hooks/descendants/useDescendant.js +3 -2
- package/esm/util/hooks/descendants/useDescendant.js.map +1 -1
- package/esm/util/hooks/useMergeRefs.d.ts +15 -9
- package/esm/util/hooks/useMergeRefs.js +93 -25
- package/esm/util/hooks/useMergeRefs.js.map +1 -1
- package/esm/util/types/AsChildProps.d.ts +0 -4
- package/esm/util/virtualfocus/Context.d.ts +1 -1
- package/package.json +3 -3
- package/src/date/Date.Dialog.tsx +6 -1
- package/src/dialog/index.ts +1 -1
- package/src/dialog/popup/DialogPopup.tsx +7 -1
- package/src/dialog/root/DialogRoot.tsx +5 -5
- package/src/layout/base/PrimitiveAsChildProps.ts +1 -4
- package/src/modal/Modal.tsx +9 -1
- package/src/overlays/action-menu/ActionMenu.tsx +3 -2
- package/src/overlays/dismissablelayer/DismissableLayer.tsx +52 -16
- package/src/overlays/dismissablelayer/util/useEscapeKeydown.ts +7 -2
- package/src/provider/Provider.tsx +1 -5
- package/src/slot/Slot.tsx +14 -9
- package/src/tabs/parts/tab/useTab.ts +4 -2
- package/src/toggle-group/parts/useToggleItem.ts +4 -2
- package/src/util/__tests__/useMergeRefs.test.ts +92 -0
- package/src/util/hooks/descendants/useDescendant.tsx +4 -2
- package/src/util/hooks/useMergeRefs.ts +147 -24
- package/src/util/types/AsChildProps.ts +0 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMergeRefs.js","sourceRoot":"","sources":["../../../src/util/hooks/useMergeRefs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useMergeRefs.js","sourceRoot":"","sources":["../../../src/util/hooks/useMergeRefs.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,14 +5,12 @@ export type AsChildProps = {
|
|
|
5
5
|
* merging the props of the component with the props of the child.
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
|
-
* ```
|
|
9
8
|
* <Component asChild data-prop>
|
|
10
9
|
* <ChildComponent data-child />
|
|
11
10
|
* </Component>
|
|
12
11
|
*
|
|
13
12
|
* Out:
|
|
14
13
|
* <MergedComponent data-prop data-child />
|
|
15
|
-
* ```
|
|
16
14
|
*/
|
|
17
15
|
asChild: true;
|
|
18
16
|
as?: never;
|
|
@@ -23,14 +21,12 @@ export type AsChildProps = {
|
|
|
23
21
|
* merging the props of the component with the props of the child.
|
|
24
22
|
*
|
|
25
23
|
* @example
|
|
26
|
-
* ```
|
|
27
24
|
* <Component asChild data-prop>
|
|
28
25
|
* <ChildComponent data-child />
|
|
29
26
|
* </Component>
|
|
30
27
|
*
|
|
31
28
|
* Out:
|
|
32
29
|
* <MergedComponent data-prop data-child />
|
|
33
|
-
* ```
|
|
34
30
|
*/
|
|
35
31
|
asChild?: false;
|
|
36
32
|
};
|
|
@@ -21,7 +21,7 @@ export declare const VirtualFocusDescendantsProvider: import("react").Provider<i
|
|
|
21
21
|
}>;
|
|
22
22
|
index: number;
|
|
23
23
|
enabledIndex: number;
|
|
24
|
-
register: (instance: HTMLDivElement | null) => void;
|
|
24
|
+
register: ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | null;
|
|
25
25
|
};
|
|
26
26
|
export declare const VirtualFocusInternalContextProvider: import("react").FC<{
|
|
27
27
|
virtualFocusIdx: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@navikt/ds-react",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.38.0",
|
|
4
4
|
"description": "React components from the Norwegian Labour and Welfare Administration.",
|
|
5
5
|
"author": "Aksel, a team part of the Norwegian Labour and Welfare Administration.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -705,8 +705,8 @@
|
|
|
705
705
|
"dependencies": {
|
|
706
706
|
"@floating-ui/react": "0.27.8",
|
|
707
707
|
"@floating-ui/react-dom": "^2.1.6",
|
|
708
|
-
"@navikt/aksel-icons": "^7.
|
|
709
|
-
"@navikt/ds-tokens": "^7.
|
|
708
|
+
"@navikt/aksel-icons": "^7.38.0",
|
|
709
|
+
"@navikt/ds-tokens": "^7.38.0",
|
|
710
710
|
"clsx": "^2.1.0",
|
|
711
711
|
"date-fns": "^4.0.0",
|
|
712
712
|
"react-day-picker": "9.7.0"
|
package/src/date/Date.Dialog.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useRef } from "react";
|
|
2
2
|
import { Button } from "../button";
|
|
3
|
+
import { useDialogContext } from "../dialog/root/DialogRoot.context";
|
|
3
4
|
import { Modal } from "../modal";
|
|
4
5
|
import { useModalContext } from "../modal/Modal.context";
|
|
5
6
|
import { Popover } from "../popover";
|
|
@@ -45,9 +46,13 @@ const DateDialog = ({
|
|
|
45
46
|
const { cn } = useRenameCSS();
|
|
46
47
|
|
|
47
48
|
const modalRef = useRef<HTMLDialogElement>(null);
|
|
49
|
+
|
|
48
50
|
const isInModal = useModalContext(false) !== undefined;
|
|
51
|
+
const isInDialog = useDialogContext(false) !== undefined;
|
|
49
52
|
const hideModal =
|
|
50
|
-
useMedia("screen and (min-width: 768px)", true) &&
|
|
53
|
+
useMedia("screen and (min-width: 768px)", true) &&
|
|
54
|
+
!isInModal &&
|
|
55
|
+
!isInDialog;
|
|
51
56
|
|
|
52
57
|
if (!open) {
|
|
53
58
|
return null;
|
package/src/dialog/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { Dialog } from "./root/DialogRoot";
|
|
2
|
+
export { default as Dialog } from "./root/DialogRoot";
|
|
3
3
|
export type { DialogProps } from "./root/DialogRoot";
|
|
4
4
|
export { DialogTrigger } from "./trigger/DialogTrigger";
|
|
5
5
|
export type { DialogTriggerProps } from "./trigger/DialogTrigger";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { forwardRef } from "react";
|
|
2
|
+
import { useModalContext } from "../../modal/Modal.context";
|
|
2
3
|
import { Portal, type PortalProps } from "../../portal";
|
|
3
4
|
import { DialogBackdropInternal } from "../backdrop/DialogBackdropInternal";
|
|
4
5
|
import { useDialogContext } from "../root/DialogRoot.context";
|
|
@@ -28,7 +29,7 @@ const DialogPopup = forwardRef<HTMLDivElement, DialogPopupProps>(
|
|
|
28
29
|
{
|
|
29
30
|
modal = true,
|
|
30
31
|
withBackdrop = modal === true,
|
|
31
|
-
rootElement,
|
|
32
|
+
rootElement: rootElementProp,
|
|
32
33
|
position,
|
|
33
34
|
...restProps
|
|
34
35
|
},
|
|
@@ -36,6 +37,11 @@ const DialogPopup = forwardRef<HTMLDivElement, DialogPopupProps>(
|
|
|
36
37
|
) => {
|
|
37
38
|
const { mounted, nested } = useDialogContext();
|
|
38
39
|
|
|
40
|
+
const modalContext = useModalContext(false);
|
|
41
|
+
const rootElement = modalContext
|
|
42
|
+
? modalContext.modalRef.current
|
|
43
|
+
: rootElementProp;
|
|
44
|
+
|
|
39
45
|
if (!mounted) {
|
|
40
46
|
return null;
|
|
41
47
|
}
|
|
@@ -179,15 +179,15 @@ interface DialogComponent extends React.FC<DialogProps> {
|
|
|
179
179
|
* Dialog body content
|
|
180
180
|
* </Dialog.Body>
|
|
181
181
|
* <Dialog.Footer>
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
182
|
+
* <Dialog.CloseTrigger>
|
|
183
|
+
* <Button>Close dialog</Button>
|
|
184
|
+
* </Dialog.CloseTrigger>
|
|
185
185
|
* </Dialog.Footer>
|
|
186
186
|
* </Dialog.Popup>
|
|
187
187
|
* </Dialog>
|
|
188
188
|
* ```
|
|
189
189
|
*/
|
|
190
|
-
const Dialog: DialogComponent = (props: DialogProps) => {
|
|
190
|
+
export const Dialog: DialogComponent = (props: DialogProps) => {
|
|
191
191
|
const {
|
|
192
192
|
children,
|
|
193
193
|
defaultOpen = false,
|
|
@@ -292,5 +292,5 @@ Dialog.Body = DialogBody;
|
|
|
292
292
|
Dialog.Footer = DialogFooter;
|
|
293
293
|
Dialog.Popup = DialogPopup;
|
|
294
294
|
|
|
295
|
-
export
|
|
295
|
+
export default Dialog;
|
|
296
296
|
export type { DialogProps };
|
|
@@ -4,15 +4,14 @@ export type PrimitiveAsChildProps =
|
|
|
4
4
|
/**
|
|
5
5
|
* Renders the component and its child as a single element,
|
|
6
6
|
* merging the props of the component with the props of the child.
|
|
7
|
+
*
|
|
7
8
|
* @example
|
|
8
|
-
* ```tsx
|
|
9
9
|
* <Component asChild data-prop>
|
|
10
10
|
* <ChildComponent data-child />
|
|
11
11
|
* </Component>
|
|
12
12
|
*
|
|
13
13
|
* // Renders
|
|
14
14
|
* <div data-prop data-child />
|
|
15
|
-
* ```
|
|
16
15
|
*/
|
|
17
16
|
asChild: true;
|
|
18
17
|
/**
|
|
@@ -29,14 +28,12 @@ export type PrimitiveAsChildProps =
|
|
|
29
28
|
* merging the props of the component with the props of the child.
|
|
30
29
|
*
|
|
31
30
|
* @example
|
|
32
|
-
* ```tsx
|
|
33
31
|
* <Component asChild data-prop>
|
|
34
32
|
* <ChildComponent data-child />
|
|
35
33
|
* </Component>
|
|
36
34
|
*
|
|
37
35
|
* // Renders
|
|
38
36
|
* <div data-prop data-child />
|
|
39
|
-
* ```
|
|
40
37
|
*/
|
|
41
38
|
asChild?: false;
|
|
42
39
|
};
|
package/src/modal/Modal.tsx
CHANGED
|
@@ -230,7 +230,7 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
|
|
|
230
230
|
: ariaLabelledby;
|
|
231
231
|
|
|
232
232
|
const component = (
|
|
233
|
-
// eslint-disable-next-line jsx-a11y/
|
|
233
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
|
|
234
234
|
<dialog
|
|
235
235
|
{...rest}
|
|
236
236
|
ref={mergedRef}
|
|
@@ -248,6 +248,14 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
|
|
|
248
248
|
: onMouseDown
|
|
249
249
|
}
|
|
250
250
|
aria-labelledby={mergedAriaLabelledBy}
|
|
251
|
+
onKeyDown={(e) => {
|
|
252
|
+
/**
|
|
253
|
+
* Stops propagation of Escape key to prevent closing parent modals/dialogs
|
|
254
|
+
*/
|
|
255
|
+
if (e.key === "Escape") {
|
|
256
|
+
e.stopPropagation();
|
|
257
|
+
}
|
|
258
|
+
}}
|
|
251
259
|
>
|
|
252
260
|
<ModalContextProvider
|
|
253
261
|
closeHandler={getCloseHandler(modalRef, header, onBeforeClose)}
|
|
@@ -317,7 +317,6 @@ export const ActionMenuTrigger = forwardRef<
|
|
|
317
317
|
ref,
|
|
318
318
|
) => {
|
|
319
319
|
const context = useActionMenuContext();
|
|
320
|
-
|
|
321
320
|
const mergedRefs = useMergeRefs(ref, context.triggerRef);
|
|
322
321
|
|
|
323
322
|
return (
|
|
@@ -386,7 +385,9 @@ export const ActionMenuContent = forwardRef<
|
|
|
386
385
|
sideOffset={4}
|
|
387
386
|
collisionPadding={10}
|
|
388
387
|
returnFocus={context.triggerRef}
|
|
389
|
-
safeZone={{
|
|
388
|
+
safeZone={{
|
|
389
|
+
anchor: context.triggerRef.current,
|
|
390
|
+
}}
|
|
390
391
|
style={{
|
|
391
392
|
...style,
|
|
392
393
|
...{
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from "react";
|
|
2
8
|
import { Slot } from "../../slot/Slot";
|
|
3
9
|
import { composeEventHandlers } from "../../util/composeEventHandlers";
|
|
4
10
|
import { useMergeRefs } from "../../util/hooks";
|
|
@@ -61,6 +67,7 @@ interface DismissableLayerBaseProps
|
|
|
61
67
|
onDismiss?: (event: Event) => void;
|
|
62
68
|
/**
|
|
63
69
|
* Stops `onDismiss` from beeing called when interacting with the `safeZone` elements.
|
|
70
|
+
* - anchor: The element that should be considered safe to interact with.
|
|
64
71
|
*/
|
|
65
72
|
safeZone?: {
|
|
66
73
|
anchor?: Element | null;
|
|
@@ -112,6 +119,8 @@ const DismissableLayer = forwardRef<HTMLDivElement, DismissableLayerProps>(
|
|
|
112
119
|
) => {
|
|
113
120
|
const context = useContext(DismissableLayerContext);
|
|
114
121
|
|
|
122
|
+
const triggerPointerDownRef = useRef<boolean>(false);
|
|
123
|
+
|
|
115
124
|
const [, forceRerender] = useState({});
|
|
116
125
|
const [node, setNode] = React.useState<DismissableLayerElement | null>(
|
|
117
126
|
null,
|
|
@@ -142,13 +151,10 @@ const DismissableLayer = forwardRef<HTMLDivElement, DismissableLayerProps>(
|
|
|
142
151
|
return;
|
|
143
152
|
}
|
|
144
153
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
hasPointerDownOutside = true;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
154
|
+
const eventType = event.detail.originalEvent.type as
|
|
155
|
+
| "pointerup"
|
|
156
|
+
| "pointerdown"
|
|
157
|
+
| "focusin";
|
|
152
158
|
|
|
153
159
|
const target = event.target as HTMLElement;
|
|
154
160
|
|
|
@@ -160,19 +166,17 @@ const DismissableLayer = forwardRef<HTMLDivElement, DismissableLayerProps>(
|
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
/**
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* 'focusoutside' event on the container.
|
|
166
|
-
*
|
|
167
|
-
* To handle this, we ignore any 'focusoutside' events if a 'pointerdownoutside' event has already occurred.
|
|
168
|
-
* 'pointerdownoutside' event is sufficient to indicate interaction outside the DismissableLayer.
|
|
169
|
+
* If the target is inside a custom element, event.target will be that element on pointerdown.
|
|
170
|
+
* Therefore, checking anchor.contains(target) etc. won't work in that case.
|
|
169
171
|
*/
|
|
170
172
|
if (
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
eventType === "pointerdown" &&
|
|
174
|
+
triggerPointerDownRef.current === true
|
|
173
175
|
) {
|
|
174
176
|
event.preventDefault();
|
|
175
177
|
}
|
|
178
|
+
|
|
179
|
+
triggerPointerDownRef.current = false;
|
|
176
180
|
}
|
|
177
181
|
|
|
178
182
|
const pointerDownOutside = usePointerDownOutside(
|
|
@@ -283,6 +287,38 @@ const DismissableLayer = forwardRef<HTMLDivElement, DismissableLayerProps>(
|
|
|
283
287
|
enabled,
|
|
284
288
|
);
|
|
285
289
|
|
|
290
|
+
useEffect(() => {
|
|
291
|
+
if (!safeZone?.anchor) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const handlePointerDown = () => {
|
|
296
|
+
triggerPointerDownRef.current = true;
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
const handlePointerEnd = () => {
|
|
300
|
+
triggerPointerDownRef.current = false;
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const anchor = safeZone.anchor;
|
|
304
|
+
|
|
305
|
+
anchor.addEventListener("pointerdown", handlePointerDown, {
|
|
306
|
+
capture: true,
|
|
307
|
+
});
|
|
308
|
+
anchor.addEventListener("pointerup", handlePointerEnd);
|
|
309
|
+
anchor.addEventListener("pointerleave", handlePointerEnd);
|
|
310
|
+
anchor.addEventListener("pointercancel", handlePointerEnd);
|
|
311
|
+
|
|
312
|
+
return () => {
|
|
313
|
+
anchor.removeEventListener("pointerdown", handlePointerDown, {
|
|
314
|
+
capture: true,
|
|
315
|
+
});
|
|
316
|
+
anchor.removeEventListener("pointerup", handlePointerEnd);
|
|
317
|
+
anchor.removeEventListener("pointerleave", handlePointerEnd);
|
|
318
|
+
anchor.removeEventListener("pointercancel", handlePointerEnd);
|
|
319
|
+
};
|
|
320
|
+
}, [safeZone?.anchor]);
|
|
321
|
+
|
|
286
322
|
/**
|
|
287
323
|
* Handles registering `layers` and `layersWithOutsidePointerEventsDisabled`.
|
|
288
324
|
*/
|
|
@@ -19,10 +19,15 @@ export function useEscapeKeydown(
|
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* We use the bubbling phase (not capture) so that elements inside the layer
|
|
24
|
+
* can handle Escape themselves and call stopPropagation() if needed.
|
|
25
|
+
* Layer ordering is handled programmatically via the DismissableLayerContext.
|
|
26
|
+
*/
|
|
27
|
+
ownerDocument.addEventListener("keydown", handleKeyDown);
|
|
23
28
|
|
|
24
29
|
return () => {
|
|
25
|
-
ownerDocument.removeEventListener("keydown", handleKeyDown
|
|
30
|
+
ownerDocument.removeEventListener("keydown", handleKeyDown);
|
|
26
31
|
};
|
|
27
32
|
}, [onEscapeKeyDown, ownerDocument, enabled]);
|
|
28
33
|
}
|
|
@@ -24,12 +24,10 @@ export type ProviderProps = {
|
|
|
24
24
|
* Aksel locale
|
|
25
25
|
* @default nb
|
|
26
26
|
* @example
|
|
27
|
-
* ```jsx
|
|
28
27
|
* import { en } from "@navikt/ds-react/locales";
|
|
29
28
|
* <Provider locale={en}>
|
|
30
|
-
*
|
|
29
|
+
* {app}
|
|
31
30
|
* </Provider>
|
|
32
|
-
* ```
|
|
33
31
|
*/
|
|
34
32
|
locale: Translations;
|
|
35
33
|
/**
|
|
@@ -54,11 +52,9 @@ export const useProvider = () => useContext(ProviderContext);
|
|
|
54
52
|
* @see 🏷️ {@link ProviderProps}
|
|
55
53
|
*
|
|
56
54
|
* @example
|
|
57
|
-
* ```jsx
|
|
58
55
|
* <Provider rootElement={rootElement}>
|
|
59
56
|
* {app}
|
|
60
57
|
* </Provider>
|
|
61
|
-
* ```
|
|
62
58
|
*/
|
|
63
59
|
export const Provider = ({
|
|
64
60
|
children,
|
package/src/slot/Slot.tsx
CHANGED
|
@@ -1,25 +1,30 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { useMergeRefs } from "../util/hooks";
|
|
3
3
|
import { mergeProps } from "./merge-props";
|
|
4
4
|
|
|
5
5
|
interface SlotProps extends React.HTMLAttributes<HTMLElement> {
|
|
6
6
|
children?: React.ReactNode;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
function getChildRef(children: React.ReactNode): React.Ref<HTMLElement> | null {
|
|
10
|
+
if (!React.isValidElement(children)) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return Object.prototype.propertyIsEnumerable.call(children.props, "ref")
|
|
14
|
+
? (children.props as any).ref // React 19 (children.ref still works, but gives a warning)
|
|
15
|
+
: (children as any).ref; // React <19
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
const Slot = React.forwardRef<HTMLElement, SlotProps>((props, forwardedRef) => {
|
|
10
19
|
const { children, ...slotProps } = props;
|
|
11
20
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
children.props,
|
|
15
|
-
"ref",
|
|
16
|
-
)
|
|
17
|
-
? (children.props as any).ref // React 19 (children.ref still works, but gives a warning)
|
|
18
|
-
: (children as any).ref; // React <19
|
|
21
|
+
const childRef = getChildRef(children);
|
|
22
|
+
const mergedRef = useMergeRefs(forwardedRef, childRef);
|
|
19
23
|
|
|
24
|
+
if (React.isValidElement(children)) {
|
|
20
25
|
return React.cloneElement<any>(children, {
|
|
21
26
|
...mergeProps(slotProps, children.props as any),
|
|
22
|
-
ref:
|
|
27
|
+
ref: mergedRef,
|
|
23
28
|
});
|
|
24
29
|
}
|
|
25
30
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { composeEventHandlers } from "../../../util/composeEventHandlers";
|
|
2
|
-
import {
|
|
2
|
+
import { useMergeRefs } from "../../../util/hooks/useMergeRefs";
|
|
3
3
|
import { useTabsContext, useTabsDescendant } from "../../Tabs.context";
|
|
4
4
|
|
|
5
5
|
export interface UseTabProps {
|
|
@@ -40,8 +40,10 @@ export function useTab<P extends UseTabProps>(
|
|
|
40
40
|
selectionFollowsFocus && setSelectedValue(value);
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
+
const refs = useMergeRefs(register, ref);
|
|
44
|
+
|
|
43
45
|
return {
|
|
44
|
-
ref:
|
|
46
|
+
ref: refs,
|
|
45
47
|
isSelected,
|
|
46
48
|
isFocused: focusedValue === value,
|
|
47
49
|
id: makeTabId(id, value),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback } from "react";
|
|
2
2
|
import { composeEventHandlers } from "../../util/composeEventHandlers";
|
|
3
|
-
import {
|
|
3
|
+
import { useMergeRefs } from "../../util/hooks/useMergeRefs";
|
|
4
4
|
import {
|
|
5
5
|
useToggleGroupContext,
|
|
6
6
|
useToggleGroupDescendant,
|
|
@@ -96,8 +96,10 @@ export function useToggleItem<P extends UseToggleItemProps>(
|
|
|
96
96
|
[descendants, focusedValue, selectedValue, setFocusedValue],
|
|
97
97
|
);
|
|
98
98
|
|
|
99
|
+
const refs = useMergeRefs(register, ref);
|
|
100
|
+
|
|
99
101
|
return {
|
|
100
|
-
ref:
|
|
102
|
+
ref: refs,
|
|
101
103
|
isSelected,
|
|
102
104
|
isFocused: focusedValue === value,
|
|
103
105
|
onClick: composeEventHandlers(
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react";
|
|
2
|
+
import { useRef } from "react";
|
|
3
|
+
import { describe, expect, test, vi } from "vitest";
|
|
4
|
+
import { useMergeRefs } from "../hooks/useMergeRefs";
|
|
5
|
+
|
|
6
|
+
describe("useMergeRefs", () => {
|
|
7
|
+
test("returns null when all refs are null or undefined", () => {
|
|
8
|
+
const { result } = renderHook(() => useMergeRefs(null, undefined));
|
|
9
|
+
expect(result.current).toBeNull();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("assigns instance to object ref", () => {
|
|
13
|
+
const { result } = renderHook(() => {
|
|
14
|
+
const ref = useRef<HTMLDivElement | null>(null);
|
|
15
|
+
return { merged: useMergeRefs(ref, null), ref };
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const div = document.createElement("div");
|
|
19
|
+
result.current.merged?.(div);
|
|
20
|
+
|
|
21
|
+
expect(result.current.ref.current).toBe(div);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("calls function ref with instance", () => {
|
|
25
|
+
const fnRef = vi.fn();
|
|
26
|
+
const { result } = renderHook(() => useMergeRefs(fnRef, null));
|
|
27
|
+
|
|
28
|
+
const div = document.createElement("div");
|
|
29
|
+
result.current?.(div);
|
|
30
|
+
|
|
31
|
+
expect(fnRef).toHaveBeenCalledWith(div);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("handles mixed ref types", () => {
|
|
35
|
+
const fnRef = vi.fn();
|
|
36
|
+
const { result } = renderHook(() => {
|
|
37
|
+
const objRef = useRef<HTMLDivElement | null>(null);
|
|
38
|
+
return { merged: useMergeRefs(objRef, fnRef, null), objRef };
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const div = document.createElement("div");
|
|
42
|
+
result.current.merged?.(div);
|
|
43
|
+
|
|
44
|
+
expect(result.current.objRef.current).toBe(div);
|
|
45
|
+
expect(fnRef).toHaveBeenCalledWith(div);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("cleanup resets object ref to null", () => {
|
|
49
|
+
const { result } = renderHook(() => {
|
|
50
|
+
const ref = useRef<HTMLDivElement | null>(null);
|
|
51
|
+
return { merged: useMergeRefs(ref, null), ref };
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const div = document.createElement("div");
|
|
55
|
+
result.current.merged?.(div);
|
|
56
|
+
expect(result.current.ref.current).toBe(div);
|
|
57
|
+
|
|
58
|
+
result.current.merged?.(null);
|
|
59
|
+
expect(result.current.ref.current).toBeNull();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("cleanup calls returned cleanup function from callback ref", () => {
|
|
63
|
+
const cleanup = vi.fn();
|
|
64
|
+
const fnRef = vi.fn().mockReturnValue(cleanup);
|
|
65
|
+
const { result } = renderHook(() => useMergeRefs(fnRef, null));
|
|
66
|
+
|
|
67
|
+
const div1 = document.createElement("div");
|
|
68
|
+
result.current?.(div1);
|
|
69
|
+
|
|
70
|
+
const div2 = document.createElement("div");
|
|
71
|
+
result.current?.(div2);
|
|
72
|
+
|
|
73
|
+
expect(cleanup).toHaveBeenCalledTimes(1);
|
|
74
|
+
expect(fnRef).not.toHaveBeenCalledWith(null);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("runs previous cleanup before assigning new instance", () => {
|
|
78
|
+
const callOrder: string[] = [];
|
|
79
|
+
const cleanup = vi.fn(() => callOrder.push("cleanup"));
|
|
80
|
+
const fnRef = vi.fn(() => {
|
|
81
|
+
callOrder.push("ref");
|
|
82
|
+
return cleanup;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const { result } = renderHook(() => useMergeRefs(fnRef, null));
|
|
86
|
+
|
|
87
|
+
result.current?.(document.createElement("div"));
|
|
88
|
+
result.current?.(document.createElement("div"));
|
|
89
|
+
|
|
90
|
+
expect(callOrder).toEqual(["ref", "cleanup", "ref"]);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import React, { useRef, useState } from "react";
|
|
5
5
|
import { createStrictContext } from "../../create-strict-context";
|
|
6
6
|
import { useClientLayoutEffect } from "../useClientLayoutEffect";
|
|
7
|
-
import {
|
|
7
|
+
import { useMergeRefs } from "../useMergeRefs";
|
|
8
8
|
import { DescendantOptions, DescendantsManager } from "./descendant";
|
|
9
9
|
import { cast } from "./utils";
|
|
10
10
|
|
|
@@ -66,11 +66,13 @@ export function createDescendantContext<
|
|
|
66
66
|
? cast<React.RefCallback<T>>(descendants.register(options))
|
|
67
67
|
: cast<React.RefCallback<T>>(descendants.register);
|
|
68
68
|
|
|
69
|
+
const refs = useMergeRefs(refCallback, ref);
|
|
70
|
+
|
|
69
71
|
return {
|
|
70
72
|
descendants,
|
|
71
73
|
index,
|
|
72
74
|
enabledIndex: descendants.enabledIndexOf(ref.current),
|
|
73
|
-
register:
|
|
75
|
+
register: refs,
|
|
74
76
|
};
|
|
75
77
|
}
|
|
76
78
|
|