Skip to content

Commit

Permalink
feat(theme/dropdown): create component, theme, and stories
Browse files Browse the repository at this point in the history
  • Loading branch information
TylerAPfledderer committed Mar 31, 2023
1 parent 3c6a8bc commit 55d41bf
Show file tree
Hide file tree
Showing 7 changed files with 376 additions and 2 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
"@formatjs/intl-numberformat": "^6.1.4",
"@mdx-js/mdx": "^1.6.5",
"@mdx-js/react": "^1.6.5",
"@zag-js/react": "^0.3.12",
"@zag-js/select": "^0.2.1",
"algoliasearch": "^4.3.0",
"axios": "^0.21.2",
"browser-lang": "^0.1.0",
Expand Down
118 changes: 118 additions & 0 deletions src/@chakra-ui/gatsby-plugin/components/Dropdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import {
createMultiStyleConfigHelpers,
cssVar,
defineStyle,
} from "@chakra-ui/react"

const { defineMultiStyleConfig, definePartsStyle } =
createMultiStyleConfigHelpers(["trigger", "triggerIcon", "content", "option"])

const $borderBaseWidth = cssVar("border-base-width")

const baseStyleTrigger = defineStyle({
[$borderBaseWidth.variable]: "1px",
borderColor: "currentColor",
borderStyle: "solid",
display: "inline-flex",
alignItems: "center",
justifyContent: "space-between",
gap: 4,
p: 2,
width: "full",
_active: {
bg: "primaryLowContrast",
boxShadow: "none",
},
_hover: {
boxShadow: "buttonHover",
color: "primary",
},
_focusVisible: {
outline: "3px solid",
outlineColor: "primaryHover",
},
_expanded: {
bg: "backgroundHighlight",
color: "primary",
boxShadow: "buttonHover",
outline: "none",
},
})

const baseStyleTriggerIcon = defineStyle({
"[data-expanded] > &": {
transform: "rotate(180deg)",
},
})

const baseStyleContent = defineStyle({
listStyle: "none",
bg: "backgroundHighlight",
width: "var(--reference-width)",
boxShadow: "buttonHover",
borderRadius: "base",
borderTopRadius: "none",
color: "primary",
m: 0,
})

const baseStyleOption = defineStyle({
p: 2,
m: 0,
cursor: "pointer",
"&[aria-selected='true'], &:hover": {
bg: "primaryHover",
color: "primaryLowContrast",
},
"&[data-focus]": {
outline: "3px solid",
outlineColor: "primaryHover",
outlineOffset: -3,
},
})

const baseStyle = definePartsStyle({
trigger: baseStyleTrigger,
triggerIcon: baseStyleTriggerIcon,
content: baseStyleContent,
option: baseStyleOption,
})

const variantOutline = definePartsStyle({
trigger: {
borderRadius: "base",
borderWidth: $borderBaseWidth.reference,
_expanded: {
borderBottomColor: "transparent",
borderBottomRadius: 0,
},
},
content: {
border: "1px",
borderColor: "currentColor",
borderTop: "0",
},
})
const variantFlushed = definePartsStyle({
trigger: {
borderTopRadius: "base",
borderBottomWidth: $borderBaseWidth.reference,
},
content: {
borderTop: "1px",
borderColor: "currentColor",
},
})

const variants = {
outline: variantOutline,
flushed: variantFlushed,
}

export const Dropdown = defineMultiStyleConfig({
baseStyle,
variants,
defaultProps: {
variant: "outline",
},
})
2 changes: 2 additions & 0 deletions src/@chakra-ui/gatsby-plugin/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Tabs } from "./Tabs"
import { Radio } from "./Radio"
import { Switch } from "./Switch"
import { Input } from "./Input"
import { Dropdown } from "./Dropdown"
import {
accordionDefaultTheme,
avatarDefaultTheme,
Expand Down Expand Up @@ -36,6 +37,7 @@ export default {
Code: codeDefaultTheme,
Divider: dividerDefaultTheme,
Drawer: drawerDefaultTheme,
Dropdown,
Form: formDefaultTheme,
FormLabel: formLabelDefaultTheme,
Heading: headingDefaultTheme,
Expand Down
6 changes: 6 additions & 0 deletions src/@chakra-ui/gatsby-plugin/semanticTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ const semanticTokens = {
"linear-gradient(102.7deg, rgba(185, 185, 241, 0.2) 0%, rgba(84, 132, 234, 0.2) 51.56%, rgba(58, 142, 137, 0.2) 100%)",
},
},
shadows: {
buttonHover: {
_light: "4px 4px 0 var(--eth-colors-blue-100)",
_dark: "4px 4px 0 #352313",
},
},
}

export default semanticTokens
24 changes: 24 additions & 0 deletions src/components/Dropdown/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from "react"
import { VStack } from "@chakra-ui/react"
import { Meta, StoryObj } from "@storybook/react"
import DropdownComponent from "."

type DropdownType = typeof DropdownComponent

const meta: Meta<DropdownType> = {
title: "Atoms / Form / Dropdown",
component: DropdownComponent,
}

export default meta

type Story = StoryObj<DropdownType>

export const Dropdown: Story = {
render: () => (
<VStack spacing={4}>
<DropdownComponent />
<DropdownComponent variant="flushed" />
</VStack>
),
}
70 changes: 70 additions & 0 deletions src/components/Dropdown/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import * as React from "react"
import { useMachine, normalizeProps } from "@zag-js/react"
import { machine, connect } from "@zag-js/select"
import {
chakra,
Portal,
SystemStyleObject,
useMultiStyleConfig,
ThemingProps,
} from "@chakra-ui/react"
import { FaChevronDown } from "react-icons/fa"

const selectData = [
{ label: "Ethereum", value: "eth" },
{ label: "Bitcoin", value: "bit" },
{ label: "Dogecoin", value: "doge" },
]

interface DropdownProps extends ThemingProps<"Dropdown"> {}

const Dropdown = (props: DropdownProps) => {
const { variant } = props

const [state, send] = useMachine(
machine({
id: React.useId(),
positioning: {
gutter: -1,
sameWidth: true,
},
})
)

const api = connect(state, send, normalizeProps)

const styles = useMultiStyleConfig("Dropdown", { variant }) as Record<
"trigger" | "triggerIcon" | "content" | "option",
SystemStyleObject
>

const triggerRef = React.useRef<HTMLButtonElement>(null)

return (
<>
<chakra.button ref={triggerRef} {...api.triggerProps} sx={styles.trigger}>
<span>{api.selectedOption?.label ?? "Select Crypto"}</span>
<chakra.div sx={styles.triggerIcon}>
<FaChevronDown />
</chakra.div>
</chakra.button>
<Portal>
<div {...api.positionerProps}>
<chakra.ul {...api.contentProps} sx={styles.content}>
{selectData.map(({ label, value }) => (
<chakra.li
key={value}
{...api.getOptionProps({ label, value })}
sx={styles.option}
>
<span>{label}</span>
</chakra.li>
))}
</chakra.ul>
</div>
</Portal>
</>
)
}

export default Dropdown
Loading

0 comments on commit 55d41bf

Please sign in to comment.