playbook_ui 10.21.0.pre.alpha.jg1 → 10.21.0.pre.alpha.lightbox

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +1 -0
  3. data/app/pb_kits/playbook/data/menu.yml +1 -0
  4. data/app/pb_kits/playbook/index.js +2 -1
  5. data/app/pb_kits/playbook/pb_avatar/_avatar.jsx +1 -1
  6. data/app/pb_kits/playbook/pb_avatar/_avatar.scss +2 -2
  7. data/app/pb_kits/playbook/pb_avatar/avatar.rb +1 -1
  8. data/app/pb_kits/playbook/pb_avatar/avatar.test.js +1 -1
  9. data/app/pb_kits/playbook/pb_background/_background.jsx +2 -7
  10. data/app/pb_kits/playbook/pb_background/_background.scss +8 -24
  11. data/app/pb_kits/playbook/pb_background/background.rb +6 -6
  12. data/app/pb_kits/playbook/pb_background/docs/_background_image.html.erb +2 -50
  13. data/app/pb_kits/playbook/pb_background/docs/_background_image.jsx +28 -71
  14. data/app/pb_kits/playbook/pb_bar_graph/_bar_graph.jsx +4 -0
  15. data/app/pb_kits/playbook/pb_bar_graph/bar_graph.rb +1 -0
  16. data/app/pb_kits/playbook/pb_button/_button.jsx +3 -3
  17. data/app/pb_kits/playbook/pb_button/_button.scss +18 -1
  18. data/app/pb_kits/playbook/pb_button/button.rb +11 -3
  19. data/app/pb_kits/playbook/pb_button/button.test.js +13 -0
  20. data/app/pb_kits/playbook/pb_button/docs/_button_size.html.erb +3 -0
  21. data/app/pb_kits/playbook/pb_button/docs/_button_size.jsx +26 -0
  22. data/app/pb_kits/playbook/pb_button/docs/_button_size.md +1 -0
  23. data/app/pb_kits/playbook/pb_button/docs/example.yml +2 -0
  24. data/app/pb_kits/playbook/pb_button/docs/index.js +1 -0
  25. data/app/pb_kits/playbook/pb_circle_chart/_circle_chart.jsx +3 -0
  26. data/app/pb_kits/playbook/pb_circle_chart/circle_chart.rb +1 -0
  27. data/app/pb_kits/playbook/pb_dashboard/pbChartsDarkTheme.js +215 -0
  28. data/app/pb_kits/playbook/pb_file_upload/_file_upload.jsx +17 -10
  29. data/app/pb_kits/playbook/pb_file_upload/fileupload.test.js +40 -0
  30. data/app/pb_kits/playbook/pb_gauge/_gauge.jsx +3 -0
  31. data/app/pb_kits/playbook/pb_gauge/gauge.rb +1 -0
  32. data/app/pb_kits/playbook/pb_image/_image.jsx +1 -1
  33. data/app/pb_kits/playbook/pb_image/_image.scss +3 -3
  34. data/app/pb_kits/playbook/pb_image/image.rb +1 -1
  35. data/app/pb_kits/playbook/pb_image/image.test.js +1 -1
  36. data/app/pb_kits/playbook/pb_lightbox/Carousel/Slide.jsx +55 -0
  37. data/app/pb_kits/playbook/pb_lightbox/Carousel/Slides.jsx +54 -0
  38. data/app/pb_kits/playbook/pb_lightbox/Carousel/Thumbnail.jsx +39 -0
  39. data/app/pb_kits/playbook/pb_lightbox/Carousel/Thumbnails.jsx +82 -0
  40. data/app/pb_kits/playbook/pb_lightbox/Carousel/index.jsx +59 -0
  41. data/app/pb_kits/playbook/pb_lightbox/Carousel/styles.scss +110 -0
  42. data/app/pb_kits/playbook/pb_lightbox/Carousel/useSlides.js +66 -0
  43. data/app/pb_kits/playbook/pb_lightbox/_lightbox.jsx +112 -0
  44. data/app/pb_kits/playbook/pb_lightbox/_lightbox_context.jsx +3 -0
  45. data/app/pb_kits/playbook/pb_lightbox/_lightbox_header.jsx +71 -0
  46. data/app/pb_kits/playbook/pb_lightbox/_lightbox_header_icon.jsx +26 -0
  47. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_compound_component.jsx +95 -0
  48. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_default.jsx +64 -0
  49. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_default.md +1 -0
  50. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_multiple.jsx +64 -0
  51. data/app/pb_kits/playbook/pb_lightbox/docs/example.yml +7 -0
  52. data/app/pb_kits/playbook/pb_lightbox/docs/index.js +3 -0
  53. data/app/pb_kits/playbook/pb_lightbox/hooks/useVisibility.js +21 -0
  54. data/app/pb_kits/playbook/pb_lightbox/hooks/useWindowSize.js +25 -0
  55. data/app/pb_kits/playbook/pb_lightbox/lightbox.scss +90 -0
  56. data/app/pb_kits/playbook/pb_lightbox/lightbox.test.jsx +30 -0
  57. data/app/pb_kits/playbook/pb_line_graph/_line_graph.jsx +4 -0
  58. data/app/pb_kits/playbook/pb_line_graph/line_graph.rb +1 -0
  59. data/app/pb_kits/playbook/pb_popover/_popover.jsx +2 -4
  60. data/app/pb_kits/playbook/pb_popover/docs/_popover_close.html.erb +7 -7
  61. data/app/pb_kits/playbook/pb_popover/index.js +4 -9
  62. data/app/pb_kits/playbook/pb_popover/popover.html.erb +1 -1
  63. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.jsx +4 -0
  64. data/app/pb_kits/playbook/pb_text_input/_text_input.scss +2 -2
  65. data/app/pb_kits/playbook/pb_text_input/text_input.test.js +14 -0
  66. data/app/pb_kits/playbook/playbook-doc.js +2 -0
  67. data/app/pb_kits/playbook/plugins/pb_chart.js +8 -4
  68. data/lib/playbook/version.rb +2 -2
  69. metadata +28 -3
  70. data/app/pb_kits/playbook/pb_background/docs/_background_image.md +0 -1
@@ -0,0 +1,110 @@
1
+ .Lightbox {
2
+ width: 100vw;
3
+ height: 100vh;
4
+ position: fixed;
5
+ left: 0;
6
+ top: 0;
7
+ display: flex;
8
+ align-items: center;
9
+ flex-direction: column;
10
+ background-color: black;
11
+ z-index: 1;
12
+ overflow: hidden;
13
+ }
14
+
15
+ .Slides {
16
+ display: flex;
17
+ flex-grow: 1;
18
+ height: calc(100% - 100px);
19
+ width: 100%;
20
+ z-index: 1;
21
+
22
+ [class^="react-transform-wrapper"] {
23
+ flex-shrink: 0;
24
+ width: 100%;
25
+ height: 100%;
26
+ }
27
+
28
+ [class^="react-transform-content"] {
29
+ width: 100%;
30
+ height: 100%;
31
+ }
32
+ }
33
+
34
+ .Slide,
35
+ .Thumbnail {
36
+ flex-shrink: 0;
37
+ border: none;
38
+ margin: 0;
39
+ padding: 0;
40
+ cursor: pointer;
41
+ background-color: transparent;
42
+ }
43
+
44
+ .Slide {
45
+ display: flex;
46
+ justify-content: center;
47
+ align-items: center;
48
+ width: 100%;
49
+ height: 100%;
50
+ overflow: hidden;
51
+
52
+ img {
53
+ width: 100vw;
54
+ height: 100vh;
55
+ object-fit: contain;
56
+ }
57
+ }
58
+
59
+ .BackBtn,
60
+ .NextBtn {
61
+ z-index: 2;
62
+ color: black;
63
+ position: absolute;
64
+ width: 50px;
65
+ height: 50px;
66
+ top: calc(50vh - 5px);
67
+ border: none;
68
+ border-radius: 50%;
69
+ background-color: white;
70
+ }
71
+
72
+ .BackBtn::before,
73
+ .NextBtn::before {
74
+ content: "▸";
75
+ }
76
+
77
+ .BackBtn {
78
+ left: 30px;
79
+ transform: rotate(180deg);
80
+ }
81
+
82
+ .NextBtn {
83
+ right: 30px;
84
+ }
85
+
86
+ .Thumbnails {
87
+ display: flex;
88
+ padding: 3px;
89
+ }
90
+
91
+ .Thumbnails.draggable {
92
+ align-self: flex-start;
93
+ }
94
+
95
+ .Thumbnail {
96
+ padding: 3px;
97
+ height: 100%;
98
+
99
+ img {
100
+ width: 100%;
101
+ height: 100%;
102
+ }
103
+ }
104
+
105
+ .Thumbnail.active {
106
+ padding: 6px;
107
+ background-color: white;
108
+ box-shadow: 0 0 6px white;
109
+ }
110
+
@@ -0,0 +1,66 @@
1
+ // @flow
2
+
3
+ import { noop } from 'lodash'
4
+ import { useEffect, useState } from 'react'
5
+ import { useAnimation } from 'framer-motion'
6
+ import { useWindowSize } from '../hooks/useWindowSize'
7
+
8
+ const cycleIndex = (current: number, min: number, max: number): number => {
9
+ if (current < min) return max
10
+ if (current > max) return min
11
+ return current
12
+ }
13
+
14
+ const swipeConfidenceThreshold = 10000
15
+ const swipePower = (offset: number, velocity: number) => {
16
+ return Math.abs(offset) * velocity
17
+ }
18
+
19
+ export default function useSlides({
20
+ current = 0,
21
+ pagesCount = 0,
22
+ onChange = noop,
23
+ }) {
24
+ const controls = useAnimation()
25
+ const viewportSize = useWindowSize()
26
+ const [currentIndex, setCurrentIndex] = useState(current)
27
+ const dragConstraints = {
28
+ left: -viewportSize.width * (pagesCount - 1),
29
+ right: 0,
30
+ }
31
+
32
+ const paginate = (newDirection: number) => {
33
+ const nextIndex = currentIndex + newDirection
34
+ const cycledNextIndex = cycleIndex(nextIndex, 0, pagesCount - 1)
35
+ setCurrentIndex(cycledNextIndex)
36
+ return cycledNextIndex
37
+ }
38
+
39
+ const handleDragEnd = (e, { offset, velocity }) => {
40
+ let nextIndex = currentIndex
41
+ const swipe = swipePower(offset.x, velocity.x)
42
+
43
+ if (swipe < -swipeConfidenceThreshold) {
44
+ nextIndex = paginate(1)
45
+ } else if (swipe > swipeConfidenceThreshold) {
46
+ nextIndex = paginate(-1)
47
+ }
48
+
49
+ controls.start({ x: -viewportSize.width * nextIndex })
50
+
51
+ if (nextIndex !== currentIndex) {
52
+ onChange(nextIndex)
53
+ }
54
+ }
55
+
56
+ useEffect(() => {
57
+ controls.set({ x: -viewportSize.width * current })
58
+ setCurrentIndex(current)
59
+ }, [controls, current, viewportSize.width])
60
+
61
+ return {
62
+ controls,
63
+ dragConstraints,
64
+ handleDragEnd,
65
+ }
66
+ }
@@ -0,0 +1,112 @@
1
+ /* eslint-disable no-unused-vars */
2
+ /* @flow */
3
+
4
+ import React, { useState } from 'react'
5
+ import classnames from 'classnames'
6
+ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props.js'
7
+ import { globalProps } from '../utilities/globalProps.js'
8
+ import Icon from '../pb_icon/_icon'
9
+ import LightboxHeader from './_lightbox_header'
10
+ import { LightboxContext } from './_lightbox_context'
11
+
12
+ import Carousel from './Carousel/index.jsx'
13
+
14
+ type LightboxType = {
15
+ aria?: object,
16
+ children: array<React.ReactNode> | React.ReactNode | string,
17
+ className?: string,
18
+ data?: object,
19
+ description?: string,
20
+ id?: string,
21
+ photos: [],
22
+ initialPhoto: string,
23
+ onClose: Function,
24
+ opened: boolean,
25
+ icon: string,
26
+ iconSize: number,
27
+ trigger?: string,
28
+ }
29
+
30
+ const Lightbox = (props: LightboxType) => {
31
+ const {
32
+ aria = {},
33
+ children,
34
+ className,
35
+ data = {},
36
+ description,
37
+ id = '',
38
+ photos,
39
+ initialPhoto,
40
+ onClose,
41
+ opened,
42
+ icon,
43
+ iconSize,
44
+ trigger,
45
+ } = props
46
+ const [activePhoto, setActivePhoto] = useState(initialPhoto)
47
+
48
+ const ariaProps = buildAriaProps(aria)
49
+ const dataProps = buildDataProps(data)
50
+ const classes = classnames(
51
+ buildCss('pb_lightbox_kit'),
52
+ globalProps(props),
53
+ className
54
+ )
55
+
56
+ const handleOnSlide = (index) => {
57
+ setActivePhoto(photos[index])
58
+ }
59
+
60
+ const api = {
61
+ onClose: trigger
62
+ ? function () {
63
+ setTriggerOpened(false)
64
+ }
65
+ : onClose,
66
+ }
67
+
68
+ const [triggerOpened, setTriggerOpened] = useState(false),
69
+ modalIsOpened = trigger ? triggerOpened : opened
70
+
71
+ if (trigger) {
72
+ const modalTrigger = document.querySelector(trigger)
73
+ modalTrigger.addEventListener(
74
+ 'click',
75
+ () => {
76
+ setTriggerOpened(true)
77
+ document
78
+ .querySelector('#cancel-button')
79
+ .addEventListener('click', () => {
80
+ setTriggerOpened(false)
81
+ })
82
+ },
83
+ { once: true }
84
+ )
85
+ }
86
+ return (
87
+ <LightboxContext.Provider value={api}>
88
+ <div
89
+ {...ariaProps}
90
+ {...dataProps}
91
+ className={classes}
92
+ id={id}
93
+ >
94
+ <div className="carousel">
95
+ <Lightbox.Header>{children}</Lightbox.Header>
96
+ <Carousel
97
+ current={photos.indexOf(initialPhoto)}
98
+ onChange={handleOnSlide}
99
+ photos={photos.map((photo) => ({
100
+ url: photo,
101
+ thumbnail: photo,
102
+ }))}
103
+ />
104
+ </div>
105
+ </div>
106
+ </LightboxContext.Provider>
107
+ )
108
+ }
109
+
110
+ Lightbox.Header = LightboxHeader
111
+
112
+ export default Lightbox
@@ -0,0 +1,3 @@
1
+ import React from 'react'
2
+
3
+ export const LightboxContext = React.createContext()
@@ -0,0 +1,71 @@
1
+ /* @flow */
2
+ import React, { useContext } from 'react'
3
+ import classnames from 'classnames'
4
+ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
5
+ import { globalProps } from '../utilities/globalProps.js'
6
+ import { LightboxContext } from './_lightbox_context'
7
+ import { LightboxHeaderIcon } from './_lightbox_header_icon'
8
+ import Flex from '../pb_flex/_flex'
9
+ import FlexItem from '../pb_flex/_flex_item'
10
+
11
+ type LightboxHeaderProps = {
12
+ aria?: object,
13
+ children: array<React.ReactNode> | React.ReactNode | string,
14
+ className?: string,
15
+ closeable: boolean,
16
+ data?: object,
17
+ icon?: string,
18
+ iconSize?: string,
19
+ id?: string,
20
+ padding?: string,
21
+ spacing?: string,
22
+ text?: string,
23
+ title?: string,
24
+ }
25
+
26
+ const LightboxHeader = (props: LightboxHeaderProps) => {
27
+ const {
28
+ aria = {},
29
+ children,
30
+ className,
31
+ data = {},
32
+ padding = 'sm',
33
+ spacing = 'between',
34
+ closeable = true,
35
+ icon = 'times',
36
+ iconSize = '2x',
37
+ } = props
38
+
39
+ const ariaProps = buildAriaProps(aria)
40
+ const dataProps = buildDataProps(data)
41
+ const api = useContext(LightboxContext)
42
+ const headerCSS = buildCss('lightbox_header')
43
+ const headerSpacing = globalProps(props, { padding })
44
+
45
+ /* eslint-disable react/jsx-handler-names */
46
+
47
+ return (
48
+ <div className="carousel-header">
49
+ <Flex
50
+ {...ariaProps}
51
+ {...dataProps}
52
+ className={classnames(headerCSS, headerSpacing, className)}
53
+ spacing={spacing}
54
+ >
55
+ <If condition={closeable}>
56
+ <FlexItem flex={1}>
57
+ <LightboxHeaderIcon
58
+ className="close-icon"
59
+ icon={icon}
60
+ iconSize={iconSize}
61
+ onClose={api.onClose}
62
+ />
63
+ </FlexItem>
64
+ </If>
65
+ {children}
66
+ </Flex>
67
+ </div>
68
+ )
69
+ }
70
+
71
+ export default LightboxHeader
@@ -0,0 +1,26 @@
1
+ /* @flow */
2
+
3
+ import React from 'react'
4
+ import Icon from '../pb_icon/_icon'
5
+
6
+ type LightboxHeaderIconProps = {
7
+ onClose: () => mixed,
8
+ icon: string,
9
+ iconSize: string,
10
+ }
11
+
12
+ export const LightboxHeaderIcon = (props: LightboxHeaderIconProps) => {
13
+ const { onClose, icon, iconSize } = props
14
+ return (
15
+ <div
16
+ className="close-icon"
17
+ onClick={onClose}
18
+ >
19
+ <Icon
20
+ fixedWidth
21
+ icon={icon}
22
+ size={iconSize}
23
+ />
24
+ </div>
25
+ )
26
+ }
@@ -0,0 +1,95 @@
1
+ /* @flow */
2
+ /* eslint-disable jsx-control-statements/jsx-use-if-tag */
3
+ import React, { useState } from 'react'
4
+ import { Caption, Flex, FlexItem, Image, Title } from '../../'
5
+ import Lightbox from '../_lightbox'
6
+
7
+ const LightboxCompoundComponent = (props) => {
8
+ const photos = [
9
+ 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80',
10
+ 'https://images.unsplash.com/photo-1501045337096-542a73dafa4f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2052&q=80',
11
+ 'https://images.unsplash.com/photo-1563693998336-93c10e5d8f91?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80,',
12
+ ]
13
+ const [selectedPhoto, setSelectedPhoto] = useState(photos[0])
14
+ const [showLightbox, toggleShowLightbox] = useState(false)
15
+
16
+ const handleCloseLightbox = () => {
17
+ toggleShowLightbox(!showLightbox)
18
+ setSelectedPhoto(null)
19
+ }
20
+
21
+ const onPhotoClick = (photo) => {
22
+ toggleShowLightbox(!showLightbox)
23
+ setSelectedPhoto(photo)
24
+ }
25
+
26
+ return (
27
+ <>
28
+ <div>
29
+ {showLightbox ? (
30
+ <Lightbox
31
+ icon="times"
32
+ iconSize="2x"
33
+ initialPhoto={selectedPhoto}
34
+ onClose={handleCloseLightbox}
35
+ photos={photos}
36
+ {...props}
37
+ >
38
+ <Lightbox.Header>
39
+ <FlexItem flex={5}>
40
+ <Flex justify="center">
41
+ <Flex
42
+ align="center"
43
+ orientation="column"
44
+ >
45
+ <Title
46
+ dark
47
+ paddingBottom="xs"
48
+ size={4}
49
+ text="Windows, Sidings, & Gutters"
50
+ />
51
+
52
+ <Caption dark>{'Dyamic Count goes here.'}</Caption>
53
+ </Flex>
54
+ </Flex>
55
+ </FlexItem>
56
+ <FlexItem flex={1}>
57
+ <Flex justify="end">
58
+ <Title
59
+ dark
60
+ size={4}
61
+ text="All Photos"
62
+ />
63
+ </Flex>
64
+ </FlexItem>
65
+ </Lightbox.Header>
66
+ </Lightbox>
67
+ ) : (
68
+ <div className="PhotoViewer">
69
+ <Flex>
70
+ {photos.map((photo, index) => {
71
+ return (
72
+ <div
73
+ key={photo[index]}
74
+ onClick={() => onPhotoClick(photo)}
75
+ >
76
+ <Image
77
+ marginRight="xl"
78
+ rounded
79
+ size="lg"
80
+ url={photo}
81
+ />
82
+
83
+ <div className="overlay" />
84
+ </div>
85
+ )
86
+ })}
87
+ </Flex>
88
+ </div>
89
+ )}
90
+ </div>
91
+ </>
92
+ )
93
+ }
94
+
95
+ export default LightboxCompoundComponent
@@ -0,0 +1,64 @@
1
+ /* @flow */
2
+ /* eslint-disable jsx-control-statements/jsx-use-if-tag */
3
+ import React, { useState } from 'react'
4
+ import { Flex, Image } from '../../'
5
+ import Lightbox from '../_lightbox'
6
+
7
+ const LightboxDefault = (props) => {
8
+ const photos = [
9
+ 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80',
10
+ ]
11
+ const [selectedPhoto, setSelectedPhoto] = useState(photos[0])
12
+ const [showLightbox, toggleShowLightbox] = useState(false)
13
+
14
+ const handleCloseLightbox = () => {
15
+ toggleShowLightbox(!showLightbox)
16
+ setSelectedPhoto(null)
17
+ }
18
+
19
+ const onPhotoClick = (photo) => {
20
+ toggleShowLightbox(!showLightbox)
21
+ setSelectedPhoto(photo)
22
+ }
23
+
24
+ return (
25
+ <>
26
+ <div>
27
+ {showLightbox ? (
28
+ <Lightbox
29
+ icon="times"
30
+ iconSize="2x"
31
+ initialPhoto={selectedPhoto}
32
+ onClose={handleCloseLightbox}
33
+ photos={photos}
34
+ {...props}
35
+ />
36
+ ) : (
37
+ <div className="PhotoViewer">
38
+ <Flex>
39
+ {photos.map((photo, index) => {
40
+ return (
41
+ <div
42
+ key={photo[index]}
43
+ onClick={() => onPhotoClick(photo)}
44
+ >
45
+ <Image
46
+ marginRight="xl"
47
+ rounded
48
+ size="lg"
49
+ url={photo}
50
+ />
51
+
52
+ <div className="overlay" />
53
+ </div>
54
+ )
55
+ })}
56
+ </Flex>
57
+ </div>
58
+ )}
59
+ </div>
60
+ </>
61
+ )
62
+ }
63
+
64
+ export default LightboxDefault
@@ -0,0 +1 @@
1
+ Lightbox contains 5 props: `photos` (an array of urls), `initialPhoto` (a number ), an `onClose` callback function, an `icon` prop that matches to our `Icon` kit, and an `iconSize` prop that also corresponds to our icon kit.
@@ -0,0 +1,64 @@
1
+ /* @flow */
2
+ /* eslint-disable jsx-control-statements/jsx-use-if-tag */
3
+ import React, { useState } from 'react'
4
+ import { Flex, Image } from '../../'
5
+ import Lightbox from '../_lightbox.jsx'
6
+
7
+ const LightboxMultiple = (props) => {
8
+ const photos = [
9
+ 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80',
10
+ 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80',
11
+ 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80',
12
+ ]
13
+ const [selectedPhoto, setSelectedPhoto] = useState(photos[0])
14
+ const [light, toggleLight] = useState(false)
15
+
16
+ const handleCloseLightbox = () => {
17
+ toggleLight(!light)
18
+ setSelectedPhoto(null)
19
+ }
20
+
21
+ const onPhotoClick = (photo) => {
22
+ toggleLight(!light)
23
+ setSelectedPhoto(photo)
24
+ }
25
+
26
+ return (
27
+ <div>
28
+ {light ? (
29
+ <Lightbox
30
+ icon="times"
31
+ iconSize="2x"
32
+ initialPhoto={selectedPhoto}
33
+ onClose={handleCloseLightbox}
34
+ photos={photos}
35
+ {...props}
36
+ />
37
+ ) : (
38
+ <div className="PhotoViewer">
39
+ <Flex>
40
+ {photos.map((photo, index) => {
41
+ return (
42
+ <div
43
+ key={photos[index]}
44
+ onClick={() => onPhotoClick(photo)}
45
+ >
46
+ <Image
47
+ marginRight="xl"
48
+ rounded
49
+ size="lg"
50
+ url={photo}
51
+ />
52
+
53
+ <div className="overlay" />
54
+ </div>
55
+ )
56
+ })}
57
+ </Flex>
58
+ </div>
59
+ )}
60
+ </div>
61
+ )
62
+ }
63
+
64
+ export default LightboxMultiple
@@ -0,0 +1,7 @@
1
+ examples:
2
+
3
+ react:
4
+ - lightbox_default: Default
5
+ - lightbox_multiple: Multiple
6
+ - lightbox_compound_component: Compound Component
7
+
@@ -0,0 +1,3 @@
1
+ export { default as LightboxDefault } from './_lightbox_default.jsx'
2
+ export { default as LightboxMultiple } from './_lightbox_multiple.jsx'
3
+ export { default as LightboxCompoundComponent } from './_lightbox_compound_component.jsx'
@@ -0,0 +1,21 @@
1
+ import { debounce } from 'lodash'
2
+ import { useCallback, useMemo, useState } from 'react'
3
+
4
+ export default function useVisibility(initialState = false) {
5
+ const [visible, setVisible] = useState(initialState)
6
+ const hide = useCallback(() => setVisible(false), [])
7
+ const show = useCallback(({ afterDelay = 0 } = {}) => {
8
+ debounce(() => setVisible(true), afterDelay)()
9
+ }, [])
10
+ const toggle = useCallback(() => setVisible((current) => !current), [])
11
+
12
+ return useMemo(
13
+ () => ({
14
+ hide,
15
+ show,
16
+ toggle,
17
+ visible,
18
+ }),
19
+ [hide, show, toggle, visible]
20
+ )
21
+ }
@@ -0,0 +1,25 @@
1
+ import { useEffect, useState } from 'react'
2
+
3
+ export const useWindowSize = () => {
4
+ const [size, setSize] = useState({
5
+ width: window.innerWidth,
6
+ height: window.innerHeight,
7
+ })
8
+
9
+ useEffect(() => {
10
+ const handleResize = () => {
11
+ setSize({
12
+ width: window.innerWidth,
13
+ height: window.innerHeight,
14
+ })
15
+ }
16
+
17
+ window.addEventListener('resize', handleResize)
18
+
19
+ handleResize()
20
+
21
+ return () => window.removeEventListener('resize', handleResize)
22
+ }, [])
23
+
24
+ return size
25
+ }