@navikt/ds-react 7.33.2 → 7.33.4

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.
Files changed (44) hide show
  1. package/cjs/form/textarea/Textarea.js +1 -8
  2. package/cjs/form/textarea/Textarea.js.map +1 -1
  3. package/cjs/overlays/action-menu/ActionMenu.d.ts +20 -0
  4. package/cjs/overlays/action-menu/ActionMenu.js +20 -0
  5. package/cjs/overlays/action-menu/ActionMenu.js.map +1 -1
  6. package/cjs/overlays/dismissablelayer/DismissableLayer.js +23 -32
  7. package/cjs/overlays/dismissablelayer/DismissableLayer.js.map +1 -1
  8. package/cjs/overlays/dismissablelayer/util/useEscapeKeydown.d.ts +1 -1
  9. package/cjs/overlays/dismissablelayer/util/useEscapeKeydown.js +8 -3
  10. package/cjs/overlays/dismissablelayer/util/useEscapeKeydown.js.map +1 -1
  11. package/cjs/overlays/dismissablelayer/util/useFocusOutside.d.ts +1 -1
  12. package/cjs/overlays/dismissablelayer/util/useFocusOutside.js +8 -3
  13. package/cjs/overlays/dismissablelayer/util/useFocusOutside.js.map +1 -1
  14. package/cjs/overlays/dismissablelayer/util/usePointerDownOutside.d.ts +1 -1
  15. package/cjs/overlays/dismissablelayer/util/usePointerDownOutside.js +5 -2
  16. package/cjs/overlays/dismissablelayer/util/usePointerDownOutside.js.map +1 -1
  17. package/cjs/util/TextareaAutoSize.js +5 -1
  18. package/cjs/util/TextareaAutoSize.js.map +1 -1
  19. package/esm/form/textarea/Textarea.js +1 -8
  20. package/esm/form/textarea/Textarea.js.map +1 -1
  21. package/esm/overlays/action-menu/ActionMenu.d.ts +20 -0
  22. package/esm/overlays/action-menu/ActionMenu.js +20 -0
  23. package/esm/overlays/action-menu/ActionMenu.js.map +1 -1
  24. package/esm/overlays/dismissablelayer/DismissableLayer.js +22 -31
  25. package/esm/overlays/dismissablelayer/DismissableLayer.js.map +1 -1
  26. package/esm/overlays/dismissablelayer/util/useEscapeKeydown.d.ts +1 -1
  27. package/esm/overlays/dismissablelayer/util/useEscapeKeydown.js +8 -3
  28. package/esm/overlays/dismissablelayer/util/useEscapeKeydown.js.map +1 -1
  29. package/esm/overlays/dismissablelayer/util/useFocusOutside.d.ts +1 -1
  30. package/esm/overlays/dismissablelayer/util/useFocusOutside.js +8 -3
  31. package/esm/overlays/dismissablelayer/util/useFocusOutside.js.map +1 -1
  32. package/esm/overlays/dismissablelayer/util/usePointerDownOutside.d.ts +1 -1
  33. package/esm/overlays/dismissablelayer/util/usePointerDownOutside.js +5 -2
  34. package/esm/overlays/dismissablelayer/util/usePointerDownOutside.js.map +1 -1
  35. package/esm/util/TextareaAutoSize.js +5 -1
  36. package/esm/util/TextareaAutoSize.js.map +1 -1
  37. package/package.json +5 -5
  38. package/src/form/textarea/Textarea.tsx +1 -9
  39. package/src/overlays/action-menu/ActionMenu.tsx +20 -0
  40. package/src/overlays/dismissablelayer/DismissableLayer.tsx +91 -97
  41. package/src/overlays/dismissablelayer/util/useEscapeKeydown.ts +9 -2
  42. package/src/overlays/dismissablelayer/util/useFocusOutside.ts +9 -2
  43. package/src/overlays/dismissablelayer/util/usePointerDownOutside.ts +6 -1
  44. package/src/util/TextareaAutoSize.tsx +6 -2
@@ -1,6 +1,5 @@
1
1
  import React, { forwardRef, useContext, useEffect, useState } from "react";
2
2
  import { Slot } from "../../slot/Slot";
3
- import { omit } from "../../util";
4
3
  import { composeEventHandlers } from "../../util/composeEventHandlers";
5
4
  import { useMergeRefs } from "../../util/hooks";
6
5
  import { ownerDocument } from "../../util/owner";
@@ -63,34 +62,7 @@ interface DismissableLayerBaseProps
63
62
 
64
63
  type DismissableLayerProps = DismissableLayerBaseProps & AsChild;
65
64
 
66
- const DismissableLayer = forwardRef<HTMLDivElement, DismissableLayerProps>(
67
- ({ enabled = true, ...restProps }: DismissableLayerProps, forwardedRef) => {
68
- if (!enabled) {
69
- const Component = restProps.asChild ? Slot : "div";
70
- return (
71
- <Component
72
- {...omit(restProps, [
73
- "asChild",
74
- "disableOutsidePointerEvents",
75
- "onDismiss",
76
- "onEscapeKeyDown",
77
- "onFocusOutside",
78
- "onInteractOutside",
79
- "onPointerDownOutside",
80
- "safeZone",
81
- ])}
82
- ref={forwardedRef}
83
- />
84
- );
85
- }
86
-
87
- return <DismissableLayerInternal {...restProps} ref={forwardedRef} />;
88
- },
89
- );
90
-
91
- type DismissableLayerElement = React.ComponentRef<
92
- typeof DismissableLayerInternal
93
- >;
65
+ type DismissableLayerElement = React.ComponentRef<typeof DismissableLayer>;
94
66
 
95
67
  const BranchedLayerContext =
96
68
  React.createContext<DismissableLayerElement | null>(null);
@@ -108,10 +80,7 @@ const DismissableLayerContext = React.createContext({
108
80
  layersWithOutsidePointerEventsDisabled: new Set<DismissableLayerElement>(),
109
81
  });
110
82
 
111
- const DismissableLayerInternal = forwardRef<
112
- HTMLDivElement,
113
- DismissableLayerProps
114
- >(
83
+ const DismissableLayer = forwardRef<HTMLDivElement, DismissableLayerProps>(
115
84
  (
116
85
  {
117
86
  children,
@@ -123,6 +92,7 @@ const DismissableLayerInternal = forwardRef<
123
92
  onPointerDownOutside,
124
93
  safeZone,
125
94
  asChild,
95
+ enabled = true,
126
96
  ...restProps
127
97
  }: DismissableLayerProps,
128
98
  forwardedRef,
@@ -194,73 +164,85 @@ const DismissableLayerInternal = forwardRef<
194
164
  }
195
165
  }
196
166
 
197
- const pointerDownOutside = usePointerDownOutside((event) => {
198
- if (!shouldEnablePointerEvents) {
199
- return;
200
- }
201
-
202
- /**
203
- * We call these before letting `handleOutsideEvent` do its checks to give consumer a chance to preventDefault.
204
- */
205
- onPointerDownOutside?.(event);
206
- onInteractOutside?.(event);
207
-
208
- /**
209
- * Add safeZone to prevent closing when interacting with trigger/anchor or its children.
210
- */
211
- safeZone && handleOutsideEvent(event);
167
+ const pointerDownOutside = usePointerDownOutside(
168
+ (event) => {
169
+ if (!shouldEnablePointerEvents) {
170
+ return;
171
+ }
212
172
 
213
- if (!event.defaultPrevented && onDismiss) {
214
- onDismiss();
215
- }
216
- }, ownerDoc);
173
+ /**
174
+ * We call these before letting `handleOutsideEvent` do its checks to give consumer a chance to preventDefault.
175
+ */
176
+ onPointerDownOutside?.(event);
177
+ onInteractOutside?.(event);
217
178
 
218
- const focusOutside = useFocusOutside((event) => {
219
- /**
220
- * We call these before letting `handleOutsideEvent` do its checks to give consumer a chance to preventDefault.
221
- */
222
- onFocusOutside?.(event);
223
- onInteractOutside?.(event);
179
+ /**
180
+ * Add safeZone to prevent closing when interacting with trigger/anchor or its children.
181
+ */
182
+ safeZone && handleOutsideEvent(event);
224
183
 
225
- /**
226
- * Add safeZone to prevent closing when interacting with trigger/anchor or its children.
227
- */
228
- safeZone && handleOutsideEvent(event);
184
+ if (!event.defaultPrevented && onDismiss) {
185
+ onDismiss();
186
+ }
187
+ },
188
+ ownerDoc,
189
+ enabled,
190
+ );
229
191
 
230
- if (!event.defaultPrevented && onDismiss) {
231
- onDismiss();
232
- }
233
- }, ownerDoc);
192
+ const focusOutside = useFocusOutside(
193
+ (event) => {
194
+ /**
195
+ * We call these before letting `handleOutsideEvent` do its checks to give consumer a chance to preventDefault.
196
+ */
197
+ onFocusOutside?.(event);
198
+ onInteractOutside?.(event);
199
+
200
+ /**
201
+ * Add safeZone to prevent closing when interacting with trigger/anchor or its children.
202
+ */
203
+ safeZone && handleOutsideEvent(event);
204
+
205
+ if (!event.defaultPrevented && onDismiss) {
206
+ onDismiss();
207
+ }
208
+ },
209
+ ownerDoc,
210
+ enabled,
211
+ );
234
212
 
235
- useEscapeKeydown((event) => {
236
- /**
237
- * The deepest nested element will always be last in the descendants list.
238
- * This allows us to only close the highest layer when pressing escape.
239
- */
240
- const isHighestLayer = index === context.layers.size - 1;
241
- if (!isHighestLayer) {
242
- return;
243
- }
213
+ useEscapeKeydown(
214
+ (event) => {
215
+ /**
216
+ * The deepest nested element will always be last in the descendants list.
217
+ * This allows us to only close the highest layer when pressing escape.
218
+ */
219
+ const isHighestLayer = index === context.layers.size - 1;
220
+ if (!isHighestLayer) {
221
+ return;
222
+ }
244
223
 
245
- /**
246
- * We call this before letting `handleOutsideEvent` do its checks to give consumer a chance to preventDefault based certain cases.
247
- */
248
- onEscapeKeyDown?.(event);
249
- /**
250
- * `onEscapeKeyDown` is able to preventDefault the event, thus stopping call for `onDismiss`.
251
- * We want to `preventDefault` the escape-event to avoid sideeffect from other elements on screen
252
- */
253
- if (!event.defaultPrevented && onDismiss) {
254
- event.preventDefault();
255
- onDismiss();
256
- }
257
- }, ownerDoc);
224
+ /**
225
+ * We call this before letting `handleOutsideEvent` do its checks to give consumer a chance to preventDefault based certain cases.
226
+ */
227
+ onEscapeKeyDown?.(event);
228
+ /**
229
+ * `onEscapeKeyDown` is able to preventDefault the event, thus stopping call for `onDismiss`.
230
+ * We want to `preventDefault` the escape-event to avoid sideeffect from other elements on screen
231
+ */
232
+ if (!event.defaultPrevented && onDismiss) {
233
+ event.preventDefault();
234
+ onDismiss();
235
+ }
236
+ },
237
+ ownerDoc,
238
+ enabled,
239
+ );
258
240
 
259
241
  /**
260
242
  * Handles registering `layers` and `layersWithOutsidePointerEventsDisabled`.
261
243
  */
262
244
  useEffect(() => {
263
- if (!node) {
245
+ if (!node || !enabled) {
264
246
  return;
265
247
  }
266
248
 
@@ -282,25 +264,32 @@ const DismissableLayerInternal = forwardRef<
282
264
  ownerDoc.body.style.pointerEvents = originalBodyPointerEvents;
283
265
  }
284
266
  };
285
- }, [node, disableOutsidePointerEvents, context, ownerDoc]);
267
+ }, [node, enabled, disableOutsidePointerEvents, context, ownerDoc]);
286
268
 
287
269
  /**
288
270
  * We purposefully prevent combining this effect with the `disableOutsidePointerEvents` effect
289
271
  * because a change to `disableOutsidePointerEvents` would remove this layer from the stack
290
272
  * and add it to the end again so the layering order wouldn't be creation order.
291
273
  * We only want them to be removed from context stacks when unmounted.
274
+ *
275
+ * We depend on `enabled` to clean up when the layer is disabled.
292
276
  */
277
+ // biome-ignore lint/correctness/useExhaustiveDependencies: We need to clean up after enabled changes.
293
278
  useEffect(() => {
294
279
  return () => {
295
280
  if (!node) {
296
281
  return;
297
282
  }
298
-
299
- context.layers.delete(node);
300
- context.layersWithOutsidePointerEventsDisabled.delete(node);
301
- dispatchUpdate();
283
+ if (
284
+ context.layers.has(node) ||
285
+ context.layersWithOutsidePointerEventsDisabled.has(node)
286
+ ) {
287
+ context.layers.delete(node);
288
+ context.layersWithOutsidePointerEventsDisabled.delete(node);
289
+ dispatchUpdate();
290
+ }
302
291
  };
303
- }, [node, context]);
292
+ }, [node, context, enabled]);
304
293
 
305
294
  const parentBranchedLayer = useContext(BranchedLayerContext);
306
295
 
@@ -309,7 +298,12 @@ const DismissableLayerInternal = forwardRef<
309
298
  * When this layer has a parent, we register it as a child of the parent.
310
299
  */
311
300
  useEffect(() => {
312
- if (!node || !parentBranchedLayer || node === parentBranchedLayer) {
301
+ if (
302
+ !node ||
303
+ !enabled ||
304
+ !parentBranchedLayer ||
305
+ node === parentBranchedLayer
306
+ ) {
313
307
  return;
314
308
  }
315
309
 
@@ -332,7 +326,7 @@ const DismissableLayerInternal = forwardRef<
332
326
 
333
327
  dispatchUpdate();
334
328
  };
335
- }, [node, parentBranchedLayer, context]);
329
+ }, [node, enabled, parentBranchedLayer, context]);
336
330
 
337
331
  /**
338
332
  * Synchronizes layer state across all mounted `DismissableLayer` instances.
@@ -4,10 +4,15 @@ import { useCallbackRef } from "../../../util/hooks";
4
4
  export function useEscapeKeydown(
5
5
  callback?: (event: KeyboardEvent) => void,
6
6
  ownerDocument: Document = globalThis?.document,
7
+ enabled: boolean = true,
7
8
  ) {
8
9
  const onEscapeKeyDown = useCallbackRef(callback);
9
10
 
10
11
  useEffect(() => {
12
+ if (!enabled) {
13
+ return;
14
+ }
15
+
11
16
  const handleKeyDown = (event: KeyboardEvent) => {
12
17
  if (event.key === "Escape") {
13
18
  onEscapeKeyDown(event);
@@ -15,7 +20,9 @@ export function useEscapeKeydown(
15
20
  };
16
21
 
17
22
  ownerDocument.addEventListener("keydown", handleKeyDown, true);
18
- return () =>
23
+
24
+ return () => {
19
25
  ownerDocument.removeEventListener("keydown", handleKeyDown, true);
20
- }, [onEscapeKeyDown, ownerDocument]);
26
+ };
27
+ }, [onEscapeKeyDown, ownerDocument, enabled]);
21
28
  }
@@ -12,11 +12,16 @@ import {
12
12
  export function useFocusOutside(
13
13
  callback?: (event: CustomFocusEvent) => void,
14
14
  ownerDocument: Document = globalThis?.document,
15
+ enabled: boolean = true,
15
16
  ) {
16
17
  const handleFocusOutside = useCallbackRef(callback) as EventListener;
17
18
  const isFocusInsideReactTreeRef = useRef(false);
18
19
 
19
20
  useEffect(() => {
21
+ if (!enabled) {
22
+ return;
23
+ }
24
+
20
25
  const handleFocus = (event: FocusEvent) => {
21
26
  if (event.target && !isFocusInsideReactTreeRef.current) {
22
27
  const eventDetail = { originalEvent: event };
@@ -38,8 +43,10 @@ export function useFocusOutside(
38
43
  }
39
44
  };
40
45
  ownerDocument.addEventListener("focusin", handleFocus);
41
- return () => ownerDocument.removeEventListener("focusin", handleFocus);
42
- }, [ownerDocument, handleFocusOutside]);
46
+ return () => {
47
+ ownerDocument.removeEventListener("focusin", handleFocus);
48
+ };
49
+ }, [ownerDocument, handleFocusOutside, enabled]);
43
50
 
44
51
  /**
45
52
  * By directly setting isFocusInsideReactTreeRef on focus-events at the root of the "dismissable" element,
@@ -16,6 +16,7 @@ import {
16
16
  export function usePointerDownOutside(
17
17
  callback?: (event: CustomPointerDownEvent) => void,
18
18
  ownerDocument: Document = globalThis?.document,
19
+ enabled: boolean = true,
19
20
  ) {
20
21
  const handlePointerDownOutside = useCallbackRef(callback) as EventListener;
21
22
  const isPointerInsideReactTreeRef = useRef(false);
@@ -23,6 +24,10 @@ export function usePointerDownOutside(
23
24
  const timeout = useTimeout();
24
25
 
25
26
  useEffect(() => {
27
+ if (!enabled) {
28
+ return;
29
+ }
30
+
26
31
  const handlePointerDown = (event: PointerEvent) => {
27
32
  /**
28
33
  * The `DismisableLayer`-API is based on the ability to stop events from propagating and in the end calling `onDismiss`
@@ -87,7 +92,7 @@ export function usePointerDownOutside(
87
92
  ownerDocument.removeEventListener("pointerdown", handlePointerDown);
88
93
  ownerDocument.removeEventListener("click", handleClickRef.current);
89
94
  };
90
- }, [ownerDocument, handlePointerDownOutside, timeout]);
95
+ }, [ownerDocument, handlePointerDownOutside, timeout, enabled]);
91
96
 
92
97
  return {
93
98
  // ensures we check React component tree (not just DOM tree)
@@ -219,8 +219,12 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
219
219
  };
220
220
 
221
221
  const mainStyle: React.CSSProperties = {
222
- "--__ac-textarea-height": state.outerHeightStyle + "px",
223
- "--__axc-textarea-height": state.outerHeightStyle + "px",
222
+ "--__ac-textarea-height": state.outerHeightStyle
223
+ ? state.outerHeightStyle + "px"
224
+ : "auto",
225
+ "--__axc-textarea-height": state.outerHeightStyle
226
+ ? state.outerHeightStyle + "px"
227
+ : "auto",
224
228
  // Need a large enough difference to allow scrolling.
225
229
  // This prevents infinite rendering loop.
226
230
  overflow: