feat(dashboard): support RTL in dashboard (#11252)

* fix: add direction attribute to components and adjust styles for RTL support

* fix(data-grid): comment it out

* Added useDocumentDirection hook

* refactor: Integrate useDocumentDirection hook

* refactor: Standardize direction prop usage across components

* resolve

* fix: resolve build errors

* fix : remove unused useDocument

* Apply RTL styles for some components

* Create smooth-gorillas-hide.md

* refactor: update some styles for RTL support

---------

Co-authored-by: William Bouchard <46496014+willbouch@users.noreply.github.com>
This commit is contained in:
Ayman Mustafa
2025-09-23 16:11:30 +01:00
committed by GitHub
parent a501364b2d
commit a75cf7fb36
70 changed files with 407 additions and 142 deletions

View File

@@ -4,6 +4,7 @@ import { EllipsisHorizontal } from "@medusajs/icons"
import { PropsWithChildren, ReactNode } from "react"
import { Link } from "react-router-dom"
import { ConditionalTooltip } from "../conditional-tooltip"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
export type Action = {
icon: ReactNode
@@ -38,6 +39,7 @@ export const ActionMenu = ({
variant = "transparent",
children,
}: ActionMenuProps) => {
const direction = useDocumentDirection()
const inner = children ?? (
<IconButton size="small" variant={variant}>
<EllipsisHorizontal />
@@ -45,7 +47,7 @@ export const ActionMenu = ({
)
return (
<DropdownMenu>
<DropdownMenu dir={direction}>
<DropdownMenu.Trigger asChild>{inner}</DropdownMenu.Trigger>
<DropdownMenu.Content>
{groups.map((group, index) => {

View File

@@ -46,7 +46,10 @@ export const JsonViewSection = ({ data }: JsonViewSectionProps) => {
<ArrowUpRightOnBox />
</IconButton>
</Drawer.Trigger>
<Drawer.Content className="bg-ui-contrast-bg-base text-ui-code-fg-subtle !shadow-elevation-commandbar overflow-hidden border border-none max-md:inset-x-2 max-md:max-w-[calc(100%-16px)]">
<Drawer.Content
dir="ltr"
className="bg-ui-contrast-bg-base text-ui-code-fg-subtle !shadow-elevation-commandbar overflow-hidden border border-none max-md:inset-x-2 max-md:max-w-[calc(100%-16px)]"
>
<div className="bg-ui-code-bg-base flex items-center justify-between px-6 py-4">
<div className="flex items-center gap-x-4">
<Drawer.Title asChild>

View File

@@ -37,7 +37,7 @@ export const SidebarLink = ({
</Text>
</div>
<div className="flex size-7 items-center justify-center">
<TriangleRightMini className="text-ui-fg-muted" />
<TriangleRightMini className="text-ui-fg-muted rtl:rotate-180" />
</div>
</div>
</div>

View File

@@ -50,6 +50,8 @@ export const SwitchBox = <
<div className="bg-ui-bg-component shadow-elevation-card-rest flex items-start gap-x-3 rounded-lg p-3">
<Form.Control>
<Switch
className="rtl:rotate-180"
dir="ltr"
{...field}
checked={value}
onCheckedChange={(e) => {

View File

@@ -29,6 +29,7 @@ import { FieldValues, UseFormReturn } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { useCommandHistory } from "../../../hooks/use-command-history"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
import { ConditionalTooltip } from "../../common/conditional-tooltip"
import { DataGridContext } from "../context"
import {
@@ -50,7 +51,7 @@ import { isCellMatch, isSpecialFocusKey } from "../utils"
import { DataGridKeyboardShortcutModal } from "./data-grid-keyboard-shortcut-modal"
export interface DataGridRootProps<
TData,
TFieldValues extends FieldValues = FieldValues
TFieldValues extends FieldValues = FieldValues,
> {
data?: TData[]
columns: ColumnDef<TData>[]
@@ -96,7 +97,7 @@ const getCommonPinningStyles = <TData,>(
export const DataGridRoot = <
TData,
TFieldValues extends FieldValues = FieldValues
TFieldValues extends FieldValues = FieldValues,
>({
data = [],
columns,
@@ -700,6 +701,7 @@ const DataGridHeader = ({
const [shortcutsOpen, setShortcutsOpen] = useState(false)
const [columnsOpen, setColumnsOpen] = useState(false)
const { t } = useTranslation()
const direction = useDocumentDirection()
// Since all columns are checked by default, we can check if any column is unchecked
const hasChanged = columnOptions.some((column) => !column.checked)
@@ -716,7 +718,11 @@ const DataGridHeader = ({
return (
<div className="bg-ui-bg-base flex items-center justify-between border-b p-4">
<div className="flex items-center gap-x-2">
<DropdownMenu open={columnsOpen} onOpenChange={handleColumnsOpenChange}>
<DropdownMenu
dir={direction}
open={columnsOpen}
onOpenChange={handleColumnsOpenChange}
>
<ConditionalTooltip
showTooltip={isDisabled}
content={t("dataGrid.columns.disabled")}

View File

@@ -106,9 +106,10 @@ const OuterComponent = ({
>
<div className="absolute inset-y-0 left-4 z-[3] flex w-fit items-center justify-center">
<Switch
dir="ltr"
ref={buttonRef}
size="small"
className="shrink-0"
className="shrink-0 rtl:rotate-180"
checked={localValue.checked}
disabled={localValue.disabledToggle}
onCheckedChange={handleCheckedChange}

View File

@@ -1,6 +1,7 @@
import { Button, DropdownMenu } from "@medusajs/ui"
import { ReactNode } from "react"
import { useSearchParams } from "react-router-dom"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
type FilterGroupProps = {
filters: {
@@ -37,8 +38,11 @@ type AddFilterMenuProps = {
}
const AddFilterMenu = ({ availableKeys }: AddFilterMenuProps) => {
const direction = useDocumentDirection()
return (
<DropdownMenu>
<DropdownMenu
dir={direction}
>
<DropdownMenu.Trigger asChild>
<Button variant="secondary" size="small">
Add filter

View File

@@ -4,6 +4,8 @@ import { useState } from "react"
import { useTranslation } from "react-i18next"
import { useSearchParams } from "react-router-dom"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
type OrderByProps = {
keys: string[]
}
@@ -56,6 +58,7 @@ export const OrderBy = ({ keys }: OrderByProps) => {
}>(initState(searchParams))
const { t } = useTranslation()
const direction = useDocumentDirection()
const handleDirChange = (dir: string) => {
setState((prev) => ({
@@ -99,7 +102,7 @@ export const OrderBy = ({ keys }: OrderByProps) => {
}
return (
<DropdownMenu>
<DropdownMenu dir={direction}>
<DropdownMenu.Trigger asChild>
<IconButton size="small">
<ArrowUpDown />

View File

@@ -7,6 +7,7 @@ import { Control } from "react-hook-form"
import { AddressSchema } from "../../../lib/schemas"
import { Form } from "../../common/form"
import { CountrySelect } from "../../inputs/country-select"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
type AddressFieldValues = z.infer<typeof AddressSchema>
@@ -22,7 +23,7 @@ export const AddressForm = ({
layout,
}: AddressFormProps) => {
const { t } = useTranslation()
const direction = useDocumentDirection()
const style = clx("gap-4", {
"flex flex-col": layout === "stack",
"grid grid-cols-2": layout === "grid",
@@ -182,7 +183,11 @@ export const AddressForm = ({
<Form.Label>{t("fields.country")}</Form.Label>
<Form.Control>
{countries ? (
<Select {...field} onValueChange={onChange}>
<Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>

View File

@@ -25,6 +25,7 @@ import { Form } from "../../common/form"
import { Skeleton } from "../../common/skeleton"
import { RouteDrawer, useRouteModal } from "../../modals"
import { KeyboundForm } from "../../utilities/keybound-form"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
type MetaDataSubmitHook<TRes> = (
params: { metadata?: Record<string, any> | null },
@@ -77,7 +78,7 @@ const InnerForm = <TRes,>({
}: Omit<MetadataFormProps<TRes>, "isPending">) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const hasUneditableRows = getHasUneditableRows(metadata)
const form = useForm<z.infer<typeof MetadataSchema>>({
@@ -215,10 +216,12 @@ const InnerForm = <TRes,>({
}}
/>
</div>
<DropdownMenu>
<DropdownMenu
dir={direction}
>
<DropdownMenu.Trigger
className={clx(
"invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
"invisible absolute inset-y-0 -end-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
{
hidden: isDisabled,
}

View File

@@ -251,7 +251,7 @@ const ComboboxImpl = <T extends Value = string>(
e.preventDefault()
handleValueChange(isArrayValue ? ([] as unknown as T) : undefined)
}}
className="bg-ui-bg-base hover:bg-ui-bg-base-hover txt-compact-small-plus text-ui-fg-subtle focus-within:border-ui-fg-interactive transition-fg absolute left-0.5 top-0.5 z-[1] flex h-[28px] items-center rounded-[4px] border py-[3px] pl-1.5 pr-1 outline-none"
className="bg-ui-bg-base hover:bg-ui-bg-base-hover txt-compact-small-plus text-ui-fg-subtle focus-within:border-ui-fg-interactive transition-fg absolute start-0.5 top-0.5 z-[1] flex h-[28px] items-center rounded-[4px] border py-[3px] ps-1.5 pe-1 outline-none"
>
<span className="tabular-nums">{selectedValues.length}</span>
<XMarkMini className="text-ui-fg-muted" />
@@ -263,8 +263,8 @@ const ComboboxImpl = <T extends Value = string>(
className={clx(
"pointer-events-none absolute inset-y-0 flex size-full items-center",
{
"left-[calc(var(--tag-width)+8px)]": showTag,
"left-2": !showTag,
"start-[calc(var(--tag-width)+8px)]": showTag,
"start-2": !showTag,
}
)}
>
@@ -278,8 +278,8 @@ const ComboboxImpl = <T extends Value = string>(
className={clx(
"pointer-events-none absolute inset-y-0 flex size-full items-center overflow-hidden",
{
"left-[calc(var(--tag-width)+8px)]": showTag,
"left-2": !showTag,
"start-[calc(var(--tag-width)+8px)]": showTag,
"start-2": !showTag,
}
)}
>
@@ -293,12 +293,12 @@ const ComboboxImpl = <T extends Value = string>(
ref={comboboxRef}
onFocus={() => setOpen(true)}
className={clx(
"txt-compact-small text-ui-fg-base !placeholder:text-ui-fg-muted transition-fg size-full cursor-pointer bg-transparent pl-2 pr-8 outline-none focus:cursor-text",
"txt-compact-small text-ui-fg-base !placeholder:text-ui-fg-muted transition-fg size-full cursor-pointer bg-transparent ps-2 pe-8 outline-none focus:cursor-text",
"hover:bg-ui-bg-field-hover",
{
"opacity-0": hideInput,
"pl-2": !showTag,
"pl-[calc(var(--tag-width)+8px)]": showTag,
"ps-2": !showTag,
"ps-[calc(var(--tag-width)+8px)]": showTag,
}
)}
placeholder={hidePlaceholder ? undefined : placeholder}
@@ -312,7 +312,7 @@ const ComboboxImpl = <T extends Value = string>(
e.preventDefault()
handleValueChange(undefined)
}}
className="bg-ui-bg-base hover:bg-ui-bg-base-hover txt-compact-small-plus text-ui-fg-subtle focus-within:border-ui-fg-interactive transition-fg absolute right-[28px] top-0.5 z-[1] flex h-[28px] items-center rounded-[4px] border px-1.5 py-[2px] outline-none"
className="bg-ui-bg-base hover:bg-ui-bg-base-hover txt-compact-small-plus text-ui-fg-subtle focus-within:border-ui-fg-interactive transition-fg absolute end-[28px] top-0.5 z-[1] flex h-[28px] items-center rounded-[4px] border px-1.5 py-[2px] outline-none"
>
<XMarkMini className="text-ui-fg-muted" />
</button>
@@ -323,7 +323,7 @@ const ComboboxImpl = <T extends Value = string>(
<button
{...props}
type="button"
className="text-ui-fg-muted transition-fg hover:bg-ui-bg-field-hover absolute right-0 flex size-8 items-center justify-center rounded-r outline-none"
className="text-ui-fg-muted transition-fg hover:bg-ui-bg-field-hover absolute end-0 flex size-8 items-center justify-center rounded-r outline-none"
>
<TrianglesMini />
</button>
@@ -341,7 +341,7 @@ const ComboboxImpl = <T extends Value = string>(
"max-h-[200px] overflow-y-auto",
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
"data-[side=bottom]:slide-in-from-top-2 data-[side=start]:slide-in-from-end-2 data-[side=end]:slide-in-from-start-2 data-[side=top]:slide-in-from-bottom-2"
)}
style={{
pointerEvents: open ? "auto" : "none",

View File

@@ -33,7 +33,7 @@ export const CountrySelect = forwardRef<
<div className="relative">
<TrianglesMini
className={clx(
"text-ui-fg-muted transition-fg pointer-events-none absolute right-2 top-1/2 -translate-y-1/2",
"text-ui-fg-muted transition-fg pointer-events-none absolute end-2 top-1/2 -translate-y-1/2",
{
"text-ui-fg-disabled": disabled,
}

View File

@@ -76,7 +76,7 @@ export const ProvinceSelect = forwardRef<
<div className="relative">
<TrianglesMini
className={clx(
"text-ui-fg-muted transition-fg pointer-events-none absolute right-2 top-1/2 -translate-y-1/2",
"text-ui-fg-muted transition-fg pointer-events-none absolute end-2 top-1/2 -translate-y-1/2",
{
"text-ui-fg-disabled": disabled,
}

View File

@@ -29,6 +29,7 @@ import { queryClient } from "../../../lib/query-client"
import { useExtension } from "../../../providers/extension-provider"
import { useSearch } from "../../../providers/search-provider"
import { UserMenu } from "../user-menu"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
export const MainLayout = () => {
return (
@@ -94,7 +95,7 @@ const Logout = () => {
const Header = () => {
const { t } = useTranslation()
const { store, isPending, isError, error } = useStore()
const direction = useDocumentDirection()
const name = store?.name
const fallback = store?.name?.slice(0, 1).toUpperCase()
@@ -106,11 +107,12 @@ const Header = () => {
return (
<div className="w-full p-3">
<DropdownMenu>
<DropdownMenu
dir={direction}>
<DropdownMenu.Trigger
disabled={!isLoaded}
className={clx(
"bg-ui-bg-subtle transition-fg grid w-full grid-cols-[24px_1fr_15px] items-center gap-x-3 rounded-md p-0.5 pr-2 outline-none",
"bg-ui-bg-subtle transition-fg grid w-full grid-cols-[24px_1fr_15px] items-center gap-x-3 rounded-md p-0.5 pe-2 outline-none",
"hover:bg-ui-bg-subtle-hover",
"data-[state=open]:bg-ui-bg-subtle-hover",
"focus-visible:shadow-borders-focus"
@@ -121,7 +123,7 @@ const Header = () => {
) : (
<Skeleton className="h-6 w-6 rounded-md" />
)}
<div className="block overflow-hidden text-left">
<div className="block overflow-hidden text-start">
{name ? (
<Text
size="small"
@@ -267,7 +269,7 @@ const Searchbar = () => {
)}
>
<MagnifyingGlass />
<div className="flex-1 text-left">
<div className="flex-1 text-start">
<Text size="small" leading="compact" weight="plus">
{t("app.search.label")}
</Text>

View File

@@ -156,7 +156,7 @@ const Breadcrumbs = () => {
)}
{!isLast && (
<span className="mx-2">
<TriangleRightMini />
<TriangleRightMini className="rtl:rotate-180" />
</span>
)}
</li>
@@ -177,7 +177,7 @@ const ToggleSidebar = () => {
onClick={() => toggle("desktop")}
size="small"
>
<SidebarLeft className="text-ui-fg-muted" />
<SidebarLeft className="text-ui-fg-muted rtl:rotate-180" />
</IconButton>
<IconButton
className="hidden max-lg:flex"
@@ -185,7 +185,7 @@ const ToggleSidebar = () => {
onClick={() => toggle("mobile")}
size="small"
>
<SidebarLeft className="text-ui-fg-muted" />
<SidebarLeft className="text-ui-fg-muted rtl:rotate-180" />
</IconButton>
</div>
)
@@ -210,7 +210,7 @@ const DesktopSidebarContainer = ({ children }: PropsWithChildren) => {
return (
<div
className={clx("hidden h-screen w-[220px] border-r", {
className={clx("hidden h-screen w-[220px] border-e", {
"lg:flex": desktop,
})}
>
@@ -234,8 +234,8 @@ const MobileSidebarContainer = ({ children }: PropsWithChildren) => {
/>
<RadixDialog.Content
className={clx(
"bg-ui-bg-subtle shadow-elevation-modal fixed inset-y-2 left-2 flex w-full max-w-[304px] flex-col overflow-hidden rounded-lg border-r",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:slide-out-to-left-1/2 data-[state=open]:slide-in-from-left-1/2 duration-200"
"bg-ui-bg-subtle shadow-elevation-modal fixed inset-y-2 start-2 flex w-full max-w-[304px] flex-col overflow-hidden rounded-lg border-r",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:slide-out-to-start-1/2 data-[state=open]:slide-in-from-start-1/2 duration-200"
)}
>
<div className="p-3">

View File

@@ -29,10 +29,12 @@ import { useLogout, useMe } from "../../../hooks/api"
import { queryClient } from "../../../lib/query-client"
import { useGlobalShortcuts } from "../../../providers/keybind-provider/hooks"
import { useTheme } from "../../../providers/theme-provider"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
export const UserMenu = () => {
const { t } = useTranslation()
const location = useLocation()
const direction = useDocumentDirection()
const [openMenu, setOpenMenu] = useState(false)
const [openModal, setOpenModal] = useState(false)
@@ -44,33 +46,33 @@ export const UserMenu = () => {
return (
<div>
<DropdownMenu open={openMenu} onOpenChange={setOpenMenu}>
<DropdownMenu dir={direction} open={openMenu} onOpenChange={setOpenMenu}>
<UserBadge />
<DropdownMenu.Content className="min-w-[var(--radix-dropdown-menu-trigger-width)] max-w-[var(--radix-dropdown-menu-trigger-width)]">
<UserItem />
<DropdownMenu.Separator />
<DropdownMenu.Item asChild>
<Link to="/settings/profile" state={{ from: location.pathname }}>
<UserIcon className="text-ui-fg-subtle mr-2" />
<UserIcon className="text-ui-fg-subtle me-2" />
{t("app.menus.user.profileSettings")}
</Link>
</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item asChild>
<Link to="https://docs.medusajs.com" target="_blank">
<BookOpen className="text-ui-fg-subtle mr-2" />
<BookOpen className="text-ui-fg-subtle me-2" />
{t("app.menus.user.documentation")}
</Link>
</DropdownMenu.Item>
<DropdownMenu.Item asChild>
<Link to="https://medusajs.com/changelog/" target="_blank">
<TimelineVertical className="text-ui-fg-subtle mr-2" />
<TimelineVertical className="text-ui-fg-subtle me-2" />
{t("app.menus.user.changelog")}
</Link>
</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item onClick={toggleModal}>
<Keyboard className="text-ui-fg-subtle mr-2" />
<Keyboard className="text-ui-fg-subtle me-2" />
{t("app.menus.user.shortcuts")}
</DropdownMenu.Item>
<ThemeToggle />
@@ -93,7 +95,7 @@ const UserBadge = () => {
if (isPending) {
return (
<button className="shadow-borders-base flex max-w-[192px] select-none items-center gap-x-2 overflow-hidden text-ellipsis whitespace-nowrap rounded-full py-1 pl-1 pr-2.5">
<button className="shadow-borders-base flex max-w-[192px] select-none items-center gap-x-2 overflow-hidden text-ellipsis whitespace-nowrap rounded-full py-1 ps-1 pe-2.5">
<Skeleton className="h-5 w-5 rounded-full" />
<Skeleton className="h-[9px] w-[70px]" />
</button>
@@ -109,7 +111,7 @@ const UserBadge = () => {
<DropdownMenu.Trigger
disabled={!user}
className={clx(
"bg-ui-bg-subtle grid w-full cursor-pointer grid-cols-[24px_1fr_15px] items-center gap-2 rounded-md py-1 pl-0.5 pr-2 outline-none",
"bg-ui-bg-subtle grid w-full cursor-pointer grid-cols-[24px_1fr_15px] items-center gap-2 rounded-md py-1 ps-0.5 pe-2 outline-none",
"hover:bg-ui-bg-subtle-hover",
"data-[state=open]:bg-ui-bg-subtle-hover",
"focus-visible:shadow-borders-focus"
@@ -148,9 +150,9 @@ const ThemeToggle = () => {
return (
<DropdownMenu.SubMenu>
<DropdownMenu.SubMenuTrigger className="rounded-md">
<CircleHalfSolid className="text-ui-fg-subtle mr-2" />
{t("app.menus.user.theme.label")}
<DropdownMenu.SubMenuTrigger dir="ltr" className="rounded-md rtl:rotate-180">
<CircleHalfSolid className="text-ui-fg-subtle me-2" />
<span className="rtl:rotate-180">{t("app.menus.user.theme.label")}</span>
</DropdownMenu.SubMenuTrigger>
<DropdownMenu.SubMenuContent>
<DropdownMenu.RadioGroup value={theme}>

View File

@@ -44,6 +44,7 @@ import {
} from "./constants"
import { SearchArea } from "./types"
import { useSearchResults } from "./use-search-results"
import { useDocumentDirection } from "../../hooks/use-document-direction"
export const Search = () => {
const [area, setArea] = useState<SearchArea>("all")
@@ -54,6 +55,7 @@ export const Search = () => {
const { t } = useTranslation()
const navigate = useNavigate()
const inputRef = useRef<HTMLInputElement>(null)
const listRef = useRef<HTMLDivElement>(null)
@@ -367,7 +369,7 @@ const CommandInput = forwardRef<
) => {
const { t } = useTranslation()
const innerRef = useRef<HTMLInputElement>(null)
const direction = useDocumentDirection()
useImperativeHandle<HTMLInputElement | null, HTMLInputElement | null>(
ref,
() => innerRef.current
@@ -376,7 +378,7 @@ const CommandInput = forwardRef<
return (
<div className="flex flex-col border-b">
<div className="px-4 pt-4">
<DropdownMenu>
<DropdownMenu dir={direction}>
<DropdownMenu.Trigger asChild>
<Badge
size="2xsmall"
@@ -432,7 +434,7 @@ const CommandInput = forwardRef<
)}
{...props}
/>
<div className="absolute right-4 top-1/2 flex -translate-y-1/2 items-center justify-end gap-x-2">
<div className="absolute end-4 top-1/2 flex -translate-y-1/2 items-center justify-end gap-x-2">
{isFetching && (
<Spinner className="text-ui-fg-muted animate-spin" />
)}

View File

@@ -4,6 +4,8 @@ import { useState } from "react"
import { useTranslation } from "react-i18next"
import { useSearchParams } from "react-router-dom"
import { useDocumentDirection } from "../../../../hooks/use-document-direction"
export type DataTableOrderByKey<TData> = {
key: keyof TData
label: string
@@ -54,6 +56,7 @@ export const DataTableOrderBy = <TData,>({
}>(initState(searchParams, prefix))
const param = prefix ? `${prefix}_order` : "order"
const { t } = useTranslation()
const direction = useDocumentDirection()
const handleDirChange = (dir: string) => {
setState((prev) => ({
@@ -97,7 +100,7 @@ export const DataTableOrderBy = <TData,>({
}
return (
<DropdownMenu>
<DropdownMenu dir={direction}>
<DropdownMenu.Trigger asChild>
<IconButton size="small">
<DescendingSorting />

View File

@@ -262,7 +262,7 @@ export const DataTableRoot = <TData,>({
<Table.Cell
key={cell.id}
className={clx({
"!pl-0 !pr-0": shouldRenderAsLink,
"!ps-0 !pe-0": shouldRenderAsLink,
"bg-ui-bg-base group-data-[selected=true]/row:bg-ui-bg-highlight group-data-[selected=true]/row:group-hover/row:bg-ui-bg-highlight-hover group-hover/row:bg-ui-bg-base-hover transition-fg group-has-[[data-row-link]:focus-visible]:bg-ui-bg-base-hover sticky left-0 after:absolute after:inset-y-0 after:right-0 after:h-full after:w-px after:bg-transparent after:content-['']":
isStickyCell,
"bg-ui-bg-subtle group-hover/row:bg-ui-bg-subtle-hover":
@@ -288,9 +288,9 @@ export const DataTableRoot = <TData,>({
>
<div
className={clx(
"flex size-full items-center pr-6",
"flex size-full items-center pe-6",
{
"pl-6": isTabableLink && !hasLeftOffset,
"ps-6": isTabableLink && !hasLeftOffset,
}
)}
>