Skip to content

Commit

Permalink
fix: hover states on filters and chip groups (#9511)
Browse files Browse the repository at this point in the history
* fix: hover states on filters and chip groups

* fix: create FilterChip component
  • Loading branch information
srindom authored Oct 9, 2024
1 parent 7ec1743 commit 0e11e89
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 332 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const Chip = ({ index, className, children }: ChipProps) => {
return (
<li
className={clx(
"bg-ui-bg-component shadow-borders-base flex items-center divide-x overflow-hidden rounded-md",
"bg-ui-bg-component shadow-borders-base flex items-stretch divide-x overflow-hidden rounded-md",
{
"bg-ui-bg-component": variant === "component",
"bg-ui-bg-base-": variant === "base",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { EllipseMiniSolid, XMarkMini } from "@medusajs/icons"
import { EllipseMiniSolid } from "@medusajs/icons"
import { DatePicker, Text, clx } from "@medusajs/ui"
import * as Popover from "@radix-ui/react-popover"
import isEqual from "lodash/isEqual"
import { MouseEvent, useMemo, useState } from "react"
import { useMemo, useState } from "react"

import { t } from "i18next"
import { useTranslation } from "react-i18next"
import { useDate } from "../../../../hooks/use-date"
import { useSelectedParams } from "../hooks"
import { useDataTableFilterContext } from "./context"
import { IFilter } from "./types"
import FilterChip from "./filter-chip"

type DateFilterProps = IFilter

Expand Down Expand Up @@ -96,6 +97,8 @@ export const DateFilter = ({

const displayValue = getDisplayValueFromPresets() || getCustomDisplayValue()

const [previousValue, setPreviousValue] = useState<string | undefined>(displayValue)

const handleRemove = () => {
selectedParams.delete()
removeFilter(key)
Expand All @@ -105,6 +108,7 @@ export const DateFilter = ({

const handleOpenChange = (open: boolean) => {
setOpen(open)
setPreviousValue(displayValue)

if (timeoutId) {
clearTimeout(timeoutId)
Expand All @@ -119,7 +123,8 @@ export const DateFilter = ({

return (
<Popover.Root modal open={open} onOpenChange={handleOpenChange}>
<DateDisplay
<FilterChip
hadPreviousValue={!!previousValue}
label={label}
value={displayValue}
onRemove={handleRemove}
Expand Down Expand Up @@ -236,73 +241,6 @@ export const DateFilter = ({
)
}

type DateDisplayProps = {
label: string
value?: string
readonly?: boolean
onRemove: () => void
}

const DateDisplay = ({
label,
value,
readonly,
onRemove,
}: DateDisplayProps) => {
const handleRemove = (e: MouseEvent<HTMLButtonElement>) => {
e.stopPropagation()
onRemove()
}

return (
<Popover.Trigger
asChild
className={clx(
"bg-ui-bg-field transition-fg shadow-borders-base text-ui-fg-subtle flex cursor-pointer select-none items-center rounded-md",
{
"hover:bg-ui-bg-field-hover": !readonly,
"data-[state=open]:bg-ui-bg-field-hover": !readonly,
}
)}
>
<div>
<div
className={clx("flex items-center justify-center px-2 py-1", {
"border-r": !!value,
})}
>
<Text size="small" weight="plus" leading="compact">
{label}
</Text>
</div>
{value && (
<div className="flex items-center">
<div key={value} className="border-r p-1 px-2">
<Text size="small" weight="plus" leading="compact">
{value}
</Text>
</div>
</div>
)}
{!readonly && value && (
<div>
<button
onClick={handleRemove}
className={clx(
"text-ui-fg-muted transition-fg flex items-center justify-center p-1",
"hover:bg-ui-bg-subtle-hover",
"active:bg-ui-bg-subtle-pressed active:text-ui-fg-base"
)}
>
<XMarkMini />
</button>
</div>
)}
</div>
</Popover.Trigger>
)
}

const today = new Date()
today.setHours(0, 0, 0, 0)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { XMarkMini } from "@medusajs/icons"
import { Text, clx } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { MouseEvent } from "react"
import * as Popover from "@radix-ui/react-popover"

export type FilterChipProps = {
hadPreviousValue?: boolean
label: string
value?: string
readonly?: boolean
hasOperator?: boolean
onRemove: () => void
}

const FilterChip = ({
hadPreviousValue,
label,
value,
readonly,
hasOperator,
onRemove,
}: FilterChipProps) => {
const { t } = useTranslation()

const handleRemove = (e: MouseEvent<HTMLButtonElement>) => {
e.stopPropagation()
onRemove()
}

return (
<div
className="bg-ui-bg-field transition-fg shadow-borders-base text-ui-fg-subtle flex cursor-default select-none items-stretch overflow-hidden rounded-md"
>
{!hadPreviousValue && (
<Popover.Anchor />
)}
<div
className={clx(
"flex items-center justify-center whitespace-nowrap px-2 py-1",
{
"border-r": !!(value || hadPreviousValue),
}
)}
>
<Text size="small" weight="plus" leading="compact">
{label}
</Text>
</div>
<div className="flex w-full items-center overflow-hidden">
{hasOperator && !!(value || hadPreviousValue) && (
<div className="border-r p-1 px-2">
<Text
size="small"
weight="plus"
leading="compact"
className="text-ui-fg-muted"
>
{t("general.is")}
</Text>
</div>
)}
{!!(value || hadPreviousValue) && (
<Popover.Trigger asChild className={clx("flex-1 cursor-pointer overflow-hidden border-r p-1 px-2",
{
"hover:bg-ui-bg-field-hover": !readonly,
"data-[state=open]:bg-ui-bg-field-hover": !readonly,
}
)}>
<Text
size="small"
leading="compact"
weight="plus"
className="truncate text-nowrap"
>
{value || "\u00A0"}
</Text>
</Popover.Trigger>
)}
</div>
{!readonly && !!(value || hadPreviousValue) && (
<button
onClick={handleRemove}
className={clx(
"text-ui-fg-muted transition-fg flex items-center justify-center p-1",
"hover:bg-ui-bg-subtle-hover",
"active:bg-ui-bg-subtle-pressed active:text-ui-fg-base"
)}
>
<XMarkMini />
</button>
)}
</div>
)
}

export default FilterChip
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { EllipseMiniSolid, XMarkMini } from "@medusajs/icons"
import { Input, Label, Text, clx } from "@medusajs/ui"
import { EllipseMiniSolid } from "@medusajs/icons"
import { Input, Label, clx } from "@medusajs/ui"
import * as Popover from "@radix-ui/react-popover"
import * as RadioGroup from "@radix-ui/react-radio-group"
import { debounce } from "lodash"
import {
ChangeEvent,
MouseEvent,
useCallback,
useEffect,
useState,
Expand All @@ -15,6 +14,8 @@ import { useTranslation } from "react-i18next"
import { useSelectedParams } from "../hooks"
import { useDataTableFilterContext } from "./context"
import { IFilter } from "./types"
import { TFunction } from "i18next"
import FilterChip from "./filter-chip"

type NumberFilterProps = IFilter

Expand All @@ -40,6 +41,9 @@ export const NumberFilter = ({
})

const currentValue = selectedParams.get()
const [previousValue, setPreviousValue] = useState<string[] | undefined>(
currentValue
)

const [operator, setOperator] = useState<Comparison | undefined>(
getOperator(currentValue)
Expand Down Expand Up @@ -99,6 +103,7 @@ export const NumberFilter = ({

const handleOpenChange = (open: boolean) => {
setOpen(open)
setPreviousValue(currentValue)

if (timeoutId) {
clearTimeout(timeoutId)
Expand Down Expand Up @@ -131,11 +136,16 @@ export const NumberFilter = ({
const LT_KEY = `${key}-lt`
const EQ_KEY = key

const displayValue = parseDisplayValue(currentValue, t)
const previousDisplayValue = parseDisplayValue(previousValue, t)

return (
<Popover.Root modal open={open} onOpenChange={handleOpenChange}>
<NumberDisplay
<FilterChip
hasOperator
hadPreviousValue={!!previousDisplayValue}
label={label}
value={currentValue}
value={displayValue}
onRemove={handleRemove}
readonly={readonly}
/>
Expand Down Expand Up @@ -242,23 +252,7 @@ export const NumberFilter = ({
)
}

const NumberDisplay = ({
label,
value,
readonly,
onRemove,
}: {
label: string
value?: string[]
readonly?: boolean
onRemove: () => void
}) => {
const { t } = useTranslation()
const handleRemove = (e: MouseEvent<HTMLButtonElement>) => {
e.stopPropagation()
onRemove()
}

const parseDisplayValue = (value: string[] | null | undefined, t: TFunction) => {
const parsed = JSON.parse(value?.join(",") || "{}")
let displayValue = ""

Expand All @@ -283,65 +277,7 @@ const NumberDisplay = ({
displayValue = parsed.toString()
}

return (
<Popover.Trigger
asChild
className={clx(
"bg-ui-bg-field transition-fg shadow-borders-base text-ui-fg-subtle flex cursor-pointer select-none items-center rounded-md",
{
"hover:bg-ui-bg-field-hover": !readonly,
"data-[state=open]:bg-ui-bg-field-hover": !readonly,
}
)}
>
<div>
<div
className={clx("flex items-center justify-center px-2 py-1", {
"border-r": !!value,
})}
>
<Text size="small" weight="plus" leading="compact">
{label}
</Text>
</div>
{!!value && (
<div className="border-r p-1 px-2">
<Text
size="small"
weight="plus"
leading="compact"
className="text-ui-fg-muted"
>
{t("general.is")}
</Text>
</div>
)}
{value && (
<div className="flex items-center">
<div className="border-r p-1 px-2">
<Text size="small" weight="plus" leading="compact">
{displayValue}
</Text>
</div>
</div>
)}
{!readonly && value && (
<div>
<button
onClick={handleRemove}
className={clx(
"text-ui-fg-muted transition-fg flex items-center justify-center p-1",
"hover:bg-ui-bg-subtle-hover",
"active:bg-ui-bg-subtle-pressed active:text-ui-fg-base"
)}
>
<XMarkMini />
</button>
</div>
)}
</div>
</Popover.Trigger>
)
return displayValue
}

const parseValue = (value: string[] | null | undefined) => {
Expand Down
Loading

0 comments on commit 0e11e89

Please sign in to comment.