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 11:11:30 -04:00
committed by GitHub
co-authored by William Bouchard
parent a501364b2d
commit a75cf7fb36
70 changed files with 407 additions and 142 deletions
@@ -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) => {
@@ -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>
@@ -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>
@@ -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) => {
@@ -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")}
@@ -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}
@@ -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
@@ -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 />
@@ -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>
@@ -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,
}
@@ -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",
@@ -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,
}
@@ -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,
}
@@ -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>
@@ -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">
@@ -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}>
@@ -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" />
)}
@@ -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 />
@@ -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,
}
)}
>
@@ -102,7 +102,7 @@ const FormExtensionFieldComponent = ({
return <Input {...field} placeholder={placeholder} type="number" />
}
case "boolean": {
return <Switch {...field} />
return <Switch className="rtl:rotate-180" dir="ltr" {...field} />
}
default: {
return (
@@ -0,0 +1,54 @@
import { useEffect, useState } from "react"
/**
* Hook to get the current document direction (ltr/rtl) and listen for changes
* @returns The current document direction as "ltr" | "rtl" | undefined
*/
export const useDocumentDirection = (): "ltr" | "rtl" | undefined => {
const [direction, setDirection] = useState<"ltr" | "rtl" | undefined>(() => {
// Initialize with current value
if (typeof document !== "undefined") {
return (
(document.documentElement.getAttribute("dir") as "ltr" | "rtl") ||
undefined
)
}
return undefined
})
useEffect(() => {
// Only run on client side
if (typeof document === "undefined") {
return
}
// Create a MutationObserver to watch for changes to the dir attribute
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (
mutation.type === "attributes" &&
mutation.attributeName === "dir" &&
mutation.target === document.documentElement
) {
const newDirection = document.documentElement.getAttribute("dir") as
| "ltr"
| "rtl"
setDirection(newDirection || undefined)
}
})
})
// Start observing the document element for attribute changes
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["dir"],
})
// Cleanup observer on unmount
return () => {
observer.disconnect()
}
}, [])
return direction
}
@@ -1,5 +1,5 @@
import { I18nProvider as Provider } from "@medusajs/ui"
import { PropsWithChildren } from "react"
import { PropsWithChildren, useEffect } from "react"
import { useTranslation } from "react-i18next"
import { languages } from "../../i18n/languages"
@@ -12,9 +12,14 @@ const formatLocaleCode = (code: string) => {
export const I18nProvider = ({ children }: I18nProviderProps) => {
const { i18n } = useTranslation()
const locale =
languages.find((lan) => lan.code === i18n.language)?.code ||
languages[0].code
const currentLanguage =
languages.find((lan) => lan.code === i18n.language) || languages[0]
const locale = currentLanguage.code
const direction = currentLanguage.ltr ? "ltr" : "rtl"
useEffect(() => {
document.documentElement.setAttribute("dir", direction)
}, [direction])
return <Provider locale={formatLocaleCode(locale)}>{children}</Provider>
}
@@ -15,14 +15,14 @@ export const CampaignBudget = ({ campaign }: CampaignBudgetProps) => {
<Container className="flex flex-col gap-y-4 px-6 py-4">
<div className="flex justify-between">
<div className="flex-grow">
<div className="bg-ui-bg-base shadow-borders-base float-left flex size-7 items-center justify-center rounded-md">
<div className="bg-ui-bg-base shadow-borders-base float-start flex size-7 items-center justify-center rounded-md">
<div className="bg-ui-bg-component flex size-6 items-center justify-center rounded-[4px]">
<ChartPie className="text-ui-fg-subtle" />
</div>
</div>
<Heading
className="text-ui-fg-subtle ml-10 mt-[1.5px] font-normal"
className="text-ui-fg-subtle ms-10 mt-[1.5px] font-normal"
level="h3"
>
{t("campaigns.fields.budget_limit")}
@@ -46,7 +46,7 @@ export const CampaignBudget = ({ campaign }: CampaignBudgetProps) => {
<div>
<Text
className="text-ui-fg-subtle border-ui-border-strong border-l-4 pl-3"
className="text-ui-fg-subtle border-ui-border-strong border-l-4 ps-3"
size="small"
leading="compact"
>
@@ -14,6 +14,7 @@ import { useTranslation } from "react-i18next"
import { Form } from "../../../../../components/common/form"
import { useStore } from "../../../../../hooks/api/store"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
import {
currencies,
getCurrencySymbol,
@@ -22,7 +23,7 @@ import {
export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
const { t } = useTranslation()
const { store } = useStore()
const direction = useDocumentDirection()
const watchValueType = useWatch({
control: form.control,
name: `${fieldScope}budget.type`,
@@ -207,6 +208,7 @@ export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
<Form.Control>
<RadioGroup
dir={direction}
className="flex gap-y-3"
{...field}
onValueChange={field.onChange}
@@ -250,6 +252,7 @@ export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
</Form.Label>
<Form.Control>
<Select
dir={direction}
{...field}
onValueChange={onChange}
disabled={!!fieldScope.length}
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next"
import { Form } from "../../../../../components/common/form"
import { HandleInput } from "../../../../../components/inputs/handle-input"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
import { CreateCategorySchema } from "./schema"
type CreateCategoryDetailsProps = {
@@ -12,7 +13,7 @@ type CreateCategoryDetailsProps = {
export const CreateCategoryDetails = ({ form }: CreateCategoryDetailsProps) => {
const { t } = useTranslation()
const direction = useDocumentDirection()
return (
<div className="flex flex-col items-center p-16">
<div className="flex w-full max-w-[720px] flex-col gap-y-8">
@@ -80,7 +81,11 @@ export const CreateCategoryDetails = ({ form }: CreateCategoryDetailsProps) => {
<Form.Item>
<Form.Label>{t("categories.fields.status.label")}</Form.Label>
<Form.Control>
<Select {...field} onValueChange={onChange}>
<Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>
@@ -109,7 +114,11 @@ export const CreateCategoryDetails = ({ form }: CreateCategoryDetailsProps) => {
{t("categories.fields.visibility.label")}
</Form.Label>
<Form.Control>
<Select {...field} onValueChange={onChange}>
<Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>
@@ -14,6 +14,7 @@ import { transformNullableFormData } from "../../../../../lib/form-helpers"
import { CreateCategoryDetails } from "./create-category-details"
import { CreateCategoryNesting } from "./create-category-nesting"
import { CreateCategoryDetailsSchema, CreateCategorySchema } from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type CreateCategoryFormProps = {
parentCategoryId: string | null
@@ -29,7 +30,7 @@ export const CreateCategoryForm = ({
}: CreateCategoryFormProps) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const [activeTab, setActiveTab] = useState<Tab>(Tab.DETAILS)
const [validDetails, setValidDetails] = useState(false)
const [shouldFreeze, setShouldFreeze] = useState(false)
@@ -129,8 +130,8 @@ export const CreateCategoryForm = ({
onSubmit={handleSubmit}
className="flex size-full flex-col overflow-hidden"
>
<ProgressTabs
value={activeTab}
<ProgressTabs
dir={direction}value={activeTab}
onValueChange={(tab) => handleTabChange(tab as Tab)}
className="flex size-full flex-col"
>
@@ -111,7 +111,7 @@ const PathDisplay = ({
</button>
</Tooltip>
<div className="flex size-[15px] shrink-0 items-center justify-center">
<TriangleRightMini />
<TriangleRightMini className="rtl:rotate-180" />
</div>
<Text
size="xsmall"
@@ -10,6 +10,7 @@ import { HandleInput } from "../../../../../components/inputs/handle-input"
import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useUpdateProductCategory } from "../../../../../hooks/api/categories"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
const EditCategorySchema = z.object({
name: z.string().min(1),
@@ -26,7 +27,7 @@ type EditCategoryFormProps = {
export const EditCategoryForm = ({ category }: EditCategoryFormProps) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof EditCategorySchema>>({
defaultValues: {
name: category.name,
@@ -126,7 +127,11 @@ export const EditCategoryForm = ({ category }: EditCategoryFormProps) => {
{t("categories.fields.status.label")}
</Form.Label>
<Form.Control>
<Select {...field} onValueChange={onChange}>
<Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>
@@ -155,7 +160,11 @@ export const EditCategoryForm = ({ category }: EditCategoryFormProps) => {
{t("categories.fields.visibility.label")}
</Form.Label>
<Form.Control>
<Select {...field} onValueChange={onChange}>
<Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>
@@ -36,6 +36,7 @@ import {
import { queryClient } from "../../../../../lib/query-client"
import { InventoryAvailabilityForm } from "./inventory-availability-form"
import { CreateInventoryItemSchema } from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
enum Tab {
DETAILS = "details",
@@ -54,7 +55,7 @@ export function InventoryCreateForm({ locations }: InventoryCreateFormProps) {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const [tab, setTab] = useState<Tab>(Tab.DETAILS)
const direction = useDocumentDirection()
const form = useForm<CreateInventoryItemSchema>({
defaultValues: {
title: "",
@@ -201,6 +202,7 @@ export function InventoryCreateForm({ locations }: InventoryCreateFormProps) {
return (
<RouteFocusModal.Form form={form}>
<ProgressTabs
dir={direction}
value={tab}
className="h-full"
onValueChange={(tab) => onTabChange(tab as Tab)}
@@ -46,7 +46,7 @@ export const InventoryItemVariantsSection = ({
</span>
</div>
<div className="size-7 flex items-center justify-center">
<TriangleRightMini className="text-ui-fg-muted" />
<TriangleRightMini className="text-ui-fg-muted rtl:rotate-180" />
</div>
</div>
</div>
@@ -12,6 +12,7 @@ import { sdk } from "../../../../../lib/client"
import { formatProvider } from "../../../../../lib/format-provider"
import { FulfillmentSetType, ShippingOptionPriceType, } from "../../../common/constants"
import { CreateShippingOptionSchema } from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type CreateShippingOptionDetailsFormProps = {
form: UseFormReturn<CreateShippingOptionSchema>
@@ -33,7 +34,7 @@ export const CreateShippingOptionDetailsForm = ({
type,
}: CreateShippingOptionDetailsFormProps) => {
const { t } = useTranslation()
const direction = useDocumentDirection()
const isPickup = type === FulfillmentSetType.Pickup
const shippingProfiles = useComboboxData({
@@ -105,6 +106,7 @@ export const CreateShippingOptionDetailsForm = ({
</Form.Label>
<Form.Control>
<RadioGroup
dir={direction}
className="grid grid-cols-1 gap-4 md:grid-cols-2"
{...field}
onValueChange={field.onChange}
@@ -252,6 +254,7 @@ export const CreateShippingOptionDetailsForm = ({
</Form.Label>
<Form.Control>
<Select
dir={direction}
{...field}
onValueChange={field.onChange}
disabled={!selectedProviderId}
@@ -24,6 +24,7 @@ import {
CreateShippingOptionSchema,
} from "./schema"
import { useFulfillmentProviderOptions } from "../../../../../hooks/api"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
enum Tab {
DETAILS = "details",
@@ -48,7 +49,7 @@ export function CreateShippingOptionsForm({
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<CreateShippingOptionSchema>({
defaultValues: {
name: "",
@@ -271,6 +272,7 @@ export function CreateShippingOptionsForm({
}}
>
<ProgressTabs
dir={direction}
value={activeTab}
className="flex h-full flex-col overflow-hidden"
onValueChange={(tab) => onTabChange(tab as Tab)}
@@ -20,6 +20,7 @@ import {
ShippingOptionPriceType,
} from "../../../common/constants"
import { formatProvider } from "../../../../../lib/format-provider"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditShippingOptionFormProps = {
locationId: string
@@ -43,7 +44,7 @@ export const EditShippingOptionForm = ({
}: EditShippingOptionFormProps) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const isPickup = type === FulfillmentSetType.Pickup
const shippingProfiles = useComboboxData({
@@ -147,7 +148,11 @@ export const EditShippingOptionForm = ({
)}
</Form.Label>
<Form.Control>
<RadioGroup {...field} onValueChange={field.onChange}>
<RadioGroup
dir={direction}
{...field}
onValueChange={field.onChange}
>
<RadioGroup.ChoiceBox
className="flex-1"
value={ShippingOptionPriceType.FlatRate}
@@ -20,6 +20,7 @@ import { queryClient } from "../../../../../lib/query-client"
import { AllocateItemsSchema } from "./constants"
import { OrderAllocateItemsItem } from "./order-allocate-items-item"
import { checkInventoryKit } from "./utils"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type OrderAllocateItemsFormProps = {
order: AdminOrder
@@ -28,7 +29,7 @@ type OrderAllocateItemsFormProps = {
export function OrderAllocateItemsForm({ order }: OrderAllocateItemsFormProps) {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const [disableSubmit, setDisableSubmit] = useState(false)
const [filterTerm, setFilterTerm] = useState("")
@@ -231,7 +232,11 @@ export function OrderAllocateItemsForm({ order }: OrderAllocateItemsFormProps) {
</div>
<div className="flex-1">
<Form.Control>
<Select onValueChange={onChange} {...field}>
<Select
dir={direction}
onValueChange={onChange}
{...field}
>
<Select.Trigger
className="bg-ui-bg-base"
ref={ref}
@@ -1028,7 +1028,8 @@ export const ClaimCreateForm = ({
<div className="flex items-center">
<Form.Control className="mr-4 self-start">
<Switch
className="mt-[2px]"
dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={!!value}
onCheckedChange={onChange}
{...field}
@@ -179,7 +179,8 @@ export const OrderEditCreateForm = ({
<div className="flex items-center">
<Form.Control className="mr-4 self-start">
<Switch
className="mt-[2px]"
dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={!!value}
onCheckedChange={onChange}
{...field}
@@ -509,7 +509,8 @@ export const ExchangeCreateForm = ({
<div className="flex items-center">
<Form.Control className="mr-4 self-start">
<Switch
className="mt-[2px]"
dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={!!value}
onCheckedChange={onChange}
{...field}
@@ -26,6 +26,7 @@ import { getReservationsLimitCount } from "../../../../../lib/orders"
import { sdk } from "../../../../../lib/client"
import { useComboboxData } from "../../../../../hooks/use-combobox-data"
import { Combobox } from "../../../../../components/inputs/combobox"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type OrderCreateFulfillmentFormProps = {
order: AdminOrder
@@ -38,7 +39,7 @@ export function OrderCreateFulfillmentForm({
}: OrderCreateFulfillmentFormProps) {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const { mutateAsync: createOrderFulfillment, isPending: isMutating } =
useCreateOrderFulfillment(order.id)
@@ -288,6 +289,7 @@ export function OrderCreateFulfillmentForm({
<div className="flex-1">
<Form.Control>
<Select
dir={direction}
onValueChange={onChange}
{...field}
disabled={!selectedLocationId}
@@ -390,6 +392,8 @@ export function OrderCreateFulfillmentForm({
<Form.Control>
<Form.Control>
<Switch
dir="ltr"
className="rtl:rotate-180"
checked={!!value}
onCheckedChange={onChange}
{...field}
@@ -23,6 +23,7 @@ import { formatCurrency } from "../../../../../lib/format-currency"
import { formatProvider } from "../../../../../lib/format-provider"
import { getLocaleAmount } from "../../../../../lib/money-amount-helpers"
import { getPaymentsFromOrder } from "../../../../../lib/orders"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type CreateRefundFormProps = {
order: HttpTypes.AdminOrder
@@ -53,6 +54,7 @@ export const CreateRefundForm = ({ order }: CreateRefundFormProps) => {
[order.currency_code]
)
const direction = useDocumentDirection()
const form = useForm<zod.infer<typeof CreateRefundSchema>>({
defaultValues: {
amount: {
@@ -118,6 +120,7 @@ export const CreateRefundForm = ({ order }: CreateRefundFormProps) => {
<RouteDrawer.Body className="flex-1 overflow-auto">
<div className="flex flex-col gap-y-4">
<Select
dir={direction}
value={paymentId}
onValueChange={(value) => {
setPaymentId(value)
@@ -726,7 +726,8 @@ export const ReturnCreateForm = ({
<div className="flex items-center">
<Form.Control className="mr-4 self-start">
<Switch
className="mt-[2px]"
dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={!!value}
onCheckedChange={onChange}
{...field}
@@ -136,6 +136,8 @@ export function OrderCreateShipmentForm({
<Form.Control>
<Form.Control>
<Switch
dir="ltr"
className="rtl:rotate-180"
checked={!!value}
onCheckedChange={onChange}
{...field}
@@ -345,7 +345,8 @@ export function OrderReceiveReturnForm({
<div className="flex items-center gap-3">
<Form.Control>
<Switch
className="mt-1 self-start"
dir="ltr"
className="mt-1 self-start rtl:rotate-180"
checked={!!value}
onCheckedChange={onChange}
{...field}
@@ -25,6 +25,7 @@ import {
PricingProductsFields,
PricingProductsSchema,
} from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
enum Tab {
DETAIL = "detail",
@@ -58,7 +59,7 @@ export const PriceListCreateForm = ({
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<PricingCreateSchemaType>({
defaultValues: {
type: "sale",
@@ -249,6 +250,7 @@ export const PriceListCreateForm = ({
return (
<RouteFocusModal.Form form={form}>
<ProgressTabs
dir={direction}
value={tab}
onValueChange={(tab) => handleChangeTab(tab as Tab)}
className="flex h-full flex-col overflow-hidden"
@@ -23,6 +23,7 @@ import type {
PricingCreateSchemaType,
PricingCustomerGroupsArrayType,
} from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type PriceListDetailsFormProps = {
form: UseFormReturn<PricingCreateSchemaType>
@@ -30,7 +31,7 @@ type PriceListDetailsFormProps = {
export const PriceListDetailsForm = ({ form }: PriceListDetailsFormProps) => {
const { t } = useTranslation()
const direction = useDocumentDirection()
const { fields, remove, append } = useFieldArray({
control: form.control,
name: "rules.customer_group_id",
@@ -78,6 +79,7 @@ export const PriceListDetailsForm = ({ form }: PriceListDetailsFormProps) => {
</div>
<Form.Control>
<RadioGroup
dir={direction}
onValueChange={onChange}
{...rest}
className="grid grid-cols-1 gap-4 md:grid-cols-2"
@@ -133,7 +135,11 @@ export const PriceListDetailsForm = ({ form }: PriceListDetailsFormProps) => {
{t("priceLists.fields.status.label")}
</Form.Label>
<Form.Control>
<Select {...field} onValueChange={onChange}>
<Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>
@@ -16,6 +16,7 @@ import { Form } from "../../../../../components/common/form"
import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useUpdatePriceList } from "../../../../../hooks/api/price-lists"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
import { PriceListStatus, PriceListType } from "../../../common/constants"
type PriceListEditFormProps = {
@@ -32,7 +33,7 @@ const PriceListEditSchema = z.object({
export const PriceListEditForm = ({ priceList }: PriceListEditFormProps) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof PriceListEditSchema>>({
defaultValues: {
type: priceList.type as PriceListType,
@@ -80,7 +81,11 @@ export const PriceListEditForm = ({ priceList }: PriceListEditFormProps) => {
<Form.Hint>{t("priceLists.fields.type.hint")}</Form.Hint>
</div>
<Form.Control>
<RadioGroup {...field} onValueChange={onChange}>
<RadioGroup
dir={direction}
{...field}
onValueChange={onChange}
>
<RadioGroup.ChoiceBox
value={PriceListType.SALE}
label={t("priceLists.fields.type.options.sale.label")}
@@ -130,7 +135,11 @@ export const PriceListEditForm = ({ priceList }: PriceListEditFormProps) => {
{t("priceLists.fields.status.label")}
</Form.Label>
<Form.Control>
<Select {...field} onValueChange={onChange}>
<Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>
@@ -21,6 +21,7 @@ import {
PriceListPricesAddProductsIdsFields,
PriceListPricesAddSchema,
} from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type PriceListPricesAddFormProps = {
priceList: HttpTypes.AdminPriceList
@@ -54,7 +55,7 @@ export const PriceListPricesAddForm = ({
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<PriceListPricesAddSchema>({
defaultValues: {
products: {},
@@ -90,10 +91,13 @@ export const PriceListPricesAddForm = ({
) => {
form.clearErrors(fields)
const values = fields.reduce((acc, key) => {
acc[key] = form.getValues(key)
return acc
}, {} as Record<string, unknown>)
const values = fields.reduce(
(acc, key) => {
acc[key] = form.getValues(key)
return acc
},
{} as Record<string, unknown>
)
const validationResult = schema.safeParse(values)
@@ -196,6 +200,7 @@ export const PriceListPricesAddForm = ({
return (
<RouteFocusModal.Form form={form}>
<ProgressTabs
dir={direction}
value={tab}
onValueChange={(tab) => handleChangeTab(tab as Tab)}
className="flex h-full flex-col overflow-hidden"
@@ -269,7 +269,9 @@ export const ProductEditVariantForm = ({
</Form.Label>
<Form.Control>
<Switch
dir="ltr"
checked={value}
className="rtl:rotate-180"
onCheckedChange={(checked) => onChange(!!checked)}
{...field}
/>
@@ -297,6 +299,8 @@ export const ProductEditVariantForm = ({
</Form.Label>
<Form.Control>
<Switch
dir="ltr"
className="rtl:rotate-180"
checked={value}
onCheckedChange={(checked) => onChange(!!checked)}
{...field}
@@ -277,14 +277,14 @@ export const CategoryCombobox = forwardRef<
e.preventDefault()
onChange([])
}}
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 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 flex h-[28px] items-center rounded-[4px] border py-[3px] ps-1.5 pe-1 outline-none"
>
<span className="tabular-nums">{value.length}</span>
<XMarkMini className="text-ui-fg-muted" />
</button>
)}
{showSelected && (
<div className="pointer-events-none absolute inset-y-0 left-[calc(var(--tag-width)+8px)] flex size-full items-center">
<div className="pointer-events-none absolute inset-y-0 start-[calc(var(--tag-width)+8px)] flex size-full items-center">
<Text size="small" leading="compact">
{t("general.selected")}
</Text>
@@ -297,13 +297,13 @@ export const CategoryCombobox = forwardRef<
onSearchValueChange(e.target.value)
}}
className={clx(
"txt-compact-small size-full cursor-pointer appearance-none bg-transparent pr-8 outline-none",
"txt-compact-small size-full cursor-pointer appearance-none bg-transparent pe-8 outline-none",
"hover:bg-ui-bg-field-hover",
"focus:cursor-text",
"placeholder:text-ui-fg-muted",
{
"pl-2": !showTag,
"pl-[calc(var(--tag-width)+8px)]": showTag,
"ps-2": !showTag,
"ps-[calc(var(--tag-width)+8px)]": showTag,
}
)}
{...props}
@@ -311,7 +311,7 @@ export const CategoryCombobox = forwardRef<
<button
type="button"
onClick={() => handleOpenChange(true)}
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 className="text-ui-fg-muted" />
</button>
@@ -321,11 +321,11 @@ export const CategoryCombobox = forwardRef<
sideOffset={4}
role="listbox"
className={clx(
"shadow-elevation-flyout bg-ui-bg-base -left-2 z-50 w-[var(--radix-popper-anchor-width)] rounded-[8px]",
"shadow-elevation-flyout bg-ui-bg-base -start-2 z-50 w-[var(--radix-popper-anchor-width)] rounded-[8px]",
"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"
)}
onInteractOutside={(e) => {
e.preventDefault()
@@ -346,7 +346,7 @@ export const CategoryCombobox = forwardRef<
data-active={focusedIndex === 0}
role="button"
className={clx(
"transition-fg grid w-full appearance-none grid-cols-[20px_1fr] items-center justify-center gap-2 rounded-md px-2 py-1.5 text-left outline-none",
"transition-fg grid w-full appearance-none grid-cols-[20px_1fr] items-center justify-center gap-2 rounded-md px-2 py-1.5 text-start outline-none",
"data-[active=true]:bg-ui-bg-field-hover"
)}
type="button"
@@ -386,7 +386,7 @@ export const CategoryCombobox = forwardRef<
type="button"
role="option"
className={clx(
"grid h-full w-full appearance-none grid-cols-[20px_1fr] items-center gap-2 overflow-hidden rounded-md px-2 py-1.5 text-left outline-none",
"grid h-full w-full appearance-none grid-cols-[20px_1fr] items-center gap-2 overflow-hidden rounded-md px-2 py-1.5 text-start outline-none",
"data-[active=true]:bg-ui-bg-field-hover"
)}
onClick={handleSelect(option)}
@@ -418,7 +418,7 @@ export const CategoryCombobox = forwardRef<
onClick={handleLevelDown(option)}
tabIndex={-1}
>
<TriangleRightMini />
<TriangleRightMini className="rtl:rotate-180" />
</button>
)}
</div>
@@ -26,6 +26,7 @@ import {
import DetailsTab from "./details-tab"
import InventoryKitTab from "./inventory-kit-tab"
import PricingTab from "./pricing-tab"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
enum Tab {
DETAIL = "detail",
@@ -50,7 +51,7 @@ export const CreateProductVariantForm = ({
}: CreateProductVariantFormProps) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const [tab, setTab] = useState<Tab>(Tab.DETAIL)
const [tabState, setTabState] = useState<TabState>(initialTabState)
@@ -75,10 +76,13 @@ export const CreateProductVariantForm = ({
return {}
}
return regions.reduce((acc, reg) => {
acc[reg.id] = reg.currency_code
return acc
}, {} as Record<string, string>)
return regions.reduce(
(acc, reg) => {
acc[reg.id] = reg.currency_code
return acc
},
{} as Record<string, string>
)
}, [regions])
const isManageInventoryEnabled = useWatch({
@@ -257,6 +261,7 @@ export const CreateProductVariantForm = ({
return (
<RouteFocusModal.Form form={form}>
<ProgressTabs
dir={direction}
value={tab}
onValueChange={(tab) => handleChangeTab(tab as Tab)}
className="flex h-full flex-col overflow-hidden"
@@ -99,7 +99,8 @@ function DetailsTab({ form, product }: DetailsTabProps) {
<div className="bg-ui-bg-component shadow-elevation-card-rest flex gap-x-3 rounded-lg p-4">
<Form.Control>
<Switch
className="mt-[2px]"
dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={value}
onCheckedChange={(checked) => onChange(!!checked)}
{...field}
@@ -130,6 +131,8 @@ function DetailsTab({ form, product }: DetailsTabProps) {
<div className="bg-ui-bg-component shadow-elevation-card-rest flex gap-x-3 rounded-lg p-4">
<Form.Control>
<Switch
dir="ltr"
className="rtl:rotate-180"
checked={value}
onCheckedChange={(checked) => onChange(!!checked)}
{...field}
@@ -159,6 +162,8 @@ function DetailsTab({ form, product }: DetailsTabProps) {
<div className="bg-ui-bg-component shadow-elevation-card-rest flex gap-x-3 rounded-lg p-4">
<Form.Control>
<Switch
dir="ltr"
className="rtl:rotate-180"
checked={value}
onCheckedChange={(checked) => onChange(!!checked)}
{...field}
@@ -21,6 +21,7 @@ import { ProductCreateDetailsForm } from "../product-create-details-form"
import { ProductCreateInventoryKitForm } from "../product-create-inventory-kit-form"
import { ProductCreateOrganizeForm } from "../product-create-organize-form"
import { ProductCreateVariantsForm } from "../product-create-variants-form"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
enum Tab {
DETAILS = "details",
@@ -58,7 +59,7 @@ export const ProductCreateForm = ({
const { handleSuccess } = useRouteModal()
const { getFormConfigs } = useExtension()
const configs = getFormConfigs("product", "create")
const direction = useDocumentDirection()
const form = useExtendableForm({
defaultValues: {
...PRODUCT_CREATE_FORM_DEFAULTS,
@@ -244,6 +245,7 @@ export const ProductCreateForm = ({
className="flex h-full flex-col"
>
<ProgressTabs
dir={direction}
value={tab}
onValueChange={async (tab) => {
const valid = await form.trigger()
@@ -13,6 +13,7 @@ import { transformNullableFormData } from "../../../../../lib/form-helpers"
import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { FormExtensionZone } from "../../../../../dashboard-app"
import { useExtension } from "../../../../../providers/extension-provider"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditProductFormProps = {
product: HttpTypes.AdminProduct
@@ -31,7 +32,7 @@ const EditProductSchema = zod.object({
export const EditProductForm = ({ product }: EditProductFormProps) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const { getFormFields, getFormConfigs } = useExtension()
const fields = getFormFields("product", "edit")
const configs = getFormConfigs("product", "edit")
@@ -97,7 +98,11 @@ export const EditProductForm = ({ product }: EditProductFormProps) => {
<Form.Item>
<Form.Label>{t("fields.status")}</Form.Label>
<Form.Control>
<Select {...field} onValueChange={onChange}>
<Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>
@@ -261,7 +261,7 @@ const Preview = ({
type="button"
onClick={prev}
>
<TriangleLeftMini />
<TriangleLeftMini className="rtl:rotate-180" />
</IconButton>
<div className="flex items-center gap-x-2">
{visibleItems.map((item) => {
@@ -292,7 +292,7 @@ const Preview = ({
type="button"
onClick={next}
>
<TriangleRightMini />
<TriangleRightMini className="rtl:rotate-180" />
</IconButton>
</div>
)
@@ -192,7 +192,8 @@ export const useProductStockColumns = (
return (
<div className="flex size-full items-center gap-x-2">
<Switch
className="shrink-0 cursor-not-allowed"
dir="ltr"
className="shrink-0 cursor-not-allowed rtl:rotate-180"
tabIndex={-1}
size="small"
checked={checked}
@@ -10,6 +10,7 @@ import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useUpdateUser } from "../../../../../hooks/api/users"
import { languages } from "../../../../../i18n/languages"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditProfileProps = {
user: HttpTypes.AdminUser
@@ -26,7 +27,7 @@ const EditProfileSchema = zod.object({
export const EditProfileForm = ({ user }: EditProfileProps) => {
const { t, i18n } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<zod.infer<typeof EditProfileSchema>>({
defaultValues: {
first_name: user.first_name ?? "",
@@ -111,7 +112,11 @@ export const EditProfileForm = ({ user }: EditProfileProps) => {
</div>
<div>
<Form.Control>
<Select {...field} onValueChange={field.onChange}>
<Select
dir={direction}
{...field}
onValueChange={field.onChange}
>
<Select.Trigger ref={ref} className="py-1 text-[13px]">
<Select.Value
placeholder={t("profile.edit.languagePlaceholder")}
@@ -151,7 +156,8 @@ export const EditProfileForm = ({ user }: EditProfileProps) => {
{t("profile.fields.usageInsightsLabel")}
</Form.Label>
<Form.Control>
<Switch
<Switch dir="ltr"
className="rtl:rotate-180"
{...rest}
checked={value}
onCheckedChange={onChange}
@@ -14,6 +14,7 @@ import {
usePromotionRuleAttributes,
usePromotionRules,
} from "../../../../../../hooks/api/promotions"
import { useDocumentDirection } from "../../../../../../hooks/use-document-direction"
import { CreatePromotionSchemaType } from "../../../../promotion-create/components/create-promotion-form/form-schema"
import { generateRuleAttributes } from "../edit-rules-form/utils"
import { RuleValueFormField } from "../rule-value-form-field"
@@ -44,6 +45,7 @@ export const RulesFormField = ({
const initialRulesSet = useRef(false)
const { t } = useTranslation()
const direction = useDocumentDirection()
const formData = form.getValues()
const { attributes } = usePromotionRuleAttributes(
ruleType,
@@ -224,6 +226,7 @@ export const RulesFormField = ({
<Form.Control>
{!disabled ? (
<Select
dir={direction}
{...fieldProps}
onValueChange={onValueChange}
disabled={fieldRule.required}
@@ -294,6 +297,7 @@ export const RulesFormField = ({
<Form.Control>
{!disabled ? (
<Select
dir= {direction}
{...fieldProps}
disabled={!fieldRule.attribute}
onValueChange={onChange}
@@ -11,6 +11,7 @@ import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useUpdatePromotion } from "../../../../../hooks/api/promotions"
import { CreateCampaignFormFields } from "../../../../campaigns/common/components/create-campaign-form-fields"
import { CampaignDetails } from "./campaign-details"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditPromotionFormProps = {
promotion: AdminPromotion
@@ -43,7 +44,7 @@ export const AddCampaignPromotionFields = ({
})
const selectedCampaign = campaigns.find((c) => c.id === watchCampaignId)
const direction = useDocumentDirection()
return (
<div className="flex flex-col gap-y-8">
<Form.Field
@@ -56,6 +57,7 @@ export const AddCampaignPromotionFields = ({
<Form.Control>
<RadioGroup
dir={direction}
className="grid grid-cols-1 gap-3"
{...field}
value={field.value}
@@ -105,7 +107,11 @@ export const AddCampaignPromotionFields = ({
</Form.Label>
<Form.Control>
<Select onValueChange={onChange} {...field}>
<Select
dir={direction}
onValueChange={onChange}
{...field}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>
@@ -46,6 +46,7 @@ import { AddCampaignPromotionFields } from "../../../promotion-add-campaign/comp
import { Tab } from "./constants"
import { CreatePromotionSchema } from "./form-schema"
import { templates } from "./templates"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
const defaultValues = {
campaign_id: undefined,
@@ -80,7 +81,7 @@ export const CreatePromotionForm = () => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof CreatePromotionSchema>>({
defaultValues,
resolver: zodResolver(CreatePromotionSchema),
@@ -364,6 +365,7 @@ export const CreatePromotionForm = () => {
<RouteFocusModal.Form form={form}>
<KeyboundForm className="flex h-full flex-col" onSubmit={handleSubmit}>
<ProgressTabs
dir={direction}
value={tab}
onValueChange={(tab) => handleTabChange(tab as Tab)}
className="flex h-full flex-col overflow-hidden"
@@ -417,6 +419,7 @@ export const CreatePromotionForm = () => {
<Form.Control>
<RadioGroup
dir={direction}
key={"template_id"}
className="flex-col gap-y-3"
{...field}
@@ -486,6 +489,7 @@ export const CreatePromotionForm = () => {
<Form.Control>
<RadioGroup
dir={direction}
className="flex gap-y-3"
{...field}
value={field.value}
@@ -530,6 +534,7 @@ export const CreatePromotionForm = () => {
<Form.Control>
<RadioGroup
dir={direction}
className="flex gap-y-3"
{...field}
value={field.value}
@@ -619,7 +624,8 @@ export const CreatePromotionForm = () => {
</div>
<Form.Control className="mr-2 self-center">
<Switch
className="mt-[2px]"
dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={!!value}
onCheckedChange={onChange}
{...field}
@@ -647,6 +653,7 @@ export const CreatePromotionForm = () => {
</Form.Label>
<Form.Control>
<RadioGroup
dir={direction}
className="flex gap-y-3"
{...field}
onValueChange={field.onChange}
@@ -699,7 +706,8 @@ export const CreatePromotionForm = () => {
</Form.Label>
<Form.Control>
<RadioGroup
className="flex gap-y-3"
dir={direction}
className="flex gap-y-3"
{...field}
onValueChange={field.onChange}
>
@@ -889,6 +897,7 @@ export const CreatePromotionForm = () => {
<Form.Control>
<RadioGroup
dir={direction}
className="flex gap-y-3"
{...field}
onValueChange={field.onChange}
@@ -16,6 +16,7 @@ import {
getCurrencySymbol,
} from "../../../../../lib/data/currencies"
import { SwitchBox } from "../../../../../components/common/switch-box"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditPromotionFormProps = {
promotion: AdminPromotion
@@ -99,7 +100,7 @@ export const EditPromotionDetailsForm = ({
form.setValue("is_tax_inclusive", false)
}
}, [allocationWatchValue, form, promotion])
const direction = useDocumentDirection()
return (
<RouteDrawer.Form form={form}>
<KeyboundForm
@@ -117,6 +118,7 @@ export const EditPromotionDetailsForm = ({
<Form.Label>{t("promotions.form.status.label")}</Form.Label>
<Form.Control>
<RadioGroup
dir={direction}
className="flex-col gap-y-3"
{...field}
value={field.value}
@@ -162,6 +164,7 @@ export const EditPromotionDetailsForm = ({
<Form.Label>{t("promotions.form.method.label")}</Form.Label>
<Form.Control>
<RadioGroup
dir={direction}
className="flex-col gap-y-3"
{...field}
value={field.value}
@@ -242,6 +245,7 @@ export const EditPromotionDetailsForm = ({
</Form.Label>
<Form.Control>
<RadioGroup
dir={direction}
className="flex-col gap-y-3"
{...field}
onValueChange={field.onChange}
@@ -336,6 +340,7 @@ export const EditPromotionDetailsForm = ({
</Form.Label>
<Form.Control>
<RadioGroup
dir={direction}
className="flex-col gap-y-3"
{...field}
onValueChange={field.onChange}
@@ -37,6 +37,7 @@ import { formatProvider } from "../../../../../lib/format-provider"
import { useCountries } from "../../../common/hooks/use-countries"
import { useCountryTableColumns } from "../../../common/hooks/use-country-table-columns"
import { useCountryTableQuery } from "../../../common/hooks/use-country-table-query"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type CreateRegionFormProps = {
currencies: CurrencyInfo[]
@@ -64,7 +65,7 @@ export const CreateRegionForm = ({
const { setIsOpen } = useStackedModal()
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<zod.infer<typeof CreateRegionSchema>>({
defaultValues: {
name: "",
@@ -226,7 +227,11 @@ export const CreateRegionForm = ({
<Form.Item>
<Form.Label>{t("fields.currency")}</Form.Label>
<Form.Control>
<Select {...field} onValueChange={onChange}>
<Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>
@@ -260,6 +265,8 @@ export const CreateRegionForm = ({
<Form.Label>{t("fields.automaticTaxes")}</Form.Label>
<Form.Control>
<Switch
dir="ltr"
className="rtl:rotate-180"
{...field}
checked={value}
onCheckedChange={onChange}
@@ -287,6 +294,8 @@ export const CreateRegionForm = ({
</Form.Label>
<Form.Control>
<Switch
className="rtl:rotate-180"
dir="ltr"
{...field}
checked={value}
onCheckedChange={onChange}
@@ -14,6 +14,7 @@ import { KeyboundForm } from "../../../../../components/utilities/keybound-form/
import { useUpdateRegion } from "../../../../../hooks/api/regions.tsx"
import { CurrencyInfo } from "../../../../../lib/data/currencies.ts"
import { formatProvider } from "../../../../../lib/format-provider.ts"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditRegionFormProps = {
region: HttpTypes.AdminRegion
@@ -42,7 +43,7 @@ export const EditRegionForm = ({
(preference) =>
preference.attribute === "region_id" && preference.value === region.id
)
const direction = useDocumentDirection()
const form = useForm<zod.infer<typeof EditRegionSchema>>({
defaultValues: {
name: region.name,
@@ -106,7 +107,11 @@ export const EditRegionForm = ({
<Form.Item>
<Form.Label>{t("fields.currency")}</Form.Label>
<Form.Control>
<Select onValueChange={onChange} {...field}>
<Select
dir={direction}
onValueChange={onChange}
{...field}
>
<Select.Trigger ref={ref}>
<Select.Value />
</Select.Trigger>
@@ -137,6 +142,8 @@ export const EditRegionForm = ({
<Form.Label>{t("fields.automaticTaxes")}</Form.Label>
<Form.Control>
<Switch
dir="ltr"
className="rtl:rotate-180"
{...field}
checked={value}
onCheckedChange={onChange}
@@ -164,6 +171,8 @@ export const EditRegionForm = ({
</Form.Label>
<Form.Control>
<Switch
dir="ltr"
className="rtl:rotate-180"
{...field}
checked={value}
onCheckedChange={onChange}
@@ -10,6 +10,7 @@ import { z } from "zod"
import { Form } from "../../../../../../components/common/form"
import { KeyboundForm } from "../../../../../../components/utilities/keybound-form"
import { useUpdateReservationItem } from "../../../../../../hooks/api/reservations"
import { useDocumentDirection } from "../../../../../../hooks/use-document-direction"
type EditReservationFormProps = {
reservation: HttpTypes.AdminReservationResponse["reservation"]
@@ -59,7 +60,7 @@ export const EditReservationForm = ({
}: EditReservationFormProps) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<zod.infer<typeof EditReservationSchema>>({
defaultValues: getDefaultValues(reservation),
resolver: zodResolver(EditReservationSchema),
@@ -102,6 +103,7 @@ export const EditReservationForm = ({
<Form.Label>{t("inventory.reservation.location")}</Form.Label>
<Form.Control>
<Select
dir={direction}
value={value}
onValueChange={(v) => {
onChange(v)
@@ -119,6 +119,8 @@ export const CreateSalesChannelForm = () => {
<Form.Label>{t("general.enabled")}</Form.Label>
<Form.Control>
<Switch
dir="ltr"
className="rtl:rotate-180"
{...field}
checked={value}
onCheckedChange={onChange}
@@ -103,6 +103,8 @@ export const EditSalesChannelForm = ({
<Form.Label>{t("general.enabled")}</Form.Label>
<Form.Control>
<Switch
dir="ltr"
className="rtl:rotate-180"
onCheckedChange={onChange}
checked={value}
{...field}
@@ -287,6 +287,8 @@ const useColumns = (
return (
<div className="flex items-center justify-end">
<Switch
dir="ltr"
className="rtl:rotate-180"
disabled={isPreSelected}
checked={isTaxInclusive ?? false}
onCheckedChange={(val) => {
@@ -12,6 +12,7 @@ import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useUpdateStore } from "../../../../../hooks/api/store"
import { useComboboxData } from "../../../../../hooks/use-combobox-data"
import { sdk } from "../../../../../lib/client"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditStoreFormProps = {
store: HttpTypes.AdminStore
@@ -28,7 +29,7 @@ const EditStoreSchema = z.object({
export const EditStoreForm = ({ store }: EditStoreFormProps) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof EditStoreSchema>>({
defaultValues: {
name: store.name,
@@ -118,7 +119,11 @@ export const EditStoreForm = ({ store }: EditStoreFormProps) => {
<Form.Item>
<Form.Label>{t("store.defaultCurrency")}</Form.Label>
<Form.Control>
<Select {...field} onValueChange={onChange}>
<Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={field.ref}>
<Select.Value />
</Select.Trigger>
@@ -36,6 +36,7 @@ import {
TaxRateRuleReferenceSchema,
} from "../../../common/schemas"
import { createTaxRulePayload } from "../../../common/utils"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
const TaxRegionCreateTaxOverrideSchema = z.object({
name: z.string().min(1),
@@ -77,7 +78,7 @@ export const TaxRegionCreateTaxOverrideForm = ({
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const { setIsOpen } = useStackedModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof TaxRegionCreateTaxOverrideSchema>>({
defaultValues: {
name: "",
@@ -547,6 +548,7 @@ export const TaxRegionCreateTaxOverrideForm = ({
<div className="text-ui-fg-subtle grid gap-1.5 px-1.5 md:grid-cols-2">
{isLast ? (
<Select
dir={direction}
value={type}
onValueChange={handleChangeType}
>
@@ -37,6 +37,7 @@ import {
} from "../../../common/schemas"
import { createTaxRulePayload } from "../../../common/utils"
import { InitialRuleValues } from "../../types"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
export const DISPLAY_OVERRIDE_ITEMS_LIMIT = 10
@@ -81,7 +82,7 @@ export const TaxRegionTaxOverrideEditForm = ({
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const { setIsOpen } = useStackedModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof TaxRegionTaxRateEditSchema>>({
defaultValues: {
name: taxRate.name,
@@ -514,6 +515,7 @@ export const TaxRegionTaxOverrideEditForm = ({
<div className="text-ui-fg-subtle grid gap-1.5 px-1.5 md:grid-cols-2">
{isLast ? (
<Select
dir={direction}
value={type}
onValueChange={handleChangeType}
>
@@ -18,6 +18,7 @@ import {
STEP_OK_STATES,
STEP_SKIPPED_STATES,
} from "../../../constants"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type WorkflowExecutionTimelineSectionProps = {
execution: HttpTypes.AdminWorkflowExecutionResponse["workflow_execution"]
@@ -87,7 +88,7 @@ const Canvas = ({
}) => {
const [zoom, setZoom] = useState<number>(1)
const [isDragging, setIsDragging] = useState(false)
const direction = useDocumentDirection()
const scale = useMotionValue(defaultState.scale)
const x = useMotionValue(defaultState.x)
const y = useMotionValue(defaultState.y)
@@ -217,7 +218,7 @@ const Canvas = ({
<PlusMini />
</button>
<div>
<DropdownMenu>
<DropdownMenu dir={direction}>
<DropdownMenu.Trigger className="disabled:text-ui-fg-disabled transition-fg hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed focus-visible:bg-ui-bg-base-pressed flex w-[50px] items-center justify-center border-r p-1 outline-none">
<Text
as="span"