playbook_ui 11.1.2 → 11.2.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 (48) 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 +14 -0
  4. data/app/pb_kits/playbook/index.js +1 -0
  5. data/app/pb_kits/playbook/pb_bread_crumbs/docs/_description.md +1 -1
  6. data/app/pb_kits/playbook/pb_button_toolbar/{_button_toolbar.jsx → _button_toolbar.tsx} +3 -3
  7. data/app/pb_kits/playbook/pb_caption/_caption.tsx +1 -1
  8. data/app/pb_kits/playbook/pb_contact/_contact.jsx +7 -6
  9. data/app/pb_kits/playbook/pb_contact/contact.rb +4 -0
  10. data/app/pb_kits/playbook/pb_contact/contact.test.js +87 -0
  11. data/app/pb_kits/playbook/pb_contact/docs/_contact_with_detail.html.erb +6 -0
  12. data/app/pb_kits/playbook/pb_contact/docs/_contact_with_detail.jsx +6 -0
  13. data/app/pb_kits/playbook/pb_dialog/_dialog.jsx +61 -12
  14. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_default.jsx +1 -1
  15. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_stacked_alert.jsx +153 -0
  16. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_stacked_alert.md +1 -0
  17. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_status.jsx +130 -0
  18. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_status.md +1 -0
  19. data/app/pb_kits/playbook/pb_dialog/docs/example.yml +2 -0
  20. data/app/pb_kits/playbook/pb_dialog/docs/index.js +2 -0
  21. data/app/pb_kits/playbook/pb_flex/_flex_item.tsx +50 -0
  22. data/app/pb_kits/playbook/pb_icon/_icon.tsx +15 -13
  23. data/app/pb_kits/playbook/pb_lightbox/Carousel/Slide.tsx +53 -0
  24. data/app/pb_kits/playbook/pb_lightbox/Carousel/Slides.tsx +35 -0
  25. data/app/pb_kits/playbook/pb_lightbox/Carousel/Thumbnail.tsx +39 -0
  26. data/app/pb_kits/playbook/pb_lightbox/Carousel/Thumbnails.tsx +75 -0
  27. data/app/pb_kits/playbook/pb_lightbox/Carousel/index.tsx +57 -0
  28. data/app/pb_kits/playbook/pb_lightbox/_lightbox.tsx +115 -0
  29. data/app/pb_kits/playbook/pb_lightbox/_lightbox_context.tsx +3 -0
  30. data/app/pb_kits/playbook/pb_lightbox/_lightbox_header.tsx +109 -0
  31. data/app/pb_kits/playbook/pb_lightbox/_lightbox_header_icon.tsx +27 -0
  32. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_compound_component.jsx +66 -0
  33. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_compound_component.md +1 -0
  34. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_default.jsx +65 -0
  35. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_default.md +1 -0
  36. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_multiple.jsx +91 -0
  37. data/app/pb_kits/playbook/pb_lightbox/docs/example.yml +6 -0
  38. data/app/pb_kits/playbook/pb_lightbox/docs/index.js +3 -0
  39. data/app/pb_kits/playbook/pb_lightbox/hooks/useKbdControls.ts +34 -0
  40. data/app/pb_kits/playbook/pb_lightbox/hooks/useVisibility.js +21 -0
  41. data/app/pb_kits/playbook/pb_lightbox/hooks/useWindowSize.ts +30 -0
  42. data/app/pb_kits/playbook/pb_lightbox/lightbox.scss +222 -0
  43. data/app/pb_kits/playbook/pb_lightbox/lightbox.test.jsx +124 -0
  44. data/app/pb_kits/playbook/playbook-doc.js +2 -0
  45. data/app/pb_kits/playbook/utilities/globalProps.ts +1 -1
  46. data/dist/reset.css +60 -1
  47. data/lib/playbook/version.rb +2 -2
  48. metadata +30 -3
@@ -0,0 +1,130 @@
1
+ /* eslint-disable react/jsx-handler-names */
2
+ /* @flow */
3
+
4
+ import React, { useState } from "react"
5
+ import { Button, Dialog, Flex } from "../.."
6
+
7
+ const useDialog = (visible = false) => {
8
+ const [opened, setOpened] = useState(visible)
9
+ const toggle = () => setOpened(!opened)
10
+ return [opened, toggle]
11
+
12
+ }
13
+
14
+ const DialogStatus = () => {
15
+ const [infoAlertOpened, toggleInfoAlert] = useDialog()
16
+ const [cautionAlertOpened, toggleCautionAlert] = useDialog()
17
+ const [successAlertOpened, toggleSuccessAlert] = useDialog()
18
+ const [errorAlertOpened, toggleErrorAlert] = useDialog()
19
+ const [deleteAlertOpened, toggleDeleteAlert] = useDialog()
20
+
21
+ const dialogs = [
22
+ {
23
+ status: "info",
24
+ text: "Text explaining why there is an alert",
25
+ title: "Are you Sure?",
26
+ toggle: toggleInfoAlert,
27
+ visible: infoAlertOpened,
28
+ buttonOneText:"No, Cancel",
29
+ buttonTwoText: "Yes, Action"
30
+ },
31
+ {
32
+ status: "caution",
33
+ text: "This is the action you will be taking",
34
+ title: "Are you Sure?",
35
+ toggle: toggleCautionAlert,
36
+ visible: cautionAlertOpened,
37
+ buttonOneText:"No, Cancel",
38
+ buttonTwoText: "Yes, Action"
39
+ },
40
+ {
41
+ status: "delete",
42
+ text: "You are about to delete ...",
43
+ title: "Delete",
44
+ toggle: toggleDeleteAlert,
45
+ visible: deleteAlertOpened,
46
+ buttonOneText:"No, Cancel",
47
+ buttonTwoText: "Yes, Delete"
48
+ },
49
+ {
50
+ status: "error",
51
+ text: "Text explaining the error",
52
+ title: "Error Message",
53
+ toggle: toggleErrorAlert,
54
+ visible: errorAlertOpened,
55
+ buttonOneText:"No, Cancel",
56
+ buttonTwoText: "Ok, Thanks"
57
+ },
58
+ {
59
+ status: "success",
60
+ text: "Text explaining what is successful",
61
+ title: "Success!",
62
+ toggle: toggleSuccessAlert,
63
+ visible: successAlertOpened,
64
+ buttonOneText:"No, Cancel",
65
+ buttonTwoText: "Ok, Thanks"
66
+ },
67
+ ]
68
+
69
+ return (
70
+ <div>
71
+ <Flex>
72
+ <Button
73
+ marginRight="md"
74
+ onClick={toggleInfoAlert}
75
+ >
76
+ {"Information Status"}
77
+ </Button>
78
+ <Button
79
+ marginRight="md"
80
+ onClick={toggleCautionAlert}
81
+ >
82
+ {"Caution Status"}
83
+ </Button>
84
+ <Button
85
+ marginRight="md"
86
+ onClick={toggleSuccessAlert}
87
+ >
88
+ {"Success Status"}
89
+ </Button>
90
+ <Button onClick={toggleErrorAlert}>
91
+ {"Error Status"}
92
+ </Button>
93
+ <Button
94
+ marginRight="md"
95
+ onClick={toggleDeleteAlert}
96
+ >
97
+ {"Delete Status"}
98
+ </Button>
99
+ </Flex>
100
+ <Flex>
101
+ {dialogs.map((dialog) => (
102
+ <Dialog
103
+ key={dialog.status}
104
+ onClose={dialog.toggle}
105
+ opened={dialog.visible}
106
+ status={dialog.status}
107
+ text={dialog.text}
108
+ title={dialog.title}
109
+ >
110
+ <Dialog.Footer>
111
+ <Button
112
+ onClick={dialog.toggle}
113
+ variant="secondary"
114
+ >
115
+ {dialog.buttonOneText}
116
+ </Button>
117
+ <Button
118
+ onClick={dialog.toggle}
119
+ >
120
+ {dialog.buttonTwoText}
121
+ </Button>
122
+ </Dialog.Footer>
123
+ </Dialog>
124
+ ))}
125
+ </Flex>
126
+ </div>
127
+ )
128
+ }
129
+
130
+ export default DialogStatus
@@ -0,0 +1 @@
1
+ This shows the different alert statuses that can be used for dialog boxes. These all have two buttons which is a default
@@ -8,3 +8,5 @@ examples:
8
8
  - dialog_sizes: Sizes
9
9
  - dialog_scrollable: Scrollable
10
10
  - dialog_should_close_on_overlay: Overlay Click
11
+ - dialog_status: Status Alert
12
+ - dialog_stacked_alert: Stacked Button Alert
@@ -4,3 +4,5 @@ export { default as DialogSizes } from './_dialog_sizes.jsx'
4
4
  export { default as DialogScrollable } from './_dialog_scrollable.jsx'
5
5
  export { default as DialogSeparators } from './_dialog_separators.jsx'
6
6
  export { default as DialogShouldCloseOnOverlay } from './_dialog_should_close_on_overlay.jsx'
7
+ export { default as DialogStatus } from './_dialog_status.jsx'
8
+ export { default as DialogStackedAlert } from './_dialog_stacked_alert.jsx'
@@ -0,0 +1,50 @@
1
+ import React from 'react'
2
+ import classnames from 'classnames'
3
+ import { buildCss } from '../utilities/props'
4
+ import { globalProps, GlobalProps } from '../utilities/globalProps'
5
+ type FlexItemPropTypes = {
6
+ children: React.ReactNode[] | React.ReactNode,
7
+ fixedSize?: string,
8
+ grow?: boolean,
9
+ shrink?: boolean,
10
+ className?: string,
11
+ overflow?: "auto" | "hidden" | "initial" | "inherit" | "scroll" | "visible",
12
+ order?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'first' | 'none',
13
+ alignSelf?: "start" | "end" | "center" | "stretch" | null,
14
+ displayFlex?: boolean
15
+ } & GlobalProps
16
+
17
+ const FlexItem = (props: FlexItemPropTypes): React.ReactElement => {
18
+ const {
19
+ children,
20
+ className,
21
+ fixedSize,
22
+ grow,
23
+ overflow = null,
24
+ shrink,
25
+ flex = 'none',
26
+ order = 'none',
27
+ alignSelf,
28
+ displayFlex
29
+ } = props
30
+ const growClass = grow === true ? 'grow' : ''
31
+ const displayFlexClass = displayFlex === true ? `display_flex_${displayFlex}` : ''
32
+ const flexClass = flex !== 'none' ? `flex_${flex}` : ''
33
+ const overflowClass = overflow ? `overflow_${overflow}` : ''
34
+ const shrinkClass = shrink === true ? 'shrink' : ''
35
+ const alignSelfClass = alignSelf ? `align_self_${alignSelf}` : ''
36
+ const fixedStyle =
37
+ fixedSize !== undefined ? { flexBasis: `${fixedSize}` } : null
38
+ const orderClass = order !== 'none' ? `order_${order}` : null
39
+
40
+ return (
41
+ <div
42
+ className={classnames(buildCss('pb_flex_item_kit', growClass, shrinkClass, flexClass, displayFlexClass), overflowClass, orderClass, alignSelfClass, globalProps(props), className)}
43
+ style={fixedStyle}
44
+ >
45
+ {children}
46
+ </div>
47
+ )
48
+ }
49
+
50
+ export default FlexItem
@@ -3,6 +3,20 @@ import classnames from 'classnames'
3
3
  import { buildAriaProps, buildDataProps } from '../utilities/props'
4
4
  import { GlobalProps, globalProps } from '../utilities/globalProps'
5
5
 
6
+ export type IconSizes = "lg"
7
+ | "xs"
8
+ | "sm"
9
+ | "1x"
10
+ | "2x"
11
+ | "3x"
12
+ | "4x"
13
+ | "5x"
14
+ | "6x"
15
+ | "7x"
16
+ | "8x"
17
+ | "9x"
18
+ | "10x"
19
+
6
20
  type IconProps = {
7
21
  aria?: {[key: string]: string},
8
22
  border?: string,
@@ -18,19 +32,7 @@ type IconProps = {
18
32
  pull?: "left" | "right" | "none",
19
33
  pulse?: boolean,
20
34
  rotation?: 90 | 180 | 270,
21
- size?: | "lg"
22
- | "xs"
23
- | "sm"
24
- | "1x"
25
- | "2x"
26
- | "3x"
27
- | "4x"
28
- | "5x"
29
- | "6x"
30
- | "7x"
31
- | "8x"
32
- | "9x"
33
- | "10x",
35
+ size?: IconSizes,
34
36
  spin?: boolean,
35
37
  } & GlobalProps
36
38
 
@@ -0,0 +1,53 @@
1
+ /* @flow */
2
+
3
+ import React from 'react'
4
+ import { noop } from 'lodash'
5
+ import { TransformComponent, TransformWrapper } from 'react-zoom-pan-pinch'
6
+ import Image from '../../pb_image/_image'
7
+
8
+ type SlideType = {
9
+ alt?: string,
10
+ current?: number,
11
+ onClick: () => void,
12
+ onChange?: (index: number) => void,
13
+ onZoom: (zoom: boolean) => void,
14
+ zooming: boolean,
15
+ url: string,
16
+ }
17
+
18
+ export default function Slide({
19
+ alt,
20
+ onClick = noop,
21
+ onZoom = noop,
22
+ url,
23
+ zooming = false,
24
+ }: SlideType): React.ReactElement {
25
+ const handlePinchingStop = ({state}: {state: any}) => {
26
+ const isZooming = state.scale > 1
27
+ onZoom(isZooming)
28
+ }
29
+
30
+ return (
31
+ <TransformWrapper
32
+ doubleClick={{ mode: 'reset' }}
33
+ initialScale={1}
34
+ onPinchingStop={handlePinchingStop}
35
+ panning={{ disabled: !zooming }}
36
+ >
37
+ <button
38
+ className="Slide"
39
+ onClick={onClick}
40
+ onDoubleClick={() => onZoom(false)}
41
+ tabIndex={-1}
42
+ >
43
+ <TransformComponent wrapperClass="TransformComponent">
44
+ <Image
45
+ alt={alt}
46
+ url={url}
47
+ zIndex={3}
48
+ />
49
+ </TransformComponent>
50
+ </button>
51
+ </TransformWrapper>
52
+ )
53
+ }
@@ -0,0 +1,35 @@
1
+ /* @flow */
2
+
3
+ import { noop } from 'lodash'
4
+ import React, { useState } from 'react'
5
+
6
+ import Slide from './Slide'
7
+
8
+ type SlidesType = {
9
+ urls: Array<string>,
10
+ current: number,
11
+ onChange: (index: number) => void,
12
+ onClick: (index: number) => void,
13
+ }
14
+
15
+ export default function Slides({
16
+ urls = [],
17
+ current = 0,
18
+ onChange = noop,
19
+ }: SlidesType): React.ReactElement {
20
+ const [zooming, setZooming] = useState(false)
21
+
22
+ const handleZoom = (isZooming: boolean) => setZooming(isZooming)
23
+ return (
24
+ <div
25
+ className="Slides"
26
+ >
27
+ <Slide
28
+ onClick={() => onChange(current)}
29
+ onZoom={handleZoom}
30
+ url={urls[current]}
31
+ zooming={zooming}
32
+ />
33
+ </div>
34
+ )
35
+ }
@@ -0,0 +1,39 @@
1
+ import React from 'react'
2
+ import { noop } from 'lodash'
3
+ import classnames from 'classnames'
4
+ import Image from '../../pb_image/_image'
5
+
6
+ type ThumbnailType = {
7
+ active?: boolean,
8
+ alt?: string,
9
+ onClick: () => void,
10
+ buttonRef?: React.RefObject<HTMLButtonElement>,
11
+ url: string,
12
+ width?: string,
13
+ }
14
+
15
+ export default function Thumbnail({
16
+ active = false,
17
+ alt,
18
+ width,
19
+ url,
20
+ onClick = noop,
21
+ buttonRef,
22
+ }: ThumbnailType): React.ReactElement {
23
+ const activeClasses = classnames('Thumbnail', { active })
24
+ return (
25
+ <button
26
+ className={classnames(activeClasses)}
27
+ onClick={onClick}
28
+ ref={buttonRef}
29
+ style={{ width }}
30
+ type="button"
31
+ >
32
+ <Image
33
+ alt={alt}
34
+ size="sm"
35
+ url={url}
36
+ />
37
+ </button>
38
+ )
39
+ }
@@ -0,0 +1,75 @@
1
+ import { noop } from 'lodash'
2
+ import classnames from 'classnames'
3
+ import React, { useLayoutEffect } from 'react'
4
+ import { useWindowSize } from '../hooks/useWindowSize'
5
+
6
+ import Thumbnail from './Thumbnail'
7
+
8
+ export const indexWithinBounds = (
9
+ current: number,
10
+ min: number,
11
+ max: number
12
+ ): number => {
13
+ if (current < min) return 0
14
+ if (current > max) return max
15
+ return current
16
+ }
17
+
18
+ type ThumbnailsType = {
19
+ current: number,
20
+ onChange: (index: number) => void,
21
+ urls: string[],
22
+ }
23
+
24
+ export default function Thumbnails({
25
+ current = 0,
26
+ onChange = noop,
27
+ urls = [],
28
+ }: ThumbnailsType): React.ReactElement {
29
+ const viewportSize = useWindowSize()
30
+ const thumbnailWidth = viewportSize.width / 8
31
+ const draggable = thumbnailWidth * urls.length > viewportSize.width
32
+ const shouldBeCentered = (thumbnailWidth * urls.length) < (viewportSize.width * 0.9)
33
+ const css = classnames('Thumbnails', { draggable }, { centered: shouldBeCentered })
34
+
35
+ const otherProps: { buttonRef?: React.RefObject<HTMLButtonElement> } = {}
36
+
37
+ const thumbnailsRef: React.RefObject<HTMLDivElement> = React.createRef()
38
+
39
+ useLayoutEffect(() => {
40
+ if (shouldBeCentered) return
41
+
42
+ const currentThumbnail = otherProps.buttonRef.current
43
+
44
+ const thumbWidth = currentThumbnail.clientWidth,
45
+ scrollLeft = thumbWidth * current,
46
+ firstThumb: HTMLButtonElement = thumbnailsRef.current.querySelector('.Thumbnail:first-child'),
47
+ lastThumb: HTMLButtonElement = thumbnailsRef.current.querySelector('.Thumbnail:last-child')
48
+
49
+ firstThumb.style.marginLeft = `${(thumbnailsRef.current?.clientWidth / 2) - (thumbWidth / 2)}px`
50
+ lastThumb.style.marginRight = `${(thumbnailsRef.current?.clientWidth / 2) - (thumbWidth / 2)}px`
51
+ thumbnailsRef.current?.scrollTo(scrollLeft, 0)
52
+ })
53
+
54
+ return (
55
+ <div
56
+ className={css}
57
+ ref={thumbnailsRef}
58
+ >
59
+ {urls.map((url, i) => {
60
+ const active = i === current
61
+ if (active) otherProps.buttonRef = React.createRef()
62
+ return (
63
+ <Thumbnail
64
+ active={active}
65
+ alt={i.toString()}
66
+ key={i}
67
+ onClick={() => onChange(i)}
68
+ url={url}
69
+ {...otherProps}
70
+ />
71
+ )
72
+ })}
73
+ </div>
74
+ )
75
+ }
@@ -0,0 +1,57 @@
1
+ /* eslint-disable jsx-control-statements/jsx-use-if-tag */
2
+ import { noop } from 'lodash'
3
+ import React, { useEffect } from 'react'
4
+
5
+ import Slides from './Slides'
6
+ import Thumbnails from './Thumbnails'
7
+
8
+ type CarouselType = {
9
+ initialPhoto?: string,
10
+ onClose?: () => void,
11
+ icon?: string,
12
+ iconSize?: number,
13
+ currentIndex: number,
14
+ photos: {
15
+ url: string,
16
+ thumbnail: string,
17
+ }[],
18
+ onChange: (index: number) => void,
19
+ onClick?: (index: number) => void,
20
+ }
21
+
22
+ export default function Carousel({
23
+ currentIndex,
24
+ photos,
25
+ onClick = noop,
26
+ onChange = noop,
27
+ }: CarouselType): React.ReactElement {
28
+ useEffect(() => {
29
+ document.body.style.overflow = 'hidden'
30
+
31
+ return () => {
32
+ document.body.style.overflow = 'initial'
33
+ }
34
+ }, [])
35
+
36
+ const handleChange = (index: number) => {
37
+ onChange(index)
38
+ }
39
+
40
+ return (
41
+ <div className="Lightbox">
42
+ <Slides
43
+ current={currentIndex}
44
+ onChange={handleChange}
45
+ onClick={onClick}
46
+ urls={photos.map((photo) => photo.url)}
47
+ />
48
+ {photos.length > 1 ? (
49
+ <Thumbnails
50
+ current={currentIndex}
51
+ onChange={handleChange}
52
+ urls={photos.map((photo) => photo.thumbnail)}
53
+ />
54
+ ) : null}
55
+ </div>
56
+ )
57
+ }
@@ -0,0 +1,115 @@
1
+ import React, { Fragment, useMemo, useRef, useState } from 'react'
2
+ import { useKbdControls } from './hooks/useKbdControls'
3
+ import classnames from 'classnames'
4
+ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
5
+ import { globalProps } from '../utilities/globalProps'
6
+ import LightboxHeader from './_lightbox_header'
7
+ import { LightboxContext } from './_lightbox_context'
8
+ import { IconSizes } from '../pb_icon/_icon'
9
+
10
+ import Carousel from './Carousel/index'
11
+
12
+ type LightboxType = {
13
+ aria?: {[key: string]: string},
14
+ children: React.ReactNode[] | React.ReactNode | string,
15
+ className?: string,
16
+ data?: {[key: string]: string | number},
17
+ description?: string,
18
+ id?: string,
19
+ photos: [],
20
+ initialPhoto?: number,
21
+ onClose: () => void,
22
+ icon: string,
23
+ iconSize: IconSizes,
24
+ showCount?: boolean,
25
+ textRight?: string,
26
+ trigger?: string,
27
+ title?: string,
28
+ }
29
+
30
+ const Lightbox = (props: LightboxType): React.ReactNode => {
31
+ const {
32
+ aria = {},
33
+ children,
34
+ className,
35
+ data = {},
36
+ description,
37
+ id = '',
38
+ initialPhoto = 0,
39
+ photos,
40
+ onClose,
41
+ icon = 'times',
42
+ iconSize = '2x',
43
+ showCount = true,
44
+ textRight = 'All Photos',
45
+ title,
46
+ } = props
47
+ const [activePhoto, setActivePhoto] = useState(initialPhoto)
48
+
49
+ const ariaProps = buildAriaProps(aria)
50
+ const dataProps = buildDataProps(data)
51
+ const classes = classnames(
52
+ buildCss('pb_lightbox_kit'),
53
+ globalProps(props),
54
+ className
55
+ )
56
+
57
+ const handleOnSlide = (photoIndex: number) => {
58
+ setActivePhoto(photoIndex)
59
+ }
60
+
61
+ const photosMap = useMemo(() => photos.map((photo) => ({
62
+ url: photo,
63
+ thumbnail: photo,
64
+ })), [photos])
65
+
66
+ const api = {
67
+ onClose: onClose,
68
+ onArrowLeft: () => {
69
+ setActivePhoto(activePhoto > 0 ? activePhoto - 1 : 0)
70
+ },
71
+ onArrowRight: () => {
72
+ const nextPhoto = activePhoto < photos.length - 1 ? activePhoto + 1 : photos.length - 1
73
+ setActivePhoto(nextPhoto)
74
+ },
75
+ }
76
+ useKbdControls(api)
77
+
78
+ const lightboxRef: any = useRef()
79
+
80
+ const headerTextRight = showCount ? `${activePhoto + 1} / ${photos.length}` : textRight
81
+
82
+ return (
83
+ <Fragment>
84
+ <LightboxContext.Provider value={api}>
85
+ <div
86
+ {...ariaProps}
87
+ {...dataProps}
88
+ className={classes}
89
+ id={id}
90
+ ref={lightboxRef}
91
+ >
92
+ <div className="carousel">
93
+ <Lightbox.Header
94
+ icon={icon}
95
+ iconSize={iconSize}
96
+ text={description}
97
+ textRight={headerTextRight}
98
+ title={title}
99
+ />
100
+ {children}
101
+ <Carousel
102
+ currentIndex={activePhoto}
103
+ onChange={handleOnSlide}
104
+ photos={photosMap}
105
+ />
106
+ </div>
107
+ </div>
108
+ </LightboxContext.Provider>
109
+ </Fragment>
110
+ )
111
+ }
112
+
113
+ Lightbox.Header = LightboxHeader
114
+
115
+ export default Lightbox
@@ -0,0 +1,3 @@
1
+ import React from 'react'
2
+
3
+ export const LightboxContext = React.createContext({})