@lumx/react 3.11.3-alpha.2 → 3.11.4-alpha.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/package.json CHANGED
@@ -6,8 +6,8 @@
6
6
  "url": "https://github.com/lumapps/design-system/issues"
7
7
  },
8
8
  "dependencies": {
9
- "@lumx/core": "^3.11.3-alpha.2",
10
- "@lumx/icons": "^3.11.3-alpha.2",
9
+ "@lumx/core": "^3.11.4-alpha.0",
10
+ "@lumx/icons": "^3.11.4-alpha.0",
11
11
  "@popperjs/core": "^2.5.4",
12
12
  "body-scroll-lock": "^3.1.5",
13
13
  "classnames": "^2.3.2",
@@ -110,5 +110,5 @@
110
110
  "build:storybook": "storybook build"
111
111
  },
112
112
  "sideEffects": false,
113
- "version": "3.11.3-alpha.2"
113
+ "version": "3.11.4-alpha.0"
114
114
  }
@@ -6,6 +6,7 @@ import { render, screen } from '@testing-library/react';
6
6
  import { commonTestsSuiteRTL, SetupRenderOptions } from '@lumx/react/testing/utils';
7
7
  import userEvent from '@testing-library/user-event';
8
8
  import { ThemeSentinel } from '@lumx/react/testing/utils/ThemeSentinel';
9
+ import { Heading, HeadingLevelProvider } from '@lumx/react';
9
10
 
10
11
  const CLASSNAME = Dialog.className as string;
11
12
 
@@ -33,6 +34,21 @@ describe(`<${Dialog.displayName}>`, () => {
33
34
  expect(container).toHaveAttribute('aria-modal', 'true');
34
35
  });
35
36
 
37
+ it('should have reset the heading level context', () => {
38
+ setup(
39
+ // Heading inside the dialog
40
+ { children: <Heading>Title</Heading> },
41
+ {
42
+ // This level context should not affect headings inside the dialog
43
+ wrapper({ children }) {
44
+ return <HeadingLevelProvider level={3}>{children}</HeadingLevelProvider>;
45
+ },
46
+ },
47
+ );
48
+ // Heading inside should use the dialog heading level 2
49
+ expect(screen.queryByRole('heading', { name: 'Title', level: 2 })).toBeInTheDocument();
50
+ });
51
+
36
52
  describe('Events', () => {
37
53
  it('should trigger `onClose` when pressing `escape` key', async () => {
38
54
  const onClose = jest.fn();
@@ -3,7 +3,7 @@ import { createPortal } from 'react-dom';
3
3
 
4
4
  import classNames from 'classnames';
5
5
 
6
- import { Progress, ProgressVariant, Size } from '@lumx/react';
6
+ import { HeadingLevelProvider, Progress, ProgressVariant, Size } from '@lumx/react';
7
7
 
8
8
  import { DIALOG_TRANSITION_DURATION, DOCUMENT } from '@lumx/react/constants';
9
9
  import { useCallbackOnEscape } from '@lumx/react/hooks/useCallbackOnEscape';
@@ -212,67 +212,77 @@ export const Dialog = forwardRef<DialogProps, HTMLDivElement>((props, ref) => {
212
212
  >
213
213
  <div className={`${CLASSNAME}__overlay`} />
214
214
 
215
- <ThemeProvider value={undefined}>
216
- <section className={`${CLASSNAME}__container`} role="dialog" aria-modal="true" {...dialogProps}>
217
- <ClickAwayProvider
218
- callback={!shouldPreventCloseOnClickAway && onClose}
219
- childrenRefs={clickAwayRefs}
220
- parentRef={rootRef}
215
+ <HeadingLevelProvider level={2}>
216
+ <ThemeProvider value={undefined}>
217
+ <section
218
+ className={`${CLASSNAME}__container`}
219
+ role="dialog"
220
+ aria-modal="true"
221
+ {...dialogProps}
221
222
  >
222
- <div className={`${CLASSNAME}__wrapper`} ref={wrapperRef}>
223
- {(header || headerChildContent) && (
224
- <header
225
- {...headerChildProps}
226
- className={classNames(
227
- `${CLASSNAME}__header`,
228
- (forceHeaderDivider || hasTopIntersection) &&
229
- `${CLASSNAME}__header--has-divider`,
230
- headerChildProps?.className,
231
- )}
232
- >
233
- {header}
234
- {headerChildContent}
235
- </header>
236
- )}
223
+ <ClickAwayProvider
224
+ callback={!shouldPreventCloseOnClickAway && onClose}
225
+ childrenRefs={clickAwayRefs}
226
+ parentRef={rootRef}
227
+ >
228
+ <div className={`${CLASSNAME}__wrapper`} ref={wrapperRef}>
229
+ {(header || headerChildContent) && (
230
+ <header
231
+ {...headerChildProps}
232
+ className={classNames(
233
+ `${CLASSNAME}__header`,
234
+ (forceHeaderDivider || hasTopIntersection) &&
235
+ `${CLASSNAME}__header--has-divider`,
236
+ headerChildProps?.className,
237
+ )}
238
+ >
239
+ {header}
240
+ {headerChildContent}
241
+ </header>
242
+ )}
237
243
 
238
- <div ref={mergeRefs(contentRef, localContentRef)} className={`${CLASSNAME}__content`}>
239
244
  <div
240
- className={`${CLASSNAME}__sentinel ${CLASSNAME}__sentinel--top`}
241
- ref={setSentinelTop}
242
- />
243
-
244
- {content}
245
+ ref={mergeRefs(contentRef, localContentRef)}
246
+ className={`${CLASSNAME}__content`}
247
+ >
248
+ <div
249
+ className={`${CLASSNAME}__sentinel ${CLASSNAME}__sentinel--top`}
250
+ ref={setSentinelTop}
251
+ />
245
252
 
246
- <div
247
- className={`${CLASSNAME}__sentinel ${CLASSNAME}__sentinel--bottom`}
248
- ref={setSentinelBottom}
249
- />
250
- </div>
253
+ {content}
251
254
 
252
- {(footer || footerChildContent) && (
253
- <footer
254
- {...footerChildProps}
255
- className={classNames(
256
- `${CLASSNAME}__footer`,
257
- (forceFooterDivider || hasBottomIntersection) &&
258
- `${CLASSNAME}__footer--has-divider`,
259
- footerChildProps?.className,
260
- )}
261
- >
262
- {footer}
263
- {footerChildContent}
264
- </footer>
265
- )}
266
-
267
- {isLoading && (
268
- <div className={`${CLASSNAME}__progress-overlay`}>
269
- <Progress variant={ProgressVariant.circular} />
255
+ <div
256
+ className={`${CLASSNAME}__sentinel ${CLASSNAME}__sentinel--bottom`}
257
+ ref={setSentinelBottom}
258
+ />
270
259
  </div>
271
- )}
272
- </div>
273
- </ClickAwayProvider>
274
- </section>
275
- </ThemeProvider>
260
+
261
+ {(footer || footerChildContent) && (
262
+ <footer
263
+ {...footerChildProps}
264
+ className={classNames(
265
+ `${CLASSNAME}__footer`,
266
+ (forceFooterDivider || hasBottomIntersection) &&
267
+ `${CLASSNAME}__footer--has-divider`,
268
+ footerChildProps?.className,
269
+ )}
270
+ >
271
+ {footer}
272
+ {footerChildContent}
273
+ </footer>
274
+ )}
275
+
276
+ {isLoading && (
277
+ <div className={`${CLASSNAME}__progress-overlay`}>
278
+ <Progress variant={ProgressVariant.circular} />
279
+ </div>
280
+ )}
281
+ </div>
282
+ </ClickAwayProvider>
283
+ </section>
284
+ </ThemeProvider>
285
+ </HeadingLevelProvider>
276
286
  </div>,
277
287
  document.body,
278
288
  )
@@ -5,6 +5,7 @@ import { queryByClassName } from '@lumx/react/testing/utils/queries';
5
5
  import { render, screen } from '@testing-library/react';
6
6
  import { ThemeSentinel } from '@lumx/react/testing/utils/ThemeSentinel';
7
7
 
8
+ import { Heading, HeadingLevelProvider } from '@lumx/react';
8
9
  import { Lightbox, LightboxProps } from './Lightbox';
9
10
 
10
11
  const CLASSNAME = Lightbox.className as string;
@@ -22,6 +23,23 @@ const setup = (props: Partial<LightboxProps> = {}, { wrapper }: SetupRenderOptio
22
23
  };
23
24
 
24
25
  describe(`<${Lightbox.displayName}>`, () => {
26
+ it('should have reset the heading level context', () => {
27
+ setup(
28
+ {
29
+ // Heading inside the lightbox
30
+ children: <Heading>Title</Heading>,
31
+ },
32
+ {
33
+ // This level context should not affect headings inside the lightbox
34
+ wrapper({ children }) {
35
+ return <HeadingLevelProvider level={3}>{children}</HeadingLevelProvider>;
36
+ },
37
+ },
38
+ );
39
+ // Heading inside should use the lightbox heading level 2
40
+ expect(screen.queryByRole('heading', { name: 'Title', level: 2 })).toBeInTheDocument();
41
+ });
42
+
25
43
  // Common tests suite.
26
44
  commonTestsSuiteRTL(setup, {
27
45
  baseClassName: CLASSNAME,
@@ -4,7 +4,7 @@ import classNames from 'classnames';
4
4
  import { createPortal } from 'react-dom';
5
5
 
6
6
  import { mdiClose } from '@lumx/icons';
7
- import { IconButton, IconButtonProps } from '@lumx/react';
7
+ import { HeadingLevelProvider, IconButton, IconButtonProps } from '@lumx/react';
8
8
  import { DIALOG_TRANSITION_DURATION, DOCUMENT } from '@lumx/react/constants';
9
9
  import { GenericProps, HasTheme } from '@lumx/react/utils/type';
10
10
  import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
@@ -162,13 +162,15 @@ export const Lightbox = forwardRef<LightboxProps, HTMLDivElement>((props, ref) =
162
162
  />
163
163
  </div>
164
164
  )}
165
- <ThemeProvider value={undefined}>
166
- <ClickAwayProvider callback={!preventAutoClose && onClose} childrenRefs={clickAwayRefs}>
167
- <div ref={childrenRef} className={`${CLASSNAME}__wrapper`} role="presentation">
168
- {children}
169
- </div>
170
- </ClickAwayProvider>
171
- </ThemeProvider>
165
+ <HeadingLevelProvider level={2}>
166
+ <ThemeProvider value={undefined}>
167
+ <ClickAwayProvider callback={!preventAutoClose && onClose} childrenRefs={clickAwayRefs}>
168
+ <div ref={childrenRef} className={`${CLASSNAME}__wrapper`} role="presentation">
169
+ {children}
170
+ </div>
171
+ </ClickAwayProvider>
172
+ </ThemeProvider>
173
+ </HeadingLevelProvider>
172
174
  </div>,
173
175
  document.body,
174
176
  );
@@ -40,7 +40,7 @@ export const WithButtonTrigger = (props: any) => {
40
40
  /**
41
41
  * Example PopoverDialog using an icon button as a trigger
42
42
  */
43
- export const WithIconButtonTrigger = (props: any) => {
43
+ export const WithIconButtonTrigger = ({ children, ...props }: any) => {
44
44
  const anchorRef = React.useRef(null);
45
45
  const [isOpen, close, open] = useBooleanState(false);
46
46
 
@@ -57,6 +57,7 @@ export const WithIconButtonTrigger = (props: any) => {
57
57
  {...props}
58
58
  >
59
59
  <Button onClick={close}>Close</Button>
60
+ {children}
60
61
  </PopoverDialog>
61
62
  </>
62
63
  );
@@ -2,8 +2,9 @@ import React from 'react';
2
2
  import { render, screen, within } from '@testing-library/react';
3
3
  import userEvent from '@testing-library/user-event';
4
4
 
5
- import { PopoverDialog } from './PopoverDialog';
5
+ import { Heading, HeadingLevelProvider } from '@lumx/react';
6
6
  import { WithButtonTrigger, WithIconButtonTrigger } from './PopoverDialog.stories';
7
+ import { PopoverDialog } from './PopoverDialog';
7
8
 
8
9
  jest.mock('@lumx/react/utils/browser/isFocusVisible');
9
10
 
@@ -117,4 +118,23 @@ describe(`<${PopoverDialog.displayName}>`, () => {
117
118
  // Focus restored to the trigger element
118
119
  expect(triggerElement).toHaveFocus();
119
120
  });
121
+
122
+ it('should have reset the heading level context', async () => {
123
+ render(
124
+ // This level context should not affect headings inside the popover dialog
125
+
126
+ <HeadingLevelProvider level={3}>
127
+ <WithIconButtonTrigger>
128
+ {/* Heading inside the popover dialog */}
129
+ <Heading>Title</Heading>
130
+ </WithIconButtonTrigger>
131
+ </HeadingLevelProvider>,
132
+ );
133
+
134
+ // Open popover
135
+ await userEvent.click(screen.getByRole('button', { name: 'Open popover' }));
136
+
137
+ // Heading inside should use the popover dialog heading level 2
138
+ expect(screen.getByRole('heading', { name: 'Title', level: 2 })).toBeInTheDocument();
139
+ });
120
140
  });
@@ -6,6 +6,7 @@ import { HasAriaLabelOrLabelledBy } from '@lumx/react/utils/type';
6
6
  import { getRootClassName } from '@lumx/react/utils/className';
7
7
  import { forwardRef } from '@lumx/react/utils/react/forwardRef';
8
8
 
9
+ import { HeadingLevelProvider } from '@lumx/react/components/heading';
9
10
  import { Popover, PopoverProps } from '../popover/Popover';
10
11
 
11
12
  /**
@@ -65,7 +66,7 @@ export const PopoverDialog = forwardRef<PopoverDialogProps, HTMLDivElement>((pro
65
66
  closeOnEscape
66
67
  withFocusTrap
67
68
  >
68
- {children}
69
+ <HeadingLevelProvider level={2}>{children}</HeadingLevelProvider>
69
70
  </Popover>
70
71
  );
71
72
  });