Skip to content

Commit

Permalink
feat(Modal)!: introduce 2.0 component
Browse files Browse the repository at this point in the history
- add in style changes
- simplify interface and update with new semantics
- update test snapshots for chromatic
  • Loading branch information
booc0mtaco committed Mar 27, 2024
1 parent 8bce819 commit e63bd36
Show file tree
Hide file tree
Showing 8 changed files with 1,124 additions and 0 deletions.
22 changes: 22 additions & 0 deletions src/components/ButtonGroup/ButtonGroup-v2.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*------------------------------------*\
# BUTTON GROUP
\*------------------------------------*/

/**
* A group of buttons displayed in an organized fashion.
*/
.button-group {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;

gap: 0.5rem;
}

.button-group--horizontal {
flex-direction: row-reverse;
}

.button-group--vertical {
flex-direction: column-reverse;
}
54 changes: 54 additions & 0 deletions src/components/ButtonGroup/ButtonGroup-v2.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { StoryObj, Meta } from '@storybook/react';
import React from 'react';

import { ButtonGroup } from './ButtonGroup-v2';
import { ButtonV2 as Button } from '../Button';

export default {
title: 'Components/V2/ButtonGroup',
component: ButtonGroup,
args: {
orientation: 'horizontal',
children: (
<>
<Button rank="primary">Button 1</Button>
<Button rank="secondary">Button 2</Button>
</>
),
},
argTypes: {
children: {
control: {
type: null,
},
},
},
parameters: {
badges: ['intro-1.0', 'current-2.0'],
},
decorators: [(Story) => <div className="p-8">{Story()}</div>],
} as Meta<Args>;

type Args = React.ComponentProps<typeof ButtonGroup>;

export const Default: StoryObj<Args> = {};

export const Vertical: StoryObj<Args> = {
args: {
buttonLayout: 'vertical',
},
};

export const WithFiveButtons: StoryObj<Args> = {
args: {
children: (
<>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
<Button>Button 4</Button>
<Button rank="primary">Button 5</Button>
</>
),
},
};
42 changes: 42 additions & 0 deletions src/components/ButtonGroup/ButtonGroup-v2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import clsx from 'clsx';
import type { ReactNode } from 'react';
import React from 'react';
import styles from './ButtonGroup-v2.module.css';

type ButtonGroupProps = {
// Component API
/**
* The buttons. Should not be wrapped in another element – we just want the buttons.
*/
children: ReactNode;
/**
* Additional classnames passed in for styling.
*
* This will be applied to the container we're placing around the buttons.
*/
className?: string;
// Design API
/**
* Whether the buttons should be laid out horizontally or stacked vertically.
* 'vertical' does not work with 'max' spacing.
*/
buttonLayout?: 'horizontal' | 'vertical';
};

/**
* `import {ButtonGroup} from "@chanzuckerberg/eds";`
*
* A container for buttons grouped together horizontally or vertically.
*/
export function ButtonGroup({
children,
className,
buttonLayout = 'horizontal',
}: ButtonGroupProps) {
const componentClassName = clsx(
styles['button-group'],
buttonLayout && styles[`button-group--${buttonLayout}`],
className,
);
return <div className={componentClassName}>{children}</div>;
}
1 change: 1 addition & 0 deletions src/components/ButtonGroup/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { ButtonGroup as default } from './ButtonGroup';
export { ButtonGroup as ButtonGroupV2 } from './ButtonGroup-v2';
209 changes: 209 additions & 0 deletions src/components/Modal/Modal-v2.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
@import '../../design-tokens/mixins.css';

/*------------------------------------*\
# MODAL
\*------------------------------------*/

/**
* The modal wrapper and overlay which takes up the entire screen.
*/
.modal,
.modal__overlay {
position: fixed;
top: 0;
left: 0;
height: 100vh; /* TODO-AH: make sure this doesn't spill out of the container */
width: 100%;
}

/**
* The inverted background of the modal to provide contrast with the actual modal.
*/
.modal__overlay {
/* TODO-AH: opacity of color based on 50% */
background-color: var(--eds-theme-color-background-utility-overlay-low-emphasis);
opacity: 0.5;
}

/**
* The modal container which positions the modal in the center of the screen.
*/
.modal {
display: flex;
align-items: center;
justify-content: center;
padding: 1rem;

/**
* Ensures modal is above other components. This is not a design token for now since we need to align on
* z-indeces across the system
*/
z-index: 1050;
}

/**
* Modal transition animations.
*/
.modal__transition--enter {
transition: opacity var(--eds-anim-fade-long) var(--eds-anim-ease);
@media (prefers-reduced-motion) {
transition: none;
}
}

.modal__transition--enterFrom {
opacity: 0;
}

.modal__transition--enterTo {
opacity: 1;
}

.modal__transition--leave {
transition: opacity var(--eds-anim-fade-long) var(--eds-anim-ease);
@media (prefers-reduced-motion) {
transition: none;
}
}

.modal__transition--leaveFrom {
opacity: 1;
}

.modal__transition--leaveTo {
opacity: 0;
}

/**
* The content of the modal, which can wrap header, body, and footer.
*/
.modal__content {
position: relative;
height: 43.125rem;
max-height: 90vh;
overflow: hidden;

/**
* This transparent border is for Window High Contrast Mode, which removes all
* background colors but makes borders 100% opacity black. Without this, the
* modal would have no clear boundary.
*/
border: var(--eds-theme-form-border-width) transparent var(--eds-theme-color-background-utility-container);

display: flex;
flex-direction: column;

width: 22.5rem;

background-color: var(--eds-theme-color-background-utility-container);
}

/**
* The medium modal size used for the md modal.
* Also used for the lg modal size for when the screen size is smaller than 75rem.
*/
.modal__content--md {
@media all and (min-width: $eds-bp-md) {
width: 42rem;
}
}

/**
* The large modal size used for the lg/default modal.
*/
.modal__content--lg {
@media all and (min-width: $eds-bp-xl) {
width: 64rem;
--modal-horizontal-padding: 4rem;
}
}

/**
* Allows scrolling of the modal content except for sticky footer.
* This functionality is our intended scroll behavior but consuming teams can
* style the body content as they wish to handle overflow in various ways.
*/
.modal__content--scrollable {
overflow: auto;
}

/**
* The modal close button.
* TODO-AH: this should be a `Button`
*/
.modal__close-button {
border: 0;
background-color: transparent;

position: absolute;
top: 0;
right: 0;

width: 3rem;
height: 3rem;

cursor: pointer;

z-index: 1;

color: var(--eds-theme-color-text-utility-default-secondary);
}

/**
* The modal close icon that resides in the close button.
*/
.modal__close-icon {
position: absolute;
top: 0.5rem;
right: 0.5rem;
}

/*------------------------------------*\
# MODAL BODY
\*------------------------------------*/

/**
* The body of the modal
*/
.modal-body {
flex: 1;
padding: 0 2rem;
}

/*------------------------------------*\
# MODAL FOOTER
\*------------------------------------*/

/**
* Footer for the modal.
*/
.modal-footer {
width: 100%;
z-index: 1000;

padding: 1.5rem 2rem;

background-color: var(--eds-theme-color-background-utility-container);
}

.modal-footer--sticky {
position: sticky;
bottom: 0;
}

/*------------------------------------*\
# MODAL HEADER
\*------------------------------------*/

/**
* Header for the modal.
*/
.modal-header {
width: 100%;

padding: 1.5rem 2rem;
}

.modal-sub-title {
color: var(--eds-theme-color-text-utility-default-secondary);
}
Loading

0 comments on commit e63bd36

Please sign in to comment.