-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(theme/dropdown): create component, theme, and stories
- Loading branch information
1 parent
3c6a8bc
commit 55d41bf
Showing
7 changed files
with
376 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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", | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.