playbook_ui 10.20.0 → 10.21.0.pre.alpha.lightbox.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) 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_bar_graph/_bar_graph.jsx +4 -0
  10. data/app/pb_kits/playbook/pb_bar_graph/bar_graph.rb +1 -0
  11. data/app/pb_kits/playbook/pb_button/_button.jsx +3 -3
  12. data/app/pb_kits/playbook/pb_button/_button.scss +18 -1
  13. data/app/pb_kits/playbook/pb_button/button.rb +11 -3
  14. data/app/pb_kits/playbook/pb_button/button.test.js +13 -0
  15. data/app/pb_kits/playbook/pb_button/docs/_button_size.html.erb +3 -0
  16. data/app/pb_kits/playbook/pb_button/docs/_button_size.jsx +26 -0
  17. data/app/pb_kits/playbook/pb_button/docs/_button_size.md +1 -0
  18. data/app/pb_kits/playbook/pb_button/docs/example.yml +2 -0
  19. data/app/pb_kits/playbook/pb_button/docs/index.js +1 -0
  20. data/app/pb_kits/playbook/pb_circle_chart/_circle_chart.jsx +3 -0
  21. data/app/pb_kits/playbook/pb_circle_chart/circle_chart.rb +1 -0
  22. data/app/pb_kits/playbook/pb_dashboard/pbChartsDarkTheme.js +215 -0
  23. data/app/pb_kits/playbook/pb_file_upload/_file_upload.jsx +17 -10
  24. data/app/pb_kits/playbook/pb_file_upload/fileupload.test.js +40 -0
  25. data/app/pb_kits/playbook/pb_gauge/_gauge.jsx +3 -0
  26. data/app/pb_kits/playbook/pb_gauge/gauge.rb +1 -0
  27. data/app/pb_kits/playbook/pb_image/_image.jsx +1 -1
  28. data/app/pb_kits/playbook/pb_image/_image.scss +3 -3
  29. data/app/pb_kits/playbook/pb_image/image.rb +1 -1
  30. data/app/pb_kits/playbook/pb_image/image.test.js +1 -1
  31. data/app/pb_kits/playbook/pb_lightbox/Carousel/Slide.jsx +53 -0
  32. data/app/pb_kits/playbook/pb_lightbox/Carousel/Slides.jsx +53 -0
  33. data/app/pb_kits/playbook/pb_lightbox/Carousel/Thumbnail.jsx +38 -0
  34. data/app/pb_kits/playbook/pb_lightbox/Carousel/Thumbnails.jsx +78 -0
  35. data/app/pb_kits/playbook/pb_lightbox/Carousel/index.jsx +58 -0
  36. data/app/pb_kits/playbook/pb_lightbox/Carousel/useSlides.js +66 -0
  37. data/app/pb_kits/playbook/pb_lightbox/_lightbox.jsx +112 -0
  38. data/app/pb_kits/playbook/pb_lightbox/_lightbox_context.jsx +3 -0
  39. data/app/pb_kits/playbook/pb_lightbox/_lightbox_header.jsx +71 -0
  40. data/app/pb_kits/playbook/pb_lightbox/_lightbox_header_icon.jsx +26 -0
  41. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_compound_component.jsx +95 -0
  42. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_default.jsx +64 -0
  43. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_default.md +1 -0
  44. data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_multiple.jsx +64 -0
  45. data/app/pb_kits/playbook/pb_lightbox/docs/example.yml +7 -0
  46. data/app/pb_kits/playbook/pb_lightbox/docs/index.js +3 -0
  47. data/app/pb_kits/playbook/pb_lightbox/hooks/useVisibility.js +21 -0
  48. data/app/pb_kits/playbook/pb_lightbox/hooks/useWindowSize.js +25 -0
  49. data/app/pb_kits/playbook/pb_lightbox/lightbox.scss +202 -0
  50. data/app/pb_kits/playbook/pb_lightbox/lightbox.test.jsx +30 -0
  51. data/app/pb_kits/playbook/pb_line_graph/_line_graph.jsx +4 -0
  52. data/app/pb_kits/playbook/pb_line_graph/line_graph.rb +1 -0
  53. data/app/pb_kits/playbook/pb_popover/_popover.jsx +2 -4
  54. data/app/pb_kits/playbook/pb_popover/docs/_popover_close.html.erb +7 -7
  55. data/app/pb_kits/playbook/pb_popover/index.js +4 -9
  56. data/app/pb_kits/playbook/pb_popover/popover.html.erb +1 -1
  57. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.jsx +4 -0
  58. data/app/pb_kits/playbook/pb_text_input/_text_input.scss +2 -2
  59. data/app/pb_kits/playbook/pb_text_input/text_input.test.js +14 -0
  60. data/app/pb_kits/playbook/playbook-doc.js +2 -0
  61. data/app/pb_kits/playbook/plugins/pb_chart.js +8 -4
  62. data/lib/playbook/version.rb +1 -1
  63. metadata +29 -4
@@ -12,6 +12,7 @@ type GaugeProps = {
12
12
  aria: Object,
13
13
  className?: string,
14
14
  chartData?: array,
15
+ dark?: Boolean,
15
16
  data?: Object,
16
17
  disableAnimation: boolean,
17
18
  fullCircle: boolean,
@@ -33,6 +34,7 @@ const Gauge = (props: GaugeProps) => {
33
34
  aria = {},
34
35
  className,
35
36
  chartData = [{ name: 'Name', value: 0 }],
37
+ dark = false,
36
38
  data = {},
37
39
  disableAnimation = false,
38
40
  fullCircle = false,
@@ -67,6 +69,7 @@ const Gauge = (props: GaugeProps) => {
67
69
  id: id,
68
70
  chartData: formattedChartData,
69
71
  circumference: fullCircle ? [0, 360] : [-100, 100],
72
+ dark,
70
73
  disableAnimation: disableAnimation,
71
74
  height: height,
72
75
  min: min,
@@ -32,6 +32,7 @@ module Playbook
32
32
  id: id,
33
33
  chartData: chart_data_formatted,
34
34
  circumference: full_circle ? [0, 360] : [-100, 100],
35
+ dark: dark ? "dark" : "",
35
36
  disableAnimation: disable_animation,
36
37
  height: height,
37
38
  min: min,
@@ -34,7 +34,7 @@ const Image = (props: ImageProps) => {
34
34
 
35
35
  const ariaProps = buildAriaProps(aria)
36
36
  const classes = classnames(
37
- buildCss('pb_image_kit', size),
37
+ buildCss('pb_image_kit', size ? `size_${size}` : null),
38
38
  'lazyload',
39
39
  transition,
40
40
  { rounded },
@@ -14,7 +14,7 @@ $image-sizes: (
14
14
  object-fit: cover;
15
15
 
16
16
  @each $name, $size in $image-sizes {
17
- &[class*=_#{$name}] {
17
+ &[class*=size_#{$name}] {
18
18
  width: $size;
19
19
  height: $size;
20
20
  object-fit: cover;
@@ -35,7 +35,7 @@ $image-sizes: (
35
35
  transition: opacity 300ms ease-in;
36
36
  }
37
37
  }
38
-
38
+
39
39
  &.blur {
40
40
  filter: blur(5px);
41
41
  &.lazyloaded {
@@ -44,7 +44,7 @@ $image-sizes: (
44
44
  transition: filter 300ms ease-in;
45
45
  }
46
46
  }
47
-
47
+
48
48
  &.scale {
49
49
  opacity: 0;
50
50
  transform: scale(0.9);
@@ -27,7 +27,7 @@ module Playbook
27
27
  end
28
28
 
29
29
  def size_class
30
- size == "none" ? nil : "_#{size}"
30
+ size == "none" ? nil : "_size_#{size}"
31
31
  end
32
32
 
33
33
  def transition_class
@@ -26,7 +26,7 @@ test('default classname', () => {
26
26
 
27
27
  test('size = xs', () => {
28
28
  const kit = renderKit(Image, props, { size: 'xs' })
29
- expect(kit).toHaveClass('pb_image_kit_xs lazyload')
29
+ expect(kit).toHaveClass('pb_image_kit_size_xs lazyload')
30
30
  })
31
31
 
32
32
  test('transition = blur', () => {
@@ -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: number) => 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) {
25
+ const handlePinchingStop = (e) => {
26
+ const isZooming = e.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 className="TransformComponent">
44
+ <Image
45
+ alt={alt}
46
+ url={url}
47
+ zIndex="3"
48
+ />
49
+ </TransformComponent>
50
+ </button>
51
+ </TransformWrapper>
52
+ )
53
+ }
@@ -0,0 +1,53 @@
1
+ /* @flow */
2
+
3
+ import { noop } from 'lodash'
4
+ import { motion } from 'framer-motion'
5
+ import React, { useState } from 'react'
6
+
7
+ import Slide from './Slide'
8
+ import useSlides from './useSlides'
9
+
10
+ type SlidesType = {
11
+ urls: Array<string>,
12
+ current: number,
13
+ onChange: (index: number) => void,
14
+ onClick: (index: number) => void,
15
+ }
16
+
17
+ export default function Slides({
18
+ urls = [],
19
+ current = 0,
20
+ onClick = noop,
21
+ onChange = noop,
22
+ }: SlidesType) {
23
+ const [zooming, setZooming] = useState(false)
24
+ const { controls, dragConstraints, handleDragEnd } = useSlides({
25
+ current,
26
+ pagesCount: urls.length,
27
+ onChange,
28
+ })
29
+
30
+ const handleZoom = (isZooming) => setZooming(isZooming)
31
+
32
+ return (
33
+ <motion.div
34
+ animate={controls}
35
+ className="Slides"
36
+ drag={!zooming && 'x'}
37
+ dragConstraints={dragConstraints}
38
+ dragElastic={0.05}
39
+ onDragEnd={handleDragEnd}
40
+ transition={{ type: 'spring', bounce: 0 }}
41
+ >
42
+ {urls.map((url, i) => (
43
+ <Slide
44
+ key={i}
45
+ onClick={() => onClick(i)}
46
+ onZoom={handleZoom}
47
+ url={url}
48
+ zooming={zooming}
49
+ />
50
+ ))}
51
+ </motion.div>
52
+ )
53
+ }
@@ -0,0 +1,38 @@
1
+ /* @flow */
2
+
3
+ import React from 'react'
4
+ import { noop } from 'lodash'
5
+ import classnames from 'classnames'
6
+ import Image from '../../pb_image/_image'
7
+
8
+ type ThumbnailType = {
9
+ active?: boolean,
10
+ alt?: string,
11
+ onClick: () => void,
12
+ url: string,
13
+ width?: string,
14
+ }
15
+
16
+ export default function Thumbnail({
17
+ active = false,
18
+ alt,
19
+ width,
20
+ url,
21
+ onClick = noop,
22
+ }: ThumbnailType) {
23
+ const activeClasses = classnames('Thumbnail', { active })
24
+ return (
25
+ <button
26
+ className={classnames(activeClasses)}
27
+ onClick={onClick}
28
+ style={{ width }}
29
+ type="button"
30
+ >
31
+ <Image
32
+ alt={alt}
33
+ size="sm"
34
+ url={url}
35
+ />
36
+ </button>
37
+ )
38
+ }
@@ -0,0 +1,78 @@
1
+ /* @flow */
2
+
3
+ import { noop } from 'lodash'
4
+ import classnames from 'classnames'
5
+ import React, { useEffect } from 'react'
6
+ import { motion, useAnimation } from 'framer-motion'
7
+ import { useWindowSize } from '../hooks/useWindowSize'
8
+
9
+ import Thumbnail from './Thumbnail'
10
+
11
+ export const indexWithinBounds = (
12
+ current: number,
13
+ min: number,
14
+ max: number
15
+ ): number => {
16
+ if (current < min) return 0
17
+ if (current > max) return max
18
+ return current
19
+ }
20
+
21
+ type ThumbnailsType = {
22
+ current: number,
23
+ onChange: () => null,
24
+ urls: [],
25
+ }
26
+
27
+ export default function Thumbnails({
28
+ current = 0,
29
+ onChange = noop,
30
+ urls = [],
31
+ }: ThumbnailsType) {
32
+ const controls = useAnimation()
33
+ const viewportSize = useWindowSize()
34
+ const thumbnailWidth = viewportSize.width / 8
35
+ const draggable = thumbnailWidth * urls.length > viewportSize.width
36
+ const css = classnames('Thumbnails', { draggable })
37
+ const dragConstraints = {
38
+ left: -1 * (thumbnailWidth * urls.length - viewportSize.width),
39
+ right: 0,
40
+ }
41
+
42
+ const modifyTarget = (target) => {
43
+ const nextIndex = Math.round(Math.abs(target) / thumbnailWidth)
44
+ const snapTargetIndex = indexWithinBounds(nextIndex, 0, urls.length)
45
+ const snapTarget = snapTargetIndex * thumbnailWidth
46
+ const direction = Math.sign(target)
47
+ return direction * snapTarget
48
+ }
49
+
50
+ useEffect(() => {
51
+ if (draggable) {
52
+ const x = Math.max(-current * thumbnailWidth, dragConstraints.left)
53
+ controls.start({ x })
54
+ }
55
+ }, [controls, current, draggable, dragConstraints.left, thumbnailWidth])
56
+
57
+ return (
58
+ <motion.div
59
+ animate={controls}
60
+ className={css}
61
+ drag={draggable && 'x'}
62
+ dragConstraints={dragConstraints}
63
+ dragElastic={0.05}
64
+ dragTransition={{ modifyTarget }}
65
+ transition={{ type: 'spring', bounce: 0 }}
66
+ >
67
+ {urls.map((url, i) => (
68
+ <Thumbnail
69
+ active={i === current}
70
+ alt={i}
71
+ key={i}
72
+ onClick={() => onChange(i)}
73
+ url={url}
74
+ />
75
+ ))}
76
+ </motion.div>
77
+ )
78
+ }
@@ -0,0 +1,58 @@
1
+ /* eslint-disable jsx-control-statements/jsx-use-if-tag */
2
+ /* @flow */
3
+
4
+ import { noop } from 'lodash'
5
+ import React, { useEffect, useState } from 'react'
6
+
7
+ import Slides from './Slides'
8
+ import Thumbnails from './Thumbnails'
9
+
10
+ type CarouselType = {
11
+ initialPhoto: string,
12
+ onClose: Function,
13
+ icon: string,
14
+ iconSize: number,
15
+ current: number,
16
+ photos: Array<string>,
17
+ onChange: (index: number) => void,
18
+ onClick: (index: number) => void,
19
+ }
20
+
21
+ export default function Carousel({
22
+ current = 0,
23
+ photos,
24
+ onClick = noop,
25
+ onChange = noop,
26
+ }: CarouselType) {
27
+ useEffect(() => {
28
+ document.body.style.overflow = 'hidden'
29
+
30
+ return () => {
31
+ document.body.style.overflow = 'initial'
32
+ }
33
+ }, [])
34
+
35
+ const [currentIndex, setCurrentIndex] = useState(current)
36
+ const handleChange = (index) => {
37
+ setCurrentIndex(index)
38
+ onChange(index)
39
+ }
40
+
41
+ return (
42
+ <div className="Lightbox">
43
+ <Slides
44
+ current={currentIndex}
45
+ onChange={handleChange}
46
+ onClick={onClick}
47
+ urls={photos.map((photo) => photo.url)}
48
+ />
49
+ {photos.length > 1 ? (
50
+ <Thumbnails
51
+ current={currentIndex}
52
+ onChange={handleChange}
53
+ urls={photos.map((photo) => photo.thumbnail)}
54
+ />
55
+ ) : null}
56
+ </div>
57
+ )
58
+ }
@@ -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
+ }