fannypack-v5
Version:
An accessible, composable, and friendly React UI Kit
287 lines (246 loc) • 7.32 kB
text/typescript
import { css, cssClass } from '../styled';
import { space, theme } from '../utils';
export const Modal = (styleProps) => cssClass`
position: fixed;
z-index: 19900410;
min-width: 320px;
@media screen and (max-width: 320px) {
min-width: unset;
width: 100%;
}
${getPlacementAttributes(styleProps)}
&:focus {
outline: none;
}
& {
${theme(styleProps.themeKey, `css.root`)(styleProps)};
}
`;
export const ModalContainer = (styleProps) => cssClass`
& {
${theme(styleProps.themeKey, `css.root`)(styleProps)};
}
`;
export const ModalDisclosure = (styleProps) => cssClass`
& {
${theme(styleProps.themeKey, `css.root`)(styleProps)};
}
`;
export const ModalBackdrop = (styleProps) => cssClass`
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 19900409;
${getAnimatedAttributes({})(styleProps)};
& {
${theme(styleProps.themeKey, `css.root`)(styleProps)};
}
`;
export const getPlacementAttributes = (styleProps) => {
const placementAttributes: { [key: string]: any } = {
// @ts-ignore
center: css`
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0px);
${getAnimatedAttributes({
transformX: '-50%',
transformY: '-50%',
defaultSlide: 'top',
})(styleProps)};
& {
${theme(styleProps.themeKey, `css.placements.center`)(styleProps)};
}
`,
// @ts-ignore
top: css`
top: ${space(5)(styleProps)}em;
left: 50%;
transform: translate3d(-50%, 0, 0px);
${getAnimatedAttributes({
transformX: '-50%',
transformY: '0px',
defaultSlide: 'top',
})(styleProps)};
& {
${theme(styleProps.themeKey, `css.placements.top`)(styleProps)};
}
`,
// @ts-ignore
bottom: css`
bottom: ${space(5)(styleProps)}em;
left: 50%;
transform: translate3d(-50%, 0, 0px);
${getAnimatedAttributes({
transformX: '-50%',
transformY: '0px',
defaultSlide: 'bottom',
})(styleProps)};
& {
${theme(styleProps.themeKey, `css.placements.bottom`)(styleProps)};
}
`,
// @ts-ignore
left: css`
top: 50%;
left: ${space(5)(styleProps)}em;
transform: translate3d(0px, -50%, 0px);
${getAnimatedAttributes({
transformX: '0px',
transformY: '-50%',
defaultSlide: 'left',
})(styleProps)};
& {
${theme(styleProps.themeKey, `css.placements.left`)(styleProps)};
}
`,
// @ts-ignore
right: css`
top: 50%;
right: ${space(5)(styleProps)}em;
transform: translate3d(0px, -50%, 0px);
${getAnimatedAttributes({
transformX: '0px',
transformY: '-50%',
defaultSlide: 'right',
})(styleProps)};
& {
${theme(styleProps.themeKey, `css.placements.right`)(styleProps)};
}
`,
// @ts-ignore
'top-start': css`
top: ${space(5)(styleProps)}em;
left: ${space(5)(styleProps)}em;
transform: translate3d(0, 0, 0px);
${getAnimatedAttributes({
transformX: '0px',
transformY: '0px',
defaultSlide: 'left',
})(styleProps)};
& {
${theme(styleProps.themeKey, `css.placements.topStart`)(styleProps)};
}
`,
// @ts-ignore
'top-end': css`
top: ${space(5)(styleProps)}em;
right: ${space(5)(styleProps)}em;
transform: translate3d(0, 0, 0px);
${getAnimatedAttributes({
transformX: '0px',
transformY: '0px',
defaultSlide: 'right',
})(styleProps)};
& {
${theme(styleProps.themeKey, `css.placements.topEnd`)(styleProps)};
}
`,
// @ts-ignore
'bottom-end': css`
bottom: ${space(5)(styleProps)}em;
right: ${space(5)(styleProps)}em;
transform: translate3d(0, 0, 0px);
${getAnimatedAttributes({
transformX: '0px',
transformY: '0px',
defaultSlide: 'bottom',
})(styleProps)};
& {
${theme(styleProps.themeKey, `css.placements.bottomEnd`)(styleProps)};
}
`,
// @ts-ignore
'bottom-start': css`
bottom: ${space(5)(styleProps)}em;
left: ${space(5)(styleProps)}em;
transform: translate3d(0, 0, 0px);
${getAnimatedAttributes({
transformX: '0px',
transformY: '0px',
defaultSlide: 'bottom',
})(styleProps)};
& {
${theme(styleProps.themeKey, `css.placements.bottomStart`)(styleProps)};
}
`,
};
return css`
${placementAttributes[styleProps.placement || 'center']};
`;
};
const getSlideOffset = ({ position, axis, defaultSlide = undefined, slideOffset = '100%' }) => (styleProps) => {
let newSlide = typeof styleProps.slide === 'string' ? styleProps.slide : defaultSlide;
let offset = '';
if (axis === 'vertical') {
if (newSlide === 'top') {
offset = ` - ${slideOffset}`;
}
if (newSlide === 'bottom') {
offset = ` + ${slideOffset}`;
}
}
if (axis === 'horizontal') {
if (newSlide === 'left') {
offset = ` - ${slideOffset}`;
}
if (newSlide === 'right') {
offset = ` + ${slideOffset}`;
}
}
return `calc(${position}${offset})`;
};
export const getAnimatedAttributes = (opts) => (styleProps) => {
if (!styleProps.slide && !styleProps.expand && !styleProps.fade) return;
const transitionPropertyValue = [(styleProps.slide || styleProps.expand) && 'transform', styleProps.fade && 'opacity']
.filter(Boolean)
.join(', ');
const hiddenTransformX = getSlideOffset({
position: opts.transformX,
axis: 'horizontal',
defaultSlide: opts.defaultSlide,
slideOffset: opts.slideOffset,
})(styleProps);
const hiddenTransformY = getSlideOffset({
position: opts.transformY,
axis: 'vertical',
defaultSlide: opts.defaultSlide,
slideOffset: opts.slideOffset,
})(styleProps);
const hiddenSlideTransformValue = `translate3d(${styleProps.slide ? hiddenTransformX : opts.transformX}, ${
styleProps.slide ? hiddenTransformY : opts.transformY
}, 0px)`;
const hiddenExpandTransformValue = styleProps.expand ? `scale(0.01)` : undefined;
const hiddenTransformValue = [hiddenSlideTransformValue, hiddenExpandTransformValue].filter(Boolean).join(' ');
const showTransformValue = `translate3d(${opts.transformX}, ${opts.transformY}, 0px) scale(1)`;
const expandTransformOrigins = {
center: '50% 50%',
left: '0% 50%',
right: '100% 50%',
top: '50% 0%',
bottom: '50% 100%',
};
return css`
transform-origin: ${expandTransformOrigins[opts.defaultExpand || styleProps.expand || 'center']};
align-items: center;
transition-property: ${transitionPropertyValue};
transition-duration: ${styleProps.duration || '250ms'};
transition-timing-function: ${styleProps.timingFunction || 'ease-in-out'};
transition-delay: ${styleProps.delay || '0s'};
transform: ${opts.prevTransformValue} ${hiddenTransformValue} ;
${styleProps.fade &&
css`
opacity: 0;
`};
&[data-enter] {
transform: ${opts.prevTransformValue} ${showTransformValue} ;
${styleProps.fade &&
css`
opacity: 1;
`};
}
`;
};