@wavv/ui 2.4.7 → 2.4.8-alpha.1

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.
@@ -1,110 +1,152 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { keyframes } from "@emotion/react";
2
3
  import styled from "@emotion/styled";
3
- import { useEffect, useState } from "react";
4
- import { useOnClickOutside } from "../hooks/index.js";
4
+ import { useCallback, useEffect, useState } from "react";
5
+ import { Dialog, Modal, ModalOverlay } from "react-aria-components";
6
+ import useEventListener from "../hooks/useEventListener.js";
5
7
  import Icon from "./Icon/index.js";
6
8
  const ImageViewer = ({ visible, close, images, startIndex, alt, maxWidth, maxHeight, opacity, ...rest })=>{
7
9
  const [currentIndex, setCurrentIndex] = useState(startIndex);
8
- const exclusions = [
9
- '#viewer-prev',
10
- '#viewer-next',
11
- '#viewer-prev *',
12
- '#viewer-next *'
13
- ];
14
- const imageRef = useOnClickOutside(close, visible, exclusions);
10
+ const handleOpenChange = (open)=>{
11
+ if (!open) close();
12
+ };
15
13
  useEffect(()=>{
16
- setCurrentIndex(startIndex);
14
+ if (visible) setCurrentIndex(startIndex);
17
15
  }, [
16
+ visible,
18
17
  startIndex
19
18
  ]);
20
- const handlePrev = ()=>currentIndex > 0 ? setCurrentIndex(currentIndex - 1) : setCurrentIndex(images.length - 1);
21
- const handleNext = ()=>currentIndex < images.length - 1 ? setCurrentIndex(currentIndex + 1) : setCurrentIndex(0);
22
- const handleKeyPress = (event)=>{
23
- const { key } = event;
24
- switch(key){
19
+ const handlePrev = ()=>setCurrentIndex((prev)=>prev > 0 ? prev - 1 : images.length - 1);
20
+ const handleNext = ()=>setCurrentIndex((prev)=>prev < images.length - 1 ? prev + 1 : 0);
21
+ const handleKeyDown = useCallback((e)=>{
22
+ switch(e.key){
23
+ case 'Escape':
24
+ e.preventDefault();
25
+ close();
26
+ break;
25
27
  case 'ArrowLeft':
26
28
  case 'ArrowDown':
27
- event.preventDefault();
28
- handlePrev();
29
+ e.preventDefault();
30
+ setCurrentIndex((prev)=>prev > 0 ? prev - 1 : images.length - 1);
29
31
  break;
30
32
  case 'ArrowRight':
31
33
  case 'ArrowUp':
32
- event.preventDefault();
33
- handleNext();
34
- break;
35
- case 'Escape':
36
- event.preventDefault();
37
- close();
34
+ e.preventDefault();
35
+ setCurrentIndex((prev)=>prev < images.length - 1 ? prev + 1 : 0);
38
36
  break;
39
37
  default:
40
38
  break;
41
39
  }
42
- };
43
- useEffect(()=>{
44
- const ssr = "u" < typeof window;
45
- const cleanup = ssr ? ()=>null : ()=>window.removeEventListener('keydown', handleKeyPress);
46
- if (visible && !ssr) window.addEventListener('keydown', handleKeyPress);
47
- return cleanup;
48
40
  }, [
49
- visible,
50
- currentIndex
41
+ close,
42
+ images.length
43
+ ]);
44
+ useEventListener("u" > typeof window ? window : {
45
+ current: null
46
+ }, 'keydown', handleKeyDown, visible, [
47
+ handleKeyDown
51
48
  ]);
52
- return visible ? /*#__PURE__*/ jsxs(Viewer, {
49
+ if (0 === images.length) return null;
50
+ return /*#__PURE__*/ jsx(Overlay, {
51
+ isOpen: visible,
52
+ onOpenChange: handleOpenChange,
53
+ isDismissable: true,
53
54
  opacity: opacity,
54
55
  prevNext: images.length > 1,
55
56
  ...rest,
56
- children: [
57
- /*#__PURE__*/ jsx(Close, {
58
- onClick: close,
59
- children: /*#__PURE__*/ jsx(Icon, {
60
- name: "close",
61
- color: "white"
62
- })
63
- }),
64
- images.length > 1 && /*#__PURE__*/ jsx(PrevNext, {
65
- id: "viewer-prev",
66
- onClick: handlePrev,
67
- children: /*#__PURE__*/ jsx(Icon, {
68
- name: "chevron-left",
69
- size: 35,
70
- color: "white"
71
- })
72
- }),
73
- /*#__PURE__*/ jsx(Media, {
74
- ref: imageRef,
75
- src: images[currentIndex],
76
- alt: alt,
77
- maxWidth: maxWidth,
78
- maxHeight: maxHeight
79
- }),
80
- images.length > 1 && /*#__PURE__*/ jsx(PrevNext, {
81
- next: true,
82
- id: "viewer-next",
83
- onClick: handleNext,
84
- children: /*#__PURE__*/ jsx(Icon, {
85
- name: "chevron-right",
86
- size: 35,
87
- color: "white"
57
+ children: /*#__PURE__*/ jsx(StyledModal, {
58
+ children: /*#__PURE__*/ jsx(StyledDialog, {
59
+ "aria-label": alt || 'Image viewer',
60
+ children: /*#__PURE__*/ jsxs(ViewerContent, {
61
+ children: [
62
+ /*#__PURE__*/ jsx(Close, {
63
+ onClick: close,
64
+ children: /*#__PURE__*/ jsx(Icon, {
65
+ name: "close",
66
+ color: "white"
67
+ })
68
+ }),
69
+ images.length > 1 && /*#__PURE__*/ jsx(PrevNext, {
70
+ id: "viewer-prev",
71
+ onClick: handlePrev,
72
+ children: /*#__PURE__*/ jsx(Icon, {
73
+ name: "chevron-left",
74
+ size: 35,
75
+ color: "white"
76
+ })
77
+ }),
78
+ /*#__PURE__*/ jsx(Media, {
79
+ src: images[currentIndex],
80
+ alt: alt,
81
+ maxWidth: maxWidth,
82
+ maxHeight: maxHeight
83
+ }),
84
+ images.length > 1 && /*#__PURE__*/ jsx(PrevNext, {
85
+ $next: true,
86
+ id: "viewer-next",
87
+ onClick: handleNext,
88
+ children: /*#__PURE__*/ jsx(Icon, {
89
+ name: "chevron-right",
90
+ size: 35,
91
+ color: "white"
92
+ })
93
+ })
94
+ ]
88
95
  })
89
96
  })
90
- ]
91
- }) : null;
97
+ })
98
+ });
92
99
  };
93
- const Viewer = styled.div(({ prevNext, opacity })=>({
94
- width: '100%',
95
- height: '100%',
96
- backgroundColor: `rgba(0, 0, 0, ${opacity ?? 0.3})`,
100
+ const fadeIn = keyframes({
101
+ from: {
102
+ opacity: 0
103
+ },
104
+ to: {
105
+ opacity: 1
106
+ }
107
+ });
108
+ const fadeOut = keyframes({
109
+ from: {
110
+ opacity: 1
111
+ },
112
+ to: {
113
+ opacity: 0
114
+ }
115
+ });
116
+ const Overlay = styled(ModalOverlay)(({ prevNext, opacity })=>({
97
117
  position: 'fixed',
98
118
  top: 0,
99
119
  left: 0,
120
+ width: '100%',
121
+ height: '100%',
122
+ backgroundColor: `rgba(0, 0, 0, ${opacity ?? 0.3})`,
100
123
  display: 'grid',
101
124
  gridTemplateColumns: prevNext ? 'auto 1fr auto' : '1fr',
102
125
  justifyContent: 'space-between',
103
126
  alignItems: 'center',
104
127
  zIndex: 10000,
105
128
  userSelect: 'none',
106
- borderRadius: 5
129
+ borderRadius: 5,
130
+ '&[data-entering]': {
131
+ animation: `${fadeIn} 200ms ease-out`
132
+ },
133
+ '&[data-exiting]': {
134
+ animation: `${fadeOut} 200ms ease-in forwards`
135
+ }
107
136
  }));
137
+ const StyledModal = styled(Modal)({
138
+ outline: 'none',
139
+ pointerEvents: 'none',
140
+ display: 'contents'
141
+ });
142
+ const StyledDialog = styled(Dialog)({
143
+ outline: 'none',
144
+ pointerEvents: 'none',
145
+ display: 'contents'
146
+ });
147
+ const ViewerContent = styled.div({
148
+ display: 'contents'
149
+ });
108
150
  const Close = styled.div({
109
151
  position: 'absolute',
110
152
  top: 0,
@@ -115,9 +157,10 @@ const Close = styled.div({
115
157
  cursor: 'pointer',
116
158
  width: 50,
117
159
  height: 50,
118
- zIndex: 1
160
+ zIndex: 1,
161
+ pointerEvents: 'auto'
119
162
  });
120
- const PrevNext = styled.div(({ next })=>({
163
+ const PrevNext = styled.div(({ $next })=>({
121
164
  display: 'flex',
122
165
  justifyContent: 'center',
123
166
  alignItems: 'center',
@@ -125,18 +168,20 @@ const PrevNext = styled.div(({ next })=>({
125
168
  width: 50,
126
169
  height: '100%',
127
170
  backgroundColor: 'transparent',
128
- left: next ? void 0 : 0,
129
- right: next ? 0 : void 0,
171
+ left: $next ? void 0 : 0,
172
+ right: $next ? 0 : void 0,
130
173
  zIndex: 0,
174
+ pointerEvents: 'auto',
131
175
  '&:hover': {
132
- background: `linear-gradient(90deg, rgba(0,0,0,${next ? 0 : 0.4}) 0%, rgba(0,0,0,${next ? 0.4 : 0}) 100%)`
176
+ background: `linear-gradient(90deg, rgba(0,0,0,${$next ? 0 : 0.4}) 0%, rgba(0,0,0,${$next ? 0.4 : 0}) 100%)`
133
177
  }
134
178
  }));
135
179
  const Media = styled.img(({ maxWidth, maxHeight })=>({
136
180
  display: 'block',
137
181
  justifySelf: 'center',
138
182
  maxWidth: maxWidth || '100%',
139
- maxHeight: maxHeight || '100%'
183
+ maxHeight: maxHeight || '100%',
184
+ pointerEvents: 'auto'
140
185
  }));
141
186
  const components_ImageViewer = ImageViewer;
142
187
  export { components_ImageViewer as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wavv/ui",
3
- "version": "2.4.7",
3
+ "version": "2.4.8-alpha.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {