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 MustafaandWilliam Bouchard authored and GitHub committed 2025-09-23 11:11:30 -04:00
1 parent a501364b2d
commit a75cf7fb36
70 files changed
+407 -142

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/dashboard": patch
---
feat(dashboard): support RTL in dashboard
@@ -4,6 +4,7 @@ import { EllipsisHorizontal } from "@medusajs/icons"
import { PropsWithChildren, ReactNode } from "react" import { PropsWithChildren, ReactNode } from "react"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
import { ConditionalTooltip } from "../conditional-tooltip" import { ConditionalTooltip } from "../conditional-tooltip"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
export type Action = { export type Action = {
icon: ReactNode icon: ReactNode
@@ -38,6 +39,7 @@ export const ActionMenu = ({
variant = "transparent", variant = "transparent",
children, children,
}: ActionMenuProps) => { }: ActionMenuProps) => {
const direction = useDocumentDirection()
const inner = children ?? ( const inner = children ?? (
<IconButton size="small" variant={variant}> <IconButton size="small" variant={variant}>
<EllipsisHorizontal /> <EllipsisHorizontal />
@@ -45,7 +47,7 @@ export const ActionMenu = ({
) )
return ( return (
<DropdownMenu> <DropdownMenu dir={direction}>
<DropdownMenu.Trigger asChild>{inner}</DropdownMenu.Trigger> <DropdownMenu.Trigger asChild>{inner}</DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
{groups.map((group, index) => { {groups.map((group, index) => {
@@ -46,7 +46,10 @@ export const JsonViewSection = ({ data }: JsonViewSectionProps) => {
<ArrowUpRightOnBox /> <ArrowUpRightOnBox />
</IconButton> </IconButton>
</Drawer.Trigger> </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="bg-ui-code-bg-base flex items-center justify-between px-6 py-4">
<div className="flex items-center gap-x-4"> <div className="flex items-center gap-x-4">
<Drawer.Title asChild> <Drawer.Title asChild>
@@ -37,7 +37,7 @@ export const SidebarLink = ({
</Text> </Text>
</div> </div>
<div className="flex size-7 items-center justify-center"> <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> </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"> <div className="bg-ui-bg-component shadow-elevation-card-rest flex items-start gap-x-3 rounded-lg p-3">
<Form.Control> <Form.Control>
<Switch <Switch
className="rtl:rotate-180"
dir="ltr"
{...field} {...field}
checked={value} checked={value}
onCheckedChange={(e) => { onCheckedChange={(e) => {
@@ -29,6 +29,7 @@ import { FieldValues, UseFormReturn } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { useCommandHistory } from "../../../hooks/use-command-history" import { useCommandHistory } from "../../../hooks/use-command-history"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
import { ConditionalTooltip } from "../../common/conditional-tooltip" import { ConditionalTooltip } from "../../common/conditional-tooltip"
import { DataGridContext } from "../context" import { DataGridContext } from "../context"
import { import {
@@ -50,7 +51,7 @@ import { isCellMatch, isSpecialFocusKey } from "../utils"
import { DataGridKeyboardShortcutModal } from "./data-grid-keyboard-shortcut-modal" import { DataGridKeyboardShortcutModal } from "./data-grid-keyboard-shortcut-modal"
export interface DataGridRootProps< export interface DataGridRootProps<
TData, TData,
TFieldValues extends FieldValues = FieldValues TFieldValues extends FieldValues = FieldValues,
> { > {
data?: TData[] data?: TData[]
columns: ColumnDef<TData>[] columns: ColumnDef<TData>[]
@@ -96,7 +97,7 @@ const getCommonPinningStyles = <TData,>(
export const DataGridRoot = < export const DataGridRoot = <
TData, TData,
TFieldValues extends FieldValues = FieldValues TFieldValues extends FieldValues = FieldValues,
>({ >({
data = [], data = [],
columns, columns,
@@ -700,6 +701,7 @@ const DataGridHeader = ({
const [shortcutsOpen, setShortcutsOpen] = useState(false) const [shortcutsOpen, setShortcutsOpen] = useState(false)
const [columnsOpen, setColumnsOpen] = useState(false) const [columnsOpen, setColumnsOpen] = useState(false)
const { t } = useTranslation() const { t } = useTranslation()
const direction = useDocumentDirection()
// Since all columns are checked by default, we can check if any column is unchecked // Since all columns are checked by default, we can check if any column is unchecked
const hasChanged = columnOptions.some((column) => !column.checked) const hasChanged = columnOptions.some((column) => !column.checked)
@@ -716,7 +718,11 @@ const DataGridHeader = ({
return ( return (
<div className="bg-ui-bg-base flex items-center justify-between border-b p-4"> <div className="bg-ui-bg-base flex items-center justify-between border-b p-4">
<div className="flex items-center gap-x-2"> <div className="flex items-center gap-x-2">
<DropdownMenu open={columnsOpen} onOpenChange={handleColumnsOpenChange}> <DropdownMenu
dir={direction}
open={columnsOpen}
onOpenChange={handleColumnsOpenChange}
>
<ConditionalTooltip <ConditionalTooltip
showTooltip={isDisabled} showTooltip={isDisabled}
content={t("dataGrid.columns.disabled")} 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"> <div className="absolute inset-y-0 left-4 z-[3] flex w-fit items-center justify-center">
<Switch <Switch
dir="ltr"
ref={buttonRef} ref={buttonRef}
size="small" size="small"
className="shrink-0" className="shrink-0 rtl:rotate-180"
checked={localValue.checked} checked={localValue.checked}
disabled={localValue.disabledToggle} disabled={localValue.disabledToggle}
onCheckedChange={handleCheckedChange} onCheckedChange={handleCheckedChange}
@@ -1,6 +1,7 @@
import { Button, DropdownMenu } from "@medusajs/ui" import { Button, DropdownMenu } from "@medusajs/ui"
import { ReactNode } from "react" import { ReactNode } from "react"
import { useSearchParams } from "react-router-dom" import { useSearchParams } from "react-router-dom"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
type FilterGroupProps = { type FilterGroupProps = {
filters: { filters: {
@@ -37,8 +38,11 @@ type AddFilterMenuProps = {
} }
const AddFilterMenu = ({ availableKeys }: AddFilterMenuProps) => { const AddFilterMenu = ({ availableKeys }: AddFilterMenuProps) => {
const direction = useDocumentDirection()
return ( return (
<DropdownMenu> <DropdownMenu
dir={direction}
>
<DropdownMenu.Trigger asChild> <DropdownMenu.Trigger asChild>
<Button variant="secondary" size="small"> <Button variant="secondary" size="small">
Add filter Add filter
@@ -4,6 +4,8 @@ import { useState } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { useSearchParams } from "react-router-dom" import { useSearchParams } from "react-router-dom"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
type OrderByProps = { type OrderByProps = {
keys: string[] keys: string[]
} }
@@ -56,6 +58,7 @@ export const OrderBy = ({ keys }: OrderByProps) => {
}>(initState(searchParams)) }>(initState(searchParams))
const { t } = useTranslation() const { t } = useTranslation()
const direction = useDocumentDirection()
const handleDirChange = (dir: string) => { const handleDirChange = (dir: string) => {
setState((prev) => ({ setState((prev) => ({
@@ -99,7 +102,7 @@ export const OrderBy = ({ keys }: OrderByProps) => {
} }
return ( return (
<DropdownMenu> <DropdownMenu dir={direction}>
<DropdownMenu.Trigger asChild> <DropdownMenu.Trigger asChild>
<IconButton size="small"> <IconButton size="small">
<ArrowUpDown /> <ArrowUpDown />
@@ -7,6 +7,7 @@ import { Control } from "react-hook-form"
import { AddressSchema } from "../../../lib/schemas" import { AddressSchema } from "../../../lib/schemas"
import { Form } from "../../common/form" import { Form } from "../../common/form"
import { CountrySelect } from "../../inputs/country-select" import { CountrySelect } from "../../inputs/country-select"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
type AddressFieldValues = z.infer<typeof AddressSchema> type AddressFieldValues = z.infer<typeof AddressSchema>
@@ -22,7 +23,7 @@ export const AddressForm = ({
layout, layout,
}: AddressFormProps) => { }: AddressFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const direction = useDocumentDirection()
const style = clx("gap-4", { const style = clx("gap-4", {
"flex flex-col": layout === "stack", "flex flex-col": layout === "stack",
"grid grid-cols-2": layout === "grid", "grid grid-cols-2": layout === "grid",
@@ -182,7 +183,11 @@ export const AddressForm = ({
<Form.Label>{t("fields.country")}</Form.Label> <Form.Label>{t("fields.country")}</Form.Label>
<Form.Control> <Form.Control>
{countries ? ( {countries ? (
<Select {...field} onValueChange={onChange}> <Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -25,6 +25,7 @@ import { Form } from "../../common/form"
import { Skeleton } from "../../common/skeleton" import { Skeleton } from "../../common/skeleton"
import { RouteDrawer, useRouteModal } from "../../modals" import { RouteDrawer, useRouteModal } from "../../modals"
import { KeyboundForm } from "../../utilities/keybound-form" import { KeyboundForm } from "../../utilities/keybound-form"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
type MetaDataSubmitHook<TRes> = ( type MetaDataSubmitHook<TRes> = (
params: { metadata?: Record<string, any> | null }, params: { metadata?: Record<string, any> | null },
@@ -77,7 +78,7 @@ const InnerForm = <TRes,>({
}: Omit<MetadataFormProps<TRes>, "isPending">) => { }: Omit<MetadataFormProps<TRes>, "isPending">) => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const hasUneditableRows = getHasUneditableRows(metadata) const hasUneditableRows = getHasUneditableRows(metadata)
const form = useForm<z.infer<typeof MetadataSchema>>({ const form = useForm<z.infer<typeof MetadataSchema>>({
@@ -215,10 +216,12 @@ const InnerForm = <TRes,>({
}} }}
/> />
</div> </div>
<DropdownMenu> <DropdownMenu
dir={direction}
>
<DropdownMenu.Trigger <DropdownMenu.Trigger
className={clx( 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, hidden: isDisabled,
} }
@@ -251,7 +251,7 @@ const ComboboxImpl = <T extends Value = string>(
e.preventDefault() e.preventDefault()
handleValueChange(isArrayValue ? ([] as unknown as T) : undefined) 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> <span className="tabular-nums">{selectedValues.length}</span>
<XMarkMini className="text-ui-fg-muted" /> <XMarkMini className="text-ui-fg-muted" />
@@ -263,8 +263,8 @@ const ComboboxImpl = <T extends Value = string>(
className={clx( className={clx(
"pointer-events-none absolute inset-y-0 flex size-full items-center", "pointer-events-none absolute inset-y-0 flex size-full items-center",
{ {
"left-[calc(var(--tag-width)+8px)]": showTag, "start-[calc(var(--tag-width)+8px)]": showTag,
"left-2": !showTag, "start-2": !showTag,
} }
)} )}
> >
@@ -278,8 +278,8 @@ const ComboboxImpl = <T extends Value = string>(
className={clx( className={clx(
"pointer-events-none absolute inset-y-0 flex size-full items-center overflow-hidden", "pointer-events-none absolute inset-y-0 flex size-full items-center overflow-hidden",
{ {
"left-[calc(var(--tag-width)+8px)]": showTag, "start-[calc(var(--tag-width)+8px)]": showTag,
"left-2": !showTag, "start-2": !showTag,
} }
)} )}
> >
@@ -293,12 +293,12 @@ const ComboboxImpl = <T extends Value = string>(
ref={comboboxRef} ref={comboboxRef}
onFocus={() => setOpen(true)} onFocus={() => setOpen(true)}
className={clx( 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", "hover:bg-ui-bg-field-hover",
{ {
"opacity-0": hideInput, "opacity-0": hideInput,
"pl-2": !showTag, "ps-2": !showTag,
"pl-[calc(var(--tag-width)+8px)]": showTag, "ps-[calc(var(--tag-width)+8px)]": showTag,
} }
)} )}
placeholder={hidePlaceholder ? undefined : placeholder} placeholder={hidePlaceholder ? undefined : placeholder}
@@ -312,7 +312,7 @@ const ComboboxImpl = <T extends Value = string>(
e.preventDefault() e.preventDefault()
handleValueChange(undefined) 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" /> <XMarkMini className="text-ui-fg-muted" />
</button> </button>
@@ -323,7 +323,7 @@ const ComboboxImpl = <T extends Value = string>(
<button <button
{...props} {...props}
type="button" 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 /> <TrianglesMini />
</button> </button>
@@ -341,7 +341,7 @@ const ComboboxImpl = <T extends Value = string>(
"max-h-[200px] overflow-y-auto", "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=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-[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={{ style={{
pointerEvents: open ? "auto" : "none", pointerEvents: open ? "auto" : "none",
@@ -33,7 +33,7 @@ export const CountrySelect = forwardRef<
<div className="relative"> <div className="relative">
<TrianglesMini <TrianglesMini
className={clx( 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, "text-ui-fg-disabled": disabled,
} }
@@ -76,7 +76,7 @@ export const ProvinceSelect = forwardRef<
<div className="relative"> <div className="relative">
<TrianglesMini <TrianglesMini
className={clx( 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, "text-ui-fg-disabled": disabled,
} }
@@ -29,6 +29,7 @@ import { queryClient } from "../../../lib/query-client"
import { useExtension } from "../../../providers/extension-provider" import { useExtension } from "../../../providers/extension-provider"
import { useSearch } from "../../../providers/search-provider" import { useSearch } from "../../../providers/search-provider"
import { UserMenu } from "../user-menu" import { UserMenu } from "../user-menu"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
export const MainLayout = () => { export const MainLayout = () => {
return ( return (
@@ -94,7 +95,7 @@ const Logout = () => {
const Header = () => { const Header = () => {
const { t } = useTranslation() const { t } = useTranslation()
const { store, isPending, isError, error } = useStore() const { store, isPending, isError, error } = useStore()
const direction = useDocumentDirection()
const name = store?.name const name = store?.name
const fallback = store?.name?.slice(0, 1).toUpperCase() const fallback = store?.name?.slice(0, 1).toUpperCase()
@@ -106,11 +107,12 @@ const Header = () => {
return ( return (
<div className="w-full p-3"> <div className="w-full p-3">
<DropdownMenu> <DropdownMenu
dir={direction}>
<DropdownMenu.Trigger <DropdownMenu.Trigger
disabled={!isLoaded} disabled={!isLoaded}
className={clx( 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", "hover:bg-ui-bg-subtle-hover",
"data-[state=open]:bg-ui-bg-subtle-hover", "data-[state=open]:bg-ui-bg-subtle-hover",
"focus-visible:shadow-borders-focus" "focus-visible:shadow-borders-focus"
@@ -121,7 +123,7 @@ const Header = () => {
) : ( ) : (
<Skeleton className="h-6 w-6 rounded-md" /> <Skeleton className="h-6 w-6 rounded-md" />
)} )}
<div className="block overflow-hidden text-left"> <div className="block overflow-hidden text-start">
{name ? ( {name ? (
<Text <Text
size="small" size="small"
@@ -267,7 +269,7 @@ const Searchbar = () => {
)} )}
> >
<MagnifyingGlass /> <MagnifyingGlass />
<div className="flex-1 text-left"> <div className="flex-1 text-start">
<Text size="small" leading="compact" weight="plus"> <Text size="small" leading="compact" weight="plus">
{t("app.search.label")} {t("app.search.label")}
</Text> </Text>
@@ -156,7 +156,7 @@ const Breadcrumbs = () => {
)} )}
{!isLast && ( {!isLast && (
<span className="mx-2"> <span className="mx-2">
<TriangleRightMini /> <TriangleRightMini className="rtl:rotate-180" />
</span> </span>
)} )}
</li> </li>
@@ -177,7 +177,7 @@ const ToggleSidebar = () => {
onClick={() => toggle("desktop")} onClick={() => toggle("desktop")}
size="small" size="small"
> >
<SidebarLeft className="text-ui-fg-muted" /> <SidebarLeft className="text-ui-fg-muted rtl:rotate-180" />
</IconButton> </IconButton>
<IconButton <IconButton
className="hidden max-lg:flex" className="hidden max-lg:flex"
@@ -185,7 +185,7 @@ const ToggleSidebar = () => {
onClick={() => toggle("mobile")} onClick={() => toggle("mobile")}
size="small" size="small"
> >
<SidebarLeft className="text-ui-fg-muted" /> <SidebarLeft className="text-ui-fg-muted rtl:rotate-180" />
</IconButton> </IconButton>
</div> </div>
) )
@@ -210,7 +210,7 @@ const DesktopSidebarContainer = ({ children }: PropsWithChildren) => {
return ( return (
<div <div
className={clx("hidden h-screen w-[220px] border-r", { className={clx("hidden h-screen w-[220px] border-e", {
"lg:flex": desktop, "lg:flex": desktop,
})} })}
> >
@@ -234,8 +234,8 @@ const MobileSidebarContainer = ({ children }: PropsWithChildren) => {
/> />
<RadixDialog.Content <RadixDialog.Content
className={clx( 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", "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-left-1/2 data-[state=open]:slide-in-from-left-1/2 duration-200" "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"> <div className="p-3">
@@ -29,10 +29,12 @@ import { useLogout, useMe } from "../../../hooks/api"
import { queryClient } from "../../../lib/query-client" import { queryClient } from "../../../lib/query-client"
import { useGlobalShortcuts } from "../../../providers/keybind-provider/hooks" import { useGlobalShortcuts } from "../../../providers/keybind-provider/hooks"
import { useTheme } from "../../../providers/theme-provider" import { useTheme } from "../../../providers/theme-provider"
import { useDocumentDirection } from "../../../hooks/use-document-direction"
export const UserMenu = () => { export const UserMenu = () => {
const { t } = useTranslation() const { t } = useTranslation()
const location = useLocation() const location = useLocation()
const direction = useDocumentDirection()
const [openMenu, setOpenMenu] = useState(false) const [openMenu, setOpenMenu] = useState(false)
const [openModal, setOpenModal] = useState(false) const [openModal, setOpenModal] = useState(false)
@@ -44,33 +46,33 @@ export const UserMenu = () => {
return ( return (
<div> <div>
<DropdownMenu open={openMenu} onOpenChange={setOpenMenu}> <DropdownMenu dir={direction} open={openMenu} onOpenChange={setOpenMenu}>
<UserBadge /> <UserBadge />
<DropdownMenu.Content className="min-w-[var(--radix-dropdown-menu-trigger-width)] max-w-[var(--radix-dropdown-menu-trigger-width)]"> <DropdownMenu.Content className="min-w-[var(--radix-dropdown-menu-trigger-width)] max-w-[var(--radix-dropdown-menu-trigger-width)]">
<UserItem /> <UserItem />
<DropdownMenu.Separator /> <DropdownMenu.Separator />
<DropdownMenu.Item asChild> <DropdownMenu.Item asChild>
<Link to="/settings/profile" state={{ from: location.pathname }}> <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")} {t("app.menus.user.profileSettings")}
</Link> </Link>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Separator /> <DropdownMenu.Separator />
<DropdownMenu.Item asChild> <DropdownMenu.Item asChild>
<Link to="https://docs.medusajs.com" target="_blank"> <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")} {t("app.menus.user.documentation")}
</Link> </Link>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item asChild> <DropdownMenu.Item asChild>
<Link to="https://medusajs.com/changelog/" target="_blank"> <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")} {t("app.menus.user.changelog")}
</Link> </Link>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Separator /> <DropdownMenu.Separator />
<DropdownMenu.Item onClick={toggleModal}> <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")} {t("app.menus.user.shortcuts")}
</DropdownMenu.Item> </DropdownMenu.Item>
<ThemeToggle /> <ThemeToggle />
@@ -93,7 +95,7 @@ const UserBadge = () => {
if (isPending) { if (isPending) {
return ( 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-5 w-5 rounded-full" />
<Skeleton className="h-[9px] w-[70px]" /> <Skeleton className="h-[9px] w-[70px]" />
</button> </button>
@@ -109,7 +111,7 @@ const UserBadge = () => {
<DropdownMenu.Trigger <DropdownMenu.Trigger
disabled={!user} disabled={!user}
className={clx( 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", "hover:bg-ui-bg-subtle-hover",
"data-[state=open]:bg-ui-bg-subtle-hover", "data-[state=open]:bg-ui-bg-subtle-hover",
"focus-visible:shadow-borders-focus" "focus-visible:shadow-borders-focus"
@@ -148,9 +150,9 @@ const ThemeToggle = () => {
return ( return (
<DropdownMenu.SubMenu> <DropdownMenu.SubMenu>
<DropdownMenu.SubMenuTrigger className="rounded-md"> <DropdownMenu.SubMenuTrigger dir="ltr" className="rounded-md rtl:rotate-180">
<CircleHalfSolid className="text-ui-fg-subtle mr-2" /> <CircleHalfSolid className="text-ui-fg-subtle me-2" />
{t("app.menus.user.theme.label")} <span className="rtl:rotate-180">{t("app.menus.user.theme.label")}</span>
</DropdownMenu.SubMenuTrigger> </DropdownMenu.SubMenuTrigger>
<DropdownMenu.SubMenuContent> <DropdownMenu.SubMenuContent>
<DropdownMenu.RadioGroup value={theme}> <DropdownMenu.RadioGroup value={theme}>
@@ -44,6 +44,7 @@ import {
} from "./constants" } from "./constants"
import { SearchArea } from "./types" import { SearchArea } from "./types"
import { useSearchResults } from "./use-search-results" import { useSearchResults } from "./use-search-results"
import { useDocumentDirection } from "../../hooks/use-document-direction"
export const Search = () => { export const Search = () => {
const [area, setArea] = useState<SearchArea>("all") const [area, setArea] = useState<SearchArea>("all")
@@ -54,6 +55,7 @@ export const Search = () => {
const { t } = useTranslation() const { t } = useTranslation()
const navigate = useNavigate() const navigate = useNavigate()
const inputRef = useRef<HTMLInputElement>(null) const inputRef = useRef<HTMLInputElement>(null)
const listRef = useRef<HTMLDivElement>(null) const listRef = useRef<HTMLDivElement>(null)
@@ -367,7 +369,7 @@ const CommandInput = forwardRef<
) => { ) => {
const { t } = useTranslation() const { t } = useTranslation()
const innerRef = useRef<HTMLInputElement>(null) const innerRef = useRef<HTMLInputElement>(null)
const direction = useDocumentDirection()
useImperativeHandle<HTMLInputElement | null, HTMLInputElement | null>( useImperativeHandle<HTMLInputElement | null, HTMLInputElement | null>(
ref, ref,
() => innerRef.current () => innerRef.current
@@ -376,7 +378,7 @@ const CommandInput = forwardRef<
return ( return (
<div className="flex flex-col border-b"> <div className="flex flex-col border-b">
<div className="px-4 pt-4"> <div className="px-4 pt-4">
<DropdownMenu> <DropdownMenu dir={direction}>
<DropdownMenu.Trigger asChild> <DropdownMenu.Trigger asChild>
<Badge <Badge
size="2xsmall" size="2xsmall"
@@ -432,7 +434,7 @@ const CommandInput = forwardRef<
)} )}
{...props} {...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 && ( {isFetching && (
<Spinner className="text-ui-fg-muted animate-spin" /> <Spinner className="text-ui-fg-muted animate-spin" />
)} )}
@@ -4,6 +4,8 @@ import { useState } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { useSearchParams } from "react-router-dom" import { useSearchParams } from "react-router-dom"
import { useDocumentDirection } from "../../../../hooks/use-document-direction"
export type DataTableOrderByKey<TData> = { export type DataTableOrderByKey<TData> = {
key: keyof TData key: keyof TData
label: string label: string
@@ -54,6 +56,7 @@ export const DataTableOrderBy = <TData,>({
}>(initState(searchParams, prefix)) }>(initState(searchParams, prefix))
const param = prefix ? `${prefix}_order` : "order" const param = prefix ? `${prefix}_order` : "order"
const { t } = useTranslation() const { t } = useTranslation()
const direction = useDocumentDirection()
const handleDirChange = (dir: string) => { const handleDirChange = (dir: string) => {
setState((prev) => ({ setState((prev) => ({
@@ -97,7 +100,7 @@ export const DataTableOrderBy = <TData,>({
} }
return ( return (
<DropdownMenu> <DropdownMenu dir={direction}>
<DropdownMenu.Trigger asChild> <DropdownMenu.Trigger asChild>
<IconButton size="small"> <IconButton size="small">
<DescendingSorting /> <DescendingSorting />
@@ -262,7 +262,7 @@ export const DataTableRoot = <TData,>({
<Table.Cell <Table.Cell
key={cell.id} key={cell.id}
className={clx({ 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-['']": "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, isStickyCell,
"bg-ui-bg-subtle group-hover/row:bg-ui-bg-subtle-hover": "bg-ui-bg-subtle group-hover/row:bg-ui-bg-subtle-hover":
@@ -288,9 +288,9 @@ export const DataTableRoot = <TData,>({
> >
<div <div
className={clx( 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" /> return <Input {...field} placeholder={placeholder} type="number" />
} }
case "boolean": { case "boolean": {
return <Switch {...field} /> return <Switch className="rtl:rotate-180" dir="ltr" {...field} />
} }
default: { default: {
return ( 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 { I18nProvider as Provider } from "@medusajs/ui"
import { PropsWithChildren } from "react" import { PropsWithChildren, useEffect } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { languages } from "../../i18n/languages" import { languages } from "../../i18n/languages"
@@ -12,9 +12,14 @@ const formatLocaleCode = (code: string) => {
export const I18nProvider = ({ children }: I18nProviderProps) => { export const I18nProvider = ({ children }: I18nProviderProps) => {
const { i18n } = useTranslation() const { i18n } = useTranslation()
const locale = const currentLanguage =
languages.find((lan) => lan.code === i18n.language)?.code || languages.find((lan) => lan.code === i18n.language) || languages[0]
languages[0].code const locale = currentLanguage.code
const direction = currentLanguage.ltr ? "ltr" : "rtl"
useEffect(() => {
document.documentElement.setAttribute("dir", direction)
}, [direction])
return <Provider locale={formatLocaleCode(locale)}>{children}</Provider> 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"> <Container className="flex flex-col gap-y-4 px-6 py-4">
<div className="flex justify-between"> <div className="flex justify-between">
<div className="flex-grow"> <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]"> <div className="bg-ui-bg-component flex size-6 items-center justify-center rounded-[4px]">
<ChartPie className="text-ui-fg-subtle" /> <ChartPie className="text-ui-fg-subtle" />
</div> </div>
</div> </div>
<Heading <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" level="h3"
> >
{t("campaigns.fields.budget_limit")} {t("campaigns.fields.budget_limit")}
@@ -46,7 +46,7 @@ export const CampaignBudget = ({ campaign }: CampaignBudgetProps) => {
<div> <div>
<Text <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" size="small"
leading="compact" leading="compact"
> >
@@ -14,6 +14,7 @@ import { useTranslation } from "react-i18next"
import { Form } from "../../../../../components/common/form" import { Form } from "../../../../../components/common/form"
import { useStore } from "../../../../../hooks/api/store" import { useStore } from "../../../../../hooks/api/store"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
import { import {
currencies, currencies,
getCurrencySymbol, getCurrencySymbol,
@@ -22,7 +23,7 @@ import {
export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => { export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { store } = useStore() const { store } = useStore()
const direction = useDocumentDirection()
const watchValueType = useWatch({ const watchValueType = useWatch({
control: form.control, control: form.control,
name: `${fieldScope}budget.type`, name: `${fieldScope}budget.type`,
@@ -207,6 +208,7 @@ export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="flex gap-y-3" className="flex gap-y-3"
{...field} {...field}
onValueChange={field.onChange} onValueChange={field.onChange}
@@ -250,6 +252,7 @@ export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Select <Select
dir={direction}
{...field} {...field}
onValueChange={onChange} onValueChange={onChange}
disabled={!!fieldScope.length} disabled={!!fieldScope.length}
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next"
import { Form } from "../../../../../components/common/form" import { Form } from "../../../../../components/common/form"
import { HandleInput } from "../../../../../components/inputs/handle-input" import { HandleInput } from "../../../../../components/inputs/handle-input"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
import { CreateCategorySchema } from "./schema" import { CreateCategorySchema } from "./schema"
type CreateCategoryDetailsProps = { type CreateCategoryDetailsProps = {
@@ -12,7 +13,7 @@ type CreateCategoryDetailsProps = {
export const CreateCategoryDetails = ({ form }: CreateCategoryDetailsProps) => { export const CreateCategoryDetails = ({ form }: CreateCategoryDetailsProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const direction = useDocumentDirection()
return ( return (
<div className="flex flex-col items-center p-16"> <div className="flex flex-col items-center p-16">
<div className="flex w-full max-w-[720px] flex-col gap-y-8"> <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.Item>
<Form.Label>{t("categories.fields.status.label")}</Form.Label> <Form.Label>{t("categories.fields.status.label")}</Form.Label>
<Form.Control> <Form.Control>
<Select {...field} onValueChange={onChange}> <Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -109,7 +114,11 @@ export const CreateCategoryDetails = ({ form }: CreateCategoryDetailsProps) => {
{t("categories.fields.visibility.label")} {t("categories.fields.visibility.label")}
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Select {...field} onValueChange={onChange}> <Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -14,6 +14,7 @@ import { transformNullableFormData } from "../../../../../lib/form-helpers"
import { CreateCategoryDetails } from "./create-category-details" import { CreateCategoryDetails } from "./create-category-details"
import { CreateCategoryNesting } from "./create-category-nesting" import { CreateCategoryNesting } from "./create-category-nesting"
import { CreateCategoryDetailsSchema, CreateCategorySchema } from "./schema" import { CreateCategoryDetailsSchema, CreateCategorySchema } from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type CreateCategoryFormProps = { type CreateCategoryFormProps = {
parentCategoryId: string | null parentCategoryId: string | null
@@ -29,7 +30,7 @@ export const CreateCategoryForm = ({
}: CreateCategoryFormProps) => { }: CreateCategoryFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const [activeTab, setActiveTab] = useState<Tab>(Tab.DETAILS) const [activeTab, setActiveTab] = useState<Tab>(Tab.DETAILS)
const [validDetails, setValidDetails] = useState(false) const [validDetails, setValidDetails] = useState(false)
const [shouldFreeze, setShouldFreeze] = useState(false) const [shouldFreeze, setShouldFreeze] = useState(false)
@@ -129,8 +130,8 @@ export const CreateCategoryForm = ({
onSubmit={handleSubmit} onSubmit={handleSubmit}
className="flex size-full flex-col overflow-hidden" className="flex size-full flex-col overflow-hidden"
> >
<ProgressTabs <ProgressTabs
value={activeTab} dir={direction}value={activeTab}
onValueChange={(tab) => handleTabChange(tab as Tab)} onValueChange={(tab) => handleTabChange(tab as Tab)}
className="flex size-full flex-col" className="flex size-full flex-col"
> >
@@ -111,7 +111,7 @@ const PathDisplay = ({
</button> </button>
</Tooltip> </Tooltip>
<div className="flex size-[15px] shrink-0 items-center justify-center"> <div className="flex size-[15px] shrink-0 items-center justify-center">
<TriangleRightMini /> <TriangleRightMini className="rtl:rotate-180" />
</div> </div>
<Text <Text
size="xsmall" size="xsmall"
@@ -10,6 +10,7 @@ import { HandleInput } from "../../../../../components/inputs/handle-input"
import { RouteDrawer, useRouteModal } from "../../../../../components/modals" import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
import { KeyboundForm } from "../../../../../components/utilities/keybound-form" import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useUpdateProductCategory } from "../../../../../hooks/api/categories" import { useUpdateProductCategory } from "../../../../../hooks/api/categories"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
const EditCategorySchema = z.object({ const EditCategorySchema = z.object({
name: z.string().min(1), name: z.string().min(1),
@@ -26,7 +27,7 @@ type EditCategoryFormProps = {
export const EditCategoryForm = ({ category }: EditCategoryFormProps) => { export const EditCategoryForm = ({ category }: EditCategoryFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof EditCategorySchema>>({ const form = useForm<z.infer<typeof EditCategorySchema>>({
defaultValues: { defaultValues: {
name: category.name, name: category.name,
@@ -126,7 +127,11 @@ export const EditCategoryForm = ({ category }: EditCategoryFormProps) => {
{t("categories.fields.status.label")} {t("categories.fields.status.label")}
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Select {...field} onValueChange={onChange}> <Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -155,7 +160,11 @@ export const EditCategoryForm = ({ category }: EditCategoryFormProps) => {
{t("categories.fields.visibility.label")} {t("categories.fields.visibility.label")}
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Select {...field} onValueChange={onChange}> <Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -36,6 +36,7 @@ import {
import { queryClient } from "../../../../../lib/query-client" import { queryClient } from "../../../../../lib/query-client"
import { InventoryAvailabilityForm } from "./inventory-availability-form" import { InventoryAvailabilityForm } from "./inventory-availability-form"
import { CreateInventoryItemSchema } from "./schema" import { CreateInventoryItemSchema } from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
enum Tab { enum Tab {
DETAILS = "details", DETAILS = "details",
@@ -54,7 +55,7 @@ export function InventoryCreateForm({ locations }: InventoryCreateFormProps) {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const [tab, setTab] = useState<Tab>(Tab.DETAILS) const [tab, setTab] = useState<Tab>(Tab.DETAILS)
const direction = useDocumentDirection()
const form = useForm<CreateInventoryItemSchema>({ const form = useForm<CreateInventoryItemSchema>({
defaultValues: { defaultValues: {
title: "", title: "",
@@ -201,6 +202,7 @@ export function InventoryCreateForm({ locations }: InventoryCreateFormProps) {
return ( return (
<RouteFocusModal.Form form={form}> <RouteFocusModal.Form form={form}>
<ProgressTabs <ProgressTabs
dir={direction}
value={tab} value={tab}
className="h-full" className="h-full"
onValueChange={(tab) => onTabChange(tab as Tab)} onValueChange={(tab) => onTabChange(tab as Tab)}
@@ -46,7 +46,7 @@ export const InventoryItemVariantsSection = ({
</span> </span>
</div> </div>
<div className="size-7 flex items-center justify-center"> <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> </div>
</div> </div>
@@ -12,6 +12,7 @@ import { sdk } from "../../../../../lib/client"
import { formatProvider } from "../../../../../lib/format-provider" import { formatProvider } from "../../../../../lib/format-provider"
import { FulfillmentSetType, ShippingOptionPriceType, } from "../../../common/constants" import { FulfillmentSetType, ShippingOptionPriceType, } from "../../../common/constants"
import { CreateShippingOptionSchema } from "./schema" import { CreateShippingOptionSchema } from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type CreateShippingOptionDetailsFormProps = { type CreateShippingOptionDetailsFormProps = {
form: UseFormReturn<CreateShippingOptionSchema> form: UseFormReturn<CreateShippingOptionSchema>
@@ -33,7 +34,7 @@ export const CreateShippingOptionDetailsForm = ({
type, type,
}: CreateShippingOptionDetailsFormProps) => { }: CreateShippingOptionDetailsFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const direction = useDocumentDirection()
const isPickup = type === FulfillmentSetType.Pickup const isPickup = type === FulfillmentSetType.Pickup
const shippingProfiles = useComboboxData({ const shippingProfiles = useComboboxData({
@@ -105,6 +106,7 @@ export const CreateShippingOptionDetailsForm = ({
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="grid grid-cols-1 gap-4 md:grid-cols-2" className="grid grid-cols-1 gap-4 md:grid-cols-2"
{...field} {...field}
onValueChange={field.onChange} onValueChange={field.onChange}
@@ -252,6 +254,7 @@ export const CreateShippingOptionDetailsForm = ({
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Select <Select
dir={direction}
{...field} {...field}
onValueChange={field.onChange} onValueChange={field.onChange}
disabled={!selectedProviderId} disabled={!selectedProviderId}
@@ -24,6 +24,7 @@ import {
CreateShippingOptionSchema, CreateShippingOptionSchema,
} from "./schema" } from "./schema"
import { useFulfillmentProviderOptions } from "../../../../../hooks/api" import { useFulfillmentProviderOptions } from "../../../../../hooks/api"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
enum Tab { enum Tab {
DETAILS = "details", DETAILS = "details",
@@ -48,7 +49,7 @@ export function CreateShippingOptionsForm({
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<CreateShippingOptionSchema>({ const form = useForm<CreateShippingOptionSchema>({
defaultValues: { defaultValues: {
name: "", name: "",
@@ -271,6 +272,7 @@ export function CreateShippingOptionsForm({
}} }}
> >
<ProgressTabs <ProgressTabs
dir={direction}
value={activeTab} value={activeTab}
className="flex h-full flex-col overflow-hidden" className="flex h-full flex-col overflow-hidden"
onValueChange={(tab) => onTabChange(tab as Tab)} onValueChange={(tab) => onTabChange(tab as Tab)}
@@ -20,6 +20,7 @@ import {
ShippingOptionPriceType, ShippingOptionPriceType,
} from "../../../common/constants" } from "../../../common/constants"
import { formatProvider } from "../../../../../lib/format-provider" import { formatProvider } from "../../../../../lib/format-provider"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditShippingOptionFormProps = { type EditShippingOptionFormProps = {
locationId: string locationId: string
@@ -43,7 +44,7 @@ export const EditShippingOptionForm = ({
}: EditShippingOptionFormProps) => { }: EditShippingOptionFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const isPickup = type === FulfillmentSetType.Pickup const isPickup = type === FulfillmentSetType.Pickup
const shippingProfiles = useComboboxData({ const shippingProfiles = useComboboxData({
@@ -147,7 +148,11 @@ export const EditShippingOptionForm = ({
)} )}
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<RadioGroup {...field} onValueChange={field.onChange}> <RadioGroup
dir={direction}
{...field}
onValueChange={field.onChange}
>
<RadioGroup.ChoiceBox <RadioGroup.ChoiceBox
className="flex-1" className="flex-1"
value={ShippingOptionPriceType.FlatRate} value={ShippingOptionPriceType.FlatRate}
@@ -20,6 +20,7 @@ import { queryClient } from "../../../../../lib/query-client"
import { AllocateItemsSchema } from "./constants" import { AllocateItemsSchema } from "./constants"
import { OrderAllocateItemsItem } from "./order-allocate-items-item" import { OrderAllocateItemsItem } from "./order-allocate-items-item"
import { checkInventoryKit } from "./utils" import { checkInventoryKit } from "./utils"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type OrderAllocateItemsFormProps = { type OrderAllocateItemsFormProps = {
order: AdminOrder order: AdminOrder
@@ -28,7 +29,7 @@ type OrderAllocateItemsFormProps = {
export function OrderAllocateItemsForm({ order }: OrderAllocateItemsFormProps) { export function OrderAllocateItemsForm({ order }: OrderAllocateItemsFormProps) {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const [disableSubmit, setDisableSubmit] = useState(false) const [disableSubmit, setDisableSubmit] = useState(false)
const [filterTerm, setFilterTerm] = useState("") const [filterTerm, setFilterTerm] = useState("")
@@ -231,7 +232,11 @@ export function OrderAllocateItemsForm({ order }: OrderAllocateItemsFormProps) {
</div> </div>
<div className="flex-1"> <div className="flex-1">
<Form.Control> <Form.Control>
<Select onValueChange={onChange} {...field}> <Select
dir={direction}
onValueChange={onChange}
{...field}
>
<Select.Trigger <Select.Trigger
className="bg-ui-bg-base" className="bg-ui-bg-base"
ref={ref} ref={ref}
@@ -1028,7 +1028,8 @@ export const ClaimCreateForm = ({
<div className="flex items-center"> <div className="flex items-center">
<Form.Control className="mr-4 self-start"> <Form.Control className="mr-4 self-start">
<Switch <Switch
className="mt-[2px]" dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={!!value} checked={!!value}
onCheckedChange={onChange} onCheckedChange={onChange}
{...field} {...field}
@@ -179,7 +179,8 @@ export const OrderEditCreateForm = ({
<div className="flex items-center"> <div className="flex items-center">
<Form.Control className="mr-4 self-start"> <Form.Control className="mr-4 self-start">
<Switch <Switch
className="mt-[2px]" dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={!!value} checked={!!value}
onCheckedChange={onChange} onCheckedChange={onChange}
{...field} {...field}
@@ -509,7 +509,8 @@ export const ExchangeCreateForm = ({
<div className="flex items-center"> <div className="flex items-center">
<Form.Control className="mr-4 self-start"> <Form.Control className="mr-4 self-start">
<Switch <Switch
className="mt-[2px]" dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={!!value} checked={!!value}
onCheckedChange={onChange} onCheckedChange={onChange}
{...field} {...field}
@@ -26,6 +26,7 @@ import { getReservationsLimitCount } from "../../../../../lib/orders"
import { sdk } from "../../../../../lib/client" import { sdk } from "../../../../../lib/client"
import { useComboboxData } from "../../../../../hooks/use-combobox-data" import { useComboboxData } from "../../../../../hooks/use-combobox-data"
import { Combobox } from "../../../../../components/inputs/combobox" import { Combobox } from "../../../../../components/inputs/combobox"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type OrderCreateFulfillmentFormProps = { type OrderCreateFulfillmentFormProps = {
order: AdminOrder order: AdminOrder
@@ -38,7 +39,7 @@ export function OrderCreateFulfillmentForm({
}: OrderCreateFulfillmentFormProps) { }: OrderCreateFulfillmentFormProps) {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const { mutateAsync: createOrderFulfillment, isPending: isMutating } = const { mutateAsync: createOrderFulfillment, isPending: isMutating } =
useCreateOrderFulfillment(order.id) useCreateOrderFulfillment(order.id)
@@ -288,6 +289,7 @@ export function OrderCreateFulfillmentForm({
<div className="flex-1"> <div className="flex-1">
<Form.Control> <Form.Control>
<Select <Select
dir={direction}
onValueChange={onChange} onValueChange={onChange}
{...field} {...field}
disabled={!selectedLocationId} disabled={!selectedLocationId}
@@ -390,6 +392,8 @@ export function OrderCreateFulfillmentForm({
<Form.Control> <Form.Control>
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
checked={!!value} checked={!!value}
onCheckedChange={onChange} onCheckedChange={onChange}
{...field} {...field}
@@ -23,6 +23,7 @@ import { formatCurrency } from "../../../../../lib/format-currency"
import { formatProvider } from "../../../../../lib/format-provider" import { formatProvider } from "../../../../../lib/format-provider"
import { getLocaleAmount } from "../../../../../lib/money-amount-helpers" import { getLocaleAmount } from "../../../../../lib/money-amount-helpers"
import { getPaymentsFromOrder } from "../../../../../lib/orders" import { getPaymentsFromOrder } from "../../../../../lib/orders"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type CreateRefundFormProps = { type CreateRefundFormProps = {
order: HttpTypes.AdminOrder order: HttpTypes.AdminOrder
@@ -53,6 +54,7 @@ export const CreateRefundForm = ({ order }: CreateRefundFormProps) => {
[order.currency_code] [order.currency_code]
) )
const direction = useDocumentDirection()
const form = useForm<zod.infer<typeof CreateRefundSchema>>({ const form = useForm<zod.infer<typeof CreateRefundSchema>>({
defaultValues: { defaultValues: {
amount: { amount: {
@@ -118,6 +120,7 @@ export const CreateRefundForm = ({ order }: CreateRefundFormProps) => {
<RouteDrawer.Body className="flex-1 overflow-auto"> <RouteDrawer.Body className="flex-1 overflow-auto">
<div className="flex flex-col gap-y-4"> <div className="flex flex-col gap-y-4">
<Select <Select
dir={direction}
value={paymentId} value={paymentId}
onValueChange={(value) => { onValueChange={(value) => {
setPaymentId(value) setPaymentId(value)
@@ -726,7 +726,8 @@ export const ReturnCreateForm = ({
<div className="flex items-center"> <div className="flex items-center">
<Form.Control className="mr-4 self-start"> <Form.Control className="mr-4 self-start">
<Switch <Switch
className="mt-[2px]" dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={!!value} checked={!!value}
onCheckedChange={onChange} onCheckedChange={onChange}
{...field} {...field}
@@ -136,6 +136,8 @@ export function OrderCreateShipmentForm({
<Form.Control> <Form.Control>
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
checked={!!value} checked={!!value}
onCheckedChange={onChange} onCheckedChange={onChange}
{...field} {...field}
@@ -345,7 +345,8 @@ export function OrderReceiveReturnForm({
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Form.Control> <Form.Control>
<Switch <Switch
className="mt-1 self-start" dir="ltr"
className="mt-1 self-start rtl:rotate-180"
checked={!!value} checked={!!value}
onCheckedChange={onChange} onCheckedChange={onChange}
{...field} {...field}
@@ -25,6 +25,7 @@ import {
PricingProductsFields, PricingProductsFields,
PricingProductsSchema, PricingProductsSchema,
} from "./schema" } from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
enum Tab { enum Tab {
DETAIL = "detail", DETAIL = "detail",
@@ -58,7 +59,7 @@ export const PriceListCreateForm = ({
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<PricingCreateSchemaType>({ const form = useForm<PricingCreateSchemaType>({
defaultValues: { defaultValues: {
type: "sale", type: "sale",
@@ -249,6 +250,7 @@ export const PriceListCreateForm = ({
return ( return (
<RouteFocusModal.Form form={form}> <RouteFocusModal.Form form={form}>
<ProgressTabs <ProgressTabs
dir={direction}
value={tab} value={tab}
onValueChange={(tab) => handleChangeTab(tab as Tab)} onValueChange={(tab) => handleChangeTab(tab as Tab)}
className="flex h-full flex-col overflow-hidden" className="flex h-full flex-col overflow-hidden"
@@ -23,6 +23,7 @@ import type {
PricingCreateSchemaType, PricingCreateSchemaType,
PricingCustomerGroupsArrayType, PricingCustomerGroupsArrayType,
} from "./schema" } from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type PriceListDetailsFormProps = { type PriceListDetailsFormProps = {
form: UseFormReturn<PricingCreateSchemaType> form: UseFormReturn<PricingCreateSchemaType>
@@ -30,7 +31,7 @@ type PriceListDetailsFormProps = {
export const PriceListDetailsForm = ({ form }: PriceListDetailsFormProps) => { export const PriceListDetailsForm = ({ form }: PriceListDetailsFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const direction = useDocumentDirection()
const { fields, remove, append } = useFieldArray({ const { fields, remove, append } = useFieldArray({
control: form.control, control: form.control,
name: "rules.customer_group_id", name: "rules.customer_group_id",
@@ -78,6 +79,7 @@ export const PriceListDetailsForm = ({ form }: PriceListDetailsFormProps) => {
</div> </div>
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
onValueChange={onChange} onValueChange={onChange}
{...rest} {...rest}
className="grid grid-cols-1 gap-4 md:grid-cols-2" 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")} {t("priceLists.fields.status.label")}
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Select {...field} onValueChange={onChange}> <Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -16,6 +16,7 @@ import { Form } from "../../../../../components/common/form"
import { RouteDrawer, useRouteModal } from "../../../../../components/modals" import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
import { KeyboundForm } from "../../../../../components/utilities/keybound-form" import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useUpdatePriceList } from "../../../../../hooks/api/price-lists" import { useUpdatePriceList } from "../../../../../hooks/api/price-lists"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
import { PriceListStatus, PriceListType } from "../../../common/constants" import { PriceListStatus, PriceListType } from "../../../common/constants"
type PriceListEditFormProps = { type PriceListEditFormProps = {
@@ -32,7 +33,7 @@ const PriceListEditSchema = z.object({
export const PriceListEditForm = ({ priceList }: PriceListEditFormProps) => { export const PriceListEditForm = ({ priceList }: PriceListEditFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof PriceListEditSchema>>({ const form = useForm<z.infer<typeof PriceListEditSchema>>({
defaultValues: { defaultValues: {
type: priceList.type as PriceListType, type: priceList.type as PriceListType,
@@ -80,7 +81,11 @@ export const PriceListEditForm = ({ priceList }: PriceListEditFormProps) => {
<Form.Hint>{t("priceLists.fields.type.hint")}</Form.Hint> <Form.Hint>{t("priceLists.fields.type.hint")}</Form.Hint>
</div> </div>
<Form.Control> <Form.Control>
<RadioGroup {...field} onValueChange={onChange}> <RadioGroup
dir={direction}
{...field}
onValueChange={onChange}
>
<RadioGroup.ChoiceBox <RadioGroup.ChoiceBox
value={PriceListType.SALE} value={PriceListType.SALE}
label={t("priceLists.fields.type.options.sale.label")} label={t("priceLists.fields.type.options.sale.label")}
@@ -130,7 +135,11 @@ export const PriceListEditForm = ({ priceList }: PriceListEditFormProps) => {
{t("priceLists.fields.status.label")} {t("priceLists.fields.status.label")}
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Select {...field} onValueChange={onChange}> <Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -21,6 +21,7 @@ import {
PriceListPricesAddProductsIdsFields, PriceListPricesAddProductsIdsFields,
PriceListPricesAddSchema, PriceListPricesAddSchema,
} from "./schema" } from "./schema"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type PriceListPricesAddFormProps = { type PriceListPricesAddFormProps = {
priceList: HttpTypes.AdminPriceList priceList: HttpTypes.AdminPriceList
@@ -54,7 +55,7 @@ export const PriceListPricesAddForm = ({
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<PriceListPricesAddSchema>({ const form = useForm<PriceListPricesAddSchema>({
defaultValues: { defaultValues: {
products: {}, products: {},
@@ -90,10 +91,13 @@ export const PriceListPricesAddForm = ({
) => { ) => {
form.clearErrors(fields) form.clearErrors(fields)
const values = fields.reduce((acc, key) => { const values = fields.reduce(
acc[key] = form.getValues(key) (acc, key) => {
return acc acc[key] = form.getValues(key)
}, {} as Record<string, unknown>) return acc
},
{} as Record<string, unknown>
)
const validationResult = schema.safeParse(values) const validationResult = schema.safeParse(values)
@@ -196,6 +200,7 @@ export const PriceListPricesAddForm = ({
return ( return (
<RouteFocusModal.Form form={form}> <RouteFocusModal.Form form={form}>
<ProgressTabs <ProgressTabs
dir={direction}
value={tab} value={tab}
onValueChange={(tab) => handleChangeTab(tab as Tab)} onValueChange={(tab) => handleChangeTab(tab as Tab)}
className="flex h-full flex-col overflow-hidden" className="flex h-full flex-col overflow-hidden"
@@ -269,7 +269,9 @@ export const ProductEditVariantForm = ({
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
checked={value} checked={value}
className="rtl:rotate-180"
onCheckedChange={(checked) => onChange(!!checked)} onCheckedChange={(checked) => onChange(!!checked)}
{...field} {...field}
/> />
@@ -297,6 +299,8 @@ export const ProductEditVariantForm = ({
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
checked={value} checked={value}
onCheckedChange={(checked) => onChange(!!checked)} onCheckedChange={(checked) => onChange(!!checked)}
{...field} {...field}
@@ -277,14 +277,14 @@ export const CategoryCombobox = forwardRef<
e.preventDefault() e.preventDefault()
onChange([]) 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> <span className="tabular-nums">{value.length}</span>
<XMarkMini className="text-ui-fg-muted" /> <XMarkMini className="text-ui-fg-muted" />
</button> </button>
)} )}
{showSelected && ( {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"> <Text size="small" leading="compact">
{t("general.selected")} {t("general.selected")}
</Text> </Text>
@@ -297,13 +297,13 @@ export const CategoryCombobox = forwardRef<
onSearchValueChange(e.target.value) onSearchValueChange(e.target.value)
}} }}
className={clx( 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", "hover:bg-ui-bg-field-hover",
"focus:cursor-text", "focus:cursor-text",
"placeholder:text-ui-fg-muted", "placeholder:text-ui-fg-muted",
{ {
"pl-2": !showTag, "ps-2": !showTag,
"pl-[calc(var(--tag-width)+8px)]": showTag, "ps-[calc(var(--tag-width)+8px)]": showTag,
} }
)} )}
{...props} {...props}
@@ -311,7 +311,7 @@ export const CategoryCombobox = forwardRef<
<button <button
type="button" type="button"
onClick={() => handleOpenChange(true)} 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" /> <TrianglesMini className="text-ui-fg-muted" />
</button> </button>
@@ -321,11 +321,11 @@ export const CategoryCombobox = forwardRef<
sideOffset={4} sideOffset={4}
role="listbox" role="listbox"
className={clx( 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", "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=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-[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) => { onInteractOutside={(e) => {
e.preventDefault() e.preventDefault()
@@ -346,7 +346,7 @@ export const CategoryCombobox = forwardRef<
data-active={focusedIndex === 0} data-active={focusedIndex === 0}
role="button" role="button"
className={clx( 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" "data-[active=true]:bg-ui-bg-field-hover"
)} )}
type="button" type="button"
@@ -386,7 +386,7 @@ export const CategoryCombobox = forwardRef<
type="button" type="button"
role="option" role="option"
className={clx( 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" "data-[active=true]:bg-ui-bg-field-hover"
)} )}
onClick={handleSelect(option)} onClick={handleSelect(option)}
@@ -418,7 +418,7 @@ export const CategoryCombobox = forwardRef<
onClick={handleLevelDown(option)} onClick={handleLevelDown(option)}
tabIndex={-1} tabIndex={-1}
> >
<TriangleRightMini /> <TriangleRightMini className="rtl:rotate-180" />
</button> </button>
)} )}
</div> </div>
@@ -26,6 +26,7 @@ import {
import DetailsTab from "./details-tab" import DetailsTab from "./details-tab"
import InventoryKitTab from "./inventory-kit-tab" import InventoryKitTab from "./inventory-kit-tab"
import PricingTab from "./pricing-tab" import PricingTab from "./pricing-tab"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
enum Tab { enum Tab {
DETAIL = "detail", DETAIL = "detail",
@@ -50,7 +51,7 @@ export const CreateProductVariantForm = ({
}: CreateProductVariantFormProps) => { }: CreateProductVariantFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const [tab, setTab] = useState<Tab>(Tab.DETAIL) const [tab, setTab] = useState<Tab>(Tab.DETAIL)
const [tabState, setTabState] = useState<TabState>(initialTabState) const [tabState, setTabState] = useState<TabState>(initialTabState)
@@ -75,10 +76,13 @@ export const CreateProductVariantForm = ({
return {} return {}
} }
return regions.reduce((acc, reg) => { return regions.reduce(
acc[reg.id] = reg.currency_code (acc, reg) => {
return acc acc[reg.id] = reg.currency_code
}, {} as Record<string, string>) return acc
},
{} as Record<string, string>
)
}, [regions]) }, [regions])
const isManageInventoryEnabled = useWatch({ const isManageInventoryEnabled = useWatch({
@@ -257,6 +261,7 @@ export const CreateProductVariantForm = ({
return ( return (
<RouteFocusModal.Form form={form}> <RouteFocusModal.Form form={form}>
<ProgressTabs <ProgressTabs
dir={direction}
value={tab} value={tab}
onValueChange={(tab) => handleChangeTab(tab as Tab)} onValueChange={(tab) => handleChangeTab(tab as Tab)}
className="flex h-full flex-col overflow-hidden" 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"> <div className="bg-ui-bg-component shadow-elevation-card-rest flex gap-x-3 rounded-lg p-4">
<Form.Control> <Form.Control>
<Switch <Switch
className="mt-[2px]" dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={value} checked={value}
onCheckedChange={(checked) => onChange(!!checked)} onCheckedChange={(checked) => onChange(!!checked)}
{...field} {...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"> <div className="bg-ui-bg-component shadow-elevation-card-rest flex gap-x-3 rounded-lg p-4">
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
checked={value} checked={value}
onCheckedChange={(checked) => onChange(!!checked)} onCheckedChange={(checked) => onChange(!!checked)}
{...field} {...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"> <div className="bg-ui-bg-component shadow-elevation-card-rest flex gap-x-3 rounded-lg p-4">
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
checked={value} checked={value}
onCheckedChange={(checked) => onChange(!!checked)} onCheckedChange={(checked) => onChange(!!checked)}
{...field} {...field}
@@ -21,6 +21,7 @@ import { ProductCreateDetailsForm } from "../product-create-details-form"
import { ProductCreateInventoryKitForm } from "../product-create-inventory-kit-form" import { ProductCreateInventoryKitForm } from "../product-create-inventory-kit-form"
import { ProductCreateOrganizeForm } from "../product-create-organize-form" import { ProductCreateOrganizeForm } from "../product-create-organize-form"
import { ProductCreateVariantsForm } from "../product-create-variants-form" import { ProductCreateVariantsForm } from "../product-create-variants-form"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
enum Tab { enum Tab {
DETAILS = "details", DETAILS = "details",
@@ -58,7 +59,7 @@ export const ProductCreateForm = ({
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const { getFormConfigs } = useExtension() const { getFormConfigs } = useExtension()
const configs = getFormConfigs("product", "create") const configs = getFormConfigs("product", "create")
const direction = useDocumentDirection()
const form = useExtendableForm({ const form = useExtendableForm({
defaultValues: { defaultValues: {
...PRODUCT_CREATE_FORM_DEFAULTS, ...PRODUCT_CREATE_FORM_DEFAULTS,
@@ -244,6 +245,7 @@ export const ProductCreateForm = ({
className="flex h-full flex-col" className="flex h-full flex-col"
> >
<ProgressTabs <ProgressTabs
dir={direction}
value={tab} value={tab}
onValueChange={async (tab) => { onValueChange={async (tab) => {
const valid = await form.trigger() const valid = await form.trigger()
@@ -13,6 +13,7 @@ import { transformNullableFormData } from "../../../../../lib/form-helpers"
import { KeyboundForm } from "../../../../../components/utilities/keybound-form" import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { FormExtensionZone } from "../../../../../dashboard-app" import { FormExtensionZone } from "../../../../../dashboard-app"
import { useExtension } from "../../../../../providers/extension-provider" import { useExtension } from "../../../../../providers/extension-provider"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditProductFormProps = { type EditProductFormProps = {
product: HttpTypes.AdminProduct product: HttpTypes.AdminProduct
@@ -31,7 +32,7 @@ const EditProductSchema = zod.object({
export const EditProductForm = ({ product }: EditProductFormProps) => { export const EditProductForm = ({ product }: EditProductFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const { getFormFields, getFormConfigs } = useExtension() const { getFormFields, getFormConfigs } = useExtension()
const fields = getFormFields("product", "edit") const fields = getFormFields("product", "edit")
const configs = getFormConfigs("product", "edit") const configs = getFormConfigs("product", "edit")
@@ -97,7 +98,11 @@ export const EditProductForm = ({ product }: EditProductFormProps) => {
<Form.Item> <Form.Item>
<Form.Label>{t("fields.status")}</Form.Label> <Form.Label>{t("fields.status")}</Form.Label>
<Form.Control> <Form.Control>
<Select {...field} onValueChange={onChange}> <Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -261,7 +261,7 @@ const Preview = ({
type="button" type="button"
onClick={prev} onClick={prev}
> >
<TriangleLeftMini /> <TriangleLeftMini className="rtl:rotate-180" />
</IconButton> </IconButton>
<div className="flex items-center gap-x-2"> <div className="flex items-center gap-x-2">
{visibleItems.map((item) => { {visibleItems.map((item) => {
@@ -292,7 +292,7 @@ const Preview = ({
type="button" type="button"
onClick={next} onClick={next}
> >
<TriangleRightMini /> <TriangleRightMini className="rtl:rotate-180" />
</IconButton> </IconButton>
</div> </div>
) )
@@ -192,7 +192,8 @@ export const useProductStockColumns = (
return ( return (
<div className="flex size-full items-center gap-x-2"> <div className="flex size-full items-center gap-x-2">
<Switch <Switch
className="shrink-0 cursor-not-allowed" dir="ltr"
className="shrink-0 cursor-not-allowed rtl:rotate-180"
tabIndex={-1} tabIndex={-1}
size="small" size="small"
checked={checked} checked={checked}
@@ -10,6 +10,7 @@ import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
import { KeyboundForm } from "../../../../../components/utilities/keybound-form" import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useUpdateUser } from "../../../../../hooks/api/users" import { useUpdateUser } from "../../../../../hooks/api/users"
import { languages } from "../../../../../i18n/languages" import { languages } from "../../../../../i18n/languages"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditProfileProps = { type EditProfileProps = {
user: HttpTypes.AdminUser user: HttpTypes.AdminUser
@@ -26,7 +27,7 @@ const EditProfileSchema = zod.object({
export const EditProfileForm = ({ user }: EditProfileProps) => { export const EditProfileForm = ({ user }: EditProfileProps) => {
const { t, i18n } = useTranslation() const { t, i18n } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<zod.infer<typeof EditProfileSchema>>({ const form = useForm<zod.infer<typeof EditProfileSchema>>({
defaultValues: { defaultValues: {
first_name: user.first_name ?? "", first_name: user.first_name ?? "",
@@ -111,7 +112,11 @@ export const EditProfileForm = ({ user }: EditProfileProps) => {
</div> </div>
<div> <div>
<Form.Control> <Form.Control>
<Select {...field} onValueChange={field.onChange}> <Select
dir={direction}
{...field}
onValueChange={field.onChange}
>
<Select.Trigger ref={ref} className="py-1 text-[13px]"> <Select.Trigger ref={ref} className="py-1 text-[13px]">
<Select.Value <Select.Value
placeholder={t("profile.edit.languagePlaceholder")} placeholder={t("profile.edit.languagePlaceholder")}
@@ -151,7 +156,8 @@ export const EditProfileForm = ({ user }: EditProfileProps) => {
{t("profile.fields.usageInsightsLabel")} {t("profile.fields.usageInsightsLabel")}
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Switch <Switch dir="ltr"
className="rtl:rotate-180"
{...rest} {...rest}
checked={value} checked={value}
onCheckedChange={onChange} onCheckedChange={onChange}
@@ -14,6 +14,7 @@ import {
usePromotionRuleAttributes, usePromotionRuleAttributes,
usePromotionRules, usePromotionRules,
} from "../../../../../../hooks/api/promotions" } from "../../../../../../hooks/api/promotions"
import { useDocumentDirection } from "../../../../../../hooks/use-document-direction"
import { CreatePromotionSchemaType } from "../../../../promotion-create/components/create-promotion-form/form-schema" import { CreatePromotionSchemaType } from "../../../../promotion-create/components/create-promotion-form/form-schema"
import { generateRuleAttributes } from "../edit-rules-form/utils" import { generateRuleAttributes } from "../edit-rules-form/utils"
import { RuleValueFormField } from "../rule-value-form-field" import { RuleValueFormField } from "../rule-value-form-field"
@@ -44,6 +45,7 @@ export const RulesFormField = ({
const initialRulesSet = useRef(false) const initialRulesSet = useRef(false)
const { t } = useTranslation() const { t } = useTranslation()
const direction = useDocumentDirection()
const formData = form.getValues() const formData = form.getValues()
const { attributes } = usePromotionRuleAttributes( const { attributes } = usePromotionRuleAttributes(
ruleType, ruleType,
@@ -224,6 +226,7 @@ export const RulesFormField = ({
<Form.Control> <Form.Control>
{!disabled ? ( {!disabled ? (
<Select <Select
dir={direction}
{...fieldProps} {...fieldProps}
onValueChange={onValueChange} onValueChange={onValueChange}
disabled={fieldRule.required} disabled={fieldRule.required}
@@ -294,6 +297,7 @@ export const RulesFormField = ({
<Form.Control> <Form.Control>
{!disabled ? ( {!disabled ? (
<Select <Select
dir= {direction}
{...fieldProps} {...fieldProps}
disabled={!fieldRule.attribute} disabled={!fieldRule.attribute}
onValueChange={onChange} onValueChange={onChange}
@@ -11,6 +11,7 @@ import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useUpdatePromotion } from "../../../../../hooks/api/promotions" import { useUpdatePromotion } from "../../../../../hooks/api/promotions"
import { CreateCampaignFormFields } from "../../../../campaigns/common/components/create-campaign-form-fields" import { CreateCampaignFormFields } from "../../../../campaigns/common/components/create-campaign-form-fields"
import { CampaignDetails } from "./campaign-details" import { CampaignDetails } from "./campaign-details"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditPromotionFormProps = { type EditPromotionFormProps = {
promotion: AdminPromotion promotion: AdminPromotion
@@ -43,7 +44,7 @@ export const AddCampaignPromotionFields = ({
}) })
const selectedCampaign = campaigns.find((c) => c.id === watchCampaignId) const selectedCampaign = campaigns.find((c) => c.id === watchCampaignId)
const direction = useDocumentDirection()
return ( return (
<div className="flex flex-col gap-y-8"> <div className="flex flex-col gap-y-8">
<Form.Field <Form.Field
@@ -56,6 +57,7 @@ export const AddCampaignPromotionFields = ({
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="grid grid-cols-1 gap-3" className="grid grid-cols-1 gap-3"
{...field} {...field}
value={field.value} value={field.value}
@@ -105,7 +107,11 @@ export const AddCampaignPromotionFields = ({
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Select onValueChange={onChange} {...field}> <Select
dir={direction}
onValueChange={onChange}
{...field}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -46,6 +46,7 @@ import { AddCampaignPromotionFields } from "../../../promotion-add-campaign/comp
import { Tab } from "./constants" import { Tab } from "./constants"
import { CreatePromotionSchema } from "./form-schema" import { CreatePromotionSchema } from "./form-schema"
import { templates } from "./templates" import { templates } from "./templates"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
const defaultValues = { const defaultValues = {
campaign_id: undefined, campaign_id: undefined,
@@ -80,7 +81,7 @@ export const CreatePromotionForm = () => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof CreatePromotionSchema>>({ const form = useForm<z.infer<typeof CreatePromotionSchema>>({
defaultValues, defaultValues,
resolver: zodResolver(CreatePromotionSchema), resolver: zodResolver(CreatePromotionSchema),
@@ -364,6 +365,7 @@ export const CreatePromotionForm = () => {
<RouteFocusModal.Form form={form}> <RouteFocusModal.Form form={form}>
<KeyboundForm className="flex h-full flex-col" onSubmit={handleSubmit}> <KeyboundForm className="flex h-full flex-col" onSubmit={handleSubmit}>
<ProgressTabs <ProgressTabs
dir={direction}
value={tab} value={tab}
onValueChange={(tab) => handleTabChange(tab as Tab)} onValueChange={(tab) => handleTabChange(tab as Tab)}
className="flex h-full flex-col overflow-hidden" className="flex h-full flex-col overflow-hidden"
@@ -417,6 +419,7 @@ export const CreatePromotionForm = () => {
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
key={"template_id"} key={"template_id"}
className="flex-col gap-y-3" className="flex-col gap-y-3"
{...field} {...field}
@@ -486,6 +489,7 @@ export const CreatePromotionForm = () => {
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="flex gap-y-3" className="flex gap-y-3"
{...field} {...field}
value={field.value} value={field.value}
@@ -530,6 +534,7 @@ export const CreatePromotionForm = () => {
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="flex gap-y-3" className="flex gap-y-3"
{...field} {...field}
value={field.value} value={field.value}
@@ -619,7 +624,8 @@ export const CreatePromotionForm = () => {
</div> </div>
<Form.Control className="mr-2 self-center"> <Form.Control className="mr-2 self-center">
<Switch <Switch
className="mt-[2px]" dir="ltr"
className="mt-[2px] rtl:rotate-180"
checked={!!value} checked={!!value}
onCheckedChange={onChange} onCheckedChange={onChange}
{...field} {...field}
@@ -647,6 +653,7 @@ export const CreatePromotionForm = () => {
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="flex gap-y-3" className="flex gap-y-3"
{...field} {...field}
onValueChange={field.onChange} onValueChange={field.onChange}
@@ -699,7 +706,8 @@ export const CreatePromotionForm = () => {
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
className="flex gap-y-3" dir={direction}
className="flex gap-y-3"
{...field} {...field}
onValueChange={field.onChange} onValueChange={field.onChange}
> >
@@ -889,6 +897,7 @@ export const CreatePromotionForm = () => {
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="flex gap-y-3" className="flex gap-y-3"
{...field} {...field}
onValueChange={field.onChange} onValueChange={field.onChange}
@@ -16,6 +16,7 @@ import {
getCurrencySymbol, getCurrencySymbol,
} from "../../../../../lib/data/currencies" } from "../../../../../lib/data/currencies"
import { SwitchBox } from "../../../../../components/common/switch-box" import { SwitchBox } from "../../../../../components/common/switch-box"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditPromotionFormProps = { type EditPromotionFormProps = {
promotion: AdminPromotion promotion: AdminPromotion
@@ -99,7 +100,7 @@ export const EditPromotionDetailsForm = ({
form.setValue("is_tax_inclusive", false) form.setValue("is_tax_inclusive", false)
} }
}, [allocationWatchValue, form, promotion]) }, [allocationWatchValue, form, promotion])
const direction = useDocumentDirection()
return ( return (
<RouteDrawer.Form form={form}> <RouteDrawer.Form form={form}>
<KeyboundForm <KeyboundForm
@@ -117,6 +118,7 @@ export const EditPromotionDetailsForm = ({
<Form.Label>{t("promotions.form.status.label")}</Form.Label> <Form.Label>{t("promotions.form.status.label")}</Form.Label>
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="flex-col gap-y-3" className="flex-col gap-y-3"
{...field} {...field}
value={field.value} value={field.value}
@@ -162,6 +164,7 @@ export const EditPromotionDetailsForm = ({
<Form.Label>{t("promotions.form.method.label")}</Form.Label> <Form.Label>{t("promotions.form.method.label")}</Form.Label>
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="flex-col gap-y-3" className="flex-col gap-y-3"
{...field} {...field}
value={field.value} value={field.value}
@@ -242,6 +245,7 @@ export const EditPromotionDetailsForm = ({
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="flex-col gap-y-3" className="flex-col gap-y-3"
{...field} {...field}
onValueChange={field.onChange} onValueChange={field.onChange}
@@ -336,6 +340,7 @@ export const EditPromotionDetailsForm = ({
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
dir={direction}
className="flex-col gap-y-3" className="flex-col gap-y-3"
{...field} {...field}
onValueChange={field.onChange} onValueChange={field.onChange}
@@ -37,6 +37,7 @@ import { formatProvider } from "../../../../../lib/format-provider"
import { useCountries } from "../../../common/hooks/use-countries" import { useCountries } from "../../../common/hooks/use-countries"
import { useCountryTableColumns } from "../../../common/hooks/use-country-table-columns" import { useCountryTableColumns } from "../../../common/hooks/use-country-table-columns"
import { useCountryTableQuery } from "../../../common/hooks/use-country-table-query" import { useCountryTableQuery } from "../../../common/hooks/use-country-table-query"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type CreateRegionFormProps = { type CreateRegionFormProps = {
currencies: CurrencyInfo[] currencies: CurrencyInfo[]
@@ -64,7 +65,7 @@ export const CreateRegionForm = ({
const { setIsOpen } = useStackedModal() const { setIsOpen } = useStackedModal()
const [rowSelection, setRowSelection] = useState<RowSelectionState>({}) const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<zod.infer<typeof CreateRegionSchema>>({ const form = useForm<zod.infer<typeof CreateRegionSchema>>({
defaultValues: { defaultValues: {
name: "", name: "",
@@ -226,7 +227,11 @@ export const CreateRegionForm = ({
<Form.Item> <Form.Item>
<Form.Label>{t("fields.currency")}</Form.Label> <Form.Label>{t("fields.currency")}</Form.Label>
<Form.Control> <Form.Control>
<Select {...field} onValueChange={onChange}> <Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -260,6 +265,8 @@ export const CreateRegionForm = ({
<Form.Label>{t("fields.automaticTaxes")}</Form.Label> <Form.Label>{t("fields.automaticTaxes")}</Form.Label>
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
{...field} {...field}
checked={value} checked={value}
onCheckedChange={onChange} onCheckedChange={onChange}
@@ -287,6 +294,8 @@ export const CreateRegionForm = ({
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Switch <Switch
className="rtl:rotate-180"
dir="ltr"
{...field} {...field}
checked={value} checked={value}
onCheckedChange={onChange} onCheckedChange={onChange}
@@ -14,6 +14,7 @@ import { KeyboundForm } from "../../../../../components/utilities/keybound-form/
import { useUpdateRegion } from "../../../../../hooks/api/regions.tsx" import { useUpdateRegion } from "../../../../../hooks/api/regions.tsx"
import { CurrencyInfo } from "../../../../../lib/data/currencies.ts" import { CurrencyInfo } from "../../../../../lib/data/currencies.ts"
import { formatProvider } from "../../../../../lib/format-provider.ts" import { formatProvider } from "../../../../../lib/format-provider.ts"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditRegionFormProps = { type EditRegionFormProps = {
region: HttpTypes.AdminRegion region: HttpTypes.AdminRegion
@@ -42,7 +43,7 @@ export const EditRegionForm = ({
(preference) => (preference) =>
preference.attribute === "region_id" && preference.value === region.id preference.attribute === "region_id" && preference.value === region.id
) )
const direction = useDocumentDirection()
const form = useForm<zod.infer<typeof EditRegionSchema>>({ const form = useForm<zod.infer<typeof EditRegionSchema>>({
defaultValues: { defaultValues: {
name: region.name, name: region.name,
@@ -106,7 +107,11 @@ export const EditRegionForm = ({
<Form.Item> <Form.Item>
<Form.Label>{t("fields.currency")}</Form.Label> <Form.Label>{t("fields.currency")}</Form.Label>
<Form.Control> <Form.Control>
<Select onValueChange={onChange} {...field}> <Select
dir={direction}
onValueChange={onChange}
{...field}
>
<Select.Trigger ref={ref}> <Select.Trigger ref={ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -137,6 +142,8 @@ export const EditRegionForm = ({
<Form.Label>{t("fields.automaticTaxes")}</Form.Label> <Form.Label>{t("fields.automaticTaxes")}</Form.Label>
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
{...field} {...field}
checked={value} checked={value}
onCheckedChange={onChange} onCheckedChange={onChange}
@@ -164,6 +171,8 @@ export const EditRegionForm = ({
</Form.Label> </Form.Label>
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
{...field} {...field}
checked={value} checked={value}
onCheckedChange={onChange} onCheckedChange={onChange}
@@ -10,6 +10,7 @@ import { z } from "zod"
import { Form } from "../../../../../../components/common/form" import { Form } from "../../../../../../components/common/form"
import { KeyboundForm } from "../../../../../../components/utilities/keybound-form" import { KeyboundForm } from "../../../../../../components/utilities/keybound-form"
import { useUpdateReservationItem } from "../../../../../../hooks/api/reservations" import { useUpdateReservationItem } from "../../../../../../hooks/api/reservations"
import { useDocumentDirection } from "../../../../../../hooks/use-document-direction"
type EditReservationFormProps = { type EditReservationFormProps = {
reservation: HttpTypes.AdminReservationResponse["reservation"] reservation: HttpTypes.AdminReservationResponse["reservation"]
@@ -59,7 +60,7 @@ export const EditReservationForm = ({
}: EditReservationFormProps) => { }: EditReservationFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<zod.infer<typeof EditReservationSchema>>({ const form = useForm<zod.infer<typeof EditReservationSchema>>({
defaultValues: getDefaultValues(reservation), defaultValues: getDefaultValues(reservation),
resolver: zodResolver(EditReservationSchema), resolver: zodResolver(EditReservationSchema),
@@ -102,6 +103,7 @@ export const EditReservationForm = ({
<Form.Label>{t("inventory.reservation.location")}</Form.Label> <Form.Label>{t("inventory.reservation.location")}</Form.Label>
<Form.Control> <Form.Control>
<Select <Select
dir={direction}
value={value} value={value}
onValueChange={(v) => { onValueChange={(v) => {
onChange(v) onChange(v)
@@ -119,6 +119,8 @@ export const CreateSalesChannelForm = () => {
<Form.Label>{t("general.enabled")}</Form.Label> <Form.Label>{t("general.enabled")}</Form.Label>
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
{...field} {...field}
checked={value} checked={value}
onCheckedChange={onChange} onCheckedChange={onChange}
@@ -103,6 +103,8 @@ export const EditSalesChannelForm = ({
<Form.Label>{t("general.enabled")}</Form.Label> <Form.Label>{t("general.enabled")}</Form.Label>
<Form.Control> <Form.Control>
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
onCheckedChange={onChange} onCheckedChange={onChange}
checked={value} checked={value}
{...field} {...field}
@@ -287,6 +287,8 @@ const useColumns = (
return ( return (
<div className="flex items-center justify-end"> <div className="flex items-center justify-end">
<Switch <Switch
dir="ltr"
className="rtl:rotate-180"
disabled={isPreSelected} disabled={isPreSelected}
checked={isTaxInclusive ?? false} checked={isTaxInclusive ?? false}
onCheckedChange={(val) => { onCheckedChange={(val) => {
@@ -12,6 +12,7 @@ import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useUpdateStore } from "../../../../../hooks/api/store" import { useUpdateStore } from "../../../../../hooks/api/store"
import { useComboboxData } from "../../../../../hooks/use-combobox-data" import { useComboboxData } from "../../../../../hooks/use-combobox-data"
import { sdk } from "../../../../../lib/client" import { sdk } from "../../../../../lib/client"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type EditStoreFormProps = { type EditStoreFormProps = {
store: HttpTypes.AdminStore store: HttpTypes.AdminStore
@@ -28,7 +29,7 @@ const EditStoreSchema = z.object({
export const EditStoreForm = ({ store }: EditStoreFormProps) => { export const EditStoreForm = ({ store }: EditStoreFormProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof EditStoreSchema>>({ const form = useForm<z.infer<typeof EditStoreSchema>>({
defaultValues: { defaultValues: {
name: store.name, name: store.name,
@@ -118,7 +119,11 @@ export const EditStoreForm = ({ store }: EditStoreFormProps) => {
<Form.Item> <Form.Item>
<Form.Label>{t("store.defaultCurrency")}</Form.Label> <Form.Label>{t("store.defaultCurrency")}</Form.Label>
<Form.Control> <Form.Control>
<Select {...field} onValueChange={onChange}> <Select
dir={direction}
{...field}
onValueChange={onChange}
>
<Select.Trigger ref={field.ref}> <Select.Trigger ref={field.ref}>
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
@@ -36,6 +36,7 @@ import {
TaxRateRuleReferenceSchema, TaxRateRuleReferenceSchema,
} from "../../../common/schemas" } from "../../../common/schemas"
import { createTaxRulePayload } from "../../../common/utils" import { createTaxRulePayload } from "../../../common/utils"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
const TaxRegionCreateTaxOverrideSchema = z.object({ const TaxRegionCreateTaxOverrideSchema = z.object({
name: z.string().min(1), name: z.string().min(1),
@@ -77,7 +78,7 @@ export const TaxRegionCreateTaxOverrideForm = ({
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const { setIsOpen } = useStackedModal() const { setIsOpen } = useStackedModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof TaxRegionCreateTaxOverrideSchema>>({ const form = useForm<z.infer<typeof TaxRegionCreateTaxOverrideSchema>>({
defaultValues: { defaultValues: {
name: "", 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"> <div className="text-ui-fg-subtle grid gap-1.5 px-1.5 md:grid-cols-2">
{isLast ? ( {isLast ? (
<Select <Select
dir={direction}
value={type} value={type}
onValueChange={handleChangeType} onValueChange={handleChangeType}
> >
@@ -37,6 +37,7 @@ import {
} from "../../../common/schemas" } from "../../../common/schemas"
import { createTaxRulePayload } from "../../../common/utils" import { createTaxRulePayload } from "../../../common/utils"
import { InitialRuleValues } from "../../types" import { InitialRuleValues } from "../../types"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
export const DISPLAY_OVERRIDE_ITEMS_LIMIT = 10 export const DISPLAY_OVERRIDE_ITEMS_LIMIT = 10
@@ -81,7 +82,7 @@ export const TaxRegionTaxOverrideEditForm = ({
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const { setIsOpen } = useStackedModal() const { setIsOpen } = useStackedModal()
const direction = useDocumentDirection()
const form = useForm<z.infer<typeof TaxRegionTaxRateEditSchema>>({ const form = useForm<z.infer<typeof TaxRegionTaxRateEditSchema>>({
defaultValues: { defaultValues: {
name: taxRate.name, 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"> <div className="text-ui-fg-subtle grid gap-1.5 px-1.5 md:grid-cols-2">
{isLast ? ( {isLast ? (
<Select <Select
dir={direction}
value={type} value={type}
onValueChange={handleChangeType} onValueChange={handleChangeType}
> >
@@ -18,6 +18,7 @@ import {
STEP_OK_STATES, STEP_OK_STATES,
STEP_SKIPPED_STATES, STEP_SKIPPED_STATES,
} from "../../../constants" } from "../../../constants"
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
type WorkflowExecutionTimelineSectionProps = { type WorkflowExecutionTimelineSectionProps = {
execution: HttpTypes.AdminWorkflowExecutionResponse["workflow_execution"] execution: HttpTypes.AdminWorkflowExecutionResponse["workflow_execution"]
@@ -87,7 +88,7 @@ const Canvas = ({
}) => { }) => {
const [zoom, setZoom] = useState<number>(1) const [zoom, setZoom] = useState<number>(1)
const [isDragging, setIsDragging] = useState(false) const [isDragging, setIsDragging] = useState(false)
const direction = useDocumentDirection()
const scale = useMotionValue(defaultState.scale) const scale = useMotionValue(defaultState.scale)
const x = useMotionValue(defaultState.x) const x = useMotionValue(defaultState.x)
const y = useMotionValue(defaultState.y) const y = useMotionValue(defaultState.y)
@@ -217,7 +218,7 @@ const Canvas = ({
<PlusMini /> <PlusMini />
</button> </button>
<div> <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"> <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 <Text
as="span" as="span"