@navikt/ds-react 5.7.6 → 5.9.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.
Files changed (164) hide show
  1. package/_docs.json +1824 -1758
  2. package/cjs/accordion/AccordionHeader.js +2 -2
  3. package/cjs/date/context/useDateInputContext.js +1 -5
  4. package/cjs/date/datepicker/DatePicker.js +26 -25
  5. package/cjs/date/hooks/useDatepicker.js +9 -17
  6. package/cjs/date/hooks/useMonthPicker.js +9 -17
  7. package/cjs/date/hooks/useRangeDatepicker.js +9 -20
  8. package/cjs/date/monthpicker/MonthPicker.js +11 -6
  9. package/cjs/date/{DateInput.js → parts/DateInput.js} +14 -10
  10. package/cjs/date/parts/DateWrapper.js +55 -0
  11. package/cjs/date/utils/labels.js +77 -1
  12. package/cjs/form/combobox/Combobox.js +2 -2
  13. package/cjs/form/combobox/ComboboxProvider.js +1 -2
  14. package/cjs/form/combobox/FilteredOptions/FilteredOptions.js +15 -14
  15. package/cjs/form/combobox/FilteredOptions/filtered-options-util.js +24 -0
  16. package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js +24 -108
  17. package/cjs/form/combobox/FilteredOptions/useVirtualFocus.js +55 -0
  18. package/cjs/form/combobox/Input/Input.js +33 -16
  19. package/cjs/form/combobox/customOptionsContext.js +2 -3
  20. package/cjs/layout/sidemal-test/Sidebar.js +1 -1
  21. package/cjs/loader/Loader.js +1 -1
  22. package/cjs/modal/Modal.js +39 -15
  23. package/cjs/popover/Popover.js +5 -7
  24. package/cjs/tooltip/Tooltip.js +14 -3
  25. package/cjs/util/useMedia.js +30 -0
  26. package/esm/accordion/AccordionHeader.js +2 -2
  27. package/esm/accordion/AccordionHeader.js.map +1 -1
  28. package/esm/date/context/useDateInputContext.d.ts +6 -2
  29. package/esm/date/context/useDateInputContext.js +1 -5
  30. package/esm/date/context/useDateInputContext.js.map +1 -1
  31. package/esm/date/datepicker/DatePicker.d.ts +1 -1
  32. package/esm/date/datepicker/DatePicker.js +28 -27
  33. package/esm/date/datepicker/DatePicker.js.map +1 -1
  34. package/esm/date/datepicker/types.d.ts +0 -5
  35. package/esm/date/hooks/useDatepicker.d.ts +8 -5
  36. package/esm/date/hooks/useDatepicker.js +10 -18
  37. package/esm/date/hooks/useDatepicker.js.map +1 -1
  38. package/esm/date/hooks/useMonthPicker.d.ts +7 -4
  39. package/esm/date/hooks/useMonthPicker.js +10 -18
  40. package/esm/date/hooks/useMonthPicker.js.map +1 -1
  41. package/esm/date/hooks/useRangeDatepicker.d.ts +9 -3
  42. package/esm/date/hooks/useRangeDatepicker.js +10 -21
  43. package/esm/date/hooks/useRangeDatepicker.js.map +1 -1
  44. package/esm/date/index.d.ts +1 -1
  45. package/esm/date/index.js.map +1 -1
  46. package/esm/date/monthpicker/MonthPicker.d.ts +1 -1
  47. package/esm/date/monthpicker/MonthPicker.js +13 -8
  48. package/esm/date/monthpicker/MonthPicker.js.map +1 -1
  49. package/esm/date/monthpicker/types.d.ts +0 -5
  50. package/esm/date/{DateInput.d.ts → parts/DateInput.d.ts} +5 -1
  51. package/esm/date/{DateInput.js → parts/DateInput.js} +15 -11
  52. package/esm/date/parts/DateInput.js.map +1 -0
  53. package/esm/date/parts/DateWrapper.d.ts +15 -0
  54. package/esm/date/parts/DateWrapper.js +26 -0
  55. package/esm/date/parts/DateWrapper.js.map +1 -0
  56. package/esm/date/utils/labels.d.ts +2 -0
  57. package/esm/date/utils/labels.js +74 -0
  58. package/esm/date/utils/labels.js.map +1 -1
  59. package/esm/form/combobox/Combobox.js +2 -2
  60. package/esm/form/combobox/Combobox.js.map +1 -1
  61. package/esm/form/combobox/ComboboxProvider.js +1 -2
  62. package/esm/form/combobox/ComboboxProvider.js.map +1 -1
  63. package/esm/form/combobox/FilteredOptions/FilteredOptions.js +15 -14
  64. package/esm/form/combobox/FilteredOptions/FilteredOptions.js.map +1 -1
  65. package/esm/form/combobox/FilteredOptions/filtered-options-util.d.ts +12 -0
  66. package/esm/form/combobox/FilteredOptions/filtered-options-util.js +23 -0
  67. package/esm/form/combobox/FilteredOptions/filtered-options-util.js.map +1 -0
  68. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.d.ts +10 -13
  69. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js +25 -109
  70. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
  71. package/esm/form/combobox/FilteredOptions/useVirtualFocus.d.ts +15 -0
  72. package/esm/form/combobox/FilteredOptions/useVirtualFocus.js +54 -0
  73. package/esm/form/combobox/FilteredOptions/useVirtualFocus.js.map +1 -0
  74. package/esm/form/combobox/Input/Input.js +33 -16
  75. package/esm/form/combobox/Input/Input.js.map +1 -1
  76. package/esm/form/combobox/customOptionsContext.d.ts +4 -1
  77. package/esm/form/combobox/customOptionsContext.js +2 -3
  78. package/esm/form/combobox/customOptionsContext.js.map +1 -1
  79. package/esm/layout/bleed/Bleed.d.ts +1 -1
  80. package/esm/layout/bleed/Bleed.js +1 -1
  81. package/esm/layout/bleed/Bleed.js.map +1 -1
  82. package/esm/layout/box/Box.d.ts +1 -2
  83. package/esm/layout/box/Box.js +1 -1
  84. package/esm/layout/box/Box.js.map +1 -1
  85. package/esm/layout/grid/HGrid.d.ts +1 -1
  86. package/esm/layout/grid/HGrid.js +1 -1
  87. package/esm/layout/grid/HGrid.js.map +1 -1
  88. package/esm/layout/responsive/Responsive.d.ts +1 -1
  89. package/esm/layout/sidemal-test/Sidebar.js +1 -1
  90. package/esm/layout/sidemal-test/Sidebar.js.map +1 -1
  91. package/esm/layout/stack/Stack.d.ts +1 -1
  92. package/esm/layout/stack/Stack.js +1 -1
  93. package/esm/layout/stack/Stack.js.map +1 -1
  94. package/esm/layout/utilities/css.d.ts +1 -8
  95. package/esm/layout/utilities/css.js.map +1 -1
  96. package/esm/layout/utilities/types.d.ts +9 -0
  97. package/esm/loader/Loader.d.ts +1 -1
  98. package/esm/loader/Loader.js +1 -1
  99. package/esm/modal/Modal.js +39 -15
  100. package/esm/modal/Modal.js.map +1 -1
  101. package/esm/modal/ModalContext.d.ts +1 -0
  102. package/esm/modal/ModalContext.js.map +1 -1
  103. package/esm/modal/types.d.ts +7 -0
  104. package/esm/popover/Popover.d.ts +0 -5
  105. package/esm/popover/Popover.js +5 -7
  106. package/esm/popover/Popover.js.map +1 -1
  107. package/esm/tooltip/Tooltip.js +16 -5
  108. package/esm/tooltip/Tooltip.js.map +1 -1
  109. package/esm/util/useMedia.d.ts +8 -0
  110. package/esm/util/useMedia.js +27 -0
  111. package/esm/util/useMedia.js.map +1 -0
  112. package/package.json +3 -3
  113. package/src/accordion/AccordionHeader.tsx +3 -3
  114. package/src/date/context/useDateInputContext.tsx +5 -5
  115. package/src/date/datepicker/DatePicker.tsx +58 -65
  116. package/src/date/datepicker/datepicker.stories.tsx +37 -46
  117. package/src/date/datepicker/types.ts +0 -5
  118. package/src/date/hooks/useDatepicker.tsx +20 -25
  119. package/src/date/hooks/useMonthPicker.tsx +18 -24
  120. package/src/date/hooks/useRangeDatepicker.tsx +27 -30
  121. package/src/date/index.ts +1 -1
  122. package/src/date/monthpicker/MonthPicker.tsx +39 -43
  123. package/src/date/monthpicker/types.ts +0 -5
  124. package/src/date/{DateInput.tsx → parts/DateInput.tsx} +23 -12
  125. package/src/date/parts/DateWrapper.tsx +80 -0
  126. package/src/date/utils/labels.ts +83 -0
  127. package/src/form/combobox/Combobox.tsx +2 -2
  128. package/src/form/combobox/ComboboxProvider.tsx +1 -2
  129. package/src/form/combobox/FilteredOptions/FilteredOptions.tsx +28 -16
  130. package/src/form/combobox/FilteredOptions/filtered-options-util.ts +38 -0
  131. package/src/form/combobox/FilteredOptions/filteredOptionsContext.tsx +71 -142
  132. package/src/form/combobox/FilteredOptions/useVirtualFocus.ts +87 -0
  133. package/src/form/combobox/Input/Input.tsx +40 -21
  134. package/src/form/combobox/combobox.stories.tsx +44 -0
  135. package/src/form/combobox/customOptionsContext.tsx +10 -5
  136. package/src/guide-panel/guidepanel.stories.tsx +2 -2
  137. package/src/layout/bleed/Bleed.tsx +2 -5
  138. package/src/layout/box/Box.tsx +1 -3
  139. package/src/layout/grid/HGrid.tsx +2 -6
  140. package/src/layout/responsive/Responsive.tsx +1 -1
  141. package/src/layout/sidemal-test/Sidebar.tsx +1 -1
  142. package/src/layout/stack/Stack.tsx +2 -6
  143. package/src/layout/utilities/css.ts +1 -36
  144. package/src/layout/utilities/types.ts +16 -0
  145. package/src/loader/Loader.tsx +1 -1
  146. package/src/modal/Modal.tsx +54 -21
  147. package/src/modal/ModalContext.ts +1 -0
  148. package/src/modal/modal.stories.tsx +30 -2
  149. package/src/modal/types.ts +7 -0
  150. package/src/popover/Popover.tsx +4 -12
  151. package/src/tooltip/Tooltip.tsx +18 -6
  152. package/src/util/__tests__/useMedia.test.tsx +19 -0
  153. package/src/util/useMedia.ts +38 -0
  154. package/cjs/date/hooks/useEscape.js +0 -23
  155. package/cjs/date/hooks/useOutsideClickHandler.js +0 -26
  156. package/esm/date/DateInput.js.map +0 -1
  157. package/esm/date/hooks/useEscape.d.ts +0 -2
  158. package/esm/date/hooks/useEscape.js +0 -20
  159. package/esm/date/hooks/useEscape.js.map +0 -1
  160. package/esm/date/hooks/useOutsideClickHandler.d.ts +0 -1
  161. package/esm/date/hooks/useOutsideClickHandler.js +0 -23
  162. package/esm/date/hooks/useOutsideClickHandler.js.map +0 -1
  163. package/src/date/hooks/useEscape.tsx +0 -30
  164. package/src/date/hooks/useOutsideClickHandler.tsx +0 -34
@@ -1,10 +1,7 @@
1
1
  import cl from "clsx";
2
2
  import React, { forwardRef } from "react";
3
- import {
4
- ResponsiveProp,
5
- SpacingScale,
6
- getResponsiveProps,
7
- } from "../utilities/css";
3
+ import { getResponsiveProps } from "../utilities/css";
4
+ import { ResponsiveProp, SpacingScale } from "../utilities/types";
8
5
  import { Slot } from "../../util/Slot";
9
6
 
10
7
  export type BleedSpacingInline = "0" | "full" | "px" | SpacingScale;
@@ -1,13 +1,11 @@
1
1
  import cl from "clsx";
2
2
  import React, { forwardRef } from "react";
3
3
  import { OverridableComponent } from "../../util/OverridableComponent";
4
+ import { getResponsiveProps } from "../utilities/css";
4
5
  import {
5
6
  SpaceDelimitedAttribute,
6
7
  ResponsiveProp,
7
8
  SpacingScale,
8
- getResponsiveProps,
9
- } from "../utilities/css";
10
- import {
11
9
  BackgroundToken,
12
10
  BorderColorToken,
13
11
  ShadowToken,
@@ -1,11 +1,7 @@
1
1
  import React, { forwardRef, HTMLAttributes } from "react";
2
2
  import cl from "clsx";
3
- import {
4
- getResponsiveProps,
5
- getResponsiveValue,
6
- ResponsiveProp,
7
- SpacingScale,
8
- } from "../utilities/css";
3
+ import { getResponsiveProps, getResponsiveValue } from "../utilities/css";
4
+ import { ResponsiveProp, SpacingScale } from "../utilities/types";
9
5
 
10
6
  export interface HGridProps extends HTMLAttributes<HTMLDivElement> {
11
7
  children: React.ReactNode;
@@ -1,6 +1,6 @@
1
1
  import cl from "clsx";
2
2
  import React, { forwardRef, HTMLAttributes } from "react";
3
- import { BreakpointsAlias } from "../utilities/css";
3
+ import { BreakpointsAlias } from "../utilities/types";
4
4
  import { Slot } from "../../util/Slot";
5
5
 
6
6
  export interface ResponsiveProps extends HTMLAttributes<HTMLDivElement> {
@@ -1,8 +1,8 @@
1
1
  import React from "react";
2
+ import { Link } from "../../link";
2
3
  import { Heading, Label } from "../../typography";
3
4
  import { Box } from "../box";
4
5
  import { VStack } from "../stack";
5
- import { Link } from "../../link";
6
6
 
7
7
  const LinkElement = ({ children }) => {
8
8
  return (
@@ -1,12 +1,8 @@
1
1
  import cl from "clsx";
2
2
  import React, { forwardRef, HTMLAttributes } from "react";
3
3
  import { OverridableComponent } from "../../util/OverridableComponent";
4
- import {
5
- getResponsiveProps,
6
- getResponsiveValue,
7
- ResponsiveProp,
8
- SpacingScale,
9
- } from "../utilities/css";
4
+ import { getResponsiveProps, getResponsiveValue } from "../utilities/css";
5
+ import { ResponsiveProp, SpacingScale } from "../utilities/types";
10
6
 
11
7
  export interface StackProps extends HTMLAttributes<HTMLDivElement> {
12
8
  children: React.ReactNode;
@@ -1,39 +1,4 @@
1
- export type BreakpointsAlias = "xs" | "sm" | "md" | "lg" | "xl";
2
-
3
- export type SpacingScale =
4
- | "0"
5
- | "05"
6
- | "1"
7
- | "1-alt"
8
- | "2"
9
- | "3"
10
- | "4"
11
- | "5"
12
- | "6"
13
- | "7"
14
- | "8"
15
- | "9"
16
- | "10"
17
- | "11"
18
- | "12"
19
- | "14"
20
- | "16"
21
- | "18"
22
- | "20"
23
- | "24"
24
- | "32";
25
-
26
- export type SpaceDelimitedAttribute<T extends string> =
27
- | T
28
- | `${T} ${T}`
29
- | `${T} ${T} ${T}`
30
- | `${T} ${T} ${T} ${T}`;
31
-
32
- type FixedResponsiveT<T> = {
33
- [Breakpoint in BreakpointsAlias]?: T;
34
- };
35
-
36
- export type ResponsiveProp<T> = T | FixedResponsiveT<T>;
1
+ import { ResponsiveProp } from "./types";
37
2
 
38
3
  export function getResponsiveValue<T = string>(
39
4
  componentName: string,
@@ -3,6 +3,7 @@ import surfaceColors from "@navikt/ds-tokens/src/colors-surface.json";
3
3
  import borderColors from "@navikt/ds-tokens/src/colors-border.json";
4
4
  import borderRadii from "@navikt/ds-tokens/src/border.json";
5
5
  import shadows from "@navikt/ds-tokens/src/shadow.json";
6
+ import Spacing from "@navikt/ds-tokens/src/spacing.json";
6
7
 
7
8
  export type BackgroundToken =
8
9
  | keyof typeof bgColors.a
@@ -12,3 +13,18 @@ export type BorderRadiiToken =
12
13
  | keyof (typeof borderRadii.a)["border-radius"]
13
14
  | "0";
14
15
  export type ShadowToken = keyof typeof shadows.a.shadow;
16
+
17
+ export type BreakpointsAlias = "xs" | "sm" | "md" | "lg" | "xl";
18
+
19
+ export type SpacingScale = keyof (typeof Spacing)["a"]["spacing"];
20
+
21
+ export type SpaceDelimitedAttribute<T extends string> =
22
+ | T
23
+ | `${T} ${T}`
24
+ | `${T} ${T} ${T}`
25
+ | `${T} ${T} ${T} ${T}`;
26
+ type FixedResponsiveT<T> = {
27
+ [Breakpoint in BreakpointsAlias]?: T;
28
+ };
29
+
30
+ export type ResponsiveProp<T> = T | FixedResponsiveT<T>;
@@ -52,7 +52,7 @@ export type LoaderType = React.ForwardRefExoticComponent<
52
52
  *
53
53
  * @example
54
54
  * ```jsx
55
- * <Loader size="3xlarge" title="venter..." />
55
+ * <Loader size="3xlarge" title="Venter..." />
56
56
  * ```
57
57
  */
58
58
  export const Loader: LoaderType = forwardRef<SVGSVGElement, LoaderProps>(
@@ -8,6 +8,7 @@ import React, {
8
8
  useRef,
9
9
  } from "react";
10
10
  import { createPortal } from "react-dom";
11
+ import { DateContext } from "../date/context";
11
12
  import { useProvider } from "../provider";
12
13
  import { Detail, Heading } from "../typography";
13
14
  import { mergeRefs, useId } from "../util";
@@ -82,11 +83,13 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
82
83
  open,
83
84
  onBeforeClose,
84
85
  onCancel,
86
+ closeOnBackdropClick,
85
87
  width,
86
88
  portal,
87
89
  className,
88
90
  "aria-labelledby": ariaLabelledby,
89
91
  style,
92
+ onClick,
90
93
  ...rest
91
94
  }: ModalProps,
92
95
  ref
@@ -97,7 +100,9 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
97
100
  const rootElement = useProvider()?.rootElement;
98
101
  const portalNode = useFloatingPortalNode({ root: rootElement });
99
102
 
100
- if (useContext(ModalContext)) {
103
+ const dateContext = useContext(DateContext);
104
+ const modalContext = useContext(ModalContext);
105
+ if (modalContext && !dateContext) {
101
106
  console.error("Modals should not be nested");
102
107
  }
103
108
 
@@ -108,6 +113,11 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
108
113
  if (needPolyfill && modalRef.current && portalNode) {
109
114
  dialogPolyfill.registerDialog(modalRef.current);
110
115
  }
116
+ // We set autofocus on the dialog element to prevent the default behavior where first focusable element gets focus when modal is opened.
117
+ // This is mainly to fix an edge case where having a Tooltip as the first focusable element would make it activate when you open the modal.
118
+ // We have to use JS because it doesn't work to set it with a prop (React bug?)
119
+ // Currently doesn't seem to work in Chrome. See also Tooltip.tsx
120
+ if (modalRef.current && portalNode) modalRef.current.autofocus = true;
111
121
  }, [modalRef, portalNode]);
112
122
 
113
123
  useEffect(() => {
@@ -128,34 +138,57 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
128
138
  const isWidthPreset =
129
139
  typeof width === "string" && ["small", "medium"].includes(width);
130
140
 
141
+ const mergedClassName = cl("navds-modal", className, {
142
+ "navds-modal--polyfilled": needPolyfill,
143
+ "navds-modal--autowidth": !width,
144
+ [`navds-modal--${width}`]: isWidthPreset,
145
+ });
146
+
147
+ const mergedStyle = {
148
+ ...style,
149
+ ...(!isWidthPreset ? { width } : {}),
150
+ };
151
+
152
+ const mergedOnCancel: React.DialogHTMLAttributes<HTMLDialogElement>["onCancel"] =
153
+ (event) => {
154
+ if (onBeforeClose && onBeforeClose() === false) {
155
+ event.preventDefault();
156
+ } else if (onCancel) onCancel(event);
157
+ };
158
+
159
+ const mergedOnClick =
160
+ closeOnBackdropClick && !needPolyfill // closeOnBackdropClick has issues on polyfill when nesting modals (DatePicker)
161
+ ? (event: React.MouseEvent<HTMLDialogElement>) => {
162
+ onClick && onClick(event);
163
+ if (
164
+ event.target === modalRef.current &&
165
+ (!onBeforeClose || onBeforeClose() !== false)
166
+ ) {
167
+ modalRef.current.close();
168
+ }
169
+ }
170
+ : onClick;
171
+
172
+ const mergedAriaLabelledBy =
173
+ !ariaLabelledby && !rest["aria-label"] && header
174
+ ? ariaLabelId
175
+ : ariaLabelledby;
176
+
131
177
  const component = (
178
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
132
179
  <dialog
133
180
  {...rest}
134
181
  ref={mergedRef}
135
- className={cl("navds-modal", className, {
136
- "navds-modal--polyfilled": needPolyfill,
137
- "navds-modal--autowidth": !width,
138
- [`navds-modal--${width}`]: isWidthPreset,
139
- })}
140
- style={{
141
- ...style,
142
- ...(!isWidthPreset ? { width } : {}),
143
- }}
144
- onCancel={(event) => {
145
- // FYI: onCancel fires when you press Esc
146
- if (onBeforeClose && onBeforeClose() === false) {
147
- event.preventDefault();
148
- } else if (onCancel) onCancel(event);
149
- }}
150
- aria-labelledby={
151
- !ariaLabelledby && !rest["aria-label"] && header
152
- ? ariaLabelId
153
- : ariaLabelledby
154
- }
182
+ className={mergedClassName}
183
+ style={mergedStyle}
184
+ onCancel={mergedOnCancel} // FYI: onCancel fires when you press Esc
185
+ onClick={mergedOnClick}
186
+ aria-labelledby={mergedAriaLabelledBy}
155
187
  >
156
188
  <ModalContext.Provider
157
189
  value={{
158
190
  closeHandler: getCloseHandler(modalRef, header, onBeforeClose),
191
+ ref: modalRef,
159
192
  }}
160
193
  >
161
194
  {header && (
@@ -2,5 +2,6 @@ import React from "react";
2
2
 
3
3
  interface ModalContextProps {
4
4
  closeHandler?: React.MouseEventHandler<HTMLButtonElement>;
5
+ ref: React.RefObject<HTMLDialogElement>;
5
6
  }
6
7
  export const ModalContext = React.createContext<ModalContextProps | null>(null);
@@ -1,6 +1,6 @@
1
- import React, { useRef, useState } from "react";
2
1
  import { FileIcon } from "@navikt/aksel-icons";
3
- import { BodyLong, Button, Heading } from "..";
2
+ import React, { useRef, useState } from "react";
3
+ import { BodyLong, Button, Heading, Tooltip } from "..";
4
4
  import Modal from "./Modal";
5
5
 
6
6
  export default {
@@ -27,6 +27,7 @@ export const WithUseRef = () => {
27
27
  heading: "Title",
28
28
  size: "small",
29
29
  }}
30
+ closeOnBackdropClick
30
31
  >
31
32
  <Modal.Body>
32
33
  <BodyLong spacing>
@@ -45,6 +46,7 @@ export const WithUseRef = () => {
45
46
  onBeforeClose={() =>
46
47
  window.confirm("Are you sure you want to close the modal?")
47
48
  }
49
+ closeOnBackdropClick
48
50
  aria-labelledby="heading123"
49
51
  >
50
52
  <Modal.Header>
@@ -111,6 +113,7 @@ export const WithUseState = () => {
111
113
  e.stopPropagation(); // onClose wil propagate to parent modal if not stopped
112
114
  setOpen2(false);
113
115
  }}
116
+ closeOnBackdropClick
114
117
  aria-label="Nested modal"
115
118
  width={800}
116
119
  >
@@ -165,3 +168,28 @@ export const MediumWithPortal = () => (
165
168
  <Modal.Body>Lorem ipsum dolor sit amet.</Modal.Body>
166
169
  </Modal>
167
170
  );
171
+
172
+ export const WithTooltip = () => {
173
+ const ref = useRef<HTMLDialogElement>(null);
174
+
175
+ return (
176
+ <div>
177
+ <Button onClick={() => ref.current?.showModal()}>Open Modal</Button>
178
+ <Modal
179
+ open={ref.current ? undefined : true /* initially open */}
180
+ ref={ref}
181
+ >
182
+ <Modal.Body>
183
+ <div style={{ marginBottom: "1rem" }}>
184
+ <Tooltip content="This_is_the_first_tooltip">
185
+ <Button>Test 1</Button>
186
+ </Tooltip>
187
+ </div>
188
+ <Tooltip content="This is the second tooltip">
189
+ <Button>Test 2</Button>
190
+ </Tooltip>
191
+ </Modal.Body>
192
+ </Modal>
193
+ </div>
194
+ );
195
+ };
@@ -42,6 +42,13 @@ export interface ModalProps
42
42
  * Called when the user presses the Esc key, unless `onBeforeClose()` returns `false`.
43
43
  */
44
44
  onCancel?: React.ReactEventHandler<HTMLDialogElement>;
45
+ /**
46
+ * Whether to close when clicking on the backdrop.
47
+ *
48
+ * **WARNING:** Users may click outside by accident. Don't use if closing can cause data loss, or the modal contains important info.
49
+ * @default false
50
+ */
51
+ closeOnBackdropClick?: boolean;
45
52
  /**
46
53
  * @default fit-content (up to 700px)
47
54
  * */
@@ -18,6 +18,7 @@ import React, {
18
18
  useMemo,
19
19
  useRef,
20
20
  } from "react";
21
+ import { DateContext } from "../date/context";
21
22
  import { ModalContext } from "../modal/ModalContext";
22
23
  import { mergeRefs, useClientLayoutEffect, useEventListener } from "../util";
23
24
  import PopoverContent, { PopoverContentType } from "./PopoverContent";
@@ -73,11 +74,6 @@ export interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
73
74
  * @default "absolute"
74
75
  */
75
76
  strategy?: "absolute" | "fixed";
76
- /**
77
- * Bubbles Escape keydown-event up trough DOM-tree. This is set to false by default to prevent closing components like Modal on Escape
78
- * @default false
79
- */
80
- bubbleEscape?: boolean;
81
77
  /**
82
78
  * Changes placement of the floating element in order to keep it in view.
83
79
  * @default true
@@ -124,7 +120,6 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
124
120
  placement = "top",
125
121
  offset,
126
122
  strategy: userStrategy,
127
- bubbleEscape = false,
128
123
  flip: _flip = true,
129
124
  ...rest
130
125
  },
@@ -132,8 +127,9 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
132
127
  ) => {
133
128
  const arrowRef = useRef<HTMLDivElement | null>(null);
134
129
  const isInModal = useContext(ModalContext) !== null;
130
+ const isInDatepicker = useContext(DateContext) !== null;
135
131
  const chosenStrategy = userStrategy ?? (isInModal ? "fixed" : "absolute");
136
- const chosenFlip = isInModal ? true : _flip;
132
+ const chosenFlip = isInDatepicker ? false : _flip;
137
133
 
138
134
  const {
139
135
  x,
@@ -160,11 +156,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
160
156
 
161
157
  const { getFloatingProps } = useInteractions([
162
158
  useClick(context),
163
- useDismiss(context, {
164
- bubbles: {
165
- escapeKey: bubbleEscape,
166
- },
167
- }),
159
+ useDismiss(context),
168
160
  ]);
169
161
 
170
162
  useClientLayoutEffect(() => {
@@ -1,8 +1,8 @@
1
1
  import {
2
- arrow as flArrow,
2
+ FloatingPortal,
3
3
  autoUpdate,
4
+ arrow as flArrow,
4
5
  flip,
5
- FloatingPortal,
6
6
  offset,
7
7
  safePolygon,
8
8
  shift,
@@ -14,16 +14,18 @@ import {
14
14
  } from "@floating-ui/react";
15
15
  import cl from "clsx";
16
16
  import React, {
17
+ HTMLAttributes,
17
18
  cloneElement,
18
19
  forwardRef,
19
- HTMLAttributes,
20
+ useContext,
20
21
  useMemo,
21
22
  useRef,
22
23
  useState,
23
24
  } from "react";
25
+ import { ModalContext } from "../modal/ModalContext";
26
+ import { useProvider } from "../provider";
24
27
  import { Detail } from "../typography";
25
28
  import { mergeRefs, useId } from "../util";
26
- import { useProvider } from "../provider";
27
29
 
28
30
  export interface TooltipProps extends HTMLAttributes<HTMLDivElement> {
29
31
  /**
@@ -110,7 +112,11 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
110
112
  ) => {
111
113
  const [open, setOpen] = useState(defaultOpen);
112
114
  const arrowRef = useRef<HTMLDivElement | null>(null);
113
- const rootElement = useProvider()?.rootElement;
115
+ const modalContext = useContext(ModalContext);
116
+ const providerRootElement = useProvider()?.rootElement;
117
+ const rootElement = modalContext
118
+ ? modalContext.ref.current
119
+ : providerRootElement;
114
120
 
115
121
  const {
116
122
  x,
@@ -133,7 +139,13 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
133
139
  flip({ padding: 5, fallbackPlacements: ["bottom", "top"] }),
134
140
  flArrow({ element: arrowRef, padding: 5 }),
135
141
  ],
136
- whileElementsMounted: autoUpdate,
142
+ whileElementsMounted: modalContext
143
+ ? (reference, floating, update) =>
144
+ // Reduces jumping in Chrome when used in a Modal and it's the first focusable element.
145
+ // Can be removed when autofocus starts working on <dialog> in Chrome. See also Modal.tsx
146
+ autoUpdate(reference, floating, update, { animationFrame: true })
147
+ : autoUpdate,
148
+ strategy: modalContext ? "fixed" : undefined,
137
149
  });
138
150
 
139
151
  const { getReferenceProps, getFloatingProps } = useInteractions([
@@ -0,0 +1,19 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import React from "react";
3
+ import { useMedia } from "../useMedia";
4
+
5
+ function TestComponent({ fallback }: { fallback?: boolean }) {
6
+ const media = useMedia("screen and (min-width: 1024px)", fallback);
7
+ return <div data-testid="media-id">{`${media}`}</div>;
8
+ }
9
+
10
+ describe("useMedia", () => {
11
+ test("Should return 'undefined' when no fallback is given", async () => {
12
+ render(<TestComponent />);
13
+ expect(screen.getByTestId("media-id").innerHTML).toEqual("undefined");
14
+ });
15
+ test("Should return fallback", async () => {
16
+ render(<TestComponent fallback={true} />);
17
+ expect(screen.getByTestId("media-id").innerHTML).toEqual("true");
18
+ });
19
+ });
@@ -0,0 +1,38 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ export const noMatchMedia =
4
+ typeof window !== "undefined" && window.matchMedia === undefined;
5
+
6
+ /**
7
+ * @example useMedia("screen and (min-width: 1024px)")
8
+ * @param media string
9
+ * @param fallback boolean
10
+ * @returns boolean | undefined
11
+ */
12
+ export const useMedia = (
13
+ media: string,
14
+ fallback?: boolean
15
+ ): boolean | undefined => {
16
+ const [matches, setMatches] = useState(fallback);
17
+
18
+ useEffect(() => {
19
+ if (noMatchMedia) {
20
+ return;
21
+ }
22
+ const mediaQueryList = window.matchMedia(media);
23
+
24
+ setMatches(mediaQueryList.matches);
25
+
26
+ const listener = (evt: MediaQueryListEvent) => {
27
+ setMatches(evt.matches);
28
+ };
29
+
30
+ mediaQueryList.addEventListener("change", listener);
31
+
32
+ return () => {
33
+ mediaQueryList.removeEventListener("change", listener);
34
+ };
35
+ }, [media]);
36
+
37
+ return matches;
38
+ };
@@ -1,23 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useEscape = void 0;
4
- const react_1 = require("react");
5
- const useEscape = (open, setOpen, focusRef) => {
6
- const handleClose = (0, react_1.useCallback)(() => {
7
- setOpen(false);
8
- (focusRef === null || focusRef === void 0 ? void 0 : focusRef.current) && focusRef.current.focus();
9
- }, [focusRef, setOpen]);
10
- const escape = (0, react_1.useCallback)((event) => {
11
- if (open && event.key === "Escape") {
12
- event.preventDefault(); // This prevents modal from closing when using datepicker inside modal
13
- handleClose();
14
- }
15
- }, [handleClose, open]);
16
- (0, react_1.useEffect)(() => {
17
- window.addEventListener("keydown", escape, false);
18
- return () => {
19
- window.removeEventListener("keydown", escape, false);
20
- };
21
- }, [escape]);
22
- };
23
- exports.useEscape = useEscape;
@@ -1,26 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useOutsideClickHandler = void 0;
4
- const react_1 = require("react");
5
- const useOutsideClickHandler = (open, setOpen, refs) => {
6
- const handleFocusIn = (0, react_1.useCallback)((e) => {
7
- var _a, _b, _c;
8
- const composed = (_b = (_a = e.composedPath) === null || _a === void 0 ? void 0 : _a.call(e)) === null || _b === void 0 ? void 0 : _b[0];
9
- if (!(e === null || e === void 0 ? void 0 : e.target) || !((_c = e === null || e === void 0 ? void 0 : e.target) === null || _c === void 0 ? void 0 : _c.nodeType) || !composed) {
10
- return;
11
- }
12
- if (!refs.some((element) => (element === null || element === void 0 ? void 0 : element.contains(e.target)) || (element === null || element === void 0 ? void 0 : element.contains(composed)))) {
13
- open && setOpen(false);
14
- }
15
- }, [open, refs, setOpen]);
16
- (0, react_1.useEffect)(() => {
17
- window.addEventListener("focusin", handleFocusIn);
18
- window.addEventListener("pointerdown", handleFocusIn);
19
- return () => {
20
- var _a, _b;
21
- (_a = window === null || window === void 0 ? void 0 : window.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(window, "focusin", handleFocusIn);
22
- (_b = window === null || window === void 0 ? void 0 : window.removeEventListener) === null || _b === void 0 ? void 0 : _b.call(window, "pointerdown", handleFocusIn);
23
- };
24
- }, [handleFocusIn]);
25
- };
26
- exports.useOutsideClickHandler = useOutsideClickHandler;
@@ -1 +0,0 @@
1
- {"version":3,"file":"DateInput.js","sourceRoot":"","sources":["../../src/date/DateInput.tsx"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import { RefObject } from "react";
2
- export declare const useEscape: (open: boolean, setOpen: (openState: boolean) => void, focusRef: RefObject<HTMLElement>) => void;
@@ -1,20 +0,0 @@
1
- import { useCallback, useEffect } from "react";
2
- export const useEscape = (open, setOpen, focusRef) => {
3
- const handleClose = useCallback(() => {
4
- setOpen(false);
5
- (focusRef === null || focusRef === void 0 ? void 0 : focusRef.current) && focusRef.current.focus();
6
- }, [focusRef, setOpen]);
7
- const escape = useCallback((event) => {
8
- if (open && event.key === "Escape") {
9
- event.preventDefault(); // This prevents modal from closing when using datepicker inside modal
10
- handleClose();
11
- }
12
- }, [handleClose, open]);
13
- useEffect(() => {
14
- window.addEventListener("keydown", escape, false);
15
- return () => {
16
- window.removeEventListener("keydown", escape, false);
17
- };
18
- }, [escape]);
19
- };
20
- //# sourceMappingURL=useEscape.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useEscape.js","sourceRoot":"","sources":["../../../src/date/hooks/useEscape.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAE1D,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAa,EACb,OAAqC,EACrC,QAAgC,EAChC,EAAE;IACF,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,OAAO,CAAC,KAAK,CAAC,CAAC;QACf,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,OAAO,KAAI,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAChD,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAExB,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,KAAoB,EAAE,EAAE;QACvB,IAAI,IAAI,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE;YAClC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,sEAAsE;YAC9F,WAAW,EAAE,CAAC;SACf;IACH,CAAC,EACD,CAAC,WAAW,EAAE,IAAI,CAAC,CACpB,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAElD,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACvD,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACf,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- export declare const useOutsideClickHandler: (open: boolean, setOpen: (openState: boolean) => void, refs: Array<any>) => void;
@@ -1,23 +0,0 @@
1
- import { useCallback, useEffect } from "react";
2
- export const useOutsideClickHandler = (open, setOpen, refs) => {
3
- const handleFocusIn = useCallback((e) => {
4
- var _a, _b, _c;
5
- const composed = (_b = (_a = e.composedPath) === null || _a === void 0 ? void 0 : _a.call(e)) === null || _b === void 0 ? void 0 : _b[0];
6
- if (!(e === null || e === void 0 ? void 0 : e.target) || !((_c = e === null || e === void 0 ? void 0 : e.target) === null || _c === void 0 ? void 0 : _c.nodeType) || !composed) {
7
- return;
8
- }
9
- if (!refs.some((element) => (element === null || element === void 0 ? void 0 : element.contains(e.target)) || (element === null || element === void 0 ? void 0 : element.contains(composed)))) {
10
- open && setOpen(false);
11
- }
12
- }, [open, refs, setOpen]);
13
- useEffect(() => {
14
- window.addEventListener("focusin", handleFocusIn);
15
- window.addEventListener("pointerdown", handleFocusIn);
16
- return () => {
17
- var _a, _b;
18
- (_a = window === null || window === void 0 ? void 0 : window.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(window, "focusin", handleFocusIn);
19
- (_b = window === null || window === void 0 ? void 0 : window.removeEventListener) === null || _b === void 0 ? void 0 : _b.call(window, "pointerdown", handleFocusIn);
20
- };
21
- }, [handleFocusIn]);
22
- };
23
- //# sourceMappingURL=useOutsideClickHandler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useOutsideClickHandler.js","sourceRoot":"","sources":["../../../src/date/hooks/useOutsideClickHandler.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE/C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,IAAa,EACb,OAAqC,EACrC,IAAgB,EAChB,EAAE;IACF,MAAM,aAAa,GAAG,WAAW,CAC/B,CAAC,CAAC,EAAE,EAAE;;QACJ,MAAM,QAAQ,GAAG,MAAA,MAAA,CAAC,CAAC,YAAY,iDAAI,0CAAG,CAAC,CAAC,CAAC;QACzC,IAAI,CAAC,CAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,MAAM,CAAA,IAAI,CAAC,CAAA,MAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,MAAM,0CAAE,QAAQ,CAAA,IAAI,CAAC,QAAQ,EAAE;YACnD,OAAO;SACR;QACD,IACE,CAAC,IAAI,CAAC,IAAI,CACR,CAAC,OAAO,EAAE,EAAE,CACV,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,CAAC,QAAQ,CAAC,CAAA,CAC7D,EACD;YACA,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;SACxB;IACH,CAAC,EACD,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CACtB,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAClD,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;QACtD,OAAO,GAAG,EAAE;;YACV,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,mBAAmB,uDAAG,SAAS,EAAE,aAAa,CAAC,CAAC;YACxD,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,mBAAmB,uDAAG,aAAa,EAAE,aAAa,CAAC,CAAC;QAC9D,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;AACtB,CAAC,CAAC"}