Skip to content

Commit

Permalink
feat(comp): Add wizard component (#377)
Browse files Browse the repository at this point in the history
  • Loading branch information
floreks authored Dec 20, 2022
1 parent 9fd4913 commit 7207b27
Show file tree
Hide file tree
Showing 18 changed files with 1,234 additions and 55 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@
"@react-stately/tabs": "3.2.3",
"@react-stately/toggle": "3.4.3",
"@react-types/shared": "3.16.0",
"@tanstack/react-table": "8.5.30",
"@tanstack/react-table": "8.7.0",
"@types/chroma-js": "2.1.4",
"chroma-js": "2.4.2",
"classnames": "2.3.2",
"grommet": "2.27.0",
"grommet": "2.28.0",
"grommet-icons": "4.8.0",
"highlight.js": "11.6.0",
"highlight.js": "11.7.0",
"honorable-recipe-mapper": "0.2.0",
"prop-types": "15.8.1",
"react-animate-height": "3.0.5",
Expand Down
7 changes: 5 additions & 2 deletions src/components/AppIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DivProps, Flex, Img } from 'honorable'
import PropTypes from 'prop-types'
import { Ref, forwardRef } from 'react'
import { ReactNode, Ref, forwardRef } from 'react'
import { CSSObject } from 'styled-components'
import last from 'lodash/last'

Expand All @@ -17,6 +17,7 @@ type AppIconProps = DivProps & {
hue?: 'default' | 'lighter' | 'lightest' | string
clickable?: boolean
url?: string
icon?: ReactNode
alt?: string
name?: string
initials?: string
Expand All @@ -35,6 +36,7 @@ const propTypes = {
hue: PropTypes.oneOf(['default', 'lighter', 'lightest']),
clickable: PropTypes.bool,
url: PropTypes.string,
IconComponent: PropTypes.elementType,
alt: PropTypes.string,
}

Expand Down Expand Up @@ -106,6 +108,7 @@ function AppIconRef({
hue,
clickable = false,
url,
icon = null,
alt,
name,
initials,
Expand Down Expand Up @@ -149,7 +152,7 @@ ref: Ref<any>) {
height={iconSize}
{...props}
/>
) : (
) : icon || (
<Flex
width="100%"
height="100%"
Expand Down
27 changes: 24 additions & 3 deletions src/components/RepositoryChip.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { ReactNode, Ref, forwardRef } from 'react'
import {
ReactNode,
Ref,
forwardRef,
useState,
} from 'react'
import {
Div,
Flex,
Expand All @@ -9,18 +14,21 @@ import {
import PropTypes from 'prop-types'

import CheckRoundedIcon from './icons/CheckRoundedIcon'
import PlusIcon from './icons/PlusIcon'

type TagProps = FlexProps & {
label: string
imageUrl?: string
checked?: boolean
disabled? : boolean
icon?: ReactNode
}

const propTypes = {
label: PropTypes.string.isRequired,
imageUrl: PropTypes.string,
checked: PropTypes.bool,
disabled: PropTypes.bool,
icon: PropTypes.node,
}

Expand All @@ -37,20 +45,27 @@ function RepositoryChipRef({
label,
imageUrl = '',
checked = false,
disabled = false,
icon = null,
...props
}: TagProps, ref: Ref<any>) {
const [hovered, setHovered] = useState(false)

return (
<Flex
ref={ref}
padding="xsmall"
align="center"
cursor="pointer"
cursor={disabled && !checked ? 'not-allowed' : 'pointer'}
opacity={disabled && !checked ? 0.5 : 1}
borderRadius="large"
border={`1px solid ${checked ? 'border-outline-focused' : 'border-fill-two'}`}
backgroundColor="fill-two"
_hover={{ backgroundColor: 'fill-two-hover' }}
_hover={disabled ? {} : { backgroundColor: 'fill-two-hover' }}
transition="background-color 200ms ease"
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
whiteSpace="nowrap"
{...props}
>
{icon ? (
Expand Down Expand Up @@ -80,6 +95,12 @@ function RepositoryChipRef({
visibility={checked ? 'visible' : 'hidden'}
marginLeft="medium"
/>
<PlusIcon
color="text-light"
display={hovered && !checked && !disabled ? 'visible' : 'none'}
marginLeft="medium"
height={16}
/>
</Flex>
)
}
Expand Down
100 changes: 74 additions & 26 deletions src/components/Stepper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
DivProps,
Flex,
FlexProps,
Img,
} from 'honorable'
import {
Fragment,
Expand All @@ -26,10 +27,33 @@ import type createIcon from './icons/createIcon'
import Tooltip from './Tooltip'
import WrapWithIf from './WrapWithIf'

type Hue = 'none' | 'default' | 'lighter' | 'lightest'

const hueToBorder: Record<Hue, string> = {
none: 'border-disabled',
default: 'border',
lighter: 'border-fill-two',
lightest: 'border-fill-three',
}

const hueToBG: Record<Hue, string> = {
none: 'fill-zero',
default: 'fill-one',
lighter: 'fill-two',
lightest: 'fill-three',
}

type StepBaseProps = {
stepTitle: ReactNode
IconComponent: ReturnType<typeof createIcon>
stepTitle?: ReactNode
IconComponent?: ReturnType<typeof createIcon>
imageUrl?: string
iconSize?: number
circleSize?: number
collapseTitle?: boolean
vertical?: boolean
hue?: Hue
compact?: boolean
canComplete?: boolean
}

type StepProps = DivProps &
Expand All @@ -44,6 +68,7 @@ type StepProps = DivProps &
type StepConnectionProps = DivProps & {
isActive: boolean
vertical?: boolean
compact?: boolean,
}

export type StepperSteps = (StepBaseProps & { key: string })[]
Expand All @@ -54,13 +79,14 @@ type StepperProps = FlexProps & {
vertical?: boolean
forceCollapse?: boolean
collapseAtWidth?: number
compact?: boolean
}

const propTypes = {
stepIndex: PropTypes.number.isRequired,
steps: PropTypes.arrayOf(PropTypes.shape({
stepTitle: PropTypes.node.isRequired,
IconComponent: PropTypes.elementType.isRequired,
stepTitle: PropTypes.node,
IconComponent: PropTypes.elementType,
iconSize: PropTypes.number,
}).isRequired).isRequired,
}
Expand All @@ -70,10 +96,14 @@ function Step({
isComplete = false,
stepTitle,
IconComponent,
imageUrl = '',
iconSize = 24,
circleSize = 48,
vertical = false,
collapseTitles = false,
hue = 'default',
compact = false,
canComplete = true,
...props
}: StepProps) {
const theme = useTheme()
Expand All @@ -93,15 +123,16 @@ function Step({

return (
<Flex
width="100%"
minWidth="68px"
width={compact ? 'auto' : '100%'}
minWidth={compact ? 'auto' : '68px'}
maxWidth={vertical ? '100%' : '100px'}
direction={vertical ? 'row' : 'column'}
align="center"
alignSelf="center"
{...props}
>
<WrapWithIf
condition={collapseTitles}
condition={collapseTitles && !!stepTitle}
wrapper={<Tooltip label={stepTitle} />}
>
<Div
Expand All @@ -110,10 +141,10 @@ function Step({
height={circleSize}
marginLeft={vertical ? 'none' : 'auto'}
marginRight={vertical ? 'none' : 'auto'}
borderRadius={1000}
backgroundColor={theme.colors['fill-one']}
borderRadius="100%"
backgroundColor={theme.colors[hueToBG[hue]]}
border={`1px solid ${
isActive ? theme.colors['border-selected'] : theme.colors.border
isActive ? theme.colors['border-selected'] : theme.colors[hueToBorder[hue]]
}`}
transition="all 0.2s ease"
transitionDelay="0.1"
Expand All @@ -125,26 +156,36 @@ function Step({
position="absolute"
justifyContent="center"
alignItems="center"
className={isComplete ? '' : shownClassName}
className={canComplete && isComplete ? '' : shownClassName}
{...completeIconStyles}
>
<IconComponent
size={iconSize}
color={isActive ? theme.colors['icon-default'] : theme.colors['icon-xlight']}
/>
{IconComponent && (
<IconComponent
size={iconSize}
color={isActive ? theme.colors['icon-default'] : theme.colors['icon-xlight']}
/>
)}
{imageUrl && (
<Img
src={imageUrl}
width={iconSize}
height={iconSize}
opacity={isActive ? 1 : 0.5}
/>
)}
</Flex>
<Flex
width="100%"
height="100%"
position="absolute"
justifyContent="center"
alignItems="center"
className={isComplete ? shownClassName : ''}
className={canComplete && isComplete ? shownClassName : ''}
{...completeIconStyles}
>
<StatusOkIcon
color={theme.colors['icon-success']}
size={24}
color={compact ? theme.colors['text-xlight'] : theme.colors['icon-success']}
size={iconSize}
/>
</Flex>
</Div>
Expand All @@ -170,18 +211,20 @@ function Step({
function StepConnection({
isActive = false,
vertical = false,
compact = false,
...props
}: StepConnectionProps) {
const theme = useTheme()

return (
<Div
width={vertical ? 1 : '100%'}
width={compact ? '16px' : vertical ? 1 : '100%'}
height={vertical ? 30 : 1}
flexGrow={1}
flexGrow={compact ? 0 : 1}
backgroundColor={theme.colors.border}
position="relative"
aria-hidden="true"
alignSelf={compact ? 'center' : 'none'}
{...props}
>
<Div
Expand All @@ -203,9 +246,9 @@ function StepperRef({
vertical = false,
collapseAtWidth = 160,
forceCollapse = false,
compact = false,
}: StepperProps,
ref: Ref<any>) {
const circleSize = 48
const eltRef = useRef<HTMLDivElement>()
const mergedRef = mergeRefs(ref, eltRef)
const [collapseTitles, setCollapseTitles] = useState(true)
Expand All @@ -226,7 +269,7 @@ ref: Ref<any>) {
return (
<Flex
ref={mergedRef}
width="100%"
width={compact ? 'auto' : '100%'}
direction={vertical ? 'column' : 'row'}
justifyContent="space-between"
overflow="hidden"
Expand All @@ -238,18 +281,23 @@ ref: Ref<any>) {
isComplete={stepIndex > index}
stepTitle={step.stepTitle}
IconComponent={step.IconComponent}
imageUrl={step.imageUrl}
iconSize={step.iconSize || 24}
circleSize={48}
vertical={vertical}
collapseTitles={vertical && collapseTitles}
circleSize={step.circleSize || 48}
vertical={step.vertical || vertical}
collapseTitles={vertical && collapseTitles || step.collapseTitle}
hue={step.hue}
compact={compact}
canComplete={step.canComplete}
/>
{index < steps.length - 1 && (
<StepConnection
isActive={stepIndex > index}
vertical={vertical}
marginTop={vertical ? 'small' : circleSize / 2}
marginTop={vertical ? 'small' : compact ? 0 : (step.circleSize || 48) / 2}
marginBottom={vertical ? 'small' : 'none'}
marginLeft={vertical ? 'large' : 'none'}
compact={compact}
/>
)}
</Fragment>
Expand Down
18 changes: 18 additions & 0 deletions src/components/icons/ReturnIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import createIcon from './createIcon'

export default createIcon(({ size, color }) => (
<svg
width={size}
height={size}
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M6.23528 0.785562C6.34503 0.900691 6.40457 1.05469 6.40082 1.2137C6.39707 1.37272 6.33034 1.52373 6.21528 1.63356L2.89848 4.79996H10.9009C12.0413 4.79996 13.135 5.253 13.9414 6.0594C14.7478 6.86581 15.2009 7.95953 15.2009 9.09996C15.2009 10.2404 14.7478 11.3341 13.9414 12.1405C13.135 12.9469 12.0413 13.4 10.9009 13.4H8.60088C8.44175 13.4 8.28914 13.3367 8.17662 13.2242C8.0641 13.1117 8.00088 12.9591 8.00088 12.8C8.00088 12.6408 8.0641 12.4882 8.17662 12.3757C8.28914 12.2632 8.44175 12.2 8.60088 12.2H10.9009C11.7231 12.2 12.5115 11.8734 13.0929 11.292C13.6743 10.7106 14.0009 9.92213 14.0009 9.09996C14.0009 8.27779 13.6743 7.48929 13.0929 6.90793C12.5115 6.32657 11.7231 5.99996 10.9009 5.99996H2.89848L6.21528 9.16556C6.33039 9.27547 6.39712 9.4266 6.40079 9.5857C6.40447 9.74481 6.34479 9.89886 6.23488 10.014C6.12498 10.1291 5.97385 10.1958 5.81474 10.1995C5.65564 10.2031 5.50159 10.1435 5.38648 10.0336L0.986482 5.83356C0.927792 5.77753 0.881075 5.71019 0.849157 5.63559C0.817238 5.56099 0.800781 5.4807 0.800781 5.39956C0.800781 5.31842 0.817238 5.23813 0.849157 5.16353C0.881075 5.08893 0.927792 5.02159 0.986482 4.96556L5.38648 0.765562C5.50161 0.655813 5.65561 0.59627 5.81462 0.600021C5.97364 0.603771 6.12465 0.670508 6.23448 0.785562H6.23528Z"
fill={color}
/>
</svg>
))
Loading

0 comments on commit 7207b27

Please sign in to comment.