Skip to content

Commit

Permalink
add reactive search bar, deployment action
Browse files Browse the repository at this point in the history
  • Loading branch information
hpratt committed Aug 27, 2022
1 parent 32aab6f commit ac5b541
Show file tree
Hide file tree
Showing 15 changed files with 211 additions and 38 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages

name: Node.js Package

on:
release:
types: [created]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- run: yarn

publish-npm:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
registry-url: https://registry.npmjs.org/
- run: yarn
- run: yarn publish --non-interactive
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.4.1",
"version": "0.5.1",
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
Expand Down
4 changes: 2 additions & 2 deletions src/components/AppBar/AppBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const StyledAppBar = styled(MUIAppBar)<AppBarProps>(() => ({
color: "#000000"
}));

const PortalsMenuItem: React.FC<{ children?: React.ReactNode, onClick?: () => void }> = ({ children, onClick }) => (
export const PortalsMenuItem: React.FC<{ children?: React.ReactNode, onClick?: () => void }> = ({ children, onClick }) => (
<MenuItem
onClick={onClick}
height="48px"
Expand All @@ -51,7 +51,7 @@ const PortalsMenu: React.FC<{ onPortalClicked?: (index: number) => void }> = ({
</>
);

export const AppBar: React.FC<AppBarProps> = props => (
const AppBar: React.FC<AppBarProps> = props => (
<Box sx={{ flexGrow: 1 }}>
<StyledAppBar position="static">
<Toolbar style={{ marginLeft: "60px" }}>
Expand Down
2 changes: 1 addition & 1 deletion src/components/AppBar/DropDownMenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const DropDownMenuItem: React.FC<MenuItemProps> = props => {
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom-start' ? 'left top' : 'left bottom' }}
>
<DropDownMenu style={{ width: "150px", height: "208px" }}>
<DropDownMenu style={{ width: "150px" }}>
<ClickAwayListener onClickAway={() => setOpen(false)}>
<MenuList style={{ textAlign: "center" }}>
{props.menu}
Expand Down
50 changes: 50 additions & 0 deletions src/components/AppBar/OptionsMenuItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* OptionsMenuItem.tsx: a PsychSCREEN app bar menu item with a hamburger icon and a pop-out sub menu for options.
*/

import React, { useState } from 'react';
import { ClickAwayListener, Grow, MenuList, Popper } from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';

import { DropDownMenu } from '../DropDownMenu';
import { MenuItemProps } from './DropDownMenuItem';

const OptionsMenuItem: React.FC<MenuItemProps> = props => {
const anchorRef = React.useRef<HTMLDivElement>(null);
const [ open, setOpen ] = useState(false);
return (
<>
<div ref={anchorRef}>
<MenuIcon
style={{ marginRight: props.flexGrow ? "0px" : props.marginRight, marginTop: "-3px", cursor: "pointer" }}
onClick={() => setOpen(true)}
/>
</div>
{ anchorRef.current && (
<Popper
anchorEl={anchorRef.current}
open={open}
placement="bottom-start"
transition
disablePortal
>
{ ({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom-start' ? 'left top' : 'left bottom' }}
>
<DropDownMenu style={{ width: "150px" }}>
<ClickAwayListener onClickAway={() => setOpen(false)}>
<MenuList style={{ textAlign: "center" }}>
{props.menu}
</MenuList>
</ClickAwayListener>
</DropDownMenu>
</Grow>
)}
</Popper>
)}
</>
);
}
export default OptionsMenuItem;
41 changes: 41 additions & 0 deletions src/components/AppBar/TabletAppBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* TabletAppBar.tsx: PsychSCREEN app bar for tablets and mobile devices.
*/

import React from 'react';
import { AppBarProps, StyledAppBar, PortalsMenuItem as OptionsMenuItem } from './AppBar';
import { Box, Toolbar } from '@mui/material';

import MenuItem from './MenuItem';
import OptionsMenu from './OptionsMenuItem';

export type TabletAppBarProps = AppBarProps & { title?: string };

const PortalsMenu: React.FC<{ onItemClicked?: (index: number) => void }> = ({ onItemClicked }) => (
<>
<OptionsMenuItem onClick={() => onItemClicked && onItemClicked(-1)}>About</OptionsMenuItem>
<OptionsMenuItem onClick={() => onItemClicked && onItemClicked(0)}>Disease/Trait Portal</OptionsMenuItem>
<OptionsMenuItem onClick={() => onItemClicked && onItemClicked(1)}>Gene/bCRE Portal</OptionsMenuItem>
<OptionsMenuItem onClick={() => onItemClicked && onItemClicked(2)}>SNP/QTL Portal</OptionsMenuItem>
<OptionsMenuItem onClick={() => onItemClicked && onItemClicked(3)}>Single-Cell Portal</OptionsMenuItem>
</>
);

const TabletAppBar: React.FC<TabletAppBarProps> = props => (
<Box sx={{ flexGrow: 1 }}>
<StyledAppBar position="static" elevation={0}>
<Toolbar style={{ paddingLeft: "19px" }}>
<OptionsMenu
marginRight="32px"
menu={<PortalsMenu onItemClicked={props.onPortalClicked} />}
>
Portals
</OptionsMenu>
<MenuItem flexGrow={1} textAlign="center" fontSize="22px" lineHeight="28px" fontWeight={400}>
{ props.title || "" }
</MenuItem>
</Toolbar>
</StyledAppBar>
</Box>
);
export default TabletAppBar;
3 changes: 2 additions & 1 deletion src/components/AppBar/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
import AppBar, { AppBarProps } from './AppBar';
export { AppBar, AppBarProps };
import TabletAppBar, { TabletAppBarProps } from './TabletAppBar';
export { AppBar, AppBarProps, TabletAppBar, TabletAppBarProps };
11 changes: 10 additions & 1 deletion src/components/SearchBox/SearchBoxWithSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MenuItem } from '@mui/material';
import React, { useState } from 'react';
import React, { useMemo, useState } from 'react';
import { Select } from '../Select';
import SearchBox, { SearchBoxProps } from './SearchBox';

Expand All @@ -13,10 +13,16 @@ export type SearchBoxWithSelectProps = SearchBoxProps & {
selectOptions: SearchBoxWithSelectOption[];
onSelectChange?: (option: SearchBoxWithSelectOption) => void;
onSearchChange?: (value: string) => void;
reactiveThreshold?: number;
reactiveWidth?: number;
containerWidth?: number;
};

const SearchBoxWithSelect: React.FC<SearchBoxWithSelectProps> = props => {
const [ option, setOption ] = useState(props.selectOptions[0]);
const belowThreshold = useMemo( () => (
props.reactiveThreshold && (props.containerWidth || 0) < props.reactiveThreshold
), [ props.reactiveThreshold, props.containerWidth ]);
return (
<>
<Select
Expand All @@ -25,6 +31,7 @@ const SearchBoxWithSelect: React.FC<SearchBoxWithSelectProps> = props => {
props.onSelectChange && props.onSelectChange(props.selectOptions[e.target.value as number]);
}}
defaultValue={0}
width={belowThreshold ? props.reactiveWidth : undefined}
>
{ props.selectOptions.map((option, i) => (
<MenuItem
Expand All @@ -35,9 +42,11 @@ const SearchBoxWithSelect: React.FC<SearchBoxWithSelectProps> = props => {
</MenuItem>
))}
</Select>
{ belowThreshold ? <br /> : null }
<SearchBox
onChange={e => props.onSearchChange && props.onSearchChange(e.target.value)}
helperText={option.helperText}
width={belowThreshold ? props.reactiveWidth : undefined}
{...props}
/>
</>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Typography/Typography.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import styled from '@emotion/styled';
import { Typography as MUITypography, TypographyProps as MUITypographyProps } from '@mui/material';
import { PSYCHSCREEN_DEFAULT_FONT_FAMILY } from '../../constants/theme';

type TypographyType = 'body' | 'title' | 'headline' | 'display' | 'label';
export type TypographyType = 'body' | 'title' | 'headline' | 'display' | 'label';
type TypographySize = 'large' | 'medium' | 'small';
type TypographyPropertyDictionary = Map<TypographyType, Map<TypographySize, string>>;

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { AppBar, AppBarProps } from './components/AppBar';
export { AppBar, AppBarProps, TabletAppBar, TabletAppBarProps } from './components/AppBar';
export { Button, ButtonProps } from './components/Button';
export { Typography, TypographyProps } from './components/Typography';
export { SearchBox, SearchBoxProps, SearchBoxWithSelect, SearchBoxWithSelectProps } from './components/SearchBox';
Expand Down
10 changes: 8 additions & 2 deletions stories/AppBar.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Meta, Story } from '@storybook/react';
import { AppBar, AppBarProps, PSYCHSCREEN_DEFAULT_THEME } from '../src';
import { AppBar, TabletAppBar, TabletAppBarProps, PSYCHSCREEN_DEFAULT_THEME } from '../src';
import "../src/App.css";
import { ThemeProvider } from '@emotion/react';

Expand All @@ -21,7 +21,11 @@ const meta: Meta = {

export default meta;

const Template: Story<AppBarProps> = args => (
const Template: Story<TabletAppBarProps & { tablet?: boolean }> = args => args.tablet ? (
<ThemeProvider theme={PSYCHSCREEN_DEFAULT_THEME}>
<TabletAppBar {...args} />
</ThemeProvider>
) : (
<ThemeProvider theme={PSYCHSCREEN_DEFAULT_THEME}>
<AppBar {...args} />
</ThemeProvider>
Expand All @@ -30,5 +34,7 @@ const Template: Story<AppBarProps> = args => (
// By passing using the Args format for exported stories, you can control the props for a component for reuse in a test
// https://storybook.js.org/docs/react/workflows/unit-testing
export const Default = Template.bind({});
export const Tablet = Template.bind({});

Default.args = {};
Tablet.args = { tablet: true, title: "Tablet App Bar" };
12 changes: 2 additions & 10 deletions stories/DropDownMenu.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,6 @@ const Template: Story<DropDownMenuProps> = args => (

// By passing using the Args format for exported stories, you can control the props for a component for reuse in a test
// https://storybook.js.org/docs/react/workflows/unit-testing
export const Body = Template.bind({});
export const Title = Template.bind({});
export const Display = Template.bind({});
export const Label = Template.bind({});
export const Headline = Template.bind({});
export const Default = Template.bind({});

Body.args = { type: 'body' };
Headline.args = { type: 'headline' };
Display.args = { type: 'display' };
Label.args = { type: 'label' };
Title.args = { type: 'title' };
Default.args = {};
63 changes: 52 additions & 11 deletions stories/SearchBox.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import { Meta, Story } from '@storybook/react';
import { SearchBox, SearchBoxProps } from '../src';
import "../src/App.css";
import { SearchBoxWithSelect } from '../src/components/SearchBox';
import { Grid } from '@mui/material';

function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height
};
}

function useViewportSize() {
const [ windowDimensions, setWindowDimensions ] = useState(getWindowDimensions());
useEffect(() => {
const handleResize = () => { setWindowDimensions(getWindowDimensions()); };
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowDimensions;
}

const meta: Meta = {
title: 'SearchBox',
Expand All @@ -27,16 +46,38 @@ const SELECT_OPTIONS = [
{ name: "SNP/QTL", value: "SNP", helperText: "e.g. rs2836883, rs7690700" }
]

const Template: Story<SearchBoxProps & { withSelect?: boolean }> = args => args.withSelect ? (
<SearchBoxWithSelect
selectOptions={SELECT_OPTIONS}
label="What can we help you find?"
variant="standard"
{...args}
/>
) : (
<SearchBox label="What can we help you find?" variant="standard" {...args} />
);
const Template: Story<SearchBoxProps & { withSelect?: boolean }> = args => {
const { width } = useViewportSize();
return args.withSelect ? (
<>
<Grid container>
<Grid item sm={6}>
<strong>Non-Reactive</strong><br />
<SearchBoxWithSelect
selectOptions={SELECT_OPTIONS}
label="What can we help you find?"
variant="standard"
{...args}
/>
</Grid>
<Grid item sm={6}>
<strong>Reactive (at width &lt;200px; current width is {width / 2})</strong><br />
<SearchBoxWithSelect
selectOptions={SELECT_OPTIONS}
label="What can we help you find?"
variant="standard"
reactiveThreshold={400}
reactiveWidth={305}
containerWidth={width / 2}
{...args}
/>
</Grid>
</Grid>
</>
) : (
<SearchBox label="What can we help you find?" variant="standard" {...args} />
);
};

// By passing using the Args format for exported stories, you can control the props for a component for reuse in a test
// https://storybook.js.org/docs/react/workflows/unit-testing
Expand Down
5 changes: 3 additions & 2 deletions stories/Typography.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import React from 'react';
import { Meta, Story } from '@storybook/react';
import { ThemeProvider } from '@emotion/react';

import { Typography, TypographyProps, PSYCHSCREEN_DEFAULT_THEME } from '../src';
import { Typography, PSYCHSCREEN_DEFAULT_THEME } from '../src';
import "../src/App.css";
import { TypographyType } from '../src/components/Typography/Typography';

const meta: Meta = {
title: 'Typography',
Expand All @@ -22,7 +23,7 @@ const meta: Meta = {

export default meta;

const Template: Story<TypographyProps> = args => (
const Template: Story<{ type: TypographyType }> = args => (
<ThemeProvider theme={PSYCHSCREEN_DEFAULT_THEME}>
<h3 style={{ fontFamily: "Roboto" }}>
Typography for <strong>{args.type}</strong> elements:
Expand Down
Loading

0 comments on commit ac5b541

Please sign in to comment.