@loadsmart/loadsmart-ui 5.14.3 → 5.15.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loadsmart/loadsmart-ui",
3
- "version": "5.14.3",
3
+ "version": "5.15.0",
4
4
  "description": "Miranda UI, a React UI library",
5
5
  "main": "dist",
6
6
  "files": [
@@ -1,5 +1,5 @@
1
1
  import React from 'react'
2
- import type { Story, Meta } from '@storybook/react/types-6-0'
2
+ import type { Meta, Story } from '@storybook/react/types-6-0'
3
3
 
4
4
  import { Drawer, useDrawer } from '.'
5
5
  import type { DrawerProps } from './Drawer'
@@ -31,7 +31,7 @@ export const Playground: Story<DrawerProps> = ({ open, ...others }: DrawerProps)
31
31
  <div className="flex flex-col space-y-2">
32
32
  <div className="flex items-center">
33
33
  <Button onClick={show}>Open Drawer</Button>
34
- <Drawer {...others} open={isOpen} onClose={hide}>
34
+ <Drawer {...others} open={isOpen} onClose={hide} onClickOutside={hide}>
35
35
  <Drawer.Header>Drawer Header</Drawer.Header>
36
36
  <Drawer.Body>
37
37
  {TWENTY_SIZE_ARR.map((_, index) => (
@@ -60,7 +60,7 @@ export const SmallerContentPlayground: Story<DrawerProps> = ({ open, ...others }
60
60
  <div className="flex flex-col space-y-2">
61
61
  <div className="flex items-center">
62
62
  <Button onClick={show}>Open Drawer</Button>
63
- <Drawer {...others} open={isOpen} onClose={hide}>
63
+ <Drawer {...others} open={isOpen} onClose={hide} onClickOutside={hide}>
64
64
  <Drawer.Header>Drawer Header</Drawer.Header>
65
65
  <Drawer.Body>
66
66
  {TWENTY_SIZE_ARR.slice(0, 3).map((_, index) => (
@@ -1,8 +1,9 @@
1
1
  import React from 'react'
2
- import renderer, { screen, fire } from '../../tests/renderer'
2
+ import renderer, { fire, screen } from '../../tests/renderer'
3
3
 
4
- import Drawer from './Drawer'
5
4
  import type { DrawerProps } from './Drawer'
5
+ import Drawer from './Drawer'
6
+ import { fireEvent, waitFor } from '@testing-library/react'
6
7
 
7
8
  const setup = (props: DrawerProps) => renderer(<Drawer {...props} />).render()
8
9
 
@@ -28,6 +29,27 @@ describe('Drawer', () => {
28
29
  expect(props.onClose).toHaveBeenCalled()
29
30
  })
30
31
 
32
+ it('closes drawer only when clicking outside', async () => {
33
+ const props = {
34
+ open: true,
35
+ onClickOutside: jest.fn(),
36
+ }
37
+
38
+ setup(props)
39
+
40
+ fireEvent.mouseUp(screen.getByRole('dialog'))
41
+
42
+ await waitFor(() => {
43
+ expect(props.onClickOutside).not.toHaveBeenCalled()
44
+ })
45
+
46
+ fireEvent.mouseUp(screen.getByRole('complementary'))
47
+
48
+ await waitFor(() => {
49
+ expect(props.onClickOutside).toHaveBeenCalledTimes(1)
50
+ })
51
+ })
52
+
31
53
  it('renders without close button', () => {
32
54
  setup({
33
55
  open: true,
@@ -1,4 +1,5 @@
1
- import React, { ReactNode, useEffect, useState } from 'react'
1
+ import type { PropsWithChildren } from 'react'
2
+ import React, { ReactNode, useEffect, useRef, useState } from 'react'
2
3
  import ReactDOM from 'react-dom'
3
4
  import styled from 'styled-components'
4
5
 
@@ -7,13 +8,12 @@ import conditional, { whenProps } from 'tools/conditional'
7
8
  import { getToken as token } from 'theming'
8
9
  import DefaultCloseButton from 'common/CloseButton'
9
10
 
10
- import type { PropsWithChildren } from 'react'
11
-
12
11
  export interface DrawerProps {
13
12
  children?: ReactNode
14
13
  className?: string
15
14
  open: boolean
16
15
  onClose?: () => void
16
+ onClickOutside?: () => void
17
17
  }
18
18
 
19
19
  const StyledAside = styled.aside<Pick<DrawerProps, 'open'>>`
@@ -160,8 +160,16 @@ function DrawerFooter({
160
160
  )
161
161
  }
162
162
 
163
- function Drawer({ className, children, open, onClose, ...others }: DrawerProps): JSX.Element {
163
+ function Drawer({
164
+ className,
165
+ children,
166
+ open,
167
+ onClose,
168
+ onClickOutside,
169
+ ...others
170
+ }: DrawerProps): JSX.Element {
164
171
  const [invisible, setInvisible] = useState(!open)
172
+ const ref = useRef<HTMLElement>(null)
165
173
 
166
174
  function handleTransitionEnd() {
167
175
  if (!open) {
@@ -175,8 +183,24 @@ function Drawer({ className, children, open, onClose, ...others }: DrawerProps):
175
183
  }
176
184
  }, [open])
177
185
 
186
+ useEffect(() => {
187
+ const currentRef = ref.current
188
+
189
+ if (currentRef && onClickOutside) {
190
+ const handleClick = (event: MouseEvent) => {
191
+ const hasClickedOutside = currentRef.isSameNode(event.target as Element)
192
+
193
+ if (hasClickedOutside) onClickOutside()
194
+ }
195
+
196
+ currentRef.addEventListener('mouseup', handleClick)
197
+
198
+ return () => currentRef.removeEventListener('mouseup', handleClick)
199
+ }
200
+ }, [onClickOutside])
201
+
178
202
  return ReactDOM.createPortal(
179
- <StyledAside open={!invisible}>
203
+ <StyledAside open={!invisible} ref={ref}>
180
204
  <StyledSection
181
205
  {...others}
182
206
  className={className}