Segmented Buttons
Описание
Segmented buttons помогают пользователям выбирать параметры, переключать виды или сортировать элементы. Подробная информация на официальном сайте
Если кратко, есть два вида данных кнопок: Single-select и Multi-select.
Первый используется для выбора одной опции, в частности когда требуется переключить отображение (grid - rows), при сортировке.
Второй вариант пригодится для выбора нескольких опций: при фильтрации и похожих задачах.
Примеры
Single-select
1000 рублей = 0$
Multi-select
С иконками
Разные значения высоты
Свойство Density можно использовать в более компактных UI, где пространство ограничено. Density применяется только к высоте.
Компонент
Скопируйте и вставьте код в свой проект.
Обратите внимание, что компонент имеет зависимости таких компонентов как Label и UIStateLayer. Если вы еще не добавили их в свой проект, следует заняться сперва ими.
Также необходимо установить зависимость @radix-ui/react-toggle-group
yarn add @radix-ui/react-toggle-group
Можно сохранить компонент в файл src/shared/ui/SegmentedButton.tsx:
"use client"import React from "react"import * as ToggleGroup from "@radix-ui/react-toggle-group"import { cva, type VariantProps } from "class-variance-authority"import Label from "@/shared/typography/Label"import UIStateLayer from "@/shared/ui/UIStateLayer"import { cn } from "@/lib/cn"const segmentedRootVariants = cva("flex border border-outline rounded-full divide-x divide-outline min-w-[200px]",{variants: {density: {"0": "h-10","-1": "h-9","-2": "h-8","-3": "h-7",},},defaultVariants: {density: "0",},})const SegmentedRoot = React.forwardRef<React.ElementRef<typeof ToggleGroup.Root>,React.ComponentPropsWithoutRef<typeof ToggleGroup.Root> &VariantProps<typeof segmentedRootVariants>>(({ className, density, ...props }, forwardedRef) => (<ToggleGroup.RootclassName={cn(segmentedRootVariants({ density }), className)}{...props}ref={forwardedRef}/>))SegmentedRoot.displayName = "SegmentedRoot"interface SegmentedButtonPropsextends React.ComponentPropsWithoutRef<typeof ToggleGroup.Item> {icon?: React.ReactNode}const SegmentedButton = React.forwardRef<React.ElementRef<typeof ToggleGroup.Item>,SegmentedButtonProps>(({ className, children, icon, ...props }, forwardedRef) => (<ToggleGroup.ItemclassName={cn("group", className)}{...props}ref={forwardedRef}asChild><button className="flex-1 text-onSurface data-[state=on]:text-onSecondaryContainer data-[state=on]:bg-secondaryContainer first:rounded-l-full last:rounded-r-full transition-colors duration-short4 ease-standard"><UIStateLayer className="flex justify-center items-center gap-2 py-2 px-3 bg-onSurface group-data-[state=on]:bg-onSecondaryContainer group-first:rounded-l-full group-last:rounded-r-full group-data-[state=on]:bg-opacity-0 group-data-[state=on]:group-hover:bg-opacity-[0.08] group-data-[state=on]:group-active:bg-opacity-[0.12]">{icon && icon}<Label size={"large"}>{children}</Label></UIStateLayer></button></ToggleGroup.Item>))SegmentedButton.displayName = "SegmentedButton"export { SegmentedButton, SegmentedRoot }
Использование
Обратите внимание, файл экспортирует два компонента: SegmentedRoot и SegmentedButton.
Первый служит в качестве контейнера, второй - в качестве самой кнопки.
Single-select и Multi-select
import { SegmentedButton, SegmentedRoot } from "@/components/ui/SegmentedButton"import { useState } from "react"...const [state, setState] = useState("usd")...<SegmentedRootclassName="w-[500px]"type="single"value={state}onValueChange={(value) => value && setState(value)}><SegmentedButtonname="currency"value="try">Лира</SegmentedButton><SegmentedButtonname="currency"value="usd">Доллары</SegmentedButton><SegmentedButtonname="currency"value="cny">Юань</SegmentedButton></SegmentedRoot>
С иконками
Обратите внимание, что по стайл гайдам размеры иконок уменьшены с 24x24 до 18x18. Вам придётся делать это вручную.
import { List, ViewGrid } from "iconoir-react"...<SegmentedRoot type="single" defaultValue="grid"><SegmentedButtonvalue="grid"icon={<ViewGrid width={18} height={18} />}>Grid</SegmentedButton><SegmentedButtonvalue="list"icon={<List width={18} height={18} />}>List</SegmentedButton></SegmentedRoot>
Density
// Density 0 уровня (по умолчанию)<SegmentedRoot type="single" defaultValue="1"><SegmentedButton value="1">1</SegmentedButton><SegmentedButton value="2">2</SegmentedButton><SegmentedButton value="3">3</SegmentedButton></SegmentedRoot>// Density -1 уровня<SegmentedRoot type="single" defaultValue="1" density="-1"><SegmentedButton value="1">1</SegmentedButton><SegmentedButton value="2">2</SegmentedButton><SegmentedButton value="3">3</SegmentedButton></SegmentedRoot>// Density -2 уровня<SegmentedRoot type="single" defaultValue="1" density="-2"><SegmentedButton value="1">1</SegmentedButton><SegmentedButton value="2">2</SegmentedButton><SegmentedButton value="3">3</SegmentedButton></SegmentedRoot>// Density -3 уровня<SegmentedRoot type="single" defaultValue="1" density="-3"><SegmentedButton value="1">1</SegmentedButton><SegmentedButton value="2">2</SegmentedButton><SegmentedButton value="3">3</SegmentedButton></SegmentedRoot>