-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Full stack/react experimental components (#1701)
* chore(react): add experimental components directory with necessary changes * chore(react): bump to alpha 1.0.0-alpha.0 * fix(react): allow carousel elements without buttons * chore(react): bump react to v1.0.0-alpha.1
- Loading branch information
1 parent
c7d5599
commit 5f43314
Showing
30 changed files
with
3,513 additions
and
5 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
packages/botonic-react/src/experimental/components/audio.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { INPUT, isBrowser } from '@botonic/core' | ||
import React from 'react' | ||
|
||
import { ROLES } from '../../constants' | ||
import { Message } from './message' | ||
|
||
const serialize = audioProps => { | ||
return { src: audioProps.src } | ||
} | ||
|
||
export const Audio = props => ( | ||
<Message | ||
role={ROLES.AUDIO_MESSAGE} | ||
json={serialize(props)} | ||
{...props} | ||
type={INPUT.AUDIO} | ||
> | ||
{isBrowser() && ( | ||
<audio style={{ maxWidth: '100%' }} id='myAudio' controls> | ||
<source src={props.src} type='audio/mpeg' /> | ||
Your browser does not support this audio format. | ||
</audio> | ||
)} | ||
{props.children} | ||
</Message> | ||
) | ||
|
||
Audio.serialize = serialize |
181 changes: 181 additions & 0 deletions
181
packages/botonic-react/src/experimental/components/carousel.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import { INPUT, isBrowser } from '@botonic/core' | ||
import React, { useContext, useEffect, useRef, useState } from 'react' | ||
import styled from 'styled-components' | ||
|
||
import LeftArrow from '../../assets/leftArrow.svg' | ||
import RightArrow from '../../assets/rightArrow.svg' | ||
import { ButtonsDisabler } from '../../components/buttons-disabler' | ||
import { COLORS, WEBCHAT } from '../../constants' | ||
import { WebchatContext } from '../../contexts' | ||
import { resolveImage } from '../../util/environment' | ||
import { StyledScrollbar } from '../../webchat/components/styled-scrollbar' | ||
import { Message } from './message' | ||
|
||
const StyledCarousel = styled.div` | ||
padding: 10px 0px; | ||
display: flex; | ||
flex-direction: row; | ||
max-width: 100%; | ||
${props => props.carouselArrowsEnabled && 'overflow-x: auto;'} | ||
` | ||
|
||
const StyledItems = styled.div` | ||
display: flex; | ||
` | ||
|
||
const StyledArrowContainer = styled.div` | ||
position: absolute; | ||
top: calc(50% - 20px); | ||
height: 40px; | ||
width: 25px; | ||
background: ${COLORS.SILVER}; | ||
display: flex; | ||
align-items: center; | ||
cursor: pointer; | ||
justify-content: ${props => props.justifyContent}; | ||
left: ${props => props.left}px; | ||
right: ${props => props.right}px; | ||
border-top-${props => props.arrow}-radius: 30px; | ||
border-bottom-${props => props.arrow}-radius: 30px; | ||
` | ||
const StyledArrow = styled.img` | ||
width: 20px; | ||
height: 20px; | ||
` | ||
|
||
const serialize = carouselProps => { | ||
let carouselChildren = carouselProps.children | ||
if (!Array.isArray(carouselChildren)) carouselChildren = [carouselChildren] | ||
return { | ||
type: INPUT.CAROUSEL, | ||
elements: carouselChildren.map( | ||
e => e && e.type && e.type.serialize && e.type.serialize(e.props) | ||
), | ||
} | ||
} | ||
|
||
/** | ||
* | ||
* @param {MessageProps} props | ||
* @returns {JSX.Element} | ||
*/ | ||
export const Carousel = props => { | ||
const { getThemeProperty } = useContext(WebchatContext) | ||
let content = props.children | ||
const scrollbarOptions = { | ||
...{ enable: true, autoHide: true }, | ||
...getThemeProperty(WEBCHAT.CUSTOM_PROPERTIES.scrollbar), | ||
} | ||
const [hasLeftArrow, setLeftArrow] = useState(false) | ||
const [hasRightArrow, setRightArrow] = useState(true) | ||
const carouselRef = useRef(null) | ||
const CustomCarouselLeftArrow = getThemeProperty( | ||
WEBCHAT.CUSTOM_PROPERTIES.customCarouselLeftArrow, | ||
undefined | ||
) | ||
const CustomCarouselRightArrow = getThemeProperty( | ||
WEBCHAT.CUSTOM_PROPERTIES.customCarouselRightArrow, | ||
undefined | ||
) | ||
const carouselArrowsEnabled = getThemeProperty( | ||
WEBCHAT.CUSTOM_PROPERTIES.enableCarouselArrows, | ||
true | ||
) | ||
|
||
const scrollCarouselBy = value => { | ||
carouselRef.current.scrollBy({ | ||
left: value, | ||
behavior: 'smooth', | ||
}) | ||
} | ||
|
||
const setArrowsVisibility = event => { | ||
const carousel = event.currentTarget | ||
const maxRightScroll = | ||
carousel.scrollWidth - | ||
carousel.offsetWidth - | ||
WEBCHAT.DEFAULTS.ELEMENT_MARGIN_RIGHT | ||
setLeftArrow(carousel.scrollLeft !== 0) | ||
setRightArrow(carousel.scrollLeft < maxRightScroll) | ||
} | ||
|
||
const getArrows = () => { | ||
const scrollBy = | ||
WEBCHAT.DEFAULTS.ELEMENT_WIDTH + WEBCHAT.DEFAULTS.ELEMENT_MARGIN_RIGHT | ||
return ( | ||
<> | ||
{hasLeftArrow && | ||
(CustomCarouselLeftArrow ? ( | ||
<CustomCarouselLeftArrow scrollCarouselBy={scrollCarouselBy} /> | ||
) : ( | ||
<StyledArrowContainer | ||
left={0} | ||
arrow={'right'} | ||
justifyContent={'flex-start'} | ||
onClick={() => scrollCarouselBy(-scrollBy)} | ||
> | ||
<StyledArrow src={resolveImage(LeftArrow)} /> | ||
</StyledArrowContainer> | ||
))} | ||
{hasRightArrow && | ||
(CustomCarouselRightArrow ? ( | ||
<CustomCarouselRightArrow scrollCarouselBy={scrollCarouselBy} /> | ||
) : ( | ||
<StyledArrowContainer | ||
right={0} | ||
arrow={'left'} | ||
justifyContent={'flex-end'} | ||
onClick={() => scrollCarouselBy(scrollBy)} | ||
> | ||
<StyledArrow src={resolveImage(RightArrow)} /> | ||
</StyledArrowContainer> | ||
))} | ||
</> | ||
) | ||
} | ||
|
||
useEffect(() => { | ||
const carousel = carouselRef.current | ||
if (carousel && carousel.addEventListener) { | ||
carousel.addEventListener('scroll', setArrowsVisibility, false) | ||
} else if (carousel && carousel.attachEvent) { | ||
carousel.attachEvent('scroll', setArrowsVisibility) | ||
} | ||
}, [carouselRef.current]) | ||
|
||
const carouselProps = { | ||
...props, | ||
children: ButtonsDisabler.updateChildrenButtons(props.children), | ||
} | ||
|
||
if (isBrowser()) { | ||
content = ( | ||
<StyledScrollbar | ||
scrollbar={scrollbarOptions} | ||
autoHide={scrollbarOptions.autoHide} | ||
> | ||
<StyledCarousel | ||
ref={carouselRef} | ||
carouselArrowsEnabled={carouselArrowsEnabled} | ||
> | ||
<StyledItems>{carouselProps.children}</StyledItems> | ||
{carouselArrowsEnabled && getArrows()} | ||
</StyledCarousel> | ||
</StyledScrollbar> | ||
) | ||
} | ||
|
||
return ( | ||
<Message | ||
style={{ width: '85%', padding: 0, backgroundColor: COLORS.TRANSPARENT }} | ||
blob={false} | ||
json={serialize(carouselProps)} | ||
type={INPUT.CAROUSEL} | ||
{...carouselProps} | ||
> | ||
{content} | ||
</Message> | ||
) | ||
} | ||
|
||
Carousel.serialize = serialize |
Oops, something went wrong.