mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-09 06:59:08 +02:00
* [client] Add RTL layout support to the desktop UI <html dir> follows the active language, Radix primitives get the matching dir, physical spacing/positioning uses logical utilities, and directional icons, animations, arrow-key navigation and tooltip sides flip in RTL. * [client] Address RTL review feedback Force LTR with isolation for monospace values, let truncated names take their direction from their content, and keep the profile name field in the UI direction. * [client] Keep translated monospace labels in their own direction The forced-LTR rule for monospace values now skips elements with an explicit dir, translated development labels use dir=auto, and monospace values rendered through TruncatedText opt into LTR. --------- Co-authored-by: Edward <43848523+thomashacker@users.noreply.github.com>
64 lines
1.8 KiB
TypeScript
64 lines
1.8 KiB
TypeScript
import * as RadioGroup from "@radix-ui/react-radio-group";
|
|
import { createContext, type ReactNode, useContext, useId, useMemo } from "react";
|
|
import { cn } from "@/lib/cn";
|
|
import { useDirection } from "@/hooks/useDirection";
|
|
|
|
type SwitchItemGroupContextValue = {
|
|
value: string;
|
|
layoutId: string;
|
|
};
|
|
|
|
const SwitchItemGroupContext = createContext<SwitchItemGroupContextValue | null>(null);
|
|
|
|
export const useSwitchItemGroup = () => {
|
|
const ctx = useContext(SwitchItemGroupContext);
|
|
if (!ctx) {
|
|
throw new Error("SwitchItem must be used inside a SwitchItemGroup");
|
|
}
|
|
return ctx;
|
|
};
|
|
|
|
type Props = {
|
|
value: string;
|
|
onChange: (value: string) => void;
|
|
children: ReactNode;
|
|
className?: string;
|
|
disabled?: boolean;
|
|
"aria-label"?: string;
|
|
"aria-labelledby"?: string;
|
|
};
|
|
|
|
export const SwitchItemGroup = ({
|
|
value,
|
|
onChange,
|
|
children,
|
|
className,
|
|
disabled = false,
|
|
"aria-label": ariaLabel,
|
|
"aria-labelledby": ariaLabelledBy,
|
|
}: Props) => {
|
|
const layoutId = useId();
|
|
const dir = useDirection();
|
|
const contextValue = useMemo(() => ({ value, layoutId }), [value, layoutId]);
|
|
|
|
return (
|
|
<SwitchItemGroupContext.Provider value={contextValue}>
|
|
<RadioGroup.Root
|
|
dir={dir}
|
|
value={value}
|
|
onValueChange={onChange}
|
|
disabled={disabled}
|
|
aria-label={ariaLabel}
|
|
aria-labelledby={ariaLabelledBy}
|
|
className={cn(
|
|
"flex shrink-0 overflow-hidden rounded-lg border border-nb-gray-800 bg-nb-gray-910 p-1 dark:border-nb-gray-850",
|
|
disabled && "pointer-events-none opacity-50",
|
|
className,
|
|
)}
|
|
>
|
|
{children}
|
|
</RadioGroup.Root>
|
|
</SwitchItemGroupContext.Provider>
|
|
);
|
|
};
|